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