11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* 2a7707adf9ee8de3c5b67e3793b98888f551ad00dDavid Brownell * serial.c -- USB gadget serial driver 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 4a7707adf9ee8de3c5b67e3793b98888f551ad00dDavid Brownell * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com) 5a7707adf9ee8de3c5b67e3793b98888f551ad00dDavid Brownell * Copyright (C) 2008 by David Brownell 67bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell * Copyright (C) 2008 by Nokia Corporation 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This software is distributed under the terms of the GNU General 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Public License ("GPL") as published by the Free Software Foundation, 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * either version 2 of that License or (at your option) any later version. 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */ 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/utsname.h> 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/device.h> 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty.h> 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/tty_flip.h> 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 19a7707adf9ee8de3c5b67e3793b98888f551ad00dDavid Brownell#include "u_serial.h" 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "gadget_chips.h" 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Defines */ 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 257bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell#define GS_VERSION_STR "v2.4" 267bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell#define GS_VERSION_NUM 0x2400 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GS_LONG_NAME "Gadget Serial" 29a7707adf9ee8de3c5b67e3793b98888f551ad00dDavid Brownell#define GS_VERSION_NAME GS_LONG_NAME " " GS_VERSION_STR 30a7707adf9ee8de3c5b67e3793b98888f551ad00dDavid Brownell 317bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell/*-------------------------------------------------------------------------*/ 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 334e9ba518ec19c6c961bf6074ec05ae1a927230bcDavid Brownell/* 344e9ba518ec19c6c961bf6074ec05ae1a927230bcDavid Brownell * Kbuild is not very cooperative with respect to linking separately 354e9ba518ec19c6c961bf6074ec05ae1a927230bcDavid Brownell * compiled library objects into one module. So for now we won't use 364e9ba518ec19c6c961bf6074ec05ae1a927230bcDavid Brownell * separate compilation ... ensuring init/exit sections work to shrink 374e9ba518ec19c6c961bf6074ec05ae1a927230bcDavid Brownell * the runtime footprint, and giving us at least some parts of what 384e9ba518ec19c6c961bf6074ec05ae1a927230bcDavid Brownell * a "gcc --combine ... part1.c part2.c part3.c ... " build would. 394e9ba518ec19c6c961bf6074ec05ae1a927230bcDavid Brownell */ 404e9ba518ec19c6c961bf6074ec05ae1a927230bcDavid Brownell#include "composite.c" 414e9ba518ec19c6c961bf6074ec05ae1a927230bcDavid Brownell#include "usbstring.c" 424e9ba518ec19c6c961bf6074ec05ae1a927230bcDavid Brownell#include "config.c" 434e9ba518ec19c6c961bf6074ec05ae1a927230bcDavid Brownell#include "epautoconf.c" 444e9ba518ec19c6c961bf6074ec05ae1a927230bcDavid Brownell 454e9ba518ec19c6c961bf6074ec05ae1a927230bcDavid Brownell#include "f_acm.c" 463086775a4916b0fe128d924d83f4e7d7c39e4d0eFelipe Balbi#include "f_obex.c" 474e9ba518ec19c6c961bf6074ec05ae1a927230bcDavid Brownell#include "f_serial.c" 484e9ba518ec19c6c961bf6074ec05ae1a927230bcDavid Brownell#include "u_serial.c" 494e9ba518ec19c6c961bf6074ec05ae1a927230bcDavid Brownell 504e9ba518ec19c6c961bf6074ec05ae1a927230bcDavid Brownell/*-------------------------------------------------------------------------*/ 514e9ba518ec19c6c961bf6074ec05ae1a927230bcDavid Brownell 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Thanks to NetChip Technologies for donating this product ID. 537bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell* 547bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell* DO NOT REUSE THESE IDs with a protocol-incompatible driver!! Ever!! 557bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell* Instead: allocate your own, using normal USB-IF procedures. 567bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell*/ 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GS_VENDOR_ID 0x0525 /* NetChip */ 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GS_PRODUCT_ID 0xa4a6 /* Linux-USB Serial Gadget */ 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define GS_CDC_PRODUCT_ID 0xa4a7 /* ... as CDC-ACM */ 603086775a4916b0fe128d924d83f4e7d7c39e4d0eFelipe Balbi#define GS_CDC_OBEX_PRODUCT_ID 0xa4a9 /* ... as CDC-OBEX */ 611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 627bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell/* string IDs are assigned dynamically */ 631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 647bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell#define STRING_MANUFACTURER_IDX 0 657bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell#define STRING_PRODUCT_IDX 1 667bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell#define STRING_DESCRIPTION_IDX 2 67a7707adf9ee8de3c5b67e3793b98888f551ad00dDavid Brownell 681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic char manufacturer[50]; 697bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell 707bb5ea54be47584869b9a748696e06788c55e28fDavid Brownellstatic struct usb_string strings_dev[] = { 717bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell [STRING_MANUFACTURER_IDX].s = manufacturer, 727bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell [STRING_PRODUCT_IDX].s = GS_VERSION_NAME, 737bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell [STRING_DESCRIPTION_IDX].s = NULL /* updated; f(use_acm) */, 741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds { } /* end of list */ 751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 777bb5ea54be47584869b9a748696e06788c55e28fDavid Brownellstatic struct usb_gadget_strings stringtab_dev = { 787bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell .language = 0x0409, /* en-us */ 797bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell .strings = strings_dev, 801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 827bb5ea54be47584869b9a748696e06788c55e28fDavid Brownellstatic struct usb_gadget_strings *dev_strings[] = { 837bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell &stringtab_dev, 847bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell NULL, 857bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell}; 867bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell 877bb5ea54be47584869b9a748696e06788c55e28fDavid Brownellstatic struct usb_device_descriptor device_desc = { 881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bLength = USB_DT_DEVICE_SIZE, 891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDescriptorType = USB_DT_DEVICE, 90551509d267905705f6d723e51ec706916f06b859Harvey Harrison .bcdUSB = cpu_to_le16(0x0200), 917bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell /* .bDeviceClass = f(use_acm) */ 921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDeviceSubClass = 0, 931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDeviceProtocol = 0, 947bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell /* .bMaxPacketSize0 = f(hardware) */ 95551509d267905705f6d723e51ec706916f06b859Harvey Harrison .idVendor = cpu_to_le16(GS_VENDOR_ID), 967bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell /* .idProduct = f(use_acm) */ 977bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell /* .bcdDevice = f(hardware) */ 987bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell /* .iManufacturer = DYNAMIC */ 997bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell /* .iProduct = DYNAMIC */ 1007bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell .bNumConfigurations = 1, 1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}; 1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1037bb5ea54be47584869b9a748696e06788c55e28fDavid Brownellstatic struct usb_otg_descriptor otg_descriptor = { 1047bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell .bLength = sizeof otg_descriptor, 1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds .bDescriptorType = USB_DT_OTG, 1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1077bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell /* REVISIT SRP-only hardware is possible, although 1087bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell * it would not be called "OTG" ... 1097bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell */ 1107bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell .bmAttributes = USB_OTG_SRP | USB_OTG_HNP, 111a7707adf9ee8de3c5b67e3793b98888f551ad00dDavid Brownell}; 112a7707adf9ee8de3c5b67e3793b98888f551ad00dDavid Brownell 1137bb5ea54be47584869b9a748696e06788c55e28fDavid Brownellstatic const struct usb_descriptor_header *otg_desc[] = { 1147bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell (struct usb_descriptor_header *) &otg_descriptor, 115a7707adf9ee8de3c5b67e3793b98888f551ad00dDavid Brownell NULL, 116a7707adf9ee8de3c5b67e3793b98888f551ad00dDavid Brownell}; 1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 118a7707adf9ee8de3c5b67e3793b98888f551ad00dDavid Brownell/*-------------------------------------------------------------------------*/ 1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 120a7707adf9ee8de3c5b67e3793b98888f551ad00dDavid Brownell/* Module */ 121a7707adf9ee8de3c5b67e3793b98888f551ad00dDavid BrownellMODULE_DESCRIPTION(GS_VERSION_NAME); 122a7707adf9ee8de3c5b67e3793b98888f551ad00dDavid BrownellMODULE_AUTHOR("Al Borchers"); 123a7707adf9ee8de3c5b67e3793b98888f551ad00dDavid BrownellMODULE_AUTHOR("David Brownell"); 124a7707adf9ee8de3c5b67e3793b98888f551ad00dDavid BrownellMODULE_LICENSE("GPL"); 1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 12690ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool use_acm = true; 1277bb5ea54be47584869b9a748696e06788c55e28fDavid Brownellmodule_param(use_acm, bool, 0); 1287bb5ea54be47584869b9a748696e06788c55e28fDavid BrownellMODULE_PARM_DESC(use_acm, "Use CDC ACM, default=yes"); 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 13090ab5ee94171b3e28de6bb42ee30b527014e0be7Rusty Russellstatic bool use_obex = false; 1313086775a4916b0fe128d924d83f4e7d7c39e4d0eFelipe Balbimodule_param(use_obex, bool, 0); 1323086775a4916b0fe128d924d83f4e7d7c39e4d0eFelipe BalbiMODULE_PARM_DESC(use_obex, "Use CDC OBEX, default=no"); 1333086775a4916b0fe128d924d83f4e7d7c39e4d0eFelipe Balbi 1347bb5ea54be47584869b9a748696e06788c55e28fDavid Brownellstatic unsigned n_ports = 1; 1357bb5ea54be47584869b9a748696e06788c55e28fDavid Brownellmodule_param(n_ports, uint, 0); 1367bb5ea54be47584869b9a748696e06788c55e28fDavid BrownellMODULE_PARM_DESC(n_ports, "number of ports to create, default=1"); 1379079e91b5b5a84836e65cdc9128d2602e3beaef2David Brownell 1387bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell/*-------------------------------------------------------------------------*/ 1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 140e12995ec8f8d99f2a339541fc28998af2d60af0fMichal Nazarewiczstatic int __init serial_bind_config(struct usb_configuration *c) 1419079e91b5b5a84836e65cdc9128d2602e3beaef2David Brownell{ 1427bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell unsigned i; 1437bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell int status = 0; 1449079e91b5b5a84836e65cdc9128d2602e3beaef2David Brownell 1457bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell for (i = 0; i < n_ports && status == 0; i++) { 1467bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell if (use_acm) 1477bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell status = acm_bind_config(c, i); 1483086775a4916b0fe128d924d83f4e7d7c39e4d0eFelipe Balbi else if (use_obex) 1493086775a4916b0fe128d924d83f4e7d7c39e4d0eFelipe Balbi status = obex_bind_config(c, i); 1507bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell else 1517bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell status = gser_bind_config(c, i); 1529079e91b5b5a84836e65cdc9128d2602e3beaef2David Brownell } 1537bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell return status; 1549079e91b5b5a84836e65cdc9128d2602e3beaef2David Brownell} 1559079e91b5b5a84836e65cdc9128d2602e3beaef2David Brownell 1567bb5ea54be47584869b9a748696e06788c55e28fDavid Brownellstatic struct usb_configuration serial_config_driver = { 1577bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell /* .label = f(use_acm) */ 1587bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell /* .bConfigurationValue = f(use_acm) */ 1597bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell /* .iConfiguration = DYNAMIC */ 1607bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell .bmAttributes = USB_CONFIG_ATT_SELFPOWER, 1617bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell}; 1627bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell 163e12995ec8f8d99f2a339541fc28998af2d60af0fMichal Nazarewiczstatic int __init gs_bind(struct usb_composite_dev *cdev) 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1657bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell int gcnum; 1667bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell struct usb_gadget *gadget = cdev->gadget; 1677bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell int status; 1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1697bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell status = gserial_setup(cdev->gadget, n_ports); 1707bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell if (status < 0) 1717bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell return status; 172a7707adf9ee8de3c5b67e3793b98888f551ad00dDavid Brownell 1737bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell /* Allocate string descriptor numbers ... note that string 1747bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell * contents can be overridden by the composite_dev glue. 17591e79c91fab10f5790159d8d0c1d16da2a9653f9David Brownell */ 1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1777bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell /* device description: manufacturer, product */ 1787bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell snprintf(manufacturer, sizeof manufacturer, "%s %s with %s", 17996b644bdec977b97a45133e5b4466ba47a7a5e65Serge E. Hallyn init_utsname()->sysname, init_utsname()->release, 1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds gadget->name); 1817bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell status = usb_string_id(cdev); 1827bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell if (status < 0) 1837bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell goto fail; 1847bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell strings_dev[STRING_MANUFACTURER_IDX].id = status; 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1867bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell device_desc.iManufacturer = status; 1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1887bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell status = usb_string_id(cdev); 1897bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell if (status < 0) 1907bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell goto fail; 1917bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell strings_dev[STRING_PRODUCT_IDX].id = status; 1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1937bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell device_desc.iProduct = status; 1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1957bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell /* config description */ 1967bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell status = usb_string_id(cdev); 1977bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell if (status < 0) 1987bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell goto fail; 1997bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell strings_dev[STRING_DESCRIPTION_IDX].id = status; 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2017bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell serial_config_driver.iConfiguration = status; 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2037bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell /* set up other descriptors */ 2047bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell gcnum = usb_gadget_controller_number(gadget); 2057bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell if (gcnum >= 0) 2067bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell device_desc.bcdDevice = cpu_to_le16(GS_VERSION_NUM | gcnum); 2077bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell else { 2087bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell /* this is so simple (for now, no altsettings) that it 2097bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell * SHOULD NOT have problems with bulk-capable hardware. 2107bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell * so warn about unrcognized controllers -- don't panic. 2117bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell * 2127bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell * things like configuration and altsetting numbering 2137bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell * can need hardware-specific attention though. 214f371e750c9324f3498842ee833a0242a11b359e6David Brownell */ 2157bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell pr_warning("gs_bind: controller '%s' not recognized\n", 2167bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell gadget->name); 2177bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell device_desc.bcdDevice = 218551509d267905705f6d723e51ec706916f06b859Harvey Harrison cpu_to_le16(GS_VERSION_NUM | 0x0099); 219f371e750c9324f3498842ee833a0242a11b359e6David Brownell } 220f371e750c9324f3498842ee833a0242a11b359e6David Brownell 2217bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell if (gadget_is_otg(cdev->gadget)) { 2227bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell serial_config_driver.descriptors = otg_desc; 2237bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell serial_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP; 2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2259079e91b5b5a84836e65cdc9128d2602e3beaef2David Brownell 2267bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell /* register our configuration */ 227c9bfff9c98671ad50e4abbfe1ab606a9957f7539Uwe Kleine-König status = usb_add_config(cdev, &serial_config_driver, 228c9bfff9c98671ad50e4abbfe1ab606a9957f7539Uwe Kleine-König serial_bind_config); 2297bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell if (status < 0) 2307bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell goto fail; 2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2327bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell INFO(cdev, "%s\n", GS_VERSION_NAME); 2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2347bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell return 0; 2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2367bb5ea54be47584869b9a748696e06788c55e28fDavid Brownellfail: 2377bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell gserial_cleanup(); 2387bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell return status; 2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2417bb5ea54be47584869b9a748696e06788c55e28fDavid Brownellstatic struct usb_composite_driver gserial_driver = { 2427bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell .name = "g_serial", 2437bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell .dev = &device_desc, 2447bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell .strings = dev_strings, 2456fecfb05c077586ba85aa6f52f10abf30a4bfb40Sebastian Andrzej Siewior .max_speed = USB_SPEED_SUPER, 2469079e91b5b5a84836e65cdc9128d2602e3beaef2David Brownell}; 2479079e91b5b5a84836e65cdc9128d2602e3beaef2David Brownell 2487bb5ea54be47584869b9a748696e06788c55e28fDavid Brownellstatic int __init init(void) 2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2507bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell /* We *could* export two configs; that'd be much cleaner... 2517bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell * but neither of these product IDs was defined that way. 252f371e750c9324f3498842ee833a0242a11b359e6David Brownell */ 2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (use_acm) { 2547bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell serial_config_driver.label = "CDC ACM config"; 2557bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell serial_config_driver.bConfigurationValue = 2; 2567bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell device_desc.bDeviceClass = USB_CLASS_COMM; 2577bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell device_desc.idProduct = 258551509d267905705f6d723e51ec706916f06b859Harvey Harrison cpu_to_le16(GS_CDC_PRODUCT_ID); 2593086775a4916b0fe128d924d83f4e7d7c39e4d0eFelipe Balbi } else if (use_obex) { 2603086775a4916b0fe128d924d83f4e7d7c39e4d0eFelipe Balbi serial_config_driver.label = "CDC OBEX config"; 2613086775a4916b0fe128d924d83f4e7d7c39e4d0eFelipe Balbi serial_config_driver.bConfigurationValue = 3; 2623086775a4916b0fe128d924d83f4e7d7c39e4d0eFelipe Balbi device_desc.bDeviceClass = USB_CLASS_COMM; 2633086775a4916b0fe128d924d83f4e7d7c39e4d0eFelipe Balbi device_desc.idProduct = 264551509d267905705f6d723e51ec706916f06b859Harvey Harrison cpu_to_le16(GS_CDC_OBEX_PRODUCT_ID); 2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } else { 2667bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell serial_config_driver.label = "Generic Serial config"; 2677bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell serial_config_driver.bConfigurationValue = 1; 2687bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC; 2697bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell device_desc.idProduct = 270551509d267905705f6d723e51ec706916f06b859Harvey Harrison cpu_to_le16(GS_PRODUCT_ID); 2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds } 2727bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label; 2739079e91b5b5a84836e65cdc9128d2602e3beaef2David Brownell 27407a18bd716ed5dea336429404b132568cfaaef95Michal Nazarewicz return usb_composite_probe(&gserial_driver, gs_bind); 2759079e91b5b5a84836e65cdc9128d2602e3beaef2David Brownell} 2767bb5ea54be47584869b9a748696e06788c55e28fDavid Brownellmodule_init(init); 2779079e91b5b5a84836e65cdc9128d2602e3beaef2David Brownell 2787bb5ea54be47584869b9a748696e06788c55e28fDavid Brownellstatic void __exit cleanup(void) 2799079e91b5b5a84836e65cdc9128d2602e3beaef2David Brownell{ 2807bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell usb_composite_unregister(&gserial_driver); 2817bb5ea54be47584869b9a748696e06788c55e28fDavid Brownell gserial_cleanup(); 2829079e91b5b5a84836e65cdc9128d2602e3beaef2David Brownell} 2837bb5ea54be47584869b9a748696e06788c55e28fDavid Brownellmodule_exit(cleanup); 284