diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index 64ce7e00e98a0c9c3d6d8d0b70dbe64dc1443c79..b3699afff002f4115b4c3ffaf1b975638aa88f1f 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
  * Copyright (C) 2008 by David Brownell
+ * Copyright (C) 2008 by Nokia Corporation
  *
  * This software is distributed under the terms of the GNU General
  * Public License ("GPL") as published by the Free Software Foundation,
@@ -21,314 +22,79 @@
 
 /* Defines */
 
-#define GS_VERSION_STR			"v2.3"
-#define GS_VERSION_NUM			0x2300
+#define GS_VERSION_STR			"v2.4"
+#define GS_VERSION_NUM			0x2400
 
 #define GS_LONG_NAME			"Gadget Serial"
-#define GS_SHORT_NAME			"g_serial"
-
 #define GS_VERSION_NAME			GS_LONG_NAME " " GS_VERSION_STR
 
-
-/* REVISIT only one port is supported for now;
- * see gs_{send,recv}_packet() ... no multiplexing,
- * and no support for multiple ACM devices.
- */
-#define GS_NUM_PORTS			1
-
-#define GS_NUM_CONFIGS			1
-#define GS_NO_CONFIG_ID			0
-#define GS_BULK_CONFIG_ID		1
-#define GS_ACM_CONFIG_ID		2
-
-#define GS_MAX_NUM_INTERFACES		2
-#define GS_BULK_INTERFACE_ID		0
-#define GS_CONTROL_INTERFACE_ID		0
-#define GS_DATA_INTERFACE_ID		1
-
-#define GS_MAX_DESC_LEN			256
-
-#define GS_DEFAULT_USE_ACM		0
-
-
-/* maxpacket and other transfer characteristics vary by speed. */
-static inline struct usb_endpoint_descriptor *
-choose_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
-		struct usb_endpoint_descriptor *fs)
-{
-	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
-		return hs;
-	return fs;
-}
-
+/*-------------------------------------------------------------------------*/
 
 /* Thanks to NetChip Technologies for donating this product ID.
- *
- * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
- * Instead:  allocate your own, using normal USB-IF procedures.
- */
+*
+* DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
+* Instead:  allocate your own, using normal USB-IF procedures.
+*/
 #define GS_VENDOR_ID			0x0525	/* NetChip */
 #define GS_PRODUCT_ID			0xa4a6	/* Linux-USB Serial Gadget */
 #define GS_CDC_PRODUCT_ID		0xa4a7	/* ... as CDC-ACM */
 
-#define GS_LOG2_NOTIFY_INTERVAL		5	/* 1 << 5 == 32 msec */
-#define GS_NOTIFY_MAXPACKET		8
+/* string IDs are assigned dynamically */
 
-/* the device structure holds info for the USB device */
-struct gs_dev {
-	struct usb_gadget	*dev_gadget;	/* gadget device pointer */
-	spinlock_t		dev_lock;	/* lock for set/reset config */
-	int			dev_config;	/* configuration number */
-	struct usb_request	*dev_ctrl_req;	/* control request */
+#define STRING_MANUFACTURER_IDX		0
+#define STRING_PRODUCT_IDX		1
+#define STRING_DESCRIPTION_IDX		2
 
-	struct gserial		gser;		/* serial/tty port */
-};
-
-
-/* Functions */
-
-/* gadget driver internals */
-static int gs_set_config(struct gs_dev *dev, unsigned config);
-static void gs_reset_config(struct gs_dev *dev);
-static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
-		u8 type, unsigned int index, int is_otg);
-
-static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
-	gfp_t kmalloc_flags);
-static void gs_free_req(struct usb_ep *ep, struct usb_request *req);
-
-/*-------------------------------------------------------------------------*/
-
-/* USB descriptors */
-
-#define GS_MANUFACTURER_STR_ID	1
-#define GS_PRODUCT_STR_ID	2
-#define GS_SERIAL_STR_ID	3
-#define GS_BULK_CONFIG_STR_ID	4
-#define GS_ACM_CONFIG_STR_ID	5
-#define GS_CONTROL_STR_ID	6
-#define GS_DATA_STR_ID		7
-
-/* static strings, in UTF-8 */
 static char manufacturer[50];
-static struct usb_string gs_strings[] = {
-	{ GS_MANUFACTURER_STR_ID, manufacturer },
-	{ GS_PRODUCT_STR_ID, GS_VERSION_NAME },
-	{ GS_BULK_CONFIG_STR_ID, "Gadget Serial Bulk" },
-	{ GS_ACM_CONFIG_STR_ID, "Gadget Serial CDC ACM" },
-	{ GS_CONTROL_STR_ID, "Gadget Serial Control" },
-	{ GS_DATA_STR_ID, "Gadget Serial Data" },
+
+static struct usb_string strings_dev[] = {
+	[STRING_MANUFACTURER_IDX].s = manufacturer,
+	[STRING_PRODUCT_IDX].s = GS_VERSION_NAME,
+	[STRING_DESCRIPTION_IDX].s = NULL /* updated; f(use_acm) */,
 	{  } /* end of list */
 };
 
-static struct usb_gadget_strings gs_string_table = {
-	.language =		0x0409,	/* en-us */
-	.strings =		gs_strings,
+static struct usb_gadget_strings stringtab_dev = {
+	.language	= 0x0409,	/* en-us */
+	.strings	= strings_dev,
 };
 
-static struct usb_device_descriptor gs_device_desc = {
+static struct usb_gadget_strings *dev_strings[] = {
+	&stringtab_dev,
+	NULL,
+};
+
+static struct usb_device_descriptor device_desc = {
 	.bLength =		USB_DT_DEVICE_SIZE,
 	.bDescriptorType =	USB_DT_DEVICE,
 	.bcdUSB =		__constant_cpu_to_le16(0x0200),
+	/* .bDeviceClass = f(use_acm) */
 	.bDeviceSubClass =	0,
 	.bDeviceProtocol =	0,
+	/* .bMaxPacketSize0 = f(hardware) */
 	.idVendor =		__constant_cpu_to_le16(GS_VENDOR_ID),
-	.idProduct =		__constant_cpu_to_le16(GS_PRODUCT_ID),
-	.iManufacturer =	GS_MANUFACTURER_STR_ID,
-	.iProduct =		GS_PRODUCT_STR_ID,
-	.bNumConfigurations =	GS_NUM_CONFIGS,
+	/* .idProduct =	f(use_acm) */
+	/* .bcdDevice = f(hardware) */
+	/* .iManufacturer = DYNAMIC */
+	/* .iProduct = DYNAMIC */
+	.bNumConfigurations =	1,
 };
 
-static struct usb_otg_descriptor gs_otg_descriptor = {
-	.bLength =		sizeof(gs_otg_descriptor),
+static struct usb_otg_descriptor otg_descriptor = {
+	.bLength =		sizeof otg_descriptor,
 	.bDescriptorType =	USB_DT_OTG,
-	.bmAttributes =		USB_OTG_SRP,
-};
 
-static struct usb_config_descriptor gs_bulk_config_desc = {
-	.bLength =		USB_DT_CONFIG_SIZE,
-	.bDescriptorType =	USB_DT_CONFIG,
-	/* .wTotalLength computed dynamically */
-	.bNumInterfaces =	1,
-	.bConfigurationValue =	GS_BULK_CONFIG_ID,
-	.iConfiguration =	GS_BULK_CONFIG_STR_ID,
-	.bmAttributes =		USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
-	.bMaxPower =		1,
-};
-
-static struct usb_config_descriptor gs_acm_config_desc = {
-	.bLength =		USB_DT_CONFIG_SIZE,
-	.bDescriptorType =	USB_DT_CONFIG,
-	/* .wTotalLength computed dynamically */
-	.bNumInterfaces =	2,
-	.bConfigurationValue =	GS_ACM_CONFIG_ID,
-	.iConfiguration =	GS_ACM_CONFIG_STR_ID,
-	.bmAttributes =		USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
-	.bMaxPower =		1,
-};
-
-static const struct usb_interface_descriptor gs_bulk_interface_desc = {
-	.bLength =		USB_DT_INTERFACE_SIZE,
-	.bDescriptorType =	USB_DT_INTERFACE,
-	.bInterfaceNumber =	GS_BULK_INTERFACE_ID,
-	.bNumEndpoints =	2,
-	.bInterfaceClass =	USB_CLASS_VENDOR_SPEC,
-	.bInterfaceSubClass =	0,
-	.bInterfaceProtocol =	0,
-	.iInterface =		GS_DATA_STR_ID,
-};
-
-static const struct usb_interface_descriptor gs_control_interface_desc = {
-	.bLength =		USB_DT_INTERFACE_SIZE,
-	.bDescriptorType =	USB_DT_INTERFACE,
-	.bInterfaceNumber =	GS_CONTROL_INTERFACE_ID,
-	.bNumEndpoints =	1,
-	.bInterfaceClass =	USB_CLASS_COMM,
-	.bInterfaceSubClass =	USB_CDC_SUBCLASS_ACM,
-	.bInterfaceProtocol =	USB_CDC_ACM_PROTO_AT_V25TER,
-	.iInterface =		GS_CONTROL_STR_ID,
-};
-
-static const struct usb_interface_descriptor gs_data_interface_desc = {
-	.bLength =		USB_DT_INTERFACE_SIZE,
-	.bDescriptorType =	USB_DT_INTERFACE,
-	.bInterfaceNumber =	GS_DATA_INTERFACE_ID,
-	.bNumEndpoints =	2,
-	.bInterfaceClass =	USB_CLASS_CDC_DATA,
-	.bInterfaceSubClass =	0,
-	.bInterfaceProtocol =	0,
-	.iInterface =		GS_DATA_STR_ID,
-};
-
-static const struct usb_cdc_header_desc gs_header_desc = {
-	.bLength =		sizeof(gs_header_desc),
-	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubType =	USB_CDC_HEADER_TYPE,
-	.bcdCDC =		__constant_cpu_to_le16(0x0110),
-};
-
-static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = {
-	.bLength =		sizeof(gs_call_mgmt_descriptor),
-	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubType =	USB_CDC_CALL_MANAGEMENT_TYPE,
-	.bmCapabilities =	0,
-	.bDataInterface =	1,	/* index of data interface */
-};
-
-static struct usb_cdc_acm_descriptor gs_acm_descriptor = {
-	.bLength =		sizeof(gs_acm_descriptor),
-	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubType =	USB_CDC_ACM_TYPE,
-	.bmCapabilities =	(1 << 1),
-};
-
-static const struct usb_cdc_union_desc gs_union_desc = {
-	.bLength =		sizeof(gs_union_desc),
-	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubType =	USB_CDC_UNION_TYPE,
-	.bMasterInterface0 =	0,	/* index of control interface */
-	.bSlaveInterface0 =	1,	/* index of data interface */
-};
-
-static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bEndpointAddress =	USB_DIR_IN,
-	.bmAttributes =		USB_ENDPOINT_XFER_INT,
-	.wMaxPacketSize =	__constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
-	.bInterval =		1 << GS_LOG2_NOTIFY_INTERVAL,
-};
-
-static struct usb_endpoint_descriptor gs_fullspeed_in_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bEndpointAddress =	USB_DIR_IN,
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-};
-
-static struct usb_endpoint_descriptor gs_fullspeed_out_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bEndpointAddress =	USB_DIR_OUT,
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-};
-
-static const struct usb_descriptor_header *gs_bulk_fullspeed_function[] = {
-	(struct usb_descriptor_header *) &gs_otg_descriptor,
-	(struct usb_descriptor_header *) &gs_bulk_interface_desc,
-	(struct usb_descriptor_header *) &gs_fullspeed_in_desc,
-	(struct usb_descriptor_header *) &gs_fullspeed_out_desc,
-	NULL,
-};
-
-static const struct usb_descriptor_header *gs_acm_fullspeed_function[] = {
-	(struct usb_descriptor_header *) &gs_otg_descriptor,
-	(struct usb_descriptor_header *) &gs_control_interface_desc,
-	(struct usb_descriptor_header *) &gs_header_desc,
-	(struct usb_descriptor_header *) &gs_call_mgmt_descriptor,
-	(struct usb_descriptor_header *) &gs_acm_descriptor,
-	(struct usb_descriptor_header *) &gs_union_desc,
-	(struct usb_descriptor_header *) &gs_fullspeed_notify_desc,
-	(struct usb_descriptor_header *) &gs_data_interface_desc,
-	(struct usb_descriptor_header *) &gs_fullspeed_in_desc,
-	(struct usb_descriptor_header *) &gs_fullspeed_out_desc,
-	NULL,
-};
-
-static struct usb_endpoint_descriptor gs_highspeed_notify_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bEndpointAddress =	USB_DIR_IN,
-	.bmAttributes =		USB_ENDPOINT_XFER_INT,
-	.wMaxPacketSize =	__constant_cpu_to_le16(GS_NOTIFY_MAXPACKET),
-	.bInterval =		GS_LOG2_NOTIFY_INTERVAL+4,
-};
-
-static struct usb_endpoint_descriptor gs_highspeed_in_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-	.wMaxPacketSize =	__constant_cpu_to_le16(512),
-};
-
-static struct usb_endpoint_descriptor gs_highspeed_out_desc = {
-	.bLength =		USB_DT_ENDPOINT_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-	.wMaxPacketSize =	__constant_cpu_to_le16(512),
-};
-
-static struct usb_qualifier_descriptor gs_qualifier_desc = {
-	.bLength =		sizeof(struct usb_qualifier_descriptor),
-	.bDescriptorType =	USB_DT_DEVICE_QUALIFIER,
-	.bcdUSB =		__constant_cpu_to_le16 (0x0200),
-	/* assumes ep0 uses the same value for both speeds ... */
-	.bNumConfigurations =	GS_NUM_CONFIGS,
-};
-
-static const struct usb_descriptor_header *gs_bulk_highspeed_function[] = {
-	(struct usb_descriptor_header *) &gs_otg_descriptor,
-	(struct usb_descriptor_header *) &gs_bulk_interface_desc,
-	(struct usb_descriptor_header *) &gs_highspeed_in_desc,
-	(struct usb_descriptor_header *) &gs_highspeed_out_desc,
-	NULL,
+	/* REVISIT SRP-only hardware is possible, although
+	 * it would not be called "OTG" ...
+	 */
+	.bmAttributes =		USB_OTG_SRP | USB_OTG_HNP,
 };
 
-static const struct usb_descriptor_header *gs_acm_highspeed_function[] = {
-	(struct usb_descriptor_header *) &gs_otg_descriptor,
-	(struct usb_descriptor_header *) &gs_control_interface_desc,
-	(struct usb_descriptor_header *) &gs_header_desc,
-	(struct usb_descriptor_header *) &gs_call_mgmt_descriptor,
-	(struct usb_descriptor_header *) &gs_acm_descriptor,
-	(struct usb_descriptor_header *) &gs_union_desc,
-	(struct usb_descriptor_header *) &gs_highspeed_notify_desc,
-	(struct usb_descriptor_header *) &gs_data_interface_desc,
-	(struct usb_descriptor_header *) &gs_highspeed_in_desc,
-	(struct usb_descriptor_header *) &gs_highspeed_out_desc,
+static const struct usb_descriptor_header *otg_desc[] = {
+	(struct usb_descriptor_header *) &otg_descriptor,
 	NULL,
 };
 
-
 /*-------------------------------------------------------------------------*/
 
 /* Module */
@@ -337,699 +103,150 @@ MODULE_AUTHOR("Al Borchers");
 MODULE_AUTHOR("David Brownell");
 MODULE_LICENSE("GPL");
 
-static unsigned int use_acm = GS_DEFAULT_USE_ACM;
-module_param(use_acm, uint, S_IRUGO);
-MODULE_PARM_DESC(use_acm, "Use CDC ACM, 0=no, 1=yes, default=no");
+static int use_acm = true;
+module_param(use_acm, bool, 0);
+MODULE_PARM_DESC(use_acm, "Use CDC ACM, default=yes");
 
-/*-------------------------------------------------------------------------*/
+static unsigned n_ports = 1;
+module_param(n_ports, uint, 0);
+MODULE_PARM_DESC(n_ports, "number of ports to create, default=1");
 
-/* Gadget Driver */
+/*-------------------------------------------------------------------------*/
 
-/*
- * gs_unbind
- *
- * Called on module unload.  Frees the control request and device
- * structure.
- */
-static void __exit gs_unbind(struct usb_gadget *gadget)
+static int __init serial_bind_config(struct usb_configuration *c)
 {
-	struct gs_dev *dev = get_gadget_data(gadget);
+	unsigned i;
+	int status = 0;
 
-	/* read/write requests already freed, only control request remains */
-	if (dev != NULL) {
-		if (dev->dev_ctrl_req != NULL) {
-			gs_free_req(gadget->ep0, dev->dev_ctrl_req);
-			dev->dev_ctrl_req = NULL;
-		}
-		gs_reset_config(dev);
-		kfree(dev);
-		set_gadget_data(gadget, NULL);
+	for (i = 0; i < n_ports && status == 0; i++) {
+		if (use_acm)
+			status = acm_bind_config(c, i);
+		else
+			status = gser_bind_config(c, i);
 	}
-
-	pr_info("gs_unbind: %s unbound\n", GS_VERSION_NAME);
-
-	gserial_cleanup();
+	return status;
 }
 
-/*
- * gs_bind
- *
- * Called on module load.  Allocates and initializes the device
- * structure and a control request.
- */
-static int __init gs_bind(struct usb_gadget *gadget)
+static struct usb_configuration serial_config_driver = {
+	/* .label = f(use_acm) */
+	.bind		= serial_bind_config,
+	/* .bConfigurationValue = f(use_acm) */
+	/* .iConfiguration = DYNAMIC */
+	.bmAttributes	= USB_CONFIG_ATT_SELFPOWER,
+	.bMaxPower	= 1,	/* 2 mA, minimal */
+};
+
+static int __init gs_bind(struct usb_composite_dev *cdev)
 {
-	int ret;
-	struct usb_ep *ep;
-	struct gs_dev *dev;
-	int gcnum;
+	int			gcnum;
+	struct usb_gadget	*gadget = cdev->gadget;
+	int			status;
 
-	ret = gserial_setup(gadget, GS_NUM_PORTS);
-	if (ret < 0)
-		return ret;
+	status = gserial_setup(cdev->gadget, n_ports);
+	if (status < 0)
+		return status;
 
-	/* Some controllers can't support CDC ACM:
-	 * - sh doesn't support multiple interfaces or configs;
-	 * - sa1100 doesn't have a third interrupt endpoint
+	/* Allocate string descriptor numbers ... note that string
+	 * contents can be overridden by the composite_dev glue.
 	 */
-	if (gadget_is_sh(gadget) || gadget_is_sa1100(gadget))
-		use_acm = 0;
-
-	gcnum = usb_gadget_controller_number(gadget);
-	if (gcnum >= 0)
-		gs_device_desc.bcdDevice =
-				cpu_to_le16(GS_VERSION_NUM | gcnum);
-	else {
-		pr_warning("gs_bind: controller '%s' not recognized\n",
-			gadget->name);
-		/* unrecognized, but safe unless bulk is REALLY quirky */
-		gs_device_desc.bcdDevice =
-			__constant_cpu_to_le16(GS_VERSION_NUM|0x0099);
-	}
-
-	dev = kzalloc(sizeof(struct gs_dev), GFP_KERNEL);
-	if (dev == NULL) {
-		ret = -ENOMEM;
-		goto autoconf_fail;
-	}
-
-	usb_ep_autoconfig_reset(gadget);
-	ret = -ENXIO;
-
-	ep = usb_ep_autoconfig(gadget, &gs_fullspeed_in_desc);
-	if (!ep)
-		goto autoconf_fail;
-	dev->gser.in = ep;
-	ep->driver_data = dev;	/* claim the endpoint */
-
-	ep = usb_ep_autoconfig(gadget, &gs_fullspeed_out_desc);
-	if (!ep)
-		goto autoconf_fail;
-	dev->gser.out = ep;
-	ep->driver_data = dev;	/* claim the endpoint */
-
-	if (use_acm) {
-		ep = usb_ep_autoconfig(gadget, &gs_fullspeed_notify_desc);
-		if (!ep) {
-			pr_err("gs_bind: cannot run ACM on %s\n", gadget->name);
-			goto autoconf_fail;
-		}
-		gs_device_desc.idProduct = __constant_cpu_to_le16(
-						GS_CDC_PRODUCT_ID),
-		dev->gser.notify = ep;
-		ep->driver_data = dev;	/* claim the endpoint */
-	}
-
-	gs_device_desc.bDeviceClass = use_acm
-		? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
-	gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
-
-	if (gadget_is_dualspeed(gadget)) {
-		gs_qualifier_desc.bDeviceClass = use_acm
-			? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
-		/* assume ep0 uses the same packet size for both speeds */
-		gs_qualifier_desc.bMaxPacketSize0 =
-			gs_device_desc.bMaxPacketSize0;
-		/* assume endpoints are dual-speed */
-		gs_highspeed_notify_desc.bEndpointAddress =
-			gs_fullspeed_notify_desc.bEndpointAddress;
-		gs_highspeed_in_desc.bEndpointAddress =
-			gs_fullspeed_in_desc.bEndpointAddress;
-		gs_highspeed_out_desc.bEndpointAddress =
-			gs_fullspeed_out_desc.bEndpointAddress;
-	}
-
-	usb_gadget_set_selfpowered(gadget);
-
-	if (gadget_is_otg(gadget)) {
-		gs_otg_descriptor.bmAttributes |= USB_OTG_HNP,
-		gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-		gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
-	}
 
-	snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
+	/* device description: manufacturer, product */
+	snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
 		init_utsname()->sysname, init_utsname()->release,
 		gadget->name);
+	status = usb_string_id(cdev);
+	if (status < 0)
+		goto fail;
+	strings_dev[STRING_MANUFACTURER_IDX].id = status;
 
-	dev->dev_gadget = gadget;
-	spin_lock_init(&dev->dev_lock);
-	set_gadget_data(gadget, dev);
-
-	/* preallocate control response and buffer */
-	dev->dev_ctrl_req = gs_alloc_req(gadget->ep0, GS_MAX_DESC_LEN,
-		GFP_KERNEL);
-	if (dev->dev_ctrl_req == NULL) {
-		ret = -ENOMEM;
-		goto autoconf_fail;
-	}
-	gadget->ep0->driver_data = dev;
-
-	pr_info("gs_bind: %s bound\n", GS_VERSION_NAME);
-
-	return 0;
-
-autoconf_fail:
-	kfree(dev);
-	gserial_cleanup();
-	pr_err("gs_bind: to %s, err %d\n", gadget->name, ret);
-	return ret;
-}
-
-static int gs_setup_standard(struct usb_gadget *gadget,
-	const struct usb_ctrlrequest *ctrl)
-{
-	int ret = -EOPNOTSUPP;
-	struct gs_dev *dev = get_gadget_data(gadget);
-	struct usb_request *req = dev->dev_ctrl_req;
-	u16 wIndex = le16_to_cpu(ctrl->wIndex);
-	u16 wValue = le16_to_cpu(ctrl->wValue);
-	u16 wLength = le16_to_cpu(ctrl->wLength);
-
-	switch (ctrl->bRequest) {
-	case USB_REQ_GET_DESCRIPTOR:
-		if (ctrl->bRequestType != USB_DIR_IN)
-			break;
-
-		switch (wValue >> 8) {
-		case USB_DT_DEVICE:
-			ret = min(wLength,
-				(u16)sizeof(struct usb_device_descriptor));
-			memcpy(req->buf, &gs_device_desc, ret);
-			break;
-
-		case USB_DT_DEVICE_QUALIFIER:
-			if (!gadget_is_dualspeed(gadget))
-				break;
-			ret = min(wLength,
-				(u16)sizeof(struct usb_qualifier_descriptor));
-			memcpy(req->buf, &gs_qualifier_desc, ret);
-			break;
-
-		case USB_DT_OTHER_SPEED_CONFIG:
-			if (!gadget_is_dualspeed(gadget))
-				break;
-			/* fall through */
-		case USB_DT_CONFIG:
-			ret = gs_build_config_buf(req->buf, gadget,
-				wValue >> 8, wValue & 0xff,
-				gadget_is_otg(gadget));
-			if (ret >= 0)
-				ret = min(wLength, (u16)ret);
-			break;
-
-		case USB_DT_STRING:
-			/* wIndex == language code. */
-			ret = usb_gadget_get_string(&gs_string_table,
-				wValue & 0xff, req->buf);
-			if (ret >= 0)
-				ret = min(wLength, (u16)ret);
-			break;
-		}
-		break;
+	device_desc.iManufacturer = status;
 
-	case USB_REQ_SET_CONFIGURATION:
-		if (ctrl->bRequestType != 0)
-			break;
-		spin_lock(&dev->dev_lock);
-		ret = gs_set_config(dev, wValue);
-		spin_unlock(&dev->dev_lock);
-		break;
+	status = usb_string_id(cdev);
+	if (status < 0)
+		goto fail;
+	strings_dev[STRING_PRODUCT_IDX].id = status;
 
-	case USB_REQ_GET_CONFIGURATION:
-		if (ctrl->bRequestType != USB_DIR_IN)
-			break;
-		*(u8 *)req->buf = dev->dev_config;
-		ret = min(wLength, (u16)1);
-		break;
+	device_desc.iProduct = status;
 
-	case USB_REQ_SET_INTERFACE:
-		if (ctrl->bRequestType != USB_RECIP_INTERFACE
-				|| !dev->dev_config
-				|| wIndex >= GS_MAX_NUM_INTERFACES)
-			break;
-		if (dev->dev_config == GS_BULK_CONFIG_ID
-				&& wIndex != GS_BULK_INTERFACE_ID)
-			break;
-		/* no alternate interface settings */
-		if (wValue != 0)
-			break;
-		spin_lock(&dev->dev_lock);
-		/* PXA hardware partially handles SET_INTERFACE;
-		 * we need to kluge around that interference.  */
-		if (gadget_is_pxa(gadget)) {
-			ret = gs_set_config(dev, use_acm ?
-				GS_ACM_CONFIG_ID : GS_BULK_CONFIG_ID);
-			goto set_interface_done;
-		}
-		if (dev->dev_config != GS_BULK_CONFIG_ID
-				&& wIndex == GS_CONTROL_INTERFACE_ID) {
-			if (dev->gser.notify) {
-				usb_ep_disable(dev->gser.notify);
-				usb_ep_enable(dev->gser.notify,
-						dev->gser.notify_desc);
-			}
-		} else {
-			gserial_connect(&dev->gser, 0);
-			gserial_disconnect(&dev->gser);
-		}
-		ret = 0;
-set_interface_done:
-		spin_unlock(&dev->dev_lock);
-		break;
+	/* config description */
+	status = usb_string_id(cdev);
+	if (status < 0)
+		goto fail;
+	strings_dev[STRING_DESCRIPTION_IDX].id = status;
 
-	case USB_REQ_GET_INTERFACE:
-		if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)
-		|| dev->dev_config == GS_NO_CONFIG_ID)
-			break;
-		if (wIndex >= GS_MAX_NUM_INTERFACES
-				|| (dev->dev_config == GS_BULK_CONFIG_ID
-				&& wIndex != GS_BULK_INTERFACE_ID)) {
-			ret = -EDOM;
-			break;
-		}
-		/* no alternate interface settings */
-		*(u8 *)req->buf = 0;
-		ret = min(wLength, (u16)1);
-		break;
+	serial_config_driver.iConfiguration = status;
 
-	default:
-		pr_err("gs_setup: unknown standard request, type=%02x, "
-			"request=%02x, value=%04x, index=%04x, length=%d\n",
-			ctrl->bRequestType, ctrl->bRequest,
-			wValue, wIndex, wLength);
-		break;
-	}
-
-	return ret;
-}
-
-static void gs_setup_complete_set_line_coding(struct usb_ep *ep,
-		struct usb_request *req)
-{
-	struct gs_dev *dev = ep->driver_data;
-
-	switch (req->status) {
-	case 0:
-		/* normal completion */
-		if (req->actual != sizeof(dev->gser.port_line_coding))
-			usb_ep_set_halt(ep);
-		else {
-			struct usb_cdc_line_coding	*value = req->buf;
-
-			/* REVISIT:  we currently just remember this data.
-			 * If we change that, (a) validate it first, then
-			 * (b) update whatever hardware needs updating.
-			 */
-			spin_lock(&dev->dev_lock);
-			dev->gser.port_line_coding = *value;
-			spin_unlock(&dev->dev_lock);
-		}
-		break;
-
-	case -ESHUTDOWN:
-		/* disconnect */
-		gs_free_req(ep, req);
-		break;
-
-	default:
-		/* unexpected */
-		break;
-	}
-	return;
-}
-
-static int gs_setup_class(struct usb_gadget *gadget,
-	const struct usb_ctrlrequest *ctrl)
-{
-	int ret = -EOPNOTSUPP;
-	struct gs_dev *dev = get_gadget_data(gadget);
-	struct usb_request *req = dev->dev_ctrl_req;
-	u16 wIndex = le16_to_cpu(ctrl->wIndex);
-	u16 wValue = le16_to_cpu(ctrl->wValue);
-	u16 wLength = le16_to_cpu(ctrl->wLength);
-
-	switch (ctrl->bRequest) {
-	case USB_CDC_REQ_SET_LINE_CODING:
-		if (wLength != sizeof(struct usb_cdc_line_coding))
-			break;
-		ret = wLength;
-		req->complete = gs_setup_complete_set_line_coding;
-		break;
-
-	case USB_CDC_REQ_GET_LINE_CODING:
-		ret = min_t(int, wLength, sizeof(struct usb_cdc_line_coding));
-		spin_lock(&dev->dev_lock);
-		memcpy(req->buf, &dev->gser.port_line_coding, ret);
-		spin_unlock(&dev->dev_lock);
-		break;
-
-	case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
-		if (wLength != 0)
-			break;
-		ret = 0;
-		/* REVISIT:  we currently just remember this data.
-		 * If we change that, update whatever hardware needs
-		 * updating.
-		 */
-		spin_lock(&dev->dev_lock);
-		dev->gser.port_handshake_bits = wValue;
-		spin_unlock(&dev->dev_lock);
-		break;
-
-	default:
-		/* NOTE:  strictly speaking, we should accept AT-commands
-		 * using SEND_ENCPSULATED_COMMAND/GET_ENCAPSULATED_RESPONSE.
-		 * But our call management descriptor says we don't handle
-		 * call management, so we should be able to get by without
-		 * handling those "required" commands (except by stalling).
+	/* set up other descriptors */
+	gcnum = usb_gadget_controller_number(gadget);
+	if (gcnum >= 0)
+		device_desc.bcdDevice = cpu_to_le16(GS_VERSION_NUM | gcnum);
+	else {
+		/* this is so simple (for now, no altsettings) that it
+		 * SHOULD NOT have problems with bulk-capable hardware.
+		 * so warn about unrcognized controllers -- don't panic.
+		 *
+		 * things like configuration and altsetting numbering
+		 * can need hardware-specific attention though.
 		 */
-		pr_err("gs_setup: unknown class request, "
-				"type=%02x, request=%02x, value=%04x, "
-				"index=%04x, length=%d\n",
-			ctrl->bRequestType, ctrl->bRequest,
-			wValue, wIndex, wLength);
-		break;
-	}
-
-	return ret;
-}
-
-/*
- * gs_setup_complete
- */
-static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req)
-{
-	if (req->status || req->actual != req->length) {
-		pr_err("gs_setup_complete: status error, status=%d, "
-			"actual=%d, length=%d\n",
-			req->status, req->actual, req->length);
-	}
-}
-
-/*
- * gs_setup
- *
- * Implements all the control endpoint functionality that's not
- * handled in hardware or the hardware driver.
- *
- * Returns the size of the data sent to the host, or a negative
- * error number.
- */
-static int gs_setup(struct usb_gadget *gadget,
-	const struct usb_ctrlrequest *ctrl)
-{
-	int		ret = -EOPNOTSUPP;
-	struct gs_dev	*dev = get_gadget_data(gadget);
-	struct usb_request *req = dev->dev_ctrl_req;
-	u16		wIndex = le16_to_cpu(ctrl->wIndex);
-	u16		wValue = le16_to_cpu(ctrl->wValue);
-	u16		wLength = le16_to_cpu(ctrl->wLength);
-
-	req->complete = gs_setup_complete;
-
-	switch (ctrl->bRequestType & USB_TYPE_MASK) {
-	case USB_TYPE_STANDARD:
-		ret = gs_setup_standard(gadget, ctrl);
-		break;
-
-	case USB_TYPE_CLASS:
-		ret = gs_setup_class(gadget, ctrl);
-		break;
-
-	default:
-		pr_err("gs_setup: unknown request, type=%02x, request=%02x, "
-			"value=%04x, index=%04x, length=%d\n",
-			ctrl->bRequestType, ctrl->bRequest,
-			wValue, wIndex, wLength);
-		break;
+		pr_warning("gs_bind: controller '%s' not recognized\n",
+			gadget->name);
+		device_desc.bcdDevice =
+			__constant_cpu_to_le16(GS_VERSION_NUM | 0x0099);
 	}
 
-	/* respond with data transfer before status phase? */
-	if (ret >= 0) {
-		req->length = ret;
-		req->zero = ret < wLength
-				&& (ret % gadget->ep0->maxpacket) == 0;
-		ret = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
-		if (ret < 0) {
-			pr_err("gs_setup: cannot queue response, ret=%d\n",
-				ret);
-			req->status = 0;
-			gs_setup_complete(gadget->ep0, req);
-		}
+	if (gadget_is_otg(cdev->gadget)) {
+		serial_config_driver.descriptors = otg_desc;
+		serial_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 	}
 
-	/* device either stalls (ret < 0) or reports success */
-	return ret;
-}
+	/* register our configuration */
+	status = usb_add_config(cdev, &serial_config_driver);
+	if (status < 0)
+		goto fail;
 
-/*
- * gs_disconnect
- *
- * Called when the device is disconnected.  Frees the closed
- * ports and disconnects open ports.  Open ports will be freed
- * on close.  Then reallocates the ports for the next connection.
- */
-static void gs_disconnect(struct usb_gadget *gadget)
-{
-	unsigned long flags;
-	struct gs_dev *dev = get_gadget_data(gadget);
+	INFO(cdev, "%s\n", GS_VERSION_NAME);
 
-	spin_lock_irqsave(&dev->dev_lock, flags);
-	gs_reset_config(dev);
-	spin_unlock_irqrestore(&dev->dev_lock, flags);
+	return 0;
 
-	pr_info("gs_disconnect: %s disconnected\n", GS_LONG_NAME);
+fail:
+	gserial_cleanup();
+	return status;
 }
 
-static struct usb_gadget_driver gs_gadget_driver = {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	.speed =		USB_SPEED_HIGH,
-#else
-	.speed =		USB_SPEED_FULL,
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
-	.function =		GS_LONG_NAME,
-	.bind =			gs_bind,
-	.unbind =		gs_unbind,
-	.setup =		gs_setup,
-	.disconnect =		gs_disconnect,
-	.driver = {
-		.name =		GS_SHORT_NAME,
-		.owner =	THIS_MODULE,
-	},
+static struct usb_composite_driver gserial_driver = {
+	.name		= "g_serial",
+	.dev		= &device_desc,
+	.strings	= dev_strings,
+	.bind		= gs_bind,
 };
 
-/*
- * gs_set_config
- *
- * Configures the device by enabling device specific
- * optimizations, setting up the endpoints, allocating
- * read and write requests and queuing read requests.
- *
- * The device lock must be held when calling this function.
- */
-static int gs_set_config(struct gs_dev *dev, unsigned config)
+static int __init init(void)
 {
-	int ret = 0;
-	struct usb_gadget *gadget = dev->dev_gadget;
-
-	if (config == dev->dev_config)
-		return 0;
-
-	gs_reset_config(dev);
-
-	switch (config) {
-	case GS_NO_CONFIG_ID:
-		return 0;
-	case GS_BULK_CONFIG_ID:
-		if (use_acm)
-			return -EINVAL;
-		break;
-	case GS_ACM_CONFIG_ID:
-		if (!use_acm)
-			return -EINVAL;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	dev->gser.in_desc = choose_ep_desc(gadget,
-			&gs_highspeed_in_desc,
-			&gs_fullspeed_in_desc);
-	dev->gser.out_desc = choose_ep_desc(gadget,
-			&gs_highspeed_out_desc,
-			&gs_fullspeed_out_desc);
-	dev->gser.notify_desc = dev->gser.notify
-		? choose_ep_desc(gadget,
-				&gs_highspeed_notify_desc,
-				&gs_fullspeed_notify_desc)
-		: NULL;
-
-	/* only support one "serial" port for now */
-	if (dev->gser.notify) {
-		ret = usb_ep_enable(dev->gser.notify, dev->gser.notify_desc);
-		if (ret < 0)
-			return ret;
-		dev->gser.notify->driver_data = dev;
-	}
-
-	ret = gserial_connect(&dev->gser, 0);
-	if (ret < 0) {
-		if (dev->gser.notify) {
-			usb_ep_disable(dev->gser.notify);
-			dev->gser.notify->driver_data = NULL;
-		}
-		return ret;
-	}
-
-	dev->dev_config = config;
-
-	/* REVISIT the ACM mode should be able to actually *issue* some
-	 * notifications, for at least serial state change events if
-	 * not also for network connection; say so in bmCapabilities.
+	/* We *could* export two configs; that'd be much cleaner...
+	 * but neither of these product IDs was defined that way.
 	 */
-
-	pr_info("gs_set_config: %s configured, %s speed %s config\n",
-		GS_LONG_NAME,
-		gadget->speed == USB_SPEED_HIGH ? "high" : "full",
-		config == GS_BULK_CONFIG_ID ? "BULK" : "CDC-ACM");
-
-	return 0;
-}
-
-/*
- * gs_reset_config
- *
- * Mark the device as not configured, disable all endpoints,
- * which forces completion of pending I/O and frees queued
- * requests, and free the remaining write requests on the
- * free list.
- *
- * The device lock must be held when calling this function.
- */
-static void gs_reset_config(struct gs_dev *dev)
-{
-	if (dev->dev_config == GS_NO_CONFIG_ID)
-		return;
-
-	dev->dev_config = GS_NO_CONFIG_ID;
-
-	gserial_disconnect(&dev->gser);
-	if (dev->gser.notify) {
-		usb_ep_disable(dev->gser.notify);
-		dev->gser.notify->driver_data = NULL;
-	}
-}
-
-/*
- * gs_build_config_buf
- *
- * Builds the config descriptors in the given buffer and returns the
- * length, or a negative error number.
- */
-static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
-	u8 type, unsigned int index, int is_otg)
-{
-	int len;
-	int high_speed = 0;
-	const struct usb_config_descriptor *config_desc;
-	const struct usb_descriptor_header **function;
-
-	if (index >= gs_device_desc.bNumConfigurations)
-		return -EINVAL;
-
-	/* other speed switches high and full speed */
-	if (gadget_is_dualspeed(g)) {
-		high_speed = (g->speed == USB_SPEED_HIGH);
-		if (type == USB_DT_OTHER_SPEED_CONFIG)
-			high_speed = !high_speed;
-	}
-
 	if (use_acm) {
-		config_desc = &gs_acm_config_desc;
-		function = high_speed
-			? gs_acm_highspeed_function
-			: gs_acm_fullspeed_function;
+		serial_config_driver.label = "CDC ACM config";
+		serial_config_driver.bConfigurationValue = 2;
+		device_desc.bDeviceClass = USB_CLASS_COMM;
+		device_desc.idProduct =
+				__constant_cpu_to_le16(GS_CDC_PRODUCT_ID);
 	} else {
-		config_desc = &gs_bulk_config_desc;
-		function = high_speed
-			? gs_bulk_highspeed_function
-			: gs_bulk_fullspeed_function;
-	}
-
-	/* for now, don't advertise srp-only devices */
-	if (!is_otg)
-		function++;
-
-	len = usb_gadget_config_buf(config_desc, buf, GS_MAX_DESC_LEN, function);
-	if (len < 0)
-		return len;
-
-	((struct usb_config_descriptor *)buf)->bDescriptorType = type;
-
-	return len;
-}
-
-/*
- * gs_alloc_req
- *
- * Allocate a usb_request and its buffer.  Returns a pointer to the
- * usb_request or NULL if there is an error.
- */
-static struct usb_request *
-gs_alloc_req(struct usb_ep *ep, unsigned int len, gfp_t kmalloc_flags)
-{
-	struct usb_request *req;
-
-	if (ep == NULL)
-		return NULL;
-
-	req = usb_ep_alloc_request(ep, kmalloc_flags);
-
-	if (req != NULL) {
-		req->length = len;
-		req->buf = kmalloc(len, kmalloc_flags);
-		if (req->buf == NULL) {
-			usb_ep_free_request(ep, req);
-			return NULL;
-		}
-	}
-
-	return req;
-}
-
-/*
- * gs_free_req
- *
- * Free a usb_request and its buffer.
- */
-static void gs_free_req(struct usb_ep *ep, struct usb_request *req)
-{
-	if (ep != NULL && req != NULL) {
-		kfree(req->buf);
-		usb_ep_free_request(ep, req);
+		serial_config_driver.label = "Generic Serial config";
+		serial_config_driver.bConfigurationValue = 1;
+		device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
+		device_desc.idProduct =
+				__constant_cpu_to_le16(GS_PRODUCT_ID);
 	}
-}
-
-/*-------------------------------------------------------------------------*/
+	strings_dev[STRING_DESCRIPTION_IDX].s = serial_config_driver.label;
 
-/*
- *  gs_module_init
- *
- *  Register as a USB gadget driver and a tty driver.
- */
-static int __init gs_module_init(void)
-{
-	return usb_gadget_register_driver(&gs_gadget_driver);
+	return usb_composite_register(&gserial_driver);
 }
-module_init(gs_module_init);
+module_init(init);
 
-/*
- * gs_module_exit
- *
- * Unregister as a tty driver and a USB gadget driver.
- */
-static void __exit gs_module_exit(void)
+static void __exit cleanup(void)
 {
-	usb_gadget_unregister_driver(&gs_gadget_driver);
+	usb_composite_unregister(&gserial_driver);
+	gserial_cleanup();
 }
-module_exit(gs_module_exit);
+module_exit(cleanup);
diff --git a/drivers/usb/gadget/u_serial.h b/drivers/usb/gadget/u_serial.h
index f9ce3005d751fc9f2f96c0a10c16d8a70bac095b..7b561138f90e06916080d406f7cfab1d655905c3 100644
--- a/drivers/usb/gadget/u_serial.h
+++ b/drivers/usb/gadget/u_serial.h
@@ -41,11 +41,6 @@ struct gserial {
 
 	/* REVISIT avoid this CDC-ACM support harder ... */
 	struct usb_cdc_line_coding port_line_coding;	/* 9600-8-N-1 etc */
-
-	/* FIXME remove these when we switch to acm_bind_config... */
-	struct usb_ep			*notify;
-	struct usb_endpoint_descriptor	*notify_desc;
-	u16				port_handshake_bits;
 };
 
 /* port setup/teardown is handled by gadget driver */