Merge branch 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

* 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (232 commits)
  USB: Add USB-ID for Multiplex RC serial adapter to cp210x.c
  xhci: Clean up 32-bit build warnings.
  USB: update documentation for usbmon
  usb: usb-storage doesn't support dynamic id currently, the patch disables the feature to fix an oops
  drivers/usb/class/cdc-acm.c: clear dangling pointer
  drivers/usb/dwc3/dwc3-pci.c: introduce missing kfree
  drivers/usb/host/isp1760-if.c: introduce missing kfree
  usb: option: add ZD Incorporated HSPA modem
  usb: ch9: fix up MaxStreams helper
  USB: usb-skeleton.c: cleanup open_count
  USB: usb-skeleton.c: fix open/disconnect race
  xhci: Properly handle COMP_2ND_BW_ERR
  USB: remove dead code from suspend/resume path
  USB: add quirk for another camera
  drivers: usb: wusbcore: Fix dependency for USB_WUSB
  xhci: Better debugging for critical host errors.
  xhci: Be less verbose during URB cancellation.
  xhci: Remove debugging about ring structure allocation.
  xhci: Remove debugging about toggling cycle bits.
  xhci: Remove debugging for individual transfers.
  ...
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb
index e647378..b4f5487 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -119,6 +119,31 @@
 		Write a 1 to force the device to disconnect
 		(equivalent to unplugging a wired USB device).
 
+What:		/sys/bus/usb/drivers/.../new_id
+Date:		October 2011
+Contact:	linux-usb@vger.kernel.org
+Description:
+		Writing a device ID to this file will attempt to
+		dynamically add a new device ID to a USB device driver.
+		This may allow the driver to support more hardware than
+		was included in the driver's static device ID support
+		table at compile time. The format for the device ID is:
+		idVendor idProduct bInterfaceClass.
+		The vendor ID and device ID fields are required, the
+		interface class is optional.
+		Upon successfully adding an ID, the driver will probe
+		for the device and attempt to bind to it.  For example:
+		# echo "8086 10f5" > /sys/bus/usb/drivers/foo/new_id
+
+What:		/sys/bus/usb-serial/drivers/.../new_id
+Date:		October 2011
+Contact:	linux-usb@vger.kernel.org
+Description:
+		For serial USB drivers, this attribute appears under the
+		extra bus folder "usb-serial" in sysfs; apart from that
+		difference, all descriptions from the entry
+		"/sys/bus/usb/drivers/.../new_id" apply.
+
 What:		/sys/bus/usb/drivers/.../remove_id
 Date:		November 2009
 Contact:	CHENG Renquan <rqcheng@smu.edu.sg>
diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt
index a1e7f3e..284b442 100644
--- a/Documentation/feature-removal-schedule.txt
+++ b/Documentation/feature-removal-schedule.txt
@@ -523,6 +523,20 @@
 	information log when acer-wmi initial.
 Who:    Lee, Chun-Yi <jlee@novell.com>
 
+---------------------------
+
+What:	/sys/devices/platform/_UDC_/udc/_UDC_/is_dualspeed file and
+	is_dualspeed line in /sys/devices/platform/ci13xxx_*/udc/device file.
+When:	3.8
+Why:	The is_dualspeed file is superseded by maximum_speed in the same
+	directory and is_dualspeed line in device file is superseded by
+	max_speed line in the same file.
+
+	The maximum_speed/max_speed specifies maximum speed supported by UDC.
+	To check if dualspeeed is supported, check if the value is >= 3.
+	Various possible speeds are defined in <linux/usb/ch9.h>.
+Who:	Michal Nazarewicz <mina86@mina86.com>
+
 ----------------------------
 
 What:	The XFS nodelaylog mount option
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index e229769..7b2e5c5 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -2637,6 +2637,10 @@
 			[USB] Start with the old device initialization
 			scheme (default 0 = off).
 
+	usbcore.usbfs_memory_mb=
+			[USB] Memory limit (in MB) for buffers allocated by
+			usbfs (default = 16, 0 = max = 2047).
+
 	usbcore.use_both_schemes=
 			[USB] Try the other device initialization scheme
 			if the first one fails (default 1 = enabled).
diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt
index a4efa04..5335fa8 100644
--- a/Documentation/usb/usbmon.txt
+++ b/Documentation/usb/usbmon.txt
@@ -47,10 +47,11 @@
 
 2. Find which bus connects to the desired device
 
-Run "cat /proc/bus/usb/devices", and find the T-line which corresponds to
-the device. Usually you do it by looking for the vendor string. If you have
-many similar devices, unplug one and compare two /proc/bus/usb/devices outputs.
-The T-line will have a bus number. Example:
+Run "cat /sys/kernel/debug/usb/devices", and find the T-line which corresponds
+to the device. Usually you do it by looking for the vendor string. If you have
+many similar devices, unplug one and compare the two
+/sys/kernel/debug/usb/devices outputs. The T-line will have a bus number.
+Example:
 
 T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 0
 D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
@@ -58,7 +59,10 @@
 S:  Manufacturer=ATEN
 S:  Product=UC100KM V2.00
 
-Bus=03 means it's bus 3.
+"Bus=03" means it's bus 3. Alternatively, you can look at the output from
+"lsusb" and get the bus number from the appropriate line. Example:
+
+Bus 003 Device 002: ID 0557:2004 ATEN UC100KM V2.00
 
 3. Start 'cat'
 
diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c
index cef2cf1..72d76ed 100644
--- a/arch/arm/mach-omap2/board-n8x0.c
+++ b/arch/arm/mach-omap2/board-n8x0.c
@@ -46,7 +46,7 @@
 #define TUSB6010_GPIO_ENABLE	0
 #define TUSB6010_DMACHAN	0x3f
 
-#ifdef CONFIG_USB_MUSB_TUSB6010
+#if defined(CONFIG_USB_MUSB_TUSB6010) || defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
 /*
  * Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and
  * 1.5 V voltage regulators of PM companion chip. Companion chip will then
diff --git a/arch/arm/mach-s3c2416/mach-smdk2416.c b/arch/arm/mach-s3c2416/mach-smdk2416.c
index 66b7173..eebe1e7 100644
--- a/arch/arm/mach-s3c2416/mach-smdk2416.c
+++ b/arch/arm/mach-s3c2416/mach-smdk2416.c
@@ -50,6 +50,7 @@
 #include <plat/nand.h>
 #include <plat/sdhci.h>
 #include <plat/udc.h>
+#include <linux/platform_data/s3c-hsudc.h>
 
 #include <plat/regs-fb-v4.h>
 #include <plat/fb.h>
diff --git a/arch/arm/plat-samsung/devs.c b/arch/arm/plat-samsung/devs.c
index 4ca8b571..92b4c02 100644
--- a/arch/arm/plat-samsung/devs.c
+++ b/arch/arm/plat-samsung/devs.c
@@ -29,6 +29,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mmc/host.h>
 #include <linux/ioport.h>
+#include <linux/platform_data/s3c-hsudc.h>
 
 #include <asm/irq.h>
 #include <asm/pmu.h>
diff --git a/arch/arm/plat-samsung/include/plat/udc.h b/arch/arm/plat-samsung/include/plat/udc.h
index 8c22d58..de8e228 100644
--- a/arch/arm/plat-samsung/include/plat/udc.h
+++ b/arch/arm/plat-samsung/include/plat/udc.h
@@ -37,20 +37,7 @@
 
 extern void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *);
 
-/**
- * s3c24xx_hsudc_platdata - Platform data for USB High-Speed gadget controller.
- * @epnum: Number of endpoints to be instantiated by the controller driver.
- * @gpio_init: Platform specific USB related GPIO initialization.
- * @gpio_uninit: Platform specific USB releted GPIO uninitialzation.
- *
- * Representation of platform data for the S3C24XX USB 2.0 High Speed gadget
- * controllers.
- */
-struct s3c24xx_hsudc_platdata {
-	unsigned int	epnum;
-	void		(*gpio_init)(void);
-	void		(*gpio_uninit)(void);
-};
+struct s3c24xx_hsudc_platdata;
 
 extern void __init s3c24xx_hsudc_set_platdata(struct s3c24xx_hsudc_platdata *pd);
 
diff --git a/drivers/hv/hv_kvp.c b/drivers/hv/hv_kvp.c
index 89f5244..0e8343f 100644
--- a/drivers/hv/hv_kvp.c
+++ b/drivers/hv/hv_kvp.c
@@ -212,11 +212,13 @@
 	 * The windows host expects the key/value pair to be encoded
 	 * in utf16.
 	 */
-	keylen = utf8s_to_utf16s(key_name, strlen(key_name),
-				(wchar_t *)kvp_data->data.key);
+	keylen = utf8s_to_utf16s(key_name, strlen(key_name), UTF16_HOST_ENDIAN,
+				(wchar_t *) kvp_data->data.key,
+				HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2);
 	kvp_data->data.key_size = 2*(keylen + 1); /* utf16 encoding */
-	valuelen = utf8s_to_utf16s(value, strlen(value),
-				(wchar_t *)kvp_data->data.value);
+	valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN,
+				(wchar_t *) kvp_data->data.value,
+				HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2);
 	kvp_data->data.value_size = 2*(valuelen + 1); /* utf16 encoding */
 
 	kvp_data->data.value_type = REG_SZ; /* all our values are strings */
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index 75eca76..53a7bc0 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -6,6 +6,8 @@
 
 obj-$(CONFIG_USB)		+= core/
 
+obj-$(CONFIG_USB_OTG_UTILS)	+= otg/
+
 obj-$(CONFIG_USB_DWC3)		+= dwc3/
 
 obj-$(CONFIG_USB_MON)		+= mon/
@@ -51,7 +53,6 @@
 
 obj-$(CONFIG_USB_MUSB_HDRC)	+= musb/
 obj-$(CONFIG_USB_RENESAS_USBHS)	+= renesas_usbhs/
-obj-$(CONFIG_USB_OTG_UTILS)	+= otg/
 obj-$(CONFIG_USB_GADGET)	+= gadget/
 
 obj-$(CONFIG_USB_COMMON)	+= usb-common.o
diff --git a/drivers/usb/c67x00/c67x00-drv.c b/drivers/usb/c67x00/c67x00-drv.c
index 57ae44c..6f3b6e2 100644
--- a/drivers/usb/c67x00/c67x00-drv.c
+++ b/drivers/usb/c67x00/c67x00-drv.c
@@ -225,21 +225,10 @@
 		.name = "c67x00",
 	},
 };
-MODULE_ALIAS("platform:c67x00");
 
-static int __init c67x00_init(void)
-{
-	return platform_driver_register(&c67x00_driver);
-}
-
-static void __exit c67x00_exit(void)
-{
-	platform_driver_unregister(&c67x00_driver);
-}
-
-module_init(c67x00_init);
-module_exit(c67x00_exit);
+module_platform_driver(c67x00_driver);
 
 MODULE_AUTHOR("Peter Korsgaard, Jan Veldeman, Grant Likely");
 MODULE_DESCRIPTION("Cypress C67X00 USB Controller Driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:c67x00");
diff --git a/drivers/usb/c67x00/c67x00-hcd.c b/drivers/usb/c67x00/c67x00-hcd.c
index d3e1356..75e47b8 100644
--- a/drivers/usb/c67x00/c67x00-hcd.c
+++ b/drivers/usb/c67x00/c67x00-hcd.c
@@ -271,7 +271,6 @@
 	if (int_status & SOFEOP_FLG(sie->sie_num)) {
 		c67x00_ll_usb_clear_status(sie, SOF_EOP_IRQ_FLG);
 		c67x00_sched_kick(c67x00);
-		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
 	}
 }
 
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index a8078d0..9543b19 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -58,12 +58,62 @@
 static struct tty_driver *acm_tty_driver;
 static struct acm *acm_table[ACM_TTY_MINORS];
 
-static DEFINE_MUTEX(open_mutex);
+static DEFINE_MUTEX(acm_table_lock);
 
-#define ACM_READY(acm)	(acm && acm->dev && acm->port.count)
+/*
+ * acm_table accessors
+ */
 
-static const struct tty_port_operations acm_port_ops = {
-};
+/*
+ * Look up an ACM structure by index. If found and not disconnected, increment
+ * its refcount and return it with its mutex held.
+ */
+static struct acm *acm_get_by_index(unsigned index)
+{
+	struct acm *acm;
+
+	mutex_lock(&acm_table_lock);
+	acm = acm_table[index];
+	if (acm) {
+		mutex_lock(&acm->mutex);
+		if (acm->disconnected) {
+			mutex_unlock(&acm->mutex);
+			acm = NULL;
+		} else {
+			tty_port_get(&acm->port);
+			mutex_unlock(&acm->mutex);
+		}
+	}
+	mutex_unlock(&acm_table_lock);
+	return acm;
+}
+
+/*
+ * Try to find an available minor number and if found, associate it with 'acm'.
+ */
+static int acm_alloc_minor(struct acm *acm)
+{
+	int minor;
+
+	mutex_lock(&acm_table_lock);
+	for (minor = 0; minor < ACM_TTY_MINORS; minor++) {
+		if (!acm_table[minor]) {
+			acm_table[minor] = acm;
+			break;
+		}
+	}
+	mutex_unlock(&acm_table_lock);
+
+	return minor;
+}
+
+/* Release the minor number associated with 'acm'.  */
+static void acm_release_minor(struct acm *acm)
+{
+	mutex_lock(&acm_table_lock);
+	acm_table[acm->minor] = NULL;
+	mutex_unlock(&acm_table_lock);
+}
 
 /*
  * Functions for ACM control messages.
@@ -267,9 +317,6 @@
 		goto exit;
 	}
 
-	if (!ACM_READY(acm))
-		goto exit;
-
 	usb_mark_last_busy(acm->dev);
 
 	data = (unsigned char *)(dr + 1);
@@ -429,8 +476,7 @@
 	spin_lock_irqsave(&acm->write_lock, flags);
 	acm_write_done(acm, wb);
 	spin_unlock_irqrestore(&acm->write_lock, flags);
-	if (ACM_READY(acm))
-		schedule_work(&acm->work);
+	schedule_work(&acm->work);
 }
 
 static void acm_softint(struct work_struct *work)
@@ -440,8 +486,6 @@
 
 	dev_vdbg(&acm->data->dev, "%s\n", __func__);
 
-	if (!ACM_READY(acm))
-		return;
 	tty = tty_port_tty_get(&acm->port);
 	if (!tty)
 		return;
@@ -453,93 +497,122 @@
  * TTY handlers
  */
 
-static int acm_tty_open(struct tty_struct *tty, struct file *filp)
+static int acm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
 {
 	struct acm *acm;
-	int rv = -ENODEV;
+	int retval;
 
-	mutex_lock(&open_mutex);
+	dev_dbg(tty->dev, "%s\n", __func__);
 
-	acm = acm_table[tty->index];
-	if (!acm || !acm->dev)
-		goto out;
-	else
-		rv = 0;
+	acm = acm_get_by_index(tty->index);
+	if (!acm)
+		return -ENODEV;
+
+	retval = tty_init_termios(tty);
+	if (retval)
+		goto error_init_termios;
+
+	tty->driver_data = acm;
+
+	/* Final install (we use the default method) */
+	tty_driver_kref_get(driver);
+	tty->count++;
+	driver->ttys[tty->index] = tty;
+
+	return 0;
+
+error_init_termios:
+	tty_port_put(&acm->port);
+	return retval;
+}
+
+static int acm_tty_open(struct tty_struct *tty, struct file *filp)
+{
+	struct acm *acm = tty->driver_data;
+
+	dev_dbg(tty->dev, "%s\n", __func__);
+
+	return tty_port_open(&acm->port, tty, filp);
+}
+
+static int acm_port_activate(struct tty_port *port, struct tty_struct *tty)
+{
+	struct acm *acm = container_of(port, struct acm, port);
+	int retval = -ENODEV;
 
 	dev_dbg(&acm->control->dev, "%s\n", __func__);
 
-	set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
-
-	tty->driver_data = acm;
-	tty_port_tty_set(&acm->port, tty);
-
-	if (usb_autopm_get_interface(acm->control) < 0)
-		goto early_bail;
-	else
-		acm->control->needs_remote_wakeup = 1;
-
 	mutex_lock(&acm->mutex);
-	if (acm->port.count++) {
-		mutex_unlock(&acm->mutex);
-		usb_autopm_put_interface(acm->control);
-		goto out;
-	}
+	if (acm->disconnected)
+		goto disconnected;
+
+	retval = usb_autopm_get_interface(acm->control);
+	if (retval)
+		goto error_get_interface;
+
+	/*
+	 * FIXME: Why do we need this? Allocating 64K of physically contiguous
+	 * memory is really nasty...
+	 */
+	set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
+	acm->control->needs_remote_wakeup = 1;
 
 	acm->ctrlurb->dev = acm->dev;
 	if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
 		dev_err(&acm->control->dev,
 			"%s - usb_submit_urb(ctrl irq) failed\n", __func__);
-		goto bail_out;
+		goto error_submit_urb;
 	}
 
-	if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
+	acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS;
+	if (acm_set_control(acm, acm->ctrlout) < 0 &&
 	    (acm->ctrl_caps & USB_CDC_CAP_LINE))
-		goto bail_out;
+		goto error_set_control;
 
 	usb_autopm_put_interface(acm->control);
 
 	if (acm_submit_read_urbs(acm, GFP_KERNEL))
-		goto bail_out;
-
-	set_bit(ASYNCB_INITIALIZED, &acm->port.flags);
-	rv = tty_port_block_til_ready(&acm->port, tty, filp);
+		goto error_submit_read_urbs;
 
 	mutex_unlock(&acm->mutex);
-out:
-	mutex_unlock(&open_mutex);
-	return rv;
 
-bail_out:
-	acm->port.count--;
-	mutex_unlock(&acm->mutex);
+	return 0;
+
+error_submit_read_urbs:
+	acm->ctrlout = 0;
+	acm_set_control(acm, acm->ctrlout);
+error_set_control:
+	usb_kill_urb(acm->ctrlurb);
+error_submit_urb:
 	usb_autopm_put_interface(acm->control);
-early_bail:
-	mutex_unlock(&open_mutex);
-	tty_port_tty_set(&acm->port, NULL);
-	return -EIO;
+error_get_interface:
+disconnected:
+	mutex_unlock(&acm->mutex);
+	return retval;
 }
 
-static void acm_tty_unregister(struct acm *acm)
+static void acm_port_destruct(struct tty_port *port)
 {
-	int i;
+	struct acm *acm = container_of(port, struct acm, port);
+
+	dev_dbg(&acm->control->dev, "%s\n", __func__);
 
 	tty_unregister_device(acm_tty_driver, acm->minor);
+	acm_release_minor(acm);
 	usb_put_intf(acm->control);
-	acm_table[acm->minor] = NULL;
-	usb_free_urb(acm->ctrlurb);
-	for (i = 0; i < ACM_NW; i++)
-		usb_free_urb(acm->wb[i].urb);
-	for (i = 0; i < acm->rx_buflimit; i++)
-		usb_free_urb(acm->read_urbs[i]);
 	kfree(acm->country_codes);
 	kfree(acm);
 }
 
-static void acm_port_down(struct acm *acm)
+static void acm_port_shutdown(struct tty_port *port)
 {
+	struct acm *acm = container_of(port, struct acm, port);
 	int i;
 
-	if (acm->dev) {
+	dev_dbg(&acm->control->dev, "%s\n", __func__);
+
+	mutex_lock(&acm->mutex);
+	if (!acm->disconnected) {
 		usb_autopm_get_interface(acm->control);
 		acm_set_control(acm, acm->ctrlout = 0);
 		usb_kill_urb(acm->ctrlurb);
@@ -550,40 +623,28 @@
 		acm->control->needs_remote_wakeup = 0;
 		usb_autopm_put_interface(acm->control);
 	}
+	mutex_unlock(&acm->mutex);
+}
+
+static void acm_tty_cleanup(struct tty_struct *tty)
+{
+	struct acm *acm = tty->driver_data;
+	dev_dbg(&acm->control->dev, "%s\n", __func__);
+	tty_port_put(&acm->port);
 }
 
 static void acm_tty_hangup(struct tty_struct *tty)
 {
 	struct acm *acm = tty->driver_data;
+	dev_dbg(&acm->control->dev, "%s\n", __func__);
 	tty_port_hangup(&acm->port);
-	mutex_lock(&open_mutex);
-	acm_port_down(acm);
-	mutex_unlock(&open_mutex);
 }
 
 static void acm_tty_close(struct tty_struct *tty, struct file *filp)
 {
 	struct acm *acm = tty->driver_data;
-
-	/* Perform the closing process and see if we need to do the hardware
-	   shutdown */
-	if (!acm)
-		return;
-
-	mutex_lock(&open_mutex);
-	if (tty_port_close_start(&acm->port, tty, filp) == 0) {
-		if (!acm->dev) {
-			tty_port_tty_set(&acm->port, NULL);
-			acm_tty_unregister(acm);
-			tty->driver_data = NULL;
-		}
-		mutex_unlock(&open_mutex);
-		return;
-	}
-	acm_port_down(acm);
-	tty_port_close_end(&acm->port, tty);
-	tty_port_tty_set(&acm->port, NULL);
-	mutex_unlock(&open_mutex);
+	dev_dbg(&acm->control->dev, "%s\n", __func__);
+	tty_port_close(&acm->port, tty, filp);
 }
 
 static int acm_tty_write(struct tty_struct *tty,
@@ -595,8 +656,6 @@
 	int wbn;
 	struct acm_wb *wb;
 
-	if (!ACM_READY(acm))
-		return -EINVAL;
 	if (!count)
 		return 0;
 
@@ -625,8 +684,6 @@
 static int acm_tty_write_room(struct tty_struct *tty)
 {
 	struct acm *acm = tty->driver_data;
-	if (!ACM_READY(acm))
-		return -EINVAL;
 	/*
 	 * Do not let the line discipline to know that we have a reserve,
 	 * or it might get too enthusiastic.
@@ -637,7 +694,11 @@
 static int acm_tty_chars_in_buffer(struct tty_struct *tty)
 {
 	struct acm *acm = tty->driver_data;
-	if (!ACM_READY(acm))
+	/*
+	 * if the device was unplugged then any remaining characters fell out
+	 * of the connector ;)
+	 */
+	if (acm->disconnected)
 		return 0;
 	/*
 	 * This is inaccurate (overcounts), but it works.
@@ -649,9 +710,6 @@
 {
 	struct acm *acm = tty->driver_data;
 
-	if (!ACM_READY(acm))
-		return;
-
 	spin_lock_irq(&acm->read_lock);
 	acm->throttle_req = 1;
 	spin_unlock_irq(&acm->read_lock);
@@ -662,9 +720,6 @@
 	struct acm *acm = tty->driver_data;
 	unsigned int was_throttled;
 
-	if (!ACM_READY(acm))
-		return;
-
 	spin_lock_irq(&acm->read_lock);
 	was_throttled = acm->throttled;
 	acm->throttled = 0;
@@ -679,8 +734,7 @@
 {
 	struct acm *acm = tty->driver_data;
 	int retval;
-	if (!ACM_READY(acm))
-		return -EINVAL;
+
 	retval = acm_send_break(acm, state ? 0xffff : 0);
 	if (retval < 0)
 		dev_dbg(&acm->control->dev, "%s - send break failed\n",
@@ -692,9 +746,6 @@
 {
 	struct acm *acm = tty->driver_data;
 
-	if (!ACM_READY(acm))
-		return -EINVAL;
-
 	return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
 	       (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
 	       (acm->ctrlin  & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
@@ -709,9 +760,6 @@
 	struct acm *acm = tty->driver_data;
 	unsigned int newctrl;
 
-	if (!ACM_READY(acm))
-		return -EINVAL;
-
 	newctrl = acm->ctrlout;
 	set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
 					(set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
@@ -728,11 +776,6 @@
 static int acm_tty_ioctl(struct tty_struct *tty,
 					unsigned int cmd, unsigned long arg)
 {
-	struct acm *acm = tty->driver_data;
-
-	if (!ACM_READY(acm))
-		return -EINVAL;
-
 	return -ENOIOCTLCMD;
 }
 
@@ -756,9 +799,6 @@
 	struct usb_cdc_line_coding newline;
 	int newctrl = acm->ctrlout;
 
-	if (!ACM_READY(acm))
-		return;
-
 	newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty));
 	newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
 	newline.bParityType = termios->c_cflag & PARENB ?
@@ -788,6 +828,12 @@
 	}
 }
 
+static const struct tty_port_operations acm_port_ops = {
+	.shutdown = acm_port_shutdown,
+	.activate = acm_port_activate,
+	.destruct = acm_port_destruct,
+};
+
 /*
  * USB probe and disconnect routines.
  */
@@ -1047,12 +1093,6 @@
 	}
 made_compressed_probe:
 	dev_dbg(&intf->dev, "interfaces are valid\n");
-	for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
-
-	if (minor == ACM_TTY_MINORS) {
-		dev_err(&intf->dev, "no more free acm devices\n");
-		return -ENODEV;
-	}
 
 	acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
 	if (acm == NULL) {
@@ -1060,6 +1100,13 @@
 		goto alloc_fail;
 	}
 
+	minor = acm_alloc_minor(acm);
+	if (minor == ACM_TTY_MINORS) {
+		dev_err(&intf->dev, "no more free acm devices\n");
+		kfree(acm);
+		return -ENODEV;
+	}
+
 	ctrlsize = usb_endpoint_maxp(epctrl);
 	readsize = usb_endpoint_maxp(epread) *
 				(quirks == SINGLE_RX_URB ? 1 : 2);
@@ -1183,6 +1230,8 @@
 		i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
 		if (i < 0) {
 			kfree(acm->country_codes);
+			acm->country_codes = NULL;
+			acm->country_code_size = 0;
 			goto skip_countries;
 		}
 
@@ -1191,6 +1240,8 @@
 		if (i < 0) {
 			device_remove_file(&intf->dev, &dev_attr_wCountryCodes);
 			kfree(acm->country_codes);
+			acm->country_codes = NULL;
+			acm->country_code_size = 0;
 			goto skip_countries;
 		}
 	}
@@ -1218,8 +1269,6 @@
 	usb_get_intf(control_interface);
 	tty_register_device(acm_tty_driver, minor, &control_interface->dev);
 
-	acm_table[minor] = acm;
-
 	return 0;
 alloc_fail7:
 	for (i = 0; i < ACM_NW; i++)
@@ -1234,6 +1283,7 @@
 alloc_fail4:
 	usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
 alloc_fail2:
+	acm_release_minor(acm);
 	kfree(acm);
 alloc_fail:
 	return -ENOMEM;
@@ -1259,12 +1309,16 @@
 	struct acm *acm = usb_get_intfdata(intf);
 	struct usb_device *usb_dev = interface_to_usbdev(intf);
 	struct tty_struct *tty;
+	int i;
+
+	dev_dbg(&intf->dev, "%s\n", __func__);
 
 	/* sibling interface is already cleaning up */
 	if (!acm)
 		return;
 
-	mutex_lock(&open_mutex);
+	mutex_lock(&acm->mutex);
+	acm->disconnected = true;
 	if (acm->country_codes) {
 		device_remove_file(&acm->control->dev,
 				&dev_attr_wCountryCodes);
@@ -1272,33 +1326,32 @@
 				&dev_attr_iCountryCodeRelDate);
 	}
 	device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
-	acm->dev = NULL;
 	usb_set_intfdata(acm->control, NULL);
 	usb_set_intfdata(acm->data, NULL);
+	mutex_unlock(&acm->mutex);
+
+	tty = tty_port_tty_get(&acm->port);
+	if (tty) {
+		tty_vhangup(tty);
+		tty_kref_put(tty);
+	}
 
 	stop_data_traffic(acm);
 
+	usb_free_urb(acm->ctrlurb);
+	for (i = 0; i < ACM_NW; i++)
+		usb_free_urb(acm->wb[i].urb);
+	for (i = 0; i < acm->rx_buflimit; i++)
+		usb_free_urb(acm->read_urbs[i]);
 	acm_write_buffers_free(acm);
-	usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer,
-			  acm->ctrl_dma);
+	usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
 	acm_read_buffers_free(acm);
 
 	if (!acm->combined_interfaces)
 		usb_driver_release_interface(&acm_driver, intf == acm->control ?
 					acm->data : acm->control);
 
-	if (acm->port.count == 0) {
-		acm_tty_unregister(acm);
-		mutex_unlock(&open_mutex);
-		return;
-	}
-
-	mutex_unlock(&open_mutex);
-	tty = tty_port_tty_get(&acm->port);
-	if (tty) {
-		tty_hangup(tty);
-		tty_kref_put(tty);
-	}
+	tty_port_put(&acm->port);
 }
 
 #ifdef CONFIG_PM
@@ -1325,16 +1378,10 @@
 
 	if (cnt)
 		return 0;
-	/*
-	we treat opened interfaces differently,
-	we must guard against open
-	*/
-	mutex_lock(&acm->mutex);
 
-	if (acm->port.count)
+	if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags))
 		stop_data_traffic(acm);
 
-	mutex_unlock(&acm->mutex);
 	return 0;
 }
 
@@ -1353,8 +1400,7 @@
 	if (cnt)
 		return 0;
 
-	mutex_lock(&acm->mutex);
-	if (acm->port.count) {
+	if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
 		rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
 
 		spin_lock_irq(&acm->write_lock);
@@ -1378,7 +1424,6 @@
 	}
 
 err_out:
-	mutex_unlock(&acm->mutex);
 	return rv;
 }
 
@@ -1387,15 +1432,14 @@
 	struct acm *acm = usb_get_intfdata(intf);
 	struct tty_struct *tty;
 
-	mutex_lock(&acm->mutex);
-	if (acm->port.count) {
+	if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
 		tty = tty_port_tty_get(&acm->port);
 		if (tty) {
 			tty_hangup(tty);
 			tty_kref_put(tty);
 		}
 	}
-	mutex_unlock(&acm->mutex);
+
 	return acm_resume(intf);
 }
 
@@ -1604,8 +1648,10 @@
  */
 
 static const struct tty_operations acm_ops = {
+	.install =		acm_tty_install,
 	.open =			acm_tty_open,
 	.close =		acm_tty_close,
+	.cleanup =		acm_tty_cleanup,
 	.hangup =		acm_tty_hangup,
 	.write =		acm_tty_write,
 	.write_room =		acm_tty_write_room,
diff --git a/drivers/usb/class/cdc-acm.h b/drivers/usb/class/cdc-acm.h
index ca7937f..35ef887 100644
--- a/drivers/usb/class/cdc-acm.h
+++ b/drivers/usb/class/cdc-acm.h
@@ -101,6 +101,7 @@
 	int transmitting;
 	spinlock_t write_lock;
 	struct mutex mutex;
+	bool disconnected;
 	struct usb_cdc_line_coding line;		/* bits, stop, parity */
 	struct work_struct work;			/* work queue entry for line discipline waking up */
 	unsigned int ctrlin;				/* input control lines (DCD, DSR, RI, break, overruns) */
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index e3beaf2..3af5e2d 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -86,6 +86,7 @@
 	void __user *userbuffer;
 	void __user *userurb;
 	struct urb *urb;
+	unsigned int mem_usage;
 	int status;
 	u32 secid;
 	u8 bulk_addr;
@@ -108,8 +109,44 @@
 
 #define USB_DEVICE_DEV		MKDEV(USB_DEVICE_MAJOR, 0)
 
-#define	MAX_USBFS_BUFFER_SIZE	16384
+/* Limit on the total amount of memory we can allocate for transfers */
+static unsigned usbfs_memory_mb = 16;
+module_param(usbfs_memory_mb, uint, 0644);
+MODULE_PARM_DESC(usbfs_memory_mb,
+		"maximum MB allowed for usbfs buffers (0 = no limit)");
 
+/* Hard limit, necessary to avoid aithmetic overflow */
+#define USBFS_XFER_MAX		(UINT_MAX / 2 - 1000000)
+
+static atomic_t usbfs_memory_usage;	/* Total memory currently allocated */
+
+/* Check whether it's okay to allocate more memory for a transfer */
+static int usbfs_increase_memory_usage(unsigned amount)
+{
+	unsigned lim;
+
+	/*
+	 * Convert usbfs_memory_mb to bytes, avoiding overflows.
+	 * 0 means use the hard limit (effectively unlimited).
+	 */
+	lim = ACCESS_ONCE(usbfs_memory_mb);
+	if (lim == 0 || lim > (USBFS_XFER_MAX >> 20))
+		lim = USBFS_XFER_MAX;
+	else
+		lim <<= 20;
+
+	atomic_add(amount, &usbfs_memory_usage);
+	if (atomic_read(&usbfs_memory_usage) <= lim)
+		return 0;
+	atomic_sub(amount, &usbfs_memory_usage);
+	return -ENOMEM;
+}
+
+/* Memory for a transfer is being deallocated */
+static void usbfs_decrease_memory_usage(unsigned amount)
+{
+	atomic_sub(amount, &usbfs_memory_usage);
+}
 
 static int connected(struct dev_state *ps)
 {
@@ -249,10 +286,12 @@
 static void free_async(struct async *as)
 {
 	put_pid(as->pid);
-	put_cred(as->cred);
+	if (as->cred)
+		put_cred(as->cred);
 	kfree(as->urb->transfer_buffer);
 	kfree(as->urb->setup_packet);
 	usb_free_urb(as->urb);
+	usbfs_decrease_memory_usage(as->mem_usage);
 	kfree(as);
 }
 
@@ -792,9 +831,15 @@
 	wLength = ctrl.wLength;		/* To suppress 64k PAGE_SIZE warning */
 	if (wLength > PAGE_SIZE)
 		return -EINVAL;
+	ret = usbfs_increase_memory_usage(PAGE_SIZE + sizeof(struct urb) +
+			sizeof(struct usb_ctrlrequest));
+	if (ret)
+		return ret;
 	tbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
-	if (!tbuf)
-		return -ENOMEM;
+	if (!tbuf) {
+		ret = -ENOMEM;
+		goto done;
+	}
 	tmo = ctrl.timeout;
 	snoop(&dev->dev, "control urb: bRequestType=%02x "
 		"bRequest=%02x wValue=%04x "
@@ -806,8 +851,8 @@
 	if (ctrl.bRequestType & 0x80) {
 		if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data,
 					       ctrl.wLength)) {
-			free_page((unsigned long)tbuf);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto done;
 		}
 		pipe = usb_rcvctrlpipe(dev, 0);
 		snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, NULL, 0);
@@ -821,15 +866,15 @@
 			  tbuf, max(i, 0));
 		if ((i > 0) && ctrl.wLength) {
 			if (copy_to_user(ctrl.data, tbuf, i)) {
-				free_page((unsigned long)tbuf);
-				return -EFAULT;
+				ret = -EFAULT;
+				goto done;
 			}
 		}
 	} else {
 		if (ctrl.wLength) {
 			if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) {
-				free_page((unsigned long)tbuf);
-				return -EFAULT;
+				ret = -EFAULT;
+				goto done;
 			}
 		}
 		pipe = usb_sndctrlpipe(dev, 0);
@@ -843,14 +888,18 @@
 		usb_lock_device(dev);
 		snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, NULL, 0);
 	}
-	free_page((unsigned long)tbuf);
 	if (i < 0 && i != -EPIPE) {
 		dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL "
 			   "failed cmd %s rqt %u rq %u len %u ret %d\n",
 			   current->comm, ctrl.bRequestType, ctrl.bRequest,
 			   ctrl.wLength, i);
 	}
-	return i;
+	ret = i;
+ done:
+	free_page((unsigned long) tbuf);
+	usbfs_decrease_memory_usage(PAGE_SIZE + sizeof(struct urb) +
+			sizeof(struct usb_ctrlrequest));
+	return ret;
 }
 
 static int proc_bulk(struct dev_state *ps, void __user *arg)
@@ -877,15 +926,20 @@
 	if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN)))
 		return -EINVAL;
 	len1 = bulk.len;
-	if (len1 > MAX_USBFS_BUFFER_SIZE)
+	if (len1 >= USBFS_XFER_MAX)
 		return -EINVAL;
-	if (!(tbuf = kmalloc(len1, GFP_KERNEL)))
-		return -ENOMEM;
+	ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb));
+	if (ret)
+		return ret;
+	if (!(tbuf = kmalloc(len1, GFP_KERNEL))) {
+		ret = -ENOMEM;
+		goto done;
+	}
 	tmo = bulk.timeout;
 	if (bulk.ep & 0x80) {
 		if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) {
-			kfree(tbuf);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto done;
 		}
 		snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0);
 
@@ -896,15 +950,15 @@
 
 		if (!i && len2) {
 			if (copy_to_user(bulk.data, tbuf, len2)) {
-				kfree(tbuf);
-				return -EFAULT;
+				ret = -EFAULT;
+				goto done;
 			}
 		}
 	} else {
 		if (len1) {
 			if (copy_from_user(tbuf, bulk.data, len1)) {
-				kfree(tbuf);
-				return -EFAULT;
+				ret = -EFAULT;
+				goto done;
 			}
 		}
 		snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, tbuf, len1);
@@ -914,10 +968,11 @@
 		usb_lock_device(dev);
 		snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, NULL, 0);
 	}
+	ret = (i < 0 ? i : len2);
+ done:
 	kfree(tbuf);
-	if (i < 0)
-		return i;
-	return len2;
+	usbfs_decrease_memory_usage(len1 + sizeof(struct urb));
+	return ret;
 }
 
 static int proc_resetep(struct dev_state *ps, void __user *arg)
@@ -1062,7 +1117,7 @@
 {
 	struct usbdevfs_iso_packet_desc *isopkt = NULL;
 	struct usb_host_endpoint *ep;
-	struct async *as;
+	struct async *as = NULL;
 	struct usb_ctrlrequest *dr = NULL;
 	unsigned int u, totlen, isofrmlen;
 	int ret, ifnum = -1;
@@ -1095,32 +1150,30 @@
 	}
 	if (!ep)
 		return -ENOENT;
+
+	u = 0;
 	switch(uurb->type) {
 	case USBDEVFS_URB_TYPE_CONTROL:
 		if (!usb_endpoint_xfer_control(&ep->desc))
 			return -EINVAL;
-		/* min 8 byte setup packet,
-		 * max 8 byte setup plus an arbitrary data stage */
-		if (uurb->buffer_length < 8 ||
-		    uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
+		/* min 8 byte setup packet */
+		if (uurb->buffer_length < 8)
 			return -EINVAL;
 		dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
 		if (!dr)
 			return -ENOMEM;
 		if (copy_from_user(dr, uurb->buffer, 8)) {
-			kfree(dr);
-			return -EFAULT;
+			ret = -EFAULT;
+			goto error;
 		}
 		if (uurb->buffer_length < (le16_to_cpup(&dr->wLength) + 8)) {
-			kfree(dr);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto error;
 		}
 		ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest,
 				      le16_to_cpup(&dr->wIndex));
-		if (ret) {
-			kfree(dr);
-			return ret;
-		}
+		if (ret)
+			goto error;
 		uurb->number_of_packets = 0;
 		uurb->buffer_length = le16_to_cpup(&dr->wLength);
 		uurb->buffer += 8;
@@ -1138,6 +1191,7 @@
 			__le16_to_cpup(&dr->wValue),
 			__le16_to_cpup(&dr->wIndex),
 			__le16_to_cpup(&dr->wLength));
+		u = sizeof(struct usb_ctrlrequest);
 		break;
 
 	case USBDEVFS_URB_TYPE_BULK:
@@ -1151,8 +1205,6 @@
 			goto interrupt_urb;
 		}
 		uurb->number_of_packets = 0;
-		if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
-			return -EINVAL;
 		break;
 
 	case USBDEVFS_URB_TYPE_INTERRUPT:
@@ -1160,8 +1212,6 @@
 			return -EINVAL;
  interrupt_urb:
 		uurb->number_of_packets = 0;
-		if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
-			return -EINVAL;
 		break;
 
 	case USBDEVFS_URB_TYPE_ISO:
@@ -1176,50 +1226,53 @@
 		if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
 			return -ENOMEM;
 		if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) {
-			kfree(isopkt);
-			return -EFAULT;
+			ret = -EFAULT;
+			goto error;
 		}
 		for (totlen = u = 0; u < uurb->number_of_packets; u++) {
 			/* arbitrary limit,
 			 * sufficient for USB 2.0 high-bandwidth iso */
 			if (isopkt[u].length > 8192) {
-				kfree(isopkt);
-				return -EINVAL;
+				ret = -EINVAL;
+				goto error;
 			}
 			totlen += isopkt[u].length;
 		}
-		/* 3072 * 64 microframes */
-		if (totlen > 196608) {
-			kfree(isopkt);
-			return -EINVAL;
-		}
+		u *= sizeof(struct usb_iso_packet_descriptor);
 		uurb->buffer_length = totlen;
 		break;
 
 	default:
 		return -EINVAL;
 	}
+
+	if (uurb->buffer_length >= USBFS_XFER_MAX) {
+		ret = -EINVAL;
+		goto error;
+	}
 	if (uurb->buffer_length > 0 &&
 			!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
 				uurb->buffer, uurb->buffer_length)) {
-		kfree(isopkt);
-		kfree(dr);
-		return -EFAULT;
+		ret = -EFAULT;
+		goto error;
 	}
 	as = alloc_async(uurb->number_of_packets);
 	if (!as) {
-		kfree(isopkt);
-		kfree(dr);
-		return -ENOMEM;
+		ret = -ENOMEM;
+		goto error;
 	}
+	u += sizeof(struct async) + sizeof(struct urb) + uurb->buffer_length;
+	ret = usbfs_increase_memory_usage(u);
+	if (ret)
+		goto error;
+	as->mem_usage = u;
+
 	if (uurb->buffer_length > 0) {
 		as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
 				GFP_KERNEL);
 		if (!as->urb->transfer_buffer) {
-			kfree(isopkt);
-			kfree(dr);
-			free_async(as);
-			return -ENOMEM;
+			ret = -ENOMEM;
+			goto error;
 		}
 		/* Isochronous input data may end up being discontiguous
 		 * if some of the packets are short.  Clear the buffer so
@@ -1253,6 +1306,7 @@
 
 	as->urb->transfer_buffer_length = uurb->buffer_length;
 	as->urb->setup_packet = (unsigned char *)dr;
+	dr = NULL;
 	as->urb->start_frame = uurb->start_frame;
 	as->urb->number_of_packets = uurb->number_of_packets;
 	if (uurb->type == USBDEVFS_URB_TYPE_ISO ||
@@ -1268,6 +1322,7 @@
 		totlen += isopkt[u].length;
 	}
 	kfree(isopkt);
+	isopkt = NULL;
 	as->ps = ps;
 	as->userurb = arg;
 	if (is_in && uurb->buffer_length > 0)
@@ -1282,8 +1337,8 @@
 	if (!is_in && uurb->buffer_length > 0) {
 		if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
 				uurb->buffer_length)) {
-			free_async(as);
-			return -EFAULT;
+			ret = -EFAULT;
+			goto error;
 		}
 	}
 	snoop_urb(ps->dev, as->userurb, as->urb->pipe,
@@ -1329,10 +1384,16 @@
 		snoop_urb(ps->dev, as->userurb, as->urb->pipe,
 				0, ret, COMPLETE, NULL, 0);
 		async_removepending(as);
-		free_async(as);
-		return ret;
+		goto error;
 	}
 	return 0;
+
+ error:
+	kfree(isopkt);
+	kfree(dr);
+	if (as)
+		free_async(as);
+	return ret;
 }
 
 static int proc_submiturb(struct dev_state *ps, void __user *arg)
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 45887a0..d40ff95 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -45,10 +45,12 @@
 	struct usb_dynid *dynid;
 	u32 idVendor = 0;
 	u32 idProduct = 0;
+	unsigned int bInterfaceClass = 0;
 	int fields = 0;
 	int retval = 0;
 
-	fields = sscanf(buf, "%x %x", &idVendor, &idProduct);
+	fields = sscanf(buf, "%x %x %x", &idVendor, &idProduct,
+					&bInterfaceClass);
 	if (fields < 2)
 		return -EINVAL;
 
@@ -60,6 +62,10 @@
 	dynid->id.idVendor = idVendor;
 	dynid->id.idProduct = idProduct;
 	dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
+	if (fields == 3) {
+		dynid->id.bInterfaceClass = (u8)bInterfaceClass;
+		dynid->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS;
+	}
 
 	spin_lock(&dynids->lock);
 	list_add_tail(&dynid->node, &dynids->list);
@@ -1073,17 +1079,10 @@
 		goto done;
 	driver = to_usb_driver(intf->dev.driver);
 
-	if (driver->suspend) {
-		status = driver->suspend(intf, msg);
-		if (status && !PMSG_IS_AUTO(msg))
-			dev_err(&intf->dev, "%s error %d\n",
-					"suspend", status);
-	} else {
-		/* Later we will unbind the driver and reprobe */
-		intf->needs_binding = 1;
-		dev_warn(&intf->dev, "no %s for driver %s?\n",
-				"suspend", driver->name);
-	}
+	/* at this time we know the driver supports suspend */
+	status = driver->suspend(intf, msg);
+	if (status && !PMSG_IS_AUTO(msg))
+		dev_err(&intf->dev, "suspend error %d\n", status);
 
  done:
 	dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status);
@@ -1132,16 +1131,9 @@
 					"reset_resume", driver->name);
 		}
 	} else {
-		if (driver->resume) {
-			status = driver->resume(intf);
-			if (status)
-				dev_err(&intf->dev, "%s error %d\n",
-						"resume", status);
-		} else {
-			intf->needs_binding = 1;
-			dev_warn(&intf->dev, "no %s for driver %s?\n",
-					"resume", driver->name);
-		}
+		status = driver->resume(intf);
+		if (status)
+			dev_err(&intf->dev, "resume error %d\n", status);
 	}
 
 done:
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index a004db3..d136b8f 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -453,10 +453,6 @@
 
 	pci_set_master(pci_dev);
 
-	clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
-	if (hcd->shared_hcd)
-		clear_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);
-
 	if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) {
 		if (event != PM_EVENT_AUTO_RESUME)
 			wait_for_companions(pci_dev, hcd);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 13222d3..eb19cba 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -658,7 +658,7 @@
 				len > offsetof(struct usb_device_descriptor,
 						bDeviceProtocol))
 			((struct usb_device_descriptor *) ubuf)->
-					bDeviceProtocol = 1;
+				bDeviceProtocol = USB_HUB_PR_HS_SINGLE_TT;
 	}
 
 	/* any errors get returned through the urb completion */
@@ -1168,20 +1168,6 @@
 	if (urb->unlinked)
 		return -EBUSY;
 	urb->unlinked = status;
-
-	/* IRQ setup can easily be broken so that USB controllers
-	 * never get completion IRQs ... maybe even the ones we need to
-	 * finish unlinking the initial failed usb_set_address()
-	 * or device descriptor fetch.
-	 */
-	if (!HCD_SAW_IRQ(hcd) && !is_root_hub(urb->dev)) {
-		dev_warn(hcd->self.controller, "Unlink after no-IRQ?  "
-			"Controller is probably using the wrong IRQ.\n");
-		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
-		if (hcd->shared_hcd)
-			set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);
-	}
-
 	return 0;
 }
 EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb);
@@ -1412,11 +1398,10 @@
 					ret = -EAGAIN;
 				else
 					urb->transfer_flags |= URB_DMA_MAP_SG;
-				if (n != urb->num_sgs) {
-					urb->num_sgs = n;
+				urb->num_mapped_sgs = n;
+				if (n != urb->num_sgs)
 					urb->transfer_flags |=
 							URB_DMA_SG_COMBINED;
-				}
 			} else if (urb->sg) {
 				struct scatterlist *sg = urb->sg;
 				urb->transfer_dma = dma_map_page(
@@ -2148,16 +2133,12 @@
 	 */
 	local_irq_save(flags);
 
-	if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd))) {
+	if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd)))
 		rc = IRQ_NONE;
-	} else if (hcd->driver->irq(hcd) == IRQ_NONE) {
+	else if (hcd->driver->irq(hcd) == IRQ_NONE)
 		rc = IRQ_NONE;
-	} else {
-		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
-		if (hcd->shared_hcd)
-			set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);
+	else
 		rc = IRQ_HANDLED;
-	}
 
 	local_irq_restore(flags);
 	return rc;
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 7978146..79d339e 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -84,7 +84,7 @@
 
 static inline int hub_is_superspeed(struct usb_device *hdev)
 {
-	return (hdev->descriptor.bDeviceProtocol == 3);
+	return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS);
 }
 
 /* Protect struct usb_device->state and ->children members
@@ -1041,58 +1041,58 @@
 		dev_dbg(hub_dev, "standalone hub\n");
 
 	switch (wHubCharacteristics & HUB_CHAR_LPSM) {
-		case 0x00:
-			dev_dbg(hub_dev, "ganged power switching\n");
-			break;
-		case 0x01:
-			dev_dbg(hub_dev, "individual port power switching\n");
-			break;
-		case 0x02:
-		case 0x03:
-			dev_dbg(hub_dev, "no power switching (usb 1.0)\n");
-			break;
+	case HUB_CHAR_COMMON_LPSM:
+		dev_dbg(hub_dev, "ganged power switching\n");
+		break;
+	case HUB_CHAR_INDV_PORT_LPSM:
+		dev_dbg(hub_dev, "individual port power switching\n");
+		break;
+	case HUB_CHAR_NO_LPSM:
+	case HUB_CHAR_LPSM:
+		dev_dbg(hub_dev, "no power switching (usb 1.0)\n");
+		break;
 	}
 
 	switch (wHubCharacteristics & HUB_CHAR_OCPM) {
-		case 0x00:
-			dev_dbg(hub_dev, "global over-current protection\n");
-			break;
-		case 0x08:
-			dev_dbg(hub_dev, "individual port over-current protection\n");
-			break;
-		case 0x10:
-		case 0x18:
-			dev_dbg(hub_dev, "no over-current protection\n");
-                        break;
+	case HUB_CHAR_COMMON_OCPM:
+		dev_dbg(hub_dev, "global over-current protection\n");
+		break;
+	case HUB_CHAR_INDV_PORT_OCPM:
+		dev_dbg(hub_dev, "individual port over-current protection\n");
+		break;
+	case HUB_CHAR_NO_OCPM:
+	case HUB_CHAR_OCPM:
+		dev_dbg(hub_dev, "no over-current protection\n");
+		break;
 	}
 
 	spin_lock_init (&hub->tt.lock);
 	INIT_LIST_HEAD (&hub->tt.clear_list);
 	INIT_WORK(&hub->tt.clear_work, hub_tt_work);
 	switch (hdev->descriptor.bDeviceProtocol) {
-		case 0:
-			break;
-		case 1:
-			dev_dbg(hub_dev, "Single TT\n");
-			hub->tt.hub = hdev;
-			break;
-		case 2:
-			ret = usb_set_interface(hdev, 0, 1);
-			if (ret == 0) {
-				dev_dbg(hub_dev, "TT per port\n");
-				hub->tt.multi = 1;
-			} else
-				dev_err(hub_dev, "Using single TT (err %d)\n",
-					ret);
-			hub->tt.hub = hdev;
-			break;
-		case 3:
-			/* USB 3.0 hubs don't have a TT */
-			break;
-		default:
-			dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",
-				hdev->descriptor.bDeviceProtocol);
-			break;
+	case USB_HUB_PR_FS:
+		break;
+	case USB_HUB_PR_HS_SINGLE_TT:
+		dev_dbg(hub_dev, "Single TT\n");
+		hub->tt.hub = hdev;
+		break;
+	case USB_HUB_PR_HS_MULTI_TT:
+		ret = usb_set_interface(hdev, 0, 1);
+		if (ret == 0) {
+			dev_dbg(hub_dev, "TT per port\n");
+			hub->tt.multi = 1;
+		} else
+			dev_err(hub_dev, "Using single TT (err %d)\n",
+				ret);
+		hub->tt.hub = hdev;
+		break;
+	case USB_HUB_PR_SS:
+		/* USB 3.0 hubs don't have a TT */
+		break;
+	default:
+		dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",
+			hdev->descriptor.bDeviceProtocol);
+		break;
 	}
 
 	/* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */
@@ -1360,7 +1360,6 @@
 	return -ENODEV;
 }
 
-/* No BKL needed */
 static int
 hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
 {
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index ecf12e1..4c65eb6 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -117,9 +117,12 @@
 	{ USB_DEVICE(0x06a3, 0x0006), .driver_info =
 			USB_QUIRK_CONFIG_INTF_STRINGS },
 
-	/* Guillemot Webcam Hercules Dualpix Exchange*/
+	/* Guillemot Webcam Hercules Dualpix Exchange (2nd ID) */
 	{ USB_DEVICE(0x06f8, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME },
 
+	/* Guillemot Webcam Hercules Dualpix Exchange*/
+	{ USB_DEVICE(0x06f8, 0x3005), .driver_info = USB_QUIRK_RESET_RESUME },
+
 	/* M-Systems Flash Disk Pioneers */
 	{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
 
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 3888778..45e8479 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -132,20 +132,6 @@
 			for_devices;
 }
 
-/* translate USB error codes to codes user space understands */
-static inline int usb_translate_errors(int error_code)
-{
-	switch (error_code) {
-	case 0:
-	case -ENOMEM:
-	case -ENODEV:
-		return error_code;
-	default:
-		return -EIO;
-	}
-}
-
-
 /* for labeling diagnostics */
 extern const char *usbcore_name;
 
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 3c1d67d..d8f741f 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -1,7 +1,10 @@
 config USB_DWC3
 	tristate "DesignWare USB3 DRD Core Support"
-	depends on (USB || USB_GADGET)
+	depends on (USB && USB_GADGET)
 	select USB_OTG_UTILS
+	select USB_GADGET_DUALSPEED
+	select USB_GADGET_SUPERSPEED
+	select USB_XHCI_PLATFORM
 	help
 	  Say Y or M here if your system has a Dual Role SuperSpeed
 	  USB controller based on the DesignWare USB3 IP Core.
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 593d1db..900ae74 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -4,10 +4,8 @@
 obj-$(CONFIG_USB_DWC3)			+= dwc3.o
 
 dwc3-y					:= core.o
-
-ifneq ($(CONFIG_USB_GADGET_DWC3),)
-	dwc3-y				+= gadget.o ep0.o
-endif
+dwc3-y					+= host.o
+dwc3-y					+= gadget.o ep0.o
 
 ifneq ($(CONFIG_DEBUG_FS),)
 	dwc3-y				+= debugfs.o
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 600d823..7c9df63 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -59,6 +59,60 @@
 
 #include "debug.h"
 
+static char *maximum_speed = "super";
+module_param(maximum_speed, charp, 0);
+MODULE_PARM_DESC(maximum_speed, "Maximum supported speed.");
+
+/* -------------------------------------------------------------------------- */
+
+#define DWC3_DEVS_POSSIBLE	32
+
+static DECLARE_BITMAP(dwc3_devs, DWC3_DEVS_POSSIBLE);
+
+int dwc3_get_device_id(void)
+{
+	int		id;
+
+again:
+	id = find_first_zero_bit(dwc3_devs, DWC3_DEVS_POSSIBLE);
+	if (id < DWC3_DEVS_POSSIBLE) {
+		int old;
+
+		old = test_and_set_bit(id, dwc3_devs);
+		if (old)
+			goto again;
+	} else {
+		pr_err("dwc3: no space for new device\n");
+		id = -ENOMEM;
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dwc3_get_device_id);
+
+void dwc3_put_device_id(int id)
+{
+	int			ret;
+
+	if (id < 0)
+		return;
+
+	ret = test_bit(id, dwc3_devs);
+	WARN(!ret, "dwc3: ID %d not in use\n", id);
+	clear_bit(id, dwc3_devs);
+}
+EXPORT_SYMBOL_GPL(dwc3_put_device_id);
+
+void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
+{
+	u32 reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+	reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
+	reg |= DWC3_GCTL_PRTCAPDIR(mode);
+	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+}
+
 /**
  * dwc3_core_soft_reset - Issues core soft reset and PHY reset
  * @dwc: pointer to our context structure
@@ -150,7 +204,7 @@
 	struct dwc3_event_buffer	*evt;
 	int i;
 
-	for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) {
+	for (i = 0; i < dwc->num_event_buffers; i++) {
 		evt = dwc->ev_buffs[i];
 		if (evt) {
 			dwc3_free_one_event_buffer(dwc, evt);
@@ -162,17 +216,25 @@
 /**
  * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
  * @dwc: Pointer to out controller context structure
- * @num: number of event buffers to allocate
  * @length: size of event buffer
  *
  * Returns 0 on success otherwise negative errno. In error the case, dwc
  * may contain some buffers allocated but not all which were requested.
  */
-static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned num,
-		unsigned length)
+static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
 {
+	int			num;
 	int			i;
 
+	num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
+	dwc->num_event_buffers = num;
+
+	dwc->ev_buffs = kzalloc(sizeof(*dwc->ev_buffs) * num, GFP_KERNEL);
+	if (!dwc->ev_buffs) {
+		dev_err(dwc->dev, "can't allocate event buffers array\n");
+		return -ENOMEM;
+	}
+
 	for (i = 0; i < num; i++) {
 		struct dwc3_event_buffer	*evt;
 
@@ -198,7 +260,7 @@
 	struct dwc3_event_buffer	*evt;
 	int				n;
 
-	for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) {
+	for (n = 0; n < dwc->num_event_buffers; n++) {
 		evt = dwc->ev_buffs[n];
 		dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
 				evt->buf, (unsigned long long) evt->dma,
@@ -221,7 +283,7 @@
 	struct dwc3_event_buffer	*evt;
 	int				n;
 
-	for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) {
+	for (n = 0; n < dwc->num_event_buffers; n++) {
 		evt = dwc->ev_buffs[n];
 		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
 		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
@@ -285,8 +347,32 @@
 		cpu_relax();
 	} while (true);
 
-	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_NUM,
-			DWC3_EVENT_BUFFERS_SIZE);
+	dwc3_cache_hwparams(dwc);
+
+	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+	reg &= ~DWC3_GCTL_SCALEDOWN(3);
+	reg &= ~DWC3_GCTL_DISSCRAMBLE;
+
+	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
+	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
+		reg &= ~DWC3_GCTL_DSBLCLKGTNG;
+		break;
+	default:
+		dev_dbg(dwc->dev, "No power optimization available\n");
+	}
+
+	/*
+	 * WORKAROUND: DWC3 revisions <1.90a have a bug
+	 * when The device fails to connect at SuperSpeed
+	 * and falls back to high-speed mode which causes
+	 * the device to enter in a Connect/Disconnect loop
+	 */
+	if (dwc->revision < DWC3_REVISION_190A)
+		reg |= DWC3_GCTL_U2RSTECN;
+
+	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
 	if (ret) {
 		dev_err(dwc->dev, "failed to allocate event buffers\n");
 		ret = -ENOMEM;
@@ -299,8 +385,6 @@
 		goto err1;
 	}
 
-	dwc3_cache_hwparams(dwc);
-
 	return 0;
 
 err1:
@@ -320,15 +404,17 @@
 
 static int __devinit dwc3_probe(struct platform_device *pdev)
 {
-	const struct platform_device_id *id = platform_get_device_id(pdev);
 	struct resource		*res;
 	struct dwc3		*dwc;
-	void __iomem		*regs;
-	unsigned int		features = id->driver_data;
+
 	int			ret = -ENOMEM;
 	int			irq;
+
+	void __iomem		*regs;
 	void			*mem;
 
+	u8			mode;
+
 	mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
 	if (!mem) {
 		dev_err(&pdev->dev, "not enough memory\n");
@@ -343,6 +429,8 @@
 		goto err1;
 	}
 
+	dwc->res = res;
+
 	res = request_mem_region(res->start, resource_size(res),
 			dev_name(&pdev->dev));
 	if (!res) {
@@ -370,6 +458,17 @@
 	dwc->dev	= &pdev->dev;
 	dwc->irq	= irq;
 
+	if (!strncmp("super", maximum_speed, 5))
+		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
+	else if (!strncmp("high", maximum_speed, 4))
+		dwc->maximum_speed = DWC3_DCFG_HIGHSPEED;
+	else if (!strncmp("full", maximum_speed, 4))
+		dwc->maximum_speed = DWC3_DCFG_FULLSPEED1;
+	else if (!strncmp("low", maximum_speed, 3))
+		dwc->maximum_speed = DWC3_DCFG_LOWSPEED;
+	else
+		dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
+
 	pm_runtime_enable(&pdev->dev);
 	pm_runtime_get_sync(&pdev->dev);
 	pm_runtime_forbid(&pdev->dev);
@@ -380,13 +479,44 @@
 		goto err3;
 	}
 
-	if (features & DWC3_HAS_PERIPHERAL) {
+	mode = DWC3_MODE(dwc->hwparams.hwparams0);
+
+	switch (mode) {
+	case DWC3_MODE_DEVICE:
+		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
 		ret = dwc3_gadget_init(dwc);
 		if (ret) {
-			dev_err(&pdev->dev, "failed to initialized gadget\n");
+			dev_err(&pdev->dev, "failed to initialize gadget\n");
 			goto err4;
 		}
+		break;
+	case DWC3_MODE_HOST:
+		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
+		ret = dwc3_host_init(dwc);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to initialize host\n");
+			goto err4;
+		}
+		break;
+	case DWC3_MODE_DRD:
+		dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
+		ret = dwc3_host_init(dwc);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to initialize host\n");
+			goto err4;
+		}
+
+		ret = dwc3_gadget_init(dwc);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to initialize gadget\n");
+			goto err4;
+		}
+		break;
+	default:
+		dev_err(&pdev->dev, "Unsupported mode of operation %d\n", mode);
+		goto err4;
 	}
+	dwc->mode = mode;
 
 	ret = dwc3_debugfs_init(dwc);
 	if (ret) {
@@ -399,8 +529,21 @@
 	return 0;
 
 err5:
-	if (features & DWC3_HAS_PERIPHERAL)
+	switch (mode) {
+	case DWC3_MODE_DEVICE:
 		dwc3_gadget_exit(dwc);
+		break;
+	case DWC3_MODE_HOST:
+		dwc3_host_exit(dwc);
+		break;
+	case DWC3_MODE_DRD:
+		dwc3_host_exit(dwc);
+		dwc3_gadget_exit(dwc);
+		break;
+	default:
+		/* do nothing */
+		break;
+	}
 
 err4:
 	dwc3_core_exit(dwc);
@@ -420,10 +563,8 @@
 
 static int __devexit dwc3_remove(struct platform_device *pdev)
 {
-	const struct platform_device_id *id = platform_get_device_id(pdev);
 	struct dwc3	*dwc = platform_get_drvdata(pdev);
 	struct resource	*res;
-	unsigned int	features = id->driver_data;
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
@@ -432,8 +573,21 @@
 
 	dwc3_debugfs_exit(dwc);
 
-	if (features & DWC3_HAS_PERIPHERAL)
+	switch (dwc->mode) {
+	case DWC3_MODE_DEVICE:
 		dwc3_gadget_exit(dwc);
+		break;
+	case DWC3_MODE_HOST:
+		dwc3_host_exit(dwc);
+		break;
+	case DWC3_MODE_DRD:
+		dwc3_host_exit(dwc);
+		dwc3_gadget_exit(dwc);
+		break;
+	default:
+		/* do nothing */
+		break;
+	}
 
 	dwc3_core_exit(dwc);
 	release_mem_region(res->start, resource_size(res));
@@ -443,30 +597,15 @@
 	return 0;
 }
 
-static const struct platform_device_id dwc3_id_table[] __devinitconst = {
-	{
-		.name	= "dwc3-omap",
-		.driver_data = (DWC3_HAS_PERIPHERAL
-			| DWC3_HAS_XHCI
-			| DWC3_HAS_OTG),
-	},
-	{
-		.name	= "dwc3-pci",
-		.driver_data = DWC3_HAS_PERIPHERAL,
-	},
-	{  },	/* Terminating Entry */
-};
-MODULE_DEVICE_TABLE(platform, dwc3_id_table);
-
 static struct platform_driver dwc3_driver = {
 	.probe		= dwc3_probe,
 	.remove		= __devexit_p(dwc3_remove),
 	.driver		= {
 		.name	= "dwc3",
 	},
-	.id_table	= dwc3_id_table,
 };
 
+MODULE_ALIAS("platform:dwc3");
 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 29a8e16..9e57f8e 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -41,6 +41,7 @@
 
 #include <linux/device.h>
 #include <linux/spinlock.h>
+#include <linux/ioport.h>
 #include <linux/list.h>
 #include <linux/dma-mapping.h>
 #include <linux/mm.h>
@@ -52,7 +53,6 @@
 /* Global constants */
 #define DWC3_ENDPOINTS_NUM	32
 
-#define DWC3_EVENT_BUFFERS_NUM	2
 #define DWC3_EVENT_BUFFERS_SIZE	PAGE_SIZE
 #define DWC3_EVENT_TYPE_MASK	0xfe
 
@@ -153,6 +153,7 @@
 #define DWC3_GCTL_CLK_PIPEHALF	(2)
 #define DWC3_GCTL_CLK_MASK	(3)
 
+#define DWC3_GCTL_PRTCAP(n)	(((n) & (3 << 12)) >> 12)
 #define DWC3_GCTL_PRTCAPDIR(n)	(n << 12)
 #define DWC3_GCTL_PRTCAP_HOST	1
 #define DWC3_GCTL_PRTCAP_DEVICE	2
@@ -347,6 +348,7 @@
 	u32			free_slot;
 	u32			busy_slot;
 	const struct usb_endpoint_descriptor *desc;
+	const struct usb_ss_ep_comp_descriptor *comp_desc;
 	struct dwc3		*dwc;
 
 	unsigned		flags;
@@ -536,6 +538,31 @@
 	u32	hwparams8;
 };
 
+/* HWPARAMS0 */
+#define DWC3_MODE(n)		((n) & 0x7)
+
+#define DWC3_MODE_DEVICE	0
+#define DWC3_MODE_HOST		1
+#define DWC3_MODE_DRD		2
+#define DWC3_MODE_HUB		3
+
+/* HWPARAMS1 */
+#define DWC3_NUM_INT(n)	(((n) & (0x3f << 15)) >> 15)
+
+struct dwc3_request {
+	struct usb_request	request;
+	struct list_head	list;
+	struct dwc3_ep		*dep;
+
+	u8			epnum;
+	struct dwc3_trb_hw	*trb;
+	dma_addr_t		trb_dma;
+
+	unsigned		direction:1;
+	unsigned		mapped:1;
+	unsigned		queued:1;
+};
+
 /**
  * struct dwc3 - representation of our controller
  * @ctrl_req: usb control request which is used for ep0
@@ -549,19 +576,24 @@
  * @ep0_bounce_addr: dma address of ep0_bounce
  * @lock: for synchronizing
  * @dev: pointer to our struct device
+ * @xhci: pointer to our xHCI child
  * @event_buffer_list: a list of event buffers
  * @gadget: device side representation of the peripheral controller
  * @gadget_driver: pointer to the gadget driver
  * @regs: base address for our registers
  * @regs_size: address space size
  * @irq: IRQ number
+ * @num_event_buffers: calculated number of event buffers
+ * @u1u2: only used on revisions <1.83a for workaround
+ * @maximum_speed: maximum speed requested (mainly for testing purposes)
  * @revision: revision register contents
+ * @mode: mode of operation
  * @is_selfpowered: true when we are selfpowered
  * @three_stage_setup: set if we perform a three phase setup
- * @ep0_status_pending: ep0 status response without a req is pending
  * @ep0_bounced: true when we used bounce buffer
  * @ep0_expect_in: true when we expect a DATA IN transfer
  * @start_config_issued: true when StartConfig command has been issued
+ * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
  * @ep0_next_event: hold the next expected event
  * @ep0state: state of endpoint zero
  * @link_state: link state
@@ -579,12 +611,15 @@
 	dma_addr_t		ep0_trb_addr;
 	dma_addr_t		setup_buf_addr;
 	dma_addr_t		ep0_bounce_addr;
-	struct usb_request	ep0_usb_req;
+	struct dwc3_request	ep0_usb_req;
 	/* device lock */
 	spinlock_t		lock;
 	struct device		*dev;
 
-	struct dwc3_event_buffer *ev_buffs[DWC3_EVENT_BUFFERS_NUM];
+	struct platform_device	*xhci;
+	struct resource		*res;
+
+	struct dwc3_event_buffer **ev_buffs;
 	struct dwc3_ep		*eps[DWC3_ENDPOINTS_NUM];
 
 	struct usb_gadget	gadget;
@@ -595,7 +630,11 @@
 
 	int			irq;
 
+	u32			num_event_buffers;
+	u32			u1u2;
+	u32			maximum_speed;
 	u32			revision;
+	u32			mode;
 
 #define DWC3_REVISION_173A	0x5533173a
 #define DWC3_REVISION_175A	0x5533175a
@@ -607,10 +646,11 @@
 
 	unsigned		is_selfpowered:1;
 	unsigned		three_stage_setup:1;
-	unsigned		ep0_status_pending:1;
 	unsigned		ep0_bounced:1;
 	unsigned		ep0_expect_in:1;
 	unsigned		start_config_issued:1;
+	unsigned		setup_packet_pending:1;
+	unsigned		delayed_status:1;
 
 	enum dwc3_ep0_next	ep0_next_event;
 	enum dwc3_ep0_state	ep0state;
@@ -765,4 +805,16 @@
 #define DWC3_HAS_XHCI			BIT(1)
 #define DWC3_HAS_OTG			BIT(3)
 
+/* prototypes */
+void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
+
+int dwc3_host_init(struct dwc3 *dwc);
+void dwc3_host_exit(struct dwc3 *dwc);
+
+int dwc3_gadget_init(struct dwc3 *dwc);
+void dwc3_gadget_exit(struct dwc3 *dwc);
+
+extern int dwc3_get_device_id(void);
+extern void dwc3_put_device_id(int id);
+
 #endif /* __DRIVERS_USB_DWC3_CORE_H */
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index fcfa915..433c97c 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -44,12 +44,12 @@
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/delay.h>
-
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #include "core.h"
 #include "gadget.h"
 #include "io.h"
+#include "debug.h"
 
 #define dump_register(nm)				\
 {							\
@@ -395,6 +395,75 @@
 	.release		= single_release,
 };
 
+static int dwc3_mode_show(struct seq_file *s, void *unused)
+{
+	struct dwc3		*dwc = s->private;
+	unsigned long		flags;
+	u32			reg;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	switch (DWC3_GCTL_PRTCAP(reg)) {
+	case DWC3_GCTL_PRTCAP_HOST:
+		seq_printf(s, "host\n");
+		break;
+	case DWC3_GCTL_PRTCAP_DEVICE:
+		seq_printf(s, "device\n");
+		break;
+	case DWC3_GCTL_PRTCAP_OTG:
+		seq_printf(s, "OTG\n");
+		break;
+	default:
+		seq_printf(s, "UNKNOWN %08x\n", DWC3_GCTL_PRTCAP(reg));
+	}
+
+	return 0;
+}
+
+static int dwc3_mode_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dwc3_mode_show, inode->i_private);
+}
+
+static ssize_t dwc3_mode_write(struct file *file,
+		const char __user *ubuf, size_t count, loff_t *ppos)
+{
+	struct seq_file		*s = file->private_data;
+	struct dwc3		*dwc = s->private;
+	unsigned long		flags;
+	u32			mode = 0;
+	char			buf[32];
+
+	if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+		return -EFAULT;
+
+	if (!strncmp(buf, "host", 4))
+		mode |= DWC3_GCTL_PRTCAP_HOST;
+
+	if (!strncmp(buf, "device", 6))
+		mode |= DWC3_GCTL_PRTCAP_DEVICE;
+
+	if (!strncmp(buf, "otg", 3))
+		mode |= DWC3_GCTL_PRTCAP_OTG;
+
+	if (mode) {
+		spin_lock_irqsave(&dwc->lock, flags);
+		dwc3_set_mode(dwc, mode);
+		spin_unlock_irqrestore(&dwc->lock, flags);
+	}
+	return count;
+}
+
+static const struct file_operations dwc3_mode_fops = {
+	.open			= dwc3_mode_open,
+	.write			= dwc3_mode_write,
+	.read			= seq_read,
+	.llseek			= seq_lseek,
+	.release		= single_release,
+};
+
 int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
 {
 	struct dentry		*root;
@@ -402,7 +471,7 @@
 	int			ret;
 
 	root = debugfs_create_dir(dev_name(dwc->dev), NULL);
-	if (IS_ERR(root)){
+	if (IS_ERR(root)) {
 		ret = PTR_ERR(root);
 		goto err0;
 	}
@@ -415,6 +484,14 @@
 		ret = PTR_ERR(file);
 		goto err1;
 	}
+
+	file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
+			dwc, &dwc3_mode_fops);
+	if (IS_ERR(file)) {
+		ret = PTR_ERR(file);
+		goto err1;
+	}
+
 	return 0;
 
 err1:
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index 062552b..3274ac8 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -48,6 +48,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 
+#include "core.h"
 #include "io.h"
 
 /*
@@ -200,6 +201,7 @@
 	struct dwc3_omap	*omap;
 	struct resource		*res;
 
+	int			devid;
 	int			ret = -ENOMEM;
 	int			irq;
 
@@ -236,16 +238,20 @@
 		goto err1;
 	}
 
-	dwc3 = platform_device_alloc("dwc3-omap", -1);
+	devid = dwc3_get_device_id();
+	if (devid < 0)
+		goto err2;
+
+	dwc3 = platform_device_alloc("dwc3", devid);
 	if (!dwc3) {
 		dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
-		goto err2;
+		goto err3;
 	}
 
 	context = kzalloc(resource_size(res), GFP_KERNEL);
 	if (!context) {
 		dev_err(&pdev->dev, "couldn't allocate dwc3 context memory\n");
-		goto err3;
+		goto err4;
 	}
 
 	spin_lock_init(&omap->lock);
@@ -299,7 +305,7 @@
 	if (ret) {
 		dev_err(&pdev->dev, "failed to request IRQ #%d --> %d\n",
 				omap->irq, ret);
-		goto err4;
+		goto err5;
 	}
 
 	/* enable all IRQs */
@@ -322,26 +328,29 @@
 			pdev->num_resources);
 	if (ret) {
 		dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
-		goto err5;
+		goto err6;
 	}
 
 	ret = platform_device_add(dwc3);
 	if (ret) {
 		dev_err(&pdev->dev, "failed to register dwc3 device\n");
-		goto err5;
+		goto err6;
 	}
 
 	return 0;
 
-err5:
+err6:
 	free_irq(omap->irq, omap);
 
-err4:
+err5:
 	kfree(omap->context);
 
-err3:
+err4:
 	platform_device_put(dwc3);
 
+err3:
+	dwc3_put_device_id(devid);
+
 err2:
 	iounmap(base);
 
@@ -358,6 +367,7 @@
 
 	platform_device_unregister(omap->dwc3);
 
+	dwc3_put_device_id(omap->dwc3->id);
 	free_irq(omap->irq, omap);
 	iounmap(omap->base);
 
@@ -384,18 +394,9 @@
 	},
 };
 
+module_platform_driver(dwc3_omap_driver);
+
+MODULE_ALIAS("platform:omap-dwc3");
 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer");
-
-static int __devinit dwc3_omap_init(void)
-{
-	return platform_driver_register(&dwc3_omap_driver);
-}
-module_init(dwc3_omap_init);
-
-static void __exit dwc3_omap_exit(void)
-{
-	platform_driver_unregister(&dwc3_omap_driver);
-}
-module_exit(dwc3_omap_exit);
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index f77c000..64e1f7c 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -42,52 +42,17 @@
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 
+#include "core.h"
+
 /* FIXME define these in <linux/pci_ids.h> */
 #define PCI_VENDOR_ID_SYNOPSYS		0x16c3
 #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3	0xabcd
 
-#define DWC3_PCI_DEVS_POSSIBLE	32
-
 struct dwc3_pci {
 	struct device		*dev;
 	struct platform_device	*dwc3;
 };
 
-static DECLARE_BITMAP(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
-
-static int dwc3_pci_get_device_id(struct dwc3_pci *glue)
-{
-	int		id;
-
-again:
-	id = find_first_zero_bit(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
-	if (id < DWC3_PCI_DEVS_POSSIBLE) {
-		int old;
-
-		old = test_and_set_bit(id, dwc3_pci_devs);
-		if (old)
-			goto again;
-	} else {
-		dev_err(glue->dev, "no space for new device\n");
-		id = -ENOMEM;
-	}
-
-	return 0;
-}
-
-static void dwc3_pci_put_device_id(struct dwc3_pci *glue, int id)
-{
-	int			ret;
-
-	if (id < 0)
-		return;
-
-	ret = test_bit(id, dwc3_pci_devs);
-	WARN(!ret, "Device: %s\nID %d not in use\n",
-			dev_driver_string(glue->dev), id);
-	clear_bit(id, dwc3_pci_devs);
-}
-
 static int __devinit dwc3_pci_probe(struct pci_dev *pci,
 		const struct pci_device_id *id)
 {
@@ -114,11 +79,11 @@
 	pci_set_power_state(pci, PCI_D0);
 	pci_set_master(pci);
 
-	devid = dwc3_pci_get_device_id(glue);
+	devid = dwc3_get_device_id();
 	if (devid < 0)
 		goto err2;
 
-	dwc3 = platform_device_alloc("dwc3-pci", devid);
+	dwc3 = platform_device_alloc("dwc3", devid);
 	if (!dwc3) {
 		dev_err(&pci->dev, "couldn't allocate dwc3 device\n");
 		goto err3;
@@ -163,13 +128,13 @@
 	platform_device_put(dwc3);
 
 err3:
-	dwc3_pci_put_device_id(glue, devid);
+	dwc3_put_device_id(devid);
 
 err2:
 	pci_disable_device(pci);
 
 err1:
-	kfree(pci);
+	kfree(glue);
 
 err0:
 	return ret;
@@ -179,7 +144,7 @@
 {
 	struct dwc3_pci	*glue = pci_get_drvdata(pci);
 
-	dwc3_pci_put_device_id(glue, glue->dwc3->id);
+	dwc3_put_device_id(glue->dwc3->id);
 	platform_device_unregister(glue->dwc3);
 	pci_set_drvdata(pci, NULL);
 	pci_disable_device(pci);
@@ -196,7 +161,7 @@
 MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
 
 static struct pci_driver dwc3_pci_driver = {
-	.name		= "pci-dwc3",
+	.name		= "dwc3-pci",
 	.id_table	= dwc3_pci_id_table,
 	.probe		= dwc3_pci_probe,
 	.remove		= __devexit_p(dwc3_pci_remove),
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 69a4e43..2f51de5 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -48,13 +48,13 @@
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/composite.h>
 
 #include "core.h"
 #include "gadget.h"
 #include "io.h"
 
-static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
-		const struct dwc3_event_depevt *event);
+static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum);
 
 static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
 {
@@ -125,6 +125,8 @@
 static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
 		struct dwc3_request *req)
 {
+	struct dwc3		*dwc = dep->dwc;
+	u32			type;
 	int			ret = 0;
 
 	req->request.actual	= 0;
@@ -143,9 +145,7 @@
 	 * IRQ we were waiting for is long gone.
 	 */
 	if (dep->flags & DWC3_EP_PENDING_REQUEST) {
-		struct dwc3	*dwc = dep->dwc;
 		unsigned	direction;
-		u32		type;
 
 		direction = !!(dep->flags & DWC3_EP0_DIR_IN);
 
@@ -165,6 +165,13 @@
 				req->request.dma, req->request.length, type);
 		dep->flags &= ~(DWC3_EP_PENDING_REQUEST |
 				DWC3_EP0_DIR_IN);
+	} else if (dwc->delayed_status) {
+		dwc->delayed_status = false;
+
+		if (dwc->ep0state == EP0_STATUS_PHASE)
+			dwc3_ep0_do_control_status(dwc, 1);
+		else
+			dev_dbg(dwc->dev, "too early for delayed status\n");
 	}
 
 	return ret;
@@ -190,9 +197,7 @@
 	}
 
 	/* we share one TRB for ep0/1 */
-	if (!list_empty(&dwc->eps[0]->request_list) ||
-			!list_empty(&dwc->eps[1]->request_list) ||
-			dwc->ep0_status_pending) {
+	if (!list_empty(&dep->request_list)) {
 		ret = -EBUSY;
 		goto out;
 	}
@@ -214,8 +219,9 @@
 	struct dwc3_ep		*dep = dwc->eps[0];
 
 	/* stall is always issued on EP0 */
-	__dwc3_gadget_ep_set_halt(dwc->eps[0], 1);
-	dwc->eps[0]->flags = DWC3_EP_ENABLED;
+	__dwc3_gadget_ep_set_halt(dep, 1);
+	dep->flags = DWC3_EP_ENABLED;
+	dwc->delayed_status = false;
 
 	if (!list_empty(&dep->request_list)) {
 		struct dwc3_request	*req;
@@ -254,17 +260,14 @@
 	return NULL;
 }
 
-static void dwc3_ep0_send_status_response(struct dwc3 *dwc)
+static void dwc3_ep0_status_cmpl(struct usb_ep *ep, struct usb_request *req)
 {
-	dwc3_ep0_start_trans(dwc, 1, dwc->setup_buf_addr,
-			dwc->ep0_usb_req.length,
-			DWC3_TRBCTL_CONTROL_DATA);
 }
-
 /*
  * ch 9.4.5
  */
-static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+static int dwc3_ep0_handle_status(struct dwc3 *dwc,
+		struct usb_ctrlrequest *ctrl)
 {
 	struct dwc3_ep		*dep;
 	u32			recip;
@@ -291,7 +294,7 @@
 	case USB_RECIP_ENDPOINT:
 		dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
 		if (!dep)
-		       return -EINVAL;
+			return -EINVAL;
 
 		if (dep->flags & DWC3_EP_STALL)
 			usb_status = 1 << USB_ENDPOINT_HALT;
@@ -302,10 +305,14 @@
 
 	response_pkt = (__le16 *) dwc->setup_buf;
 	*response_pkt = cpu_to_le16(usb_status);
-	dwc->ep0_usb_req.length = sizeof(*response_pkt);
-	dwc->ep0_status_pending = 1;
 
-	return 0;
+	dep = dwc->eps[0];
+	dwc->ep0_usb_req.dep = dep;
+	dwc->ep0_usb_req.request.length = sizeof(*response_pkt);
+	dwc->ep0_usb_req.request.dma = dwc->setup_buf_addr;
+	dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl;
+
+	return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);
 }
 
 static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
@@ -396,8 +403,7 @@
 	case USB_RECIP_ENDPOINT:
 		switch (wValue) {
 		case USB_ENDPOINT_HALT:
-
-			dep =  dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
+			dep =  dwc3_wIndex_to_dep(dwc, wIndex);
 			if (!dep)
 				return -EINVAL;
 			ret = __dwc3_gadget_ep_set_halt(dep, set);
@@ -422,8 +428,15 @@
 	u32 reg;
 
 	addr = le16_to_cpu(ctrl->wValue);
-	if (addr > 127)
+	if (addr > 127) {
+		dev_dbg(dwc->dev, "invalid device address %d\n", addr);
 		return -EINVAL;
+	}
+
+	if (dwc->dev_state == DWC3_CONFIGURED_STATE) {
+		dev_dbg(dwc->dev, "trying to set address when configured\n");
+		return -EINVAL;
+	}
 
 	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
 	reg &= ~(DWC3_DCFG_DEVADDR_MASK);
@@ -473,8 +486,10 @@
 		if (!cfg)
 			dwc->dev_state = DWC3_ADDRESS_STATE;
 		break;
+	default:
+		ret = -EINVAL;
 	}
-	return 0;
+	return ret;
 }
 
 static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
@@ -537,6 +552,9 @@
 	else
 		ret = dwc3_ep0_delegate_req(dwc, ctrl);
 
+	if (ret == USB_GADGET_DELAYED_STATUS)
+		dwc->delayed_status = true;
+
 	if (ret >= 0)
 		return;
 
@@ -550,27 +568,21 @@
 	struct dwc3_request	*r = NULL;
 	struct usb_request	*ur;
 	struct dwc3_trb		trb;
-	struct dwc3_ep		*dep;
+	struct dwc3_ep		*ep0;
 	u32			transferred;
 	u8			epnum;
 
 	epnum = event->endpoint_number;
-	dep = dwc->eps[epnum];
+	ep0 = dwc->eps[0];
 
 	dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
 
-	if (!dwc->ep0_status_pending) {
-		r = next_request(&dwc->eps[0]->request_list);
-		ur = &r->request;
-	} else {
-		ur = &dwc->ep0_usb_req;
-		dwc->ep0_status_pending = 0;
-	}
+	r = next_request(&ep0->request_list);
+	ur = &r->request;
 
 	dwc3_trb_to_nat(dwc->ep0_trb, &trb);
 
 	if (dwc->ep0_bounced) {
-		struct dwc3_ep	*ep0 = dwc->eps[0];
 
 		transferred = min_t(u32, ur->length,
 				ep0->endpoint.maxpacket - trb.length);
@@ -591,7 +603,7 @@
 		 * seems to be case when req.length > maxpacket. Could it be?
 		 */
 		if (r)
-			dwc3_gadget_giveback(dep, r, 0);
+			dwc3_gadget_giveback(ep0, r, 0);
 	}
 }
 
@@ -619,6 +631,7 @@
 	struct dwc3_ep		*dep = dwc->eps[event->endpoint_number];
 
 	dep->flags &= ~DWC3_EP_BUSY;
+	dwc->setup_packet_pending = false;
 
 	switch (dwc->ep0state) {
 	case EP0_SETUP_PHASE:
@@ -643,7 +656,6 @@
 static void dwc3_ep0_do_control_setup(struct dwc3 *dwc,
 		const struct dwc3_event_depevt *event)
 {
-	dwc->ep0state = EP0_SETUP_PHASE;
 	dwc3_ep0_out_start(dwc);
 }
 
@@ -655,12 +667,6 @@
 	int			ret;
 
 	dep = dwc->eps[0];
-	dwc->ep0state = EP0_DATA_PHASE;
-
-	if (dwc->ep0_status_pending) {
-		dwc3_ep0_send_status_response(dwc);
-		return;
-	}
 
 	if (list_empty(&dep->request_list)) {
 		dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n");
@@ -674,7 +680,6 @@
 	req = next_request(&dep->request_list);
 	req->direction = !!event->endpoint_number;
 
-	dwc->ep0state = EP0_DATA_PHASE;
 	if (req->request.length == 0) {
 		ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
 				dwc->ctrl_req_addr, 0,
@@ -706,35 +711,79 @@
 	WARN_ON(ret < 0);
 }
 
-static void dwc3_ep0_do_control_status(struct dwc3 *dwc,
-		const struct dwc3_event_depevt *event)
+static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
 {
+	struct dwc3		*dwc = dep->dwc;
 	u32			type;
-	int			ret;
-
-	dwc->ep0state = EP0_STATUS_PHASE;
 
 	type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3
 		: DWC3_TRBCTL_CONTROL_STATUS2;
 
-	ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
+	return dwc3_ep0_start_trans(dwc, dep->number,
 			dwc->ctrl_req_addr, 0, type);
+}
 
-	WARN_ON(ret < 0);
+static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum)
+{
+	struct dwc3_ep		*dep = dwc->eps[epnum];
+
+	WARN_ON(dwc3_ep0_start_control_status(dep));
 }
 
 static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
 		const struct dwc3_event_depevt *event)
 {
+	dwc->setup_packet_pending = true;
+
+	/*
+	 * This part is very tricky: If we has just handled
+	 * XferNotReady(Setup) and we're now expecting a
+	 * XferComplete but, instead, we receive another
+	 * XferNotReady(Setup), we should STALL and restart
+	 * the state machine.
+	 *
+	 * In all other cases, we just continue waiting
+	 * for the XferComplete event.
+	 *
+	 * We are a little bit unsafe here because we're
+	 * not trying to ensure that last event was, indeed,
+	 * XferNotReady(Setup).
+	 *
+	 * Still, we don't expect any condition where that
+	 * should happen and, even if it does, it would be
+	 * another error condition.
+	 */
+	if (dwc->ep0_next_event == DWC3_EP0_COMPLETE) {
+		switch (event->status) {
+		case DEPEVT_STATUS_CONTROL_SETUP:
+			dev_vdbg(dwc->dev, "Unexpected XferNotReady(Setup)\n");
+			dwc3_ep0_stall_and_restart(dwc);
+			break;
+		case DEPEVT_STATUS_CONTROL_DATA:
+			/* FALLTHROUGH */
+		case DEPEVT_STATUS_CONTROL_STATUS:
+			/* FALLTHROUGH */
+		default:
+			dev_vdbg(dwc->dev, "waiting for XferComplete\n");
+		}
+
+		return;
+	}
+
 	switch (event->status) {
 	case DEPEVT_STATUS_CONTROL_SETUP:
 		dev_vdbg(dwc->dev, "Control Setup\n");
+
+		dwc->ep0state = EP0_SETUP_PHASE;
+
 		dwc3_ep0_do_control_setup(dwc, event);
 		break;
 
 	case DEPEVT_STATUS_CONTROL_DATA:
 		dev_vdbg(dwc->dev, "Control Data\n");
 
+		dwc->ep0state = EP0_DATA_PHASE;
+
 		if (dwc->ep0_next_event != DWC3_EP0_NRDY_DATA) {
 			dev_vdbg(dwc->dev, "Expected %d got %d\n",
 					dwc->ep0_next_event,
@@ -764,6 +813,8 @@
 	case DEPEVT_STATUS_CONTROL_STATUS:
 		dev_vdbg(dwc->dev, "Control Status\n");
 
+		dwc->ep0state = EP0_STATUS_PHASE;
+
 		if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) {
 			dev_vdbg(dwc->dev, "Expected %d got %d\n",
 					dwc->ep0_next_event,
@@ -772,12 +823,19 @@
 			dwc3_ep0_stall_and_restart(dwc);
 			return;
 		}
-		dwc3_ep0_do_control_status(dwc, event);
+
+		if (dwc->delayed_status) {
+			WARN_ON_ONCE(event->endpoint_number != 1);
+			dev_vdbg(dwc->dev, "Mass Storage delayed status\n");
+			return;
+		}
+
+		dwc3_ep0_do_control_status(dwc, event->endpoint_number);
 	}
 }
 
 void dwc3_ep0_interrupt(struct dwc3 *dwc,
-		const const struct dwc3_event_depevt *event)
+		const struct dwc3_event_depevt *event)
 {
 	u8			epnum = event->endpoint_number;
 
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 25dbd86..a696bde 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -65,6 +65,22 @@
 		return;
 	}
 
+	if (req->request.num_sgs) {
+		int	mapped;
+
+		mapped = dma_map_sg(dwc->dev, req->request.sg,
+				req->request.num_sgs,
+				req->direction ? DMA_TO_DEVICE
+				: DMA_FROM_DEVICE);
+		if (mapped < 0) {
+			dev_err(dwc->dev, "failed to map SGs\n");
+			return;
+		}
+
+		req->request.num_mapped_sgs = mapped;
+		return;
+	}
+
 	if (req->request.dma == DMA_ADDR_INVALID) {
 		req->request.dma = dma_map_single(dwc->dev, req->request.buf,
 				req->request.length, req->direction
@@ -82,6 +98,17 @@
 		return;
 	}
 
+	if (req->request.num_mapped_sgs) {
+		req->request.dma = DMA_ADDR_INVALID;
+		dma_unmap_sg(dwc->dev, req->request.sg,
+				req->request.num_sgs,
+				req->direction ? DMA_TO_DEVICE
+				: DMA_FROM_DEVICE);
+
+		req->request.num_mapped_sgs = 0;
+		return;
+	}
+
 	if (req->mapped) {
 		dma_unmap_single(dwc->dev, req->request.dma,
 				req->request.length, req->direction
@@ -97,7 +124,11 @@
 	struct dwc3			*dwc = dep->dwc;
 
 	if (req->queued) {
-		dep->busy_slot++;
+		if (req->request.num_mapped_sgs)
+			dep->busy_slot += req->request.num_mapped_sgs;
+		else
+			dep->busy_slot++;
+
 		/*
 		 * Skip LINK TRB. We can't use req->trb and check for
 		 * DWC3_TRBCTL_LINK_TRB because it points the TRB we just
@@ -108,6 +139,7 @@
 			dep->busy_slot++;
 	}
 	list_del(&req->list);
+	req->trb = NULL;
 
 	if (req->request.status == -EINPROGRESS)
 		req->request.status = status;
@@ -251,7 +283,8 @@
 }
 
 static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
-		const struct usb_endpoint_descriptor *desc)
+		const struct usb_endpoint_descriptor *desc,
+		const struct usb_ss_ep_comp_descriptor *comp_desc)
 {
 	struct dwc3_gadget_ep_cmd_params params;
 
@@ -264,7 +297,7 @@
 	params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN
 		| DWC3_DEPCFG_XFER_NOT_READY_EN;
 
-	if (usb_endpoint_xfer_bulk(desc) && dep->endpoint.max_streams) {
+	if (usb_ss_max_streams(comp_desc) && usb_endpoint_xfer_bulk(desc)) {
 		params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE
 			| DWC3_DEPCFG_STREAM_EVENT_EN;
 		dep->stream_capable = true;
@@ -317,7 +350,8 @@
  * Caller should take care of locking
  */
 static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
-		const struct usb_endpoint_descriptor *desc)
+		const struct usb_endpoint_descriptor *desc,
+		const struct usb_ss_ep_comp_descriptor *comp_desc)
 {
 	struct dwc3		*dwc = dep->dwc;
 	u32			reg;
@@ -329,7 +363,7 @@
 			return ret;
 	}
 
-	ret = dwc3_gadget_set_ep_config(dwc, dep, desc);
+	ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc);
 	if (ret)
 		return ret;
 
@@ -343,6 +377,7 @@
 			return ret;
 
 		dep->desc = desc;
+		dep->comp_desc = comp_desc;
 		dep->type = usb_endpoint_type(desc);
 		dep->flags |= DWC3_EP_ENABLED;
 
@@ -405,6 +440,7 @@
 
 	dep->stream_capable = false;
 	dep->desc = NULL;
+	dep->comp_desc = NULL;
 	dep->type = 0;
 	dep->flags = 0;
 
@@ -473,7 +509,7 @@
 	dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
 
 	spin_lock_irqsave(&dwc->lock, flags);
-	ret = __dwc3_gadget_ep_enable(dep, desc);
+	ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc);
 	spin_unlock_irqrestore(&dwc->lock, flags);
 
 	return ret;
@@ -539,6 +575,85 @@
 	kfree(req);
 }
 
+/**
+ * dwc3_prepare_one_trb - setup one TRB from one request
+ * @dep: endpoint for which this request is prepared
+ * @req: dwc3_request pointer
+ */
+static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
+		struct dwc3_request *req, dma_addr_t dma,
+		unsigned length, unsigned last, unsigned chain)
+{
+	struct dwc3		*dwc = dep->dwc;
+	struct dwc3_trb_hw	*trb_hw;
+	struct dwc3_trb		trb;
+
+	unsigned int		cur_slot;
+
+	dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
+			dep->name, req, (unsigned long long) dma,
+			length, last ? " last" : "",
+			chain ? " chain" : "");
+
+	trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+	cur_slot = dep->free_slot;
+	dep->free_slot++;
+
+	/* Skip the LINK-TRB on ISOC */
+	if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
+			usb_endpoint_xfer_isoc(dep->desc))
+		return;
+
+	memset(&trb, 0, sizeof(trb));
+	if (!req->trb) {
+		dwc3_gadget_move_request_queued(req);
+		req->trb = trb_hw;
+		req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
+	}
+
+	if (usb_endpoint_xfer_isoc(dep->desc)) {
+		trb.isp_imi = true;
+		trb.csp = true;
+	} else {
+		trb.chn = chain;
+		trb.lst = last;
+	}
+
+	if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
+		trb.sid_sofn = req->request.stream_id;
+
+	switch (usb_endpoint_type(dep->desc)) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
+		break;
+
+	case USB_ENDPOINT_XFER_ISOC:
+		trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
+
+		/* IOC every DWC3_TRB_NUM / 4 so we can refill */
+		if (!(cur_slot % (DWC3_TRB_NUM / 4)))
+			trb.ioc = last;
+		break;
+
+	case USB_ENDPOINT_XFER_BULK:
+	case USB_ENDPOINT_XFER_INT:
+		trb.trbctl = DWC3_TRBCTL_NORMAL;
+		break;
+	default:
+		/*
+		 * This is only possible with faulty memory because we
+		 * checked it already :)
+		 */
+		BUG();
+	}
+
+	trb.length	= length;
+	trb.bplh	= dma;
+	trb.hwo		= true;
+
+	dwc3_trb_to_hw(&trb, trb_hw);
+}
+
 /*
  * dwc3_prepare_trbs - setup TRBs from requests
  * @dep: endpoint for which requests are being prepared
@@ -548,18 +663,17 @@
  * transfers. The functions returns once there are not more TRBs available or
  * it run out of requests.
  */
-static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,
-		bool starting)
+static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
 {
-	struct dwc3_request	*req, *n, *ret = NULL;
-	struct dwc3_trb_hw	*trb_hw;
-	struct dwc3_trb		trb;
+	struct dwc3_request	*req, *n;
 	u32			trbs_left;
+	unsigned int		last_one = 0;
 
 	BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
 
 	/* the first request must not be queued */
 	trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
+
 	/*
 	 * if busy & slot are equal than it is either full or empty. If we are
 	 * starting to proceed requests then we are empty. Otherwise we ar
@@ -567,7 +681,7 @@
 	 */
 	if (!trbs_left) {
 		if (!starting)
-			return NULL;
+			return;
 		trbs_left = DWC3_TRB_NUM;
 		/*
 		 * In case we start from scratch, we queue the ISOC requests
@@ -591,94 +705,62 @@
 
 	/* The last TRB is a link TRB, not used for xfer */
 	if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->desc))
-		return NULL;
+		return;
 
 	list_for_each_entry_safe(req, n, &dep->request_list, list) {
-		unsigned int last_one = 0;
-		unsigned int cur_slot;
+		unsigned	length;
+		dma_addr_t	dma;
 
-		trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
-		cur_slot = dep->free_slot;
-		dep->free_slot++;
+		if (req->request.num_mapped_sgs > 0) {
+			struct usb_request *request = &req->request;
+			struct scatterlist *sg = request->sg;
+			struct scatterlist *s;
+			int		i;
 
-		/* Skip the LINK-TRB on ISOC */
-		if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
-				usb_endpoint_xfer_isoc(dep->desc))
-			continue;
+			for_each_sg(sg, s, request->num_mapped_sgs, i) {
+				unsigned chain = true;
 
-		dwc3_gadget_move_request_queued(req);
-		memset(&trb, 0, sizeof(trb));
-		trbs_left--;
+				length = sg_dma_len(s);
+				dma = sg_dma_address(s);
 
-		/* Is our TRB pool empty? */
-		if (!trbs_left)
-			last_one = 1;
-		/* Is this the last request? */
-		if (list_empty(&dep->request_list))
-			last_one = 1;
+				if (i == (request->num_mapped_sgs - 1)
+						|| sg_is_last(s)) {
+					last_one = true;
+					chain = false;
+				}
 
-		/*
-		 * FIXME we shouldn't need to set LST bit always but we are
-		 * facing some weird problem with the Hardware where it doesn't
-		 * complete even though it has been previously started.
-		 *
-		 * While we're debugging the problem, as a workaround to
-		 * multiple TRBs handling, use only one TRB at a time.
-		 */
-		last_one = 1;
+				trbs_left--;
+				if (!trbs_left)
+					last_one = true;
 
-		req->trb = trb_hw;
-		if (!ret)
-			ret = req;
+				if (last_one)
+					chain = false;
 
-		trb.bplh = req->request.dma;
+				dwc3_prepare_one_trb(dep, req, dma, length,
+						last_one, chain);
 
-		if (usb_endpoint_xfer_isoc(dep->desc)) {
-			trb.isp_imi = true;
-			trb.csp = true;
+				if (last_one)
+					break;
+			}
 		} else {
-			trb.lst = last_one;
+			dma = req->request.dma;
+			length = req->request.length;
+			trbs_left--;
+
+			if (!trbs_left)
+				last_one = 1;
+
+			/* Is this the last request? */
+			if (list_is_last(&req->list, &dep->request_list))
+				last_one = 1;
+
+			dwc3_prepare_one_trb(dep, req, dma, length,
+					last_one, false);
+
+			if (last_one)
+				break;
 		}
-
-		if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
-			trb.sid_sofn = req->request.stream_id;
-
-		switch (usb_endpoint_type(dep->desc)) {
-		case USB_ENDPOINT_XFER_CONTROL:
-			trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
-			break;
-
-		case USB_ENDPOINT_XFER_ISOC:
-			trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
-
-			/* IOC every DWC3_TRB_NUM / 4 so we can refill */
-			if (!(cur_slot % (DWC3_TRB_NUM / 4)))
-				trb.ioc = last_one;
-			break;
-
-		case USB_ENDPOINT_XFER_BULK:
-		case USB_ENDPOINT_XFER_INT:
-			trb.trbctl = DWC3_TRBCTL_NORMAL;
-			break;
-		default:
-			/*
-			 * This is only possible with faulty memory because we
-			 * checked it already :)
-			 */
-			BUG();
-		}
-
-		trb.length	= req->request.length;
-		trb.hwo = true;
-
-		dwc3_trb_to_hw(&trb, trb_hw);
-		req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
-
-		if (last_one)
-			break;
 	}
-
-	return ret;
 }
 
 static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
@@ -707,11 +789,13 @@
 		/* req points to the first request which will be sent */
 		req = next_request(&dep->req_queued);
 	} else {
+		dwc3_prepare_trbs(dep, start_new);
+
 		/*
 		 * req points to the first request where HWO changed
 		 * from 0 to 1
 		 */
-		req = dwc3_prepare_trbs(dep, start_new);
+		req = next_request(&dep->req_queued);
 	}
 	if (!req) {
 		dep->flags |= DWC3_EP_PENDING_REQUEST;
@@ -745,8 +829,9 @@
 	dep->flags |= DWC3_EP_BUSY;
 	dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
 			dep->number);
-	if (!dep->res_trans_idx)
-		printk_once(KERN_ERR "%s() res_trans_idx is invalid\n", __func__);
+
+	WARN_ON_ONCE(!dep->res_trans_idx);
+
 	return 0;
 }
 
@@ -1155,35 +1240,9 @@
 	dwc->gadget_driver	= driver;
 	dwc->gadget.dev.driver	= &driver->driver;
 
-	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
-
-	reg &= ~DWC3_GCTL_SCALEDOWN(3);
-	reg &= ~DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG);
-	reg &= ~DWC3_GCTL_DISSCRAMBLE;
-	reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE);
-
-	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams0)) {
-	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
-		reg &= ~DWC3_GCTL_DSBLCLKGTNG;
-		break;
-	default:
-		dev_dbg(dwc->dev, "No power optimization available\n");
-	}
-
-	/*
-	 * WORKAROUND: DWC3 revisions <1.90a have a bug
-	 * when The device fails to connect at SuperSpeed
-	 * and falls back to high-speed mode which causes
-	 * the device to enter in a Connect/Disconnect loop
-	 */
-	if (dwc->revision < DWC3_REVISION_190A)
-		reg |= DWC3_GCTL_U2RSTECN;
-
-	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
-
 	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
 	reg &= ~(DWC3_DCFG_SPEED_MASK);
-	reg |= DWC3_DCFG_SUPERSPEED;
+	reg |= dwc->maximum_speed;
 	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
 
 	dwc->start_config_issued = false;
@@ -1192,14 +1251,14 @@
 	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
 
 	dep = dwc->eps[0];
-	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
 	if (ret) {
 		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
 		goto err0;
 	}
 
 	dep = dwc->eps[1];
-	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
 	if (ret) {
 		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
 		goto err1;
@@ -1290,11 +1349,10 @@
 					&dwc->gadget.ep_list);
 
 			ret = dwc3_alloc_trb_pool(dep);
-			if (ret) {
-				dev_err(dwc->dev, "%s: failed to allocate TRB pool\n", dep->name);
+			if (ret)
 				return ret;
-			}
 		}
+
 		INIT_LIST_HEAD(&dep->request_list);
 		INIT_LIST_HEAD(&dep->req_queued);
 	}
@@ -1334,8 +1392,10 @@
 
 	do {
 		req = next_request(&dep->req_queued);
-		if (!req)
-			break;
+		if (!req) {
+			WARN_ON_ONCE(1);
+			return 1;
+		}
 
 		dwc3_trb_to_nat(req->trb, &trb);
 
@@ -1400,6 +1460,31 @@
 		dep->flags &= ~DWC3_EP_BUSY;
 		dep->res_trans_idx = 0;
 	}
+
+	/*
+	 * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround.
+	 * See dwc3_gadget_linksts_change_interrupt() for 1st half.
+	 */
+	if (dwc->revision < DWC3_REVISION_183A) {
+		u32		reg;
+		int		i;
+
+		for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) {
+			struct dwc3_ep	*dep = dwc->eps[i];
+
+			if (!(dep->flags & DWC3_EP_ENABLED))
+				continue;
+
+			if (!list_empty(&dep->req_queued))
+				return;
+		}
+
+		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+		reg |= dwc->u1u2;
+		dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+		dwc->u1u2 = 0;
+	}
 }
 
 static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
@@ -1639,6 +1724,7 @@
 	dwc->start_config_issued = false;
 
 	dwc->gadget.speed = USB_SPEED_UNKNOWN;
+	dwc->setup_packet_pending = false;
 }
 
 static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on)
@@ -1675,6 +1761,40 @@
 
 	dev_vdbg(dwc->dev, "%s\n", __func__);
 
+	/*
+	 * WORKAROUND: DWC3 revisions <1.88a have an issue which
+	 * would cause a missing Disconnect Event if there's a
+	 * pending Setup Packet in the FIFO.
+	 *
+	 * There's no suggested workaround on the official Bug
+	 * report, which states that "unless the driver/application
+	 * is doing any special handling of a disconnect event,
+	 * there is no functional issue".
+	 *
+	 * Unfortunately, it turns out that we _do_ some special
+	 * handling of a disconnect event, namely complete all
+	 * pending transfers, notify gadget driver of the
+	 * disconnection, and so on.
+	 *
+	 * Our suggested workaround is to follow the Disconnect
+	 * Event steps here, instead, based on a setup_packet_pending
+	 * flag. Such flag gets set whenever we have a XferNotReady
+	 * event on EP0 and gets cleared on XferComplete for the
+	 * same endpoint.
+	 *
+	 * Refers to:
+	 *
+	 * STAR#9000466709: RTL: Device : Disconnect event not
+	 * generated if setup packet pending in FIFO
+	 */
+	if (dwc->revision < DWC3_REVISION_188A) {
+		if (dwc->setup_packet_pending)
+			dwc3_gadget_disconnect_interrupt(dwc);
+	}
+
+	/* after reset -> Default State */
+	dwc->dev_state = DWC3_DEFAULT_STATE;
+
 	/* Enable PHYs */
 	dwc3_gadget_usb2_phy_power(dwc, true);
 	dwc3_gadget_usb3_phy_power(dwc, true);
@@ -1755,6 +1875,22 @@
 
 	switch (speed) {
 	case DWC3_DCFG_SUPERSPEED:
+		/*
+		 * WORKAROUND: DWC3 revisions <1.90a have an issue which
+		 * would cause a missing USB3 Reset event.
+		 *
+		 * In such situations, we should force a USB3 Reset
+		 * event by calling our dwc3_gadget_reset_interrupt()
+		 * routine.
+		 *
+		 * Refers to:
+		 *
+		 * STAR#9000483510: RTL: SS : USB3 reset event may
+		 * not be generated always when the link enters poll
+		 */
+		if (dwc->revision < DWC3_REVISION_190A)
+			dwc3_gadget_reset_interrupt(dwc);
+
 		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
 		dwc->gadget.ep0->maxpacket = 512;
 		dwc->gadget.speed = USB_SPEED_SUPER;
@@ -1781,14 +1917,14 @@
 	dwc3_gadget_disable_phy(dwc, dwc->gadget.speed);
 
 	dep = dwc->eps[0];
-	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
 	if (ret) {
 		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
 		return;
 	}
 
 	dep = dwc->eps[1];
-	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
 	if (ret) {
 		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
 		return;
@@ -1818,8 +1954,55 @@
 static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
 		unsigned int evtinfo)
 {
-	/*  The fith bit says SuperSpeed yes or no. */
-	dwc->link_state = evtinfo & DWC3_LINK_STATE_MASK;
+	enum dwc3_link_state	next = evtinfo & DWC3_LINK_STATE_MASK;
+
+	/*
+	 * WORKAROUND: DWC3 Revisions <1.83a have an issue which, depending
+	 * on the link partner, the USB session might do multiple entry/exit
+	 * of low power states before a transfer takes place.
+	 *
+	 * Due to this problem, we might experience lower throughput. The
+	 * suggested workaround is to disable DCTL[12:9] bits if we're
+	 * transitioning from U1/U2 to U0 and enable those bits again
+	 * after a transfer completes and there are no pending transfers
+	 * on any of the enabled endpoints.
+	 *
+	 * This is the first half of that workaround.
+	 *
+	 * Refers to:
+	 *
+	 * STAR#9000446952: RTL: Device SS : if U1/U2 ->U0 takes >128us
+	 * core send LGO_Ux entering U0
+	 */
+	if (dwc->revision < DWC3_REVISION_183A) {
+		if (next == DWC3_LINK_STATE_U0) {
+			u32	u1u2;
+			u32	reg;
+
+			switch (dwc->link_state) {
+			case DWC3_LINK_STATE_U1:
+			case DWC3_LINK_STATE_U2:
+				reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+				u1u2 = reg & (DWC3_DCTL_INITU2ENA
+						| DWC3_DCTL_ACCEPTU2ENA
+						| DWC3_DCTL_INITU1ENA
+						| DWC3_DCTL_ACCEPTU1ENA);
+
+				if (!dwc->u1u2)
+					dwc->u1u2 = reg & u1u2;
+
+				reg &= ~u1u2;
+
+				dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+				break;
+			default:
+				/* do nothing */
+				break;
+			}
+		}
+	}
+
+	dwc->link_state = next;
 
 	dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
 }
@@ -1925,7 +2108,7 @@
 
 	spin_lock(&dwc->lock);
 
-	for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) {
+	for (i = 0; i < dwc->num_event_buffers; i++) {
 		irqreturn_t status;
 
 		status = dwc3_process_event_buf(dwc, i);
@@ -1986,9 +2169,10 @@
 	dev_set_name(&dwc->gadget.dev, "gadget");
 
 	dwc->gadget.ops			= &dwc3_gadget_ops;
-	dwc->gadget.is_dualspeed	= true;
+	dwc->gadget.max_speed		= USB_SPEED_SUPER;
 	dwc->gadget.speed		= USB_SPEED_UNKNOWN;
 	dwc->gadget.dev.parent		= dwc->dev;
+	dwc->gadget.sg_supported	= true;
 
 	dma_set_coherent_mask(&dwc->gadget.dev, dwc->dev->coherent_dma_mask);
 
@@ -2076,7 +2260,6 @@
 void dwc3_gadget_exit(struct dwc3 *dwc)
 {
 	int			irq;
-	int			i;
 
 	usb_del_gadget_udc(&dwc->gadget);
 	irq = platform_get_irq(to_platform_device(dwc->dev), 0);
@@ -2084,9 +2267,6 @@
 	dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
 	free_irq(irq, dwc);
 
-	for (i = 0; i < ARRAY_SIZE(dwc->eps); i++)
-		__dwc3_gadget_ep_disable(dwc->eps[i]);
-
 	dwc3_gadget_free_endpoints(dwc);
 
 	dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index 71145a44..d97f467 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -79,19 +79,6 @@
 
 /* -------------------------------------------------------------------------- */
 
-struct dwc3_request {
-	struct usb_request	request;
-	struct list_head	list;
-	struct dwc3_ep		*dep;
-
-	u8			epnum;
-	struct dwc3_trb_hw	*trb;
-	dma_addr_t		trb_dma;
-
-	unsigned		direction:1;
-	unsigned		mapped:1;
-	unsigned		queued:1;
-};
 #define to_dwc3_request(r)	(container_of(r, struct dwc3_request, request))
 
 static inline struct dwc3_request *next_request(struct list_head *list)
@@ -110,23 +97,11 @@
 	list_move_tail(&req->list, &dep->req_queued);
 }
 
-#if defined(CONFIG_USB_GADGET_DWC3) || defined(CONFIG_USB_GADGET_DWC3_MODULE)
-int dwc3_gadget_init(struct dwc3 *dwc);
-void dwc3_gadget_exit(struct dwc3 *dwc);
-#else
-static inline int dwc3_gadget_init(struct dwc3 *dwc) { return 0; }
-static inline void dwc3_gadget_exit(struct dwc3 *dwc) { }
-static inline int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
-		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
-{
-	return 0;
-}
-#endif
-
 void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
 		int status);
 
-void dwc3_ep0_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event);
+void dwc3_ep0_interrupt(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event);
 void dwc3_ep0_out_start(struct dwc3 *dwc);
 int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
 		gfp_t gfp_flags);
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
new file mode 100644
index 0000000..7cfe211b
--- /dev/null
+++ b/drivers/usb/dwc3/host.c
@@ -0,0 +1,102 @@
+/**
+ * host.c - DesignWare USB3 DRD Controller Host Glue
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/platform_device.h>
+
+#include "core.h"
+
+static struct resource generic_resources[] = {
+	{
+		.flags = IORESOURCE_IRQ,
+	},
+	{
+		.flags = IORESOURCE_MEM,
+	},
+};
+
+int dwc3_host_init(struct dwc3 *dwc)
+{
+	struct platform_device	*xhci;
+	int			ret;
+
+	xhci = platform_device_alloc("xhci", -1);
+	if (!xhci) {
+		dev_err(dwc->dev, "couldn't allocate xHCI device\n");
+		ret = -ENOMEM;
+		goto err0;
+	}
+
+	dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask);
+
+	xhci->dev.parent	= dwc->dev;
+	xhci->dev.dma_mask	= dwc->dev->dma_mask;
+	xhci->dev.dma_parms	= dwc->dev->dma_parms;
+
+	dwc->xhci = xhci;
+
+	/* setup resources */
+	generic_resources[0].start = dwc->irq;
+
+	generic_resources[1].start = dwc->res->start;
+	generic_resources[1].end = dwc->res->start + 0x7fff;
+
+	ret = platform_device_add_resources(xhci, generic_resources,
+			ARRAY_SIZE(generic_resources));
+	if (ret) {
+		dev_err(dwc->dev, "couldn't add resources to xHCI device\n");
+		goto err1;
+	}
+
+	ret = platform_device_add(xhci);
+	if (ret) {
+		dev_err(dwc->dev, "failed to register xHCI device\n");
+		goto err1;
+	}
+
+	return 0;
+
+err1:
+	platform_device_put(xhci);
+
+err0:
+	return ret;
+}
+
+void dwc3_host_exit(struct dwc3 *dwc)
+{
+	platform_device_unregister(dwc->xhci);
+}
diff --git a/drivers/usb/dwc3/io.h b/drivers/usb/dwc3/io.h
index bc957db..071d561 100644
--- a/drivers/usb/dwc3/io.h
+++ b/drivers/usb/dwc3/io.h
@@ -39,7 +39,7 @@
 #ifndef __DRIVERS_USB_DWC3_IO_H
 #define __DRIVERS_USB_DWC3_IO_H
 
-#include <asm/io.h>
+#include <linux/io.h>
 
 static inline u32 dwc3_readl(void __iomem *base, u32 offset)
 {
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 12a401a..7ecb68a 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -15,6 +15,7 @@
 
 menuconfig USB_GADGET
 	tristate "USB Gadget Support"
+	select NLS
 	help
 	   USB is a master/slave protocol, organized with one master
 	   host (such as a PC) controlling up to 127 peripheral devices.
@@ -124,7 +125,6 @@
 #
 choice
 	prompt "USB Peripheral Controller"
-	depends on USB_GADGET
 	help
 	   A USB device uses a controller to talk to its host.
 	   Systems should have only one such upstream link.
@@ -234,7 +234,6 @@
 
 config USB_RENESAS_USBHS_UDC
 	tristate 'Renesas USBHS controller'
-	depends on SUPERH || ARCH_SHMOBILE
 	depends on USB_RENESAS_USBHS
 	select USB_GADGET_DUALSPEED
 	help
@@ -309,25 +308,13 @@
 
 	  This driver has been tested on S3C2416 and S3C2450 processors.
 
-config USB_PXA_U2O
-	tristate "PXA9xx Processor USB2.0 controller"
-	depends on ARCH_MMP
+config USB_MV_UDC
+	tristate "Marvell USB2.0 Device Controller"
 	select USB_GADGET_DUALSPEED
 	help
-	  PXA9xx Processor series include a high speed USB2.0 device
-	  controller, which support high speed and full speed USB peripheral.
-
-config USB_GADGET_DWC3
-	tristate "DesignWare USB3.0 (DRD) Controller"
-	depends on USB_DWC3
-	select USB_GADGET_DUALSPEED
-	select USB_GADGET_SUPERSPEED
-	help
-	  DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
-	  which can be configured for peripheral-only, host-only, hub-only
-	  and Dual-Role operation. This Controller was first integrated into
-	  the OMAP5 series of processors. More information about the OMAP5
-	  version of this controller, refer to http://www.ti.com/omap5.
+	  Marvell Socs (including PXA and MMP series) include a high speed
+	  USB2.0 OTG controller, which can be configured as high speed or
+	  full speed USB peripheral.
 
 #
 # Controllers available in both integrated and discrete versions
@@ -543,12 +530,10 @@
 # Selected by UDC drivers that support high-speed operation.
 config USB_GADGET_DUALSPEED
 	bool
-	depends on USB_GADGET
 
 # Selected by UDC drivers that support super-speed opperation
 config USB_GADGET_SUPERSPEED
 	bool
-	depends on USB_GADGET
 	depends on USB_GADGET_DUALSPEED
 
 #
@@ -556,7 +541,6 @@
 #
 choice
 	tristate "USB Gadget Drivers"
-	depends on USB_GADGET
 	default USB_ETH
 	help
 	  A Linux "Gadget Driver" talks to the USB Peripheral Controller
diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
index b54ac61..b7f6eef 100644
--- a/drivers/usb/gadget/Makefile
+++ b/drivers/usb/gadget/Makefile
@@ -27,7 +27,7 @@
 obj-$(CONFIG_USB_S3C_HSUDC)	+= s3c-hsudc.o
 obj-$(CONFIG_USB_LANGWELL)	+= langwell_udc.o
 obj-$(CONFIG_USB_EG20T)		+= pch_udc.o
-obj-$(CONFIG_USB_PXA_U2O)	+= mv_udc.o
+obj-$(CONFIG_USB_MV_UDC)	+= mv_udc.o
 mv_udc-y			:= mv_udc_core.o
 obj-$(CONFIG_USB_CI13XXX_MSM)	+= ci13xxx_msm.o
 obj-$(CONFIG_USB_FUSB300)	+= fusb300_udc.o
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index 45f422a..e9a2c5c 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -1959,7 +1959,7 @@
 	u32 tmp;
 
 	if (!driver || !bind || !driver->setup
-			|| driver->speed < USB_SPEED_HIGH)
+			|| driver->max_speed < USB_SPEED_HIGH)
 		return -EINVAL;
 	if (!dev)
 		return -ENODEV;
@@ -3349,7 +3349,7 @@
 	dev_set_name(&dev->gadget.dev, "gadget");
 	dev->gadget.dev.release = gadget_release;
 	dev->gadget.name = name;
-	dev->gadget.is_dualspeed = 1;
+	dev->gadget.max_speed = USB_SPEED_HIGH;
 
 	/* init registers, interrupts, ... */
 	startup_registers(dev);
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 8efe0fa..ac41f71 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -1633,7 +1633,7 @@
 	unsigned long	flags;
 
 	if (!driver
-			|| driver->speed < USB_SPEED_FULL
+			|| driver->max_speed < USB_SPEED_FULL
 			|| !bind
 			|| !driver->setup) {
 		DBG("bad parameter.\n");
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index 271a9d8..e2fb6d5 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -1038,7 +1038,7 @@
 	.gadget	= {
 		.ops		= &usba_udc_ops,
 		.ep_list	= LIST_HEAD_INIT(the_udc.gadget.ep_list),
-		.is_dualspeed	= 1,
+		.max_speed	= USB_SPEED_HIGH,
 		.name		= "atmel_usba_udc",
 		.dev	= {
 			.init_name	= "gadget",
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 9a0c397..27e3137 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -182,6 +182,16 @@
 	return num + (dir ? 16 : 0);
 }
 
+static int ep_to_bit(int n)
+{
+	int fill = 16 - hw_ep_max / 2;
+
+	if (n >= hw_ep_max / 2)
+		n += fill;
+
+	return n;
+}
+
 /**
  * hw_aread: reads from register bitfield
  * @addr: address relative to bus map
@@ -440,12 +450,13 @@
 /**
  * hw_test_and_clear_setup_status: test & clear setup status (execute without
  *                                 interruption)
- * @n: bit number (endpoint)
+ * @n: endpoint number
  *
  * This function returns setup status
  */
 static int hw_test_and_clear_setup_status(int n)
 {
+	n = ep_to_bit(n);
 	return hw_ctest_and_clear(CAP_ENDPTSETUPSTAT, BIT(n));
 }
 
@@ -641,12 +652,13 @@
 /**
  * hw_test_and_clear_complete: test & clear complete status (execute without
  *                             interruption)
- * @n: bit number (endpoint)
+ * @n: endpoint number
  *
  * This function returns complete status
  */
 static int hw_test_and_clear_complete(int n)
 {
+	n = ep_to_bit(n);
 	return hw_ctest_and_clear(CAP_ENDPTCOMPLETE, BIT(n));
 }
 
@@ -754,8 +766,11 @@
 
 	n += scnprintf(buf + n, PAGE_SIZE - n, "speed             = %d\n",
 		       gadget->speed);
+	n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed         = %d\n",
+		       gadget->max_speed);
+	/* TODO: Scheduled for removal in 3.8. */
 	n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed      = %d\n",
-		       gadget->is_dualspeed);
+		       gadget_is_dualspeed(gadget));
 	n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg            = %d\n",
 		       gadget->is_otg);
 	n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral   = %d\n",
@@ -798,7 +813,7 @@
 	n += scnprintf(buf + n, PAGE_SIZE - n, "function  = %s\n",
 		       (driver->function ? driver->function : ""));
 	n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n",
-		       driver->speed);
+		       driver->max_speed);
 
 	return n;
 }
@@ -2563,9 +2578,7 @@
 	if (driver             == NULL ||
 	    bind               == NULL ||
 	    driver->setup      == NULL ||
-	    driver->disconnect == NULL ||
-	    driver->suspend    == NULL ||
-	    driver->resume     == NULL)
+	    driver->disconnect == NULL)
 		return -EINVAL;
 	else if (udc         == NULL)
 		return -ENODEV;
@@ -2693,8 +2706,6 @@
 	    driver->unbind     == NULL ||
 	    driver->setup      == NULL ||
 	    driver->disconnect == NULL ||
-	    driver->suspend    == NULL ||
-	    driver->resume     == NULL ||
 	    driver             != udc->driver)
 		return -EINVAL;
 
@@ -2793,7 +2804,7 @@
 			isr_statistics.pci++;
 			udc->gadget.speed = hw_port_is_high_speed() ?
 				USB_SPEED_HIGH : USB_SPEED_FULL;
-			if (udc->suspended) {
+			if (udc->suspended && udc->driver->resume) {
 				spin_unlock(udc->lock);
 				udc->driver->resume(&udc->gadget);
 				spin_lock(udc->lock);
@@ -2807,7 +2818,8 @@
 			isr_tr_complete_handler(udc);
 		}
 		if (USBi_SLI & intr) {
-			if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
+			if (udc->gadget.speed != USB_SPEED_UNKNOWN &&
+			    udc->driver->suspend) {
 				udc->suspended = 1;
 				spin_unlock(udc->lock);
 				udc->driver->suspend(&udc->gadget);
@@ -2871,7 +2883,7 @@
 
 	udc->gadget.ops          = &usb_gadget_ops;
 	udc->gadget.speed        = USB_SPEED_UNKNOWN;
-	udc->gadget.is_dualspeed = 1;
+	udc->gadget.max_speed    = USB_SPEED_HIGH;
 	udc->gadget.is_otg       = 0;
 	udc->gadget.name         = driver->name;
 
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index 2370777..f4871e1 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -127,7 +127,7 @@
 	struct ci13xxx_ep          ci13xxx_ep[ENDPT_MAX]; /* extended endpts */
 	u32                        ep0_dir;    /* ep0 direction */
 #define ep0out ci13xxx_ep[0]
-#define ep0in  ci13xxx_ep[16]
+#define ep0in  ci13xxx_ep[hw_ep_max / 2]
 	u8                         remote_wakeup; /* Is remote wakeup feature
 							enabled by the host? */
 	u8                         suspended;  /* suspended by the host */
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index f71b078..a95de6a 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1535,9 +1535,9 @@
 
 static struct usb_gadget_driver composite_driver = {
 #ifdef CONFIG_USB_GADGET_SUPERSPEED
-	.speed		= USB_SPEED_SUPER,
+	.max_speed	= USB_SPEED_SUPER,
 #else
-	.speed		= USB_SPEED_HIGH,
+	.max_speed	= USB_SPEED_HIGH,
 #endif
 
 	.unbind		= composite_unbind,
@@ -1584,8 +1584,8 @@
 		driver->iProduct = driver->name;
 	composite_driver.function =  (char *) driver->name;
 	composite_driver.driver.name = driver->name;
-	composite_driver.speed = min((u8)composite_driver.speed,
-				     (u8)driver->max_speed);
+	composite_driver.max_speed =
+		min_t(u8, composite_driver.max_speed, driver->max_speed);
 	composite = driver;
 	composite_gadget_bind = bind;
 
diff --git a/drivers/usb/gadget/dbgp.c b/drivers/usb/gadget/dbgp.c
index 6256420..19d7bb0 100644
--- a/drivers/usb/gadget/dbgp.c
+++ b/drivers/usb/gadget/dbgp.c
@@ -404,7 +404,7 @@
 
 static struct usb_gadget_driver dbgp_driver = {
 	.function = "dbgp",
-	.speed = USB_SPEED_HIGH,
+	.max_speed = USB_SPEED_HIGH,
 	.unbind = dbgp_unbind,
 	.setup = dbgp_setup,
 	.disconnect = dbgp_disconnect,
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index ab8f1b4..db815c2 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -823,19 +823,18 @@
 
 	if (value && dum->driver) {
 		if (mod_data.is_super_speed)
-			dum->gadget.speed = dum->driver->speed;
+			dum->gadget.speed = dum->driver->max_speed;
 		else if (mod_data.is_high_speed)
 			dum->gadget.speed = min_t(u8, USB_SPEED_HIGH,
-					dum->driver->speed);
+					dum->driver->max_speed);
 		else
 			dum->gadget.speed = USB_SPEED_FULL;
 		dummy_udc_udpate_ep0(dum);
 
-		if (dum->gadget.speed < dum->driver->speed)
+		if (dum->gadget.speed < dum->driver->max_speed)
 			dev_dbg(udc_dev(dum), "This device can perform faster"
-					" if you connect it to a %s port...\n",
-					(dum->driver->speed == USB_SPEED_SUPER ?
-					 "SuperSpeed" : "HighSpeed"));
+				" if you connect it to a %s port...\n",
+				usb_speed_string(dum->driver->max_speed));
 	}
 	dum_hcd = gadget_to_dummy_hcd(_gadget);
 
@@ -898,7 +897,7 @@
 	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(g);
 	struct dummy		*dum = dum_hcd->dum;
 
-	if (driver->speed == USB_SPEED_UNKNOWN)
+	if (driver->max_speed == USB_SPEED_UNKNOWN)
 		return -EINVAL;
 
 	/*
@@ -977,7 +976,7 @@
 
 	dum->gadget.name = gadget_name;
 	dum->gadget.ops = &dummy_ops;
-	dum->gadget.is_dualspeed = 1;
+	dum->gadget.max_speed = USB_SPEED_SUPER;
 
 	dev_set_name(&dum->gadget.dev, "gadget");
 	dum->gadget.dev.parent = &pdev->dev;
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 4dff83d..753aa06 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -149,7 +149,7 @@
 	switch (type) {
 	case USB_ENDPOINT_XFER_INT:
 		/* INT:  limit 64 bytes full speed, 1024 high/super speed */
-		if (!gadget->is_dualspeed && max > 64)
+		if (!gadget_is_dualspeed(gadget) && max > 64)
 			return 0;
 		/* FALLTHROUGH */
 
@@ -157,12 +157,12 @@
 		/* ISO:  limit 1023 bytes full speed, 1024 high/super speed */
 		if (ep->maxpacket < max)
 			return 0;
-		if (!gadget->is_dualspeed && max > 1023)
+		if (!gadget_is_dualspeed(gadget) && max > 1023)
 			return 0;
 
 		/* BOTH:  "high bandwidth" works only at high speed */
 		if ((desc->wMaxPacketSize & cpu_to_le16(3<<11))) {
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				return 0;
 			/* configure your hardware with enough buffering!! */
 		}
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index b5f6f9f..f63dc6c 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -1399,7 +1399,7 @@
 	ENTER();
 
 	count = ffs->eps_count;
-	epfiles = kzalloc(count * sizeof *epfiles, GFP_KERNEL);
+	epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL);
 	if (!epfiles)
 		return -ENOMEM;
 
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index 1a6f415..6353eca 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -1873,17 +1873,14 @@
 		    common->lun, lun);
 
 	/* Check the LUN */
-	if (common->lun < common->nluns) {
-		curlun = &common->luns[common->lun];
-		common->curlun = curlun;
+	curlun = common->curlun;
+	if (curlun) {
 		if (common->cmnd[0] != REQUEST_SENSE) {
 			curlun->sense_data = SS_NO_SENSE;
 			curlun->sense_data_info = 0;
 			curlun->info_valid = 0;
 		}
 	} else {
-		common->curlun = NULL;
-		curlun = NULL;
 		common->bad_lun_okay = 0;
 
 		/*
@@ -1929,6 +1926,17 @@
 	return 0;
 }
 
+/* wrapper of check_command for data size in blocks handling */
+static int check_command_size_in_blocks(struct fsg_common *common,
+		int cmnd_size, enum data_direction data_dir,
+		unsigned int mask, int needs_medium, const char *name)
+{
+	if (common->curlun)
+		common->data_size_from_cmnd <<= common->curlun->blkbits;
+	return check_command(common, cmnd_size, data_dir,
+			mask, needs_medium, name);
+}
+
 static int do_scsi_command(struct fsg_common *common)
 {
 	struct fsg_buffhd	*bh;
@@ -2011,9 +2019,9 @@
 
 	case READ_6:
 		i = common->cmnd[4];
-		common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
-				common->curlun->blkbits;
-		reply = check_command(common, 6, DATA_DIR_TO_HOST,
+		common->data_size_from_cmnd = (i == 0) ? 256 : i;
+		reply = check_command_size_in_blocks(common, 6,
+				      DATA_DIR_TO_HOST,
 				      (7<<1) | (1<<4), 1,
 				      "READ(6)");
 		if (reply == 0)
@@ -2022,9 +2030,9 @@
 
 	case READ_10:
 		common->data_size_from_cmnd =
-				get_unaligned_be16(&common->cmnd[7]) <<
-						common->curlun->blkbits;
-		reply = check_command(common, 10, DATA_DIR_TO_HOST,
+				get_unaligned_be16(&common->cmnd[7]);
+		reply = check_command_size_in_blocks(common, 10,
+				      DATA_DIR_TO_HOST,
 				      (1<<1) | (0xf<<2) | (3<<7), 1,
 				      "READ(10)");
 		if (reply == 0)
@@ -2033,9 +2041,9 @@
 
 	case READ_12:
 		common->data_size_from_cmnd =
-				get_unaligned_be32(&common->cmnd[6]) <<
-						common->curlun->blkbits;
-		reply = check_command(common, 12, DATA_DIR_TO_HOST,
+				get_unaligned_be32(&common->cmnd[6]);
+		reply = check_command_size_in_blocks(common, 12,
+				      DATA_DIR_TO_HOST,
 				      (1<<1) | (0xf<<2) | (0xf<<6), 1,
 				      "READ(12)");
 		if (reply == 0)
@@ -2134,9 +2142,9 @@
 
 	case WRITE_6:
 		i = common->cmnd[4];
-		common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
-					common->curlun->blkbits;
-		reply = check_command(common, 6, DATA_DIR_FROM_HOST,
+		common->data_size_from_cmnd = (i == 0) ? 256 : i;
+		reply = check_command_size_in_blocks(common, 6,
+				      DATA_DIR_FROM_HOST,
 				      (7<<1) | (1<<4), 1,
 				      "WRITE(6)");
 		if (reply == 0)
@@ -2145,9 +2153,9 @@
 
 	case WRITE_10:
 		common->data_size_from_cmnd =
-				get_unaligned_be16(&common->cmnd[7]) <<
-						common->curlun->blkbits;
-		reply = check_command(common, 10, DATA_DIR_FROM_HOST,
+				get_unaligned_be16(&common->cmnd[7]);
+		reply = check_command_size_in_blocks(common, 10,
+				      DATA_DIR_FROM_HOST,
 				      (1<<1) | (0xf<<2) | (3<<7), 1,
 				      "WRITE(10)");
 		if (reply == 0)
@@ -2156,9 +2164,9 @@
 
 	case WRITE_12:
 		common->data_size_from_cmnd =
-				get_unaligned_be32(&common->cmnd[6]) <<
-						common->curlun->blkbits;
-		reply = check_command(common, 12, DATA_DIR_FROM_HOST,
+				get_unaligned_be32(&common->cmnd[6]);
+		reply = check_command_size_in_blocks(common, 12,
+				      DATA_DIR_FROM_HOST,
 				      (1<<1) | (0xf<<2) | (0xf<<6), 1,
 				      "WRITE(12)");
 		if (reply == 0)
@@ -2273,6 +2281,10 @@
 	if (common->data_size == 0)
 		common->data_dir = DATA_DIR_NONE;
 	common->lun = cbw->Lun;
+	if (common->lun >= 0 && common->lun < common->nluns)
+		common->curlun = &common->luns[common->lun];
+	else
+		common->curlun = NULL;
 	common->tag = cbw->Tag;
 	return 0;
 }
@@ -2763,7 +2775,7 @@
 	 * Create the LUNs, open their backing files, and register the
 	 * LUN devices in sysfs.
 	 */
-	curlun = kzalloc(nluns * sizeof *curlun, GFP_KERNEL);
+	curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL);
 	if (unlikely(!curlun)) {
 		rc = -ENOMEM;
 		goto error_release;
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 11b5196..e0f30fc 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -2297,19 +2297,17 @@
 			DBG(fsg, "using LUN %d from CBW, "
 					"not LUN %d from CDB\n",
 					fsg->lun, lun);
-	} else
-		fsg->lun = lun;		// Use LUN from the command
+	}
 
 	/* Check the LUN */
-	if (fsg->lun < fsg->nluns) {
-		fsg->curlun = curlun = &fsg->luns[fsg->lun];
+	curlun = fsg->curlun;
+	if (curlun) {
 		if (fsg->cmnd[0] != REQUEST_SENSE) {
 			curlun->sense_data = SS_NO_SENSE;
 			curlun->sense_data_info = 0;
 			curlun->info_valid = 0;
 		}
 	} else {
-		fsg->curlun = curlun = NULL;
 		fsg->bad_lun_okay = 0;
 
 		/* INQUIRY and REQUEST SENSE commands are explicitly allowed
@@ -2351,6 +2349,16 @@
 	return 0;
 }
 
+/* wrapper of check_command for data size in blocks handling */
+static int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size,
+		enum data_direction data_dir, unsigned int mask,
+		int needs_medium, const char *name)
+{
+	if (fsg->curlun)
+		fsg->data_size_from_cmnd <<= fsg->curlun->blkbits;
+	return check_command(fsg, cmnd_size, data_dir,
+			mask, needs_medium, name);
+}
 
 static int do_scsi_command(struct fsg_dev *fsg)
 {
@@ -2425,26 +2433,27 @@
 
 	case READ_6:
 		i = fsg->cmnd[4];
-		fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits;
-		if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
+		fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
+		if ((reply = check_command_size_in_blocks(fsg, 6,
+				DATA_DIR_TO_HOST,
 				(7<<1) | (1<<4), 1,
 				"READ(6)")) == 0)
 			reply = do_read(fsg);
 		break;
 
 	case READ_10:
-		fsg->data_size_from_cmnd =
-				get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits;
-		if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
+		fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
+		if ((reply = check_command_size_in_blocks(fsg, 10,
+				DATA_DIR_TO_HOST,
 				(1<<1) | (0xf<<2) | (3<<7), 1,
 				"READ(10)")) == 0)
 			reply = do_read(fsg);
 		break;
 
 	case READ_12:
-		fsg->data_size_from_cmnd =
-				get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits;
-		if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST,
+		fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
+		if ((reply = check_command_size_in_blocks(fsg, 12,
+				DATA_DIR_TO_HOST,
 				(1<<1) | (0xf<<2) | (0xf<<6), 1,
 				"READ(12)")) == 0)
 			reply = do_read(fsg);
@@ -2529,26 +2538,27 @@
 
 	case WRITE_6:
 		i = fsg->cmnd[4];
-		fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits;
-		if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
+		fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
+		if ((reply = check_command_size_in_blocks(fsg, 6,
+				DATA_DIR_FROM_HOST,
 				(7<<1) | (1<<4), 1,
 				"WRITE(6)")) == 0)
 			reply = do_write(fsg);
 		break;
 
 	case WRITE_10:
-		fsg->data_size_from_cmnd =
-				get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits;
-		if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
+		fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
+		if ((reply = check_command_size_in_blocks(fsg, 10,
+				DATA_DIR_FROM_HOST,
 				(1<<1) | (0xf<<2) | (3<<7), 1,
 				"WRITE(10)")) == 0)
 			reply = do_write(fsg);
 		break;
 
 	case WRITE_12:
-		fsg->data_size_from_cmnd =
-				get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits;
-		if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST,
+		fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
+		if ((reply = check_command_size_in_blocks(fsg, 12,
+				DATA_DIR_FROM_HOST,
 				(1<<1) | (0xf<<2) | (0xf<<6), 1,
 				"WRITE(12)")) == 0)
 			reply = do_write(fsg);
@@ -2715,7 +2725,17 @@
 		memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size);
 		fsg->cbbuf_cmnd_size = 0;
 		spin_unlock_irq(&fsg->lock);
+
+		/* Use LUN from the command */
+		fsg->lun = fsg->cmnd[1] >> 5;
 	}
+
+	/* Update current lun */
+	if (fsg->lun >= 0 && fsg->lun < fsg->nluns)
+		fsg->curlun = &fsg->luns[fsg->lun];
+	else
+		fsg->curlun = NULL;
+
 	return rc;
 }
 
@@ -3584,7 +3604,7 @@
 /*-------------------------------------------------------------------------*/
 
 static struct usb_gadget_driver		fsg_driver = {
-	.speed		= USB_SPEED_SUPER,
+	.max_speed	= USB_SPEED_SUPER,
 	.function	= (char *) fsg_string_product,
 	.unbind		= fsg_unbind,
 	.disconnect	= fsg_disconnect,
diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c
index e00cf92..b95697c 100644
--- a/drivers/usb/gadget/fsl_qe_udc.c
+++ b/drivers/usb/gadget/fsl_qe_udc.c
@@ -2336,7 +2336,7 @@
 	if (!udc_controller)
 		return -ENODEV;
 
-	if (!driver || driver->speed < USB_SPEED_FULL
+	if (!driver || driver->max_speed < USB_SPEED_FULL
 			|| !bind || !driver->disconnect || !driver->setup)
 		return -EINVAL;
 
@@ -2350,7 +2350,7 @@
 	/* hook up the driver */
 	udc_controller->driver = driver;
 	udc_controller->gadget.dev.driver = &driver->driver;
-	udc_controller->gadget.speed = (enum usb_device_speed)(driver->speed);
+	udc_controller->gadget.speed = driver->max_speed;
 	spin_unlock_irqrestore(&udc_controller->lock, flags);
 
 	retval = bind(&udc_controller->gadget);
@@ -2814,20 +2814,7 @@
 #endif
 };
 
-static int __init qe_udc_init(void)
-{
-	printk(KERN_INFO "%s: %s, %s\n", driver_name, driver_desc,
-			DRIVER_VERSION);
-	return platform_driver_register(&udc_driver);
-}
-
-static void __exit qe_udc_exit(void)
-{
-	platform_driver_unregister(&udc_driver);
-}
-
-module_init(qe_udc_init);
-module_exit(qe_udc_exit);
+module_platform_driver(udc_driver);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index dd28ef3..d7ea6c0 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -1934,7 +1934,7 @@
 	if (!udc_controller)
 		return -ENODEV;
 
-	if (!driver || driver->speed < USB_SPEED_FULL
+	if (!driver || driver->max_speed < USB_SPEED_FULL
 			|| !bind || !driver->disconnect || !driver->setup)
 		return -EINVAL;
 
@@ -2525,7 +2525,7 @@
 
 	/* Setup gadget structure */
 	udc_controller->gadget.ops = &fsl_gadget_ops;
-	udc_controller->gadget.is_dualspeed = 1;
+	udc_controller->gadget.max_speed = USB_SPEED_HIGH;
 	udc_controller->gadget.ep0 = &udc_controller->eps[0].ep;
 	INIT_LIST_HEAD(&udc_controller->gadget.ep_list);
 	udc_controller->gadget.speed = USB_SPEED_UNKNOWN;
diff --git a/drivers/usb/gadget/fusb300_udc.c b/drivers/usb/gadget/fusb300_udc.c
index 74da206..5831cb4 100644
--- a/drivers/usb/gadget/fusb300_udc.c
+++ b/drivers/usb/gadget/fusb300_udc.c
@@ -1317,7 +1317,7 @@
 	int retval;
 
 	if (!driver
-			|| driver->speed < USB_SPEED_FULL
+			|| driver->max_speed < USB_SPEED_FULL
 			|| !bind
 			|| !driver->setup)
 		return -EINVAL;
@@ -1463,7 +1463,7 @@
 
 	dev_set_name(&fusb300->gadget.dev, "gadget");
 
-	fusb300->gadget.is_dualspeed = 1;
+	fusb300->gadget.max_speed = USB_SPEED_HIGH;
 	fusb300->gadget.dev.parent = &pdev->dev;
 	fusb300->gadget.dev.dma_mask = pdev->dev.dma_mask;
 	fusb300->gadget.dev.release = pdev->dev.release;
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 7f87805..5af70fc 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -1357,7 +1357,7 @@
 	int			retval;
 
 	if (!driver
-			|| driver->speed < USB_SPEED_FULL
+			|| driver->max_speed < USB_SPEED_FULL
 			|| !bind
 			|| !driver->disconnect
 			|| !driver->setup)
@@ -1796,6 +1796,7 @@
 	spin_lock_init(&dev->lock);
 	dev->pdev = pdev;
 	dev->gadget.ops = &goku_ops;
+	dev->gadget.max_speed = USB_SPEED_FULL;
 
 	/* the "gadget" abstracts/virtualizes the controller */
 	dev_set_name(&dev->gadget.dev, "gadget");
diff --git a/drivers/usb/gadget/imx_udc.c b/drivers/usb/gadget/imx_udc.c
index 2d978c0..8d1c75a 100644
--- a/drivers/usb/gadget/imx_udc.c
+++ b/drivers/usb/gadget/imx_udc.c
@@ -1336,7 +1336,7 @@
 	int retval;
 
 	if (!driver
-		|| driver->speed < USB_SPEED_FULL
+		|| driver->max_speed < USB_SPEED_FULL
 		|| !bind
 		|| !driver->disconnect
 		|| !driver->setup)
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 6b7ea25..ae04266 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -1766,9 +1766,9 @@
 
 static struct usb_gadget_driver gadgetfs_driver = {
 #ifdef	CONFIG_USB_GADGET_DUALSPEED
-	.speed		= USB_SPEED_HIGH,
+	.max_speed	= USB_SPEED_HIGH,
 #else
-	.speed		= USB_SPEED_FULL,
+	.max_speed	= USB_SPEED_FULL,
 #endif
 	.function	= (char *) driver_desc,
 	.unbind		= gadgetfs_unbind,
@@ -1792,7 +1792,7 @@
 }
 
 static struct usb_gadget_driver probe_driver = {
-	.speed		= USB_SPEED_HIGH,
+	.max_speed	= USB_SPEED_HIGH,
 	.unbind		= gadgetfs_nop,
 	.setup		= (void *)gadgetfs_nop,
 	.disconnect	= gadgetfs_nop,
diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c
index c9fa3bf..fa0fcc1 100644
--- a/drivers/usb/gadget/langwell_udc.c
+++ b/drivers/usb/gadget/langwell_udc.c
@@ -3267,7 +3267,7 @@
 	dev->gadget.ep0 = &dev->ep[0].ep;	/* gadget ep0 */
 	INIT_LIST_HEAD(&dev->gadget.ep_list);	/* ep_list */
 	dev->gadget.speed = USB_SPEED_UNKNOWN;	/* speed */
-	dev->gadget.is_dualspeed = 1;		/* support dual speed */
+	dev->gadget.max_speed = USB_SPEED_HIGH;	/* support dual speed */
 #ifdef	OTG_TRANSCEIVER
 	dev->gadget.is_otg = 1;			/* support otg mode */
 #endif
diff --git a/drivers/usb/gadget/m66592-udc.c b/drivers/usb/gadget/m66592-udc.c
index 9aa1cbb..3608b3b 100644
--- a/drivers/usb/gadget/m66592-udc.c
+++ b/drivers/usb/gadget/m66592-udc.c
@@ -1472,7 +1472,7 @@
 	int retval;
 
 	if (!driver
-			|| driver->speed < USB_SPEED_HIGH
+			|| driver->max_speed < USB_SPEED_HIGH
 			|| !bind
 			|| !driver->setup)
 		return -EINVAL;
@@ -1653,7 +1653,7 @@
 	m66592->gadget.ops = &m66592_gadget_ops;
 	device_initialize(&m66592->gadget.dev);
 	dev_set_name(&m66592->gadget.dev, "gadget");
-	m66592->gadget.is_dualspeed = 1;
+	m66592->gadget.max_speed = USB_SPEED_HIGH;
 	m66592->gadget.dev.parent = &pdev->dev;
 	m66592->gadget.dev.dma_mask = pdev->dev.dma_mask;
 	m66592->gadget.dev.release = pdev->dev.release;
diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h
index daa75c1..34aadfa 100644
--- a/drivers/usb/gadget/mv_udc.h
+++ b/drivers/usb/gadget/mv_udc.h
@@ -180,7 +180,7 @@
 
 	struct mv_cap_regs __iomem	*cap_regs;
 	struct mv_op_regs __iomem	*op_regs;
-	unsigned int			phy_regs;
+	void __iomem                    *phy_regs;
 	unsigned int			max_eps;
 	struct mv_dqh			*ep_dqh;
 	size_t				ep_dqh_size;
@@ -211,11 +211,14 @@
 				softconnected:1,
 				force_fs:1,
 				clock_gating:1,
-				active:1;
+				active:1,
+				stopped:1;      /* stop bit is setted */
 
 	struct work_struct	vbus_work;
 	struct workqueue_struct *qwork;
 
+	struct otg_transceiver	*transceiver;
+
 	struct mv_usb_platform_data     *pdata;
 
 	/* some SOC has mutiple clock sources for USB*/
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index 8924121..f97e737 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -276,11 +276,12 @@
 
 static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
 {
-	u32 tmp, epstatus, bit_pos, direction;
 	struct mv_udc *udc;
 	struct mv_dqh *dqh;
+	u32 bit_pos, direction;
+	u32 usbcmd, epstatus;
 	unsigned int loops;
-	int readsafe, retval = 0;
+	int retval = 0;
 
 	udc = ep->udc;
 	direction = ep_dir(ep);
@@ -293,30 +294,18 @@
 		lastreq = list_entry(ep->queue.prev, struct mv_req, queue);
 		lastreq->tail->dtd_next =
 			req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
-		if (readl(&udc->op_regs->epprime) & bit_pos) {
-			loops = LOOPS(PRIME_TIMEOUT);
-			while (readl(&udc->op_regs->epprime) & bit_pos) {
-				if (loops == 0) {
-					retval = -ETIME;
-					goto done;
-				}
-				udelay(LOOPS_USEC);
-				loops--;
-			}
-			if (readl(&udc->op_regs->epstatus) & bit_pos)
-				goto done;
-		}
-		readsafe = 0;
+
+		wmb();
+
+		if (readl(&udc->op_regs->epprime) & bit_pos)
+			goto done;
+
 		loops = LOOPS(READSAFE_TIMEOUT);
-		while (readsafe == 0) {
-			if (loops == 0) {
-				retval = -ETIME;
-				goto done;
-			}
+		while (1) {
 			/* start with setting the semaphores */
-			tmp = readl(&udc->op_regs->usbcmd);
-			tmp |= USBCMD_ATDTW_TRIPWIRE_SET;
-			writel(tmp, &udc->op_regs->usbcmd);
+			usbcmd = readl(&udc->op_regs->usbcmd);
+			usbcmd |= USBCMD_ATDTW_TRIPWIRE_SET;
+			writel(usbcmd, &udc->op_regs->usbcmd);
 
 			/* read the endpoint status */
 			epstatus = readl(&udc->op_regs->epstatus) & bit_pos;
@@ -329,98 +318,46 @@
 			 * primed.
 			 */
 			if (readl(&udc->op_regs->usbcmd)
-				& USBCMD_ATDTW_TRIPWIRE_SET) {
-				readsafe = 1;
-			}
+				& USBCMD_ATDTW_TRIPWIRE_SET)
+				break;
+
 			loops--;
+			if (loops == 0) {
+				dev_err(&udc->dev->dev,
+					"Timeout for ATDTW_TRIPWIRE...\n");
+				retval = -ETIME;
+				goto done;
+			}
 			udelay(LOOPS_USEC);
 		}
 
 		/* Clear the semaphore */
-		tmp = readl(&udc->op_regs->usbcmd);
-		tmp &= USBCMD_ATDTW_TRIPWIRE_CLEAR;
-		writel(tmp, &udc->op_regs->usbcmd);
+		usbcmd = readl(&udc->op_regs->usbcmd);
+		usbcmd &= USBCMD_ATDTW_TRIPWIRE_CLEAR;
+		writel(usbcmd, &udc->op_regs->usbcmd);
 
-		/* If endpoint is not active, we activate it now. */
-		if (!epstatus) {
-			if (direction == EP_DIR_IN) {
-				struct mv_dtd *curr_dtd = dma_to_virt(
-					&udc->dev->dev, dqh->curr_dtd_ptr);
-
-				loops = LOOPS(DTD_TIMEOUT);
-				while (curr_dtd->size_ioc_sts
-					& DTD_STATUS_ACTIVE) {
-					if (loops == 0) {
-						retval = -ETIME;
-						goto done;
-					}
-					loops--;
-					udelay(LOOPS_USEC);
-				}
-			}
-			/* No other transfers on the queue */
-
-			/* Write dQH next pointer and terminate bit to 0 */
-			dqh->next_dtd_ptr = req->head->td_dma
-				& EP_QUEUE_HEAD_NEXT_POINTER_MASK;
-			dqh->size_ioc_int_sts = 0;
-
-			/*
-			 * Ensure that updates to the QH will
-			 * occur before priming.
-			 */
-			wmb();
-
-			/* Prime the Endpoint */
-			writel(bit_pos, &udc->op_regs->epprime);
-		}
-	} else {
-		/* Write dQH next pointer and terminate bit to 0 */
-		dqh->next_dtd_ptr = req->head->td_dma
-			& EP_QUEUE_HEAD_NEXT_POINTER_MASK;
-		dqh->size_ioc_int_sts = 0;
-
-		/* Ensure that updates to the QH will occur before priming. */
-		wmb();
-
-		/* Prime the Endpoint */
-		writel(bit_pos, &udc->op_regs->epprime);
-
-		if (direction == EP_DIR_IN) {
-			/* FIXME add status check after prime the IN ep */
-			int prime_again;
-			u32 curr_dtd_ptr = dqh->curr_dtd_ptr;
-
-			loops = LOOPS(DTD_TIMEOUT);
-			prime_again = 0;
-			while ((curr_dtd_ptr != req->head->td_dma)) {
-				curr_dtd_ptr = dqh->curr_dtd_ptr;
-				if (loops == 0) {
-					dev_err(&udc->dev->dev,
-						"failed to prime %s\n",
-						ep->name);
-					retval = -ETIME;
-					goto done;
-				}
-				loops--;
-				udelay(LOOPS_USEC);
-
-				if (loops == (LOOPS(DTD_TIMEOUT) >> 2)) {
-					if (prime_again)
-						goto done;
-					dev_info(&udc->dev->dev,
-						"prime again\n");
-					writel(bit_pos,
-						&udc->op_regs->epprime);
-					prime_again = 1;
-				}
-			}
-		}
+		if (epstatus)
+			goto done;
 	}
+
+	/* Write dQH next pointer and terminate bit to 0 */
+	dqh->next_dtd_ptr = req->head->td_dma
+				& EP_QUEUE_HEAD_NEXT_POINTER_MASK;
+
+	/* clear active and halt bit, in case set from a previous error */
+	dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED);
+
+	/* Ensure that updates to the QH will occure before priming. */
+	wmb();
+
+	/* Prime the Endpoint */
+	writel(bit_pos, &udc->op_regs->epprime);
+
 done:
 	return retval;
 }
 
+
 static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length,
 		dma_addr_t *dma, int *is_last)
 {
@@ -841,6 +778,27 @@
 	return 0;
 }
 
+static void mv_prime_ep(struct mv_ep *ep, struct mv_req *req)
+{
+	struct mv_dqh *dqh = ep->dqh;
+	u32 bit_pos;
+
+	/* Write dQH next pointer and terminate bit to 0 */
+	dqh->next_dtd_ptr = req->head->td_dma
+		& EP_QUEUE_HEAD_NEXT_POINTER_MASK;
+
+	/* clear active and halt bit, in case set from a previous error */
+	dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED);
+
+	/* Ensure that updates to the QH will occure before priming. */
+	wmb();
+
+	bit_pos = 1 << (((ep_dir(ep) == EP_DIR_OUT) ? 0 : 16) + ep->ep_num);
+
+	/* Prime the Endpoint */
+	writel(bit_pos, &ep->udc->op_regs->epprime);
+}
+
 /* dequeues (cancels, unlinks) an I/O request from an endpoint */
 static int mv_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
 {
@@ -883,15 +841,13 @@
 
 		/* The request isn't the last request in this ep queue */
 		if (req->queue.next != &ep->queue) {
-			struct mv_dqh *qh;
 			struct mv_req *next_req;
 
-			qh = ep->dqh;
-			next_req = list_entry(req->queue.next, struct mv_req,
-					queue);
+			next_req = list_entry(req->queue.next,
+				struct mv_req, queue);
 
 			/* Point the QH to the first TD of next request */
-			writel((u32) next_req->head, &qh->curr_dtd_ptr);
+			mv_prime_ep(ep, next_req);
 		} else {
 			struct mv_dqh *qh;
 
@@ -1056,6 +1012,8 @@
 		USBINTR_PORT_CHANGE_DETECT_EN | USBINTR_RESET_EN);
 	writel(tmp, &udc->op_regs->usbintr);
 
+	udc->stopped = 1;
+
 	/* Reset the Run the bit in the command register to stop VUSB */
 	tmp = readl(&udc->op_regs->usbcmd);
 	tmp &= ~USBCMD_RUN_STOP;
@@ -1072,6 +1030,8 @@
 	/* Enable interrupts */
 	writel(usbintr, &udc->op_regs->usbintr);
 
+	udc->stopped = 0;
+
 	/* Set the Run bit in the command register */
 	writel(USBCMD_RUN_STOP, &udc->op_regs->usbcmd);
 }
@@ -1134,11 +1094,11 @@
 	return 0;
 }
 
-static int mv_udc_enable(struct mv_udc *udc)
+static int mv_udc_enable_internal(struct mv_udc *udc)
 {
 	int retval;
 
-	if (udc->clock_gating == 0 || udc->active)
+	if (udc->active)
 		return 0;
 
 	dev_dbg(&udc->dev->dev, "enable udc\n");
@@ -1157,9 +1117,17 @@
 	return 0;
 }
 
-static void mv_udc_disable(struct mv_udc *udc)
+static int mv_udc_enable(struct mv_udc *udc)
 {
-	if (udc->clock_gating && udc->active) {
+	if (udc->clock_gating)
+		return mv_udc_enable_internal(udc);
+
+	return 0;
+}
+
+static void mv_udc_disable_internal(struct mv_udc *udc)
+{
+	if (udc->active) {
 		dev_dbg(&udc->dev->dev, "disable udc\n");
 		if (udc->pdata->phy_deinit)
 			udc->pdata->phy_deinit(udc->phy_regs);
@@ -1168,6 +1136,12 @@
 	}
 }
 
+static void mv_udc_disable(struct mv_udc *udc)
+{
+	if (udc->clock_gating)
+		mv_udc_disable_internal(udc);
+}
+
 static int mv_udc_get_frame(struct usb_gadget *gadget)
 {
 	struct mv_udc *udc;
@@ -1178,7 +1152,7 @@
 
 	udc = container_of(gadget, struct mv_udc, gadget);
 
-	retval = readl(udc->op_regs->frindex) & USB_FRINDEX_MASKS;
+	retval = readl(&udc->op_regs->frindex) & USB_FRINDEX_MASKS;
 
 	return retval;
 }
@@ -1212,10 +1186,11 @@
 	udc = container_of(gadget, struct mv_udc, gadget);
 	spin_lock_irqsave(&udc->lock, flags);
 
+	udc->vbus_active = (is_active != 0);
+
 	dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n",
 		__func__, udc->softconnect, udc->vbus_active);
 
-	udc->vbus_active = (is_active != 0);
 	if (udc->driver && udc->softconnect && udc->vbus_active) {
 		retval = mv_udc_enable(udc);
 		if (retval == 0) {
@@ -1244,10 +1219,11 @@
 	udc = container_of(gadget, struct mv_udc, gadget);
 	spin_lock_irqsave(&udc->lock, flags);
 
+	udc->softconnect = (is_on != 0);
+
 	dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n",
 			__func__, udc->softconnect, udc->vbus_active);
 
-	udc->softconnect = (is_on != 0);
 	if (udc->driver && udc->softconnect && udc->vbus_active) {
 		retval = mv_udc_enable(udc);
 		if (retval == 0) {
@@ -1407,6 +1383,20 @@
 		return retval;
 	}
 
+	if (udc->transceiver) {
+		retval = otg_set_peripheral(udc->transceiver, &udc->gadget);
+		if (retval) {
+			dev_err(&udc->dev->dev,
+				"unable to register peripheral to otg\n");
+			if (driver->unbind) {
+				driver->unbind(&udc->gadget);
+				udc->gadget.dev.driver = NULL;
+				udc->driver = NULL;
+			}
+			return retval;
+		}
+	}
+
 	/* pullup is always on */
 	mv_udc_pullup(&udc->gadget, 1);
 
@@ -2026,6 +2016,10 @@
 	struct mv_udc *udc = (struct mv_udc *)dev;
 	u32 status, intr;
 
+	/* Disable ISR when stopped bit is set */
+	if (udc->stopped)
+		return IRQ_NONE;
+
 	spin_lock(&udc->lock);
 
 	status = readl(&udc->op_regs->usbsts);
@@ -2109,7 +2103,12 @@
 		destroy_workqueue(udc->qwork);
 	}
 
-	if (udc->pdata && udc->pdata->vbus && udc->clock_gating)
+	/*
+	 * If we have transceiver inited,
+	 * then vbus irq will not be requested in udc driver.
+	 */
+	if (udc->pdata && udc->pdata->vbus
+		&& udc->clock_gating && udc->transceiver == NULL)
 		free_irq(udc->pdata->vbus->irq, &dev->dev);
 
 	/* free memory allocated in probe */
@@ -2129,11 +2128,9 @@
 
 	if (udc->cap_regs)
 		iounmap(udc->cap_regs);
-	udc->cap_regs = NULL;
 
 	if (udc->phy_regs)
-		iounmap((void *)udc->phy_regs);
-	udc->phy_regs = 0;
+		iounmap(udc->phy_regs);
 
 	if (udc->status_req) {
 		kfree(udc->status_req->req.buf);
@@ -2182,6 +2179,11 @@
 
 	udc->dev = dev;
 
+#ifdef CONFIG_USB_OTG_UTILS
+	if (pdata->mode == MV_USB_MODE_OTG)
+		udc->transceiver = otg_get_transceiver();
+#endif
+
 	udc->clknum = pdata->clknum;
 	for (clk_i = 0; clk_i < udc->clknum; clk_i++) {
 		udc->clk[clk_i] = clk_get(&dev->dev, pdata->clkname[clk_i]);
@@ -2213,24 +2215,20 @@
 		goto err_iounmap_capreg;
 	}
 
-	udc->phy_regs = (unsigned int)ioremap(r->start, resource_size(r));
-	if (udc->phy_regs == 0) {
+	udc->phy_regs = ioremap(r->start, resource_size(r));
+	if (udc->phy_regs == NULL) {
 		dev_err(&dev->dev, "failed to map phy I/O memory\n");
 		retval = -EBUSY;
 		goto err_iounmap_capreg;
 	}
 
 	/* we will acces controller register, so enable the clk */
-	udc_clock_enable(udc);
-	if (pdata->phy_init) {
-		retval = pdata->phy_init(udc->phy_regs);
-		if (retval) {
-			dev_err(&dev->dev, "phy init error %d\n", retval);
-			goto err_iounmap_phyreg;
-		}
-	}
+	retval = mv_udc_enable_internal(udc);
+	if (retval)
+		goto err_iounmap_phyreg;
 
-	udc->op_regs = (struct mv_op_regs __iomem *)((u32)udc->cap_regs
+	udc->op_regs =
+		(struct mv_op_regs __iomem *)((unsigned long)udc->cap_regs
 		+ (readl(&udc->cap_regs->caplength_hciversion)
 			& CAPLENGTH_MASK));
 	udc->max_eps = readl(&udc->cap_regs->dccparams) & DCCPARAMS_DEN_MASK;
@@ -2312,7 +2310,7 @@
 	udc->gadget.ep0 = &udc->eps[0].ep;	/* gadget ep0 */
 	INIT_LIST_HEAD(&udc->gadget.ep_list);	/* ep_list */
 	udc->gadget.speed = USB_SPEED_UNKNOWN;	/* speed */
-	udc->gadget.is_dualspeed = 1;		/* support dual speed */
+	udc->gadget.max_speed = USB_SPEED_HIGH;	/* support dual speed */
 
 	/* the "gadget" abstracts/virtualizes the controller */
 	dev_set_name(&udc->gadget.dev, "gadget");
@@ -2328,7 +2326,9 @@
 	eps_init(udc);
 
 	/* VBUS detect: we can disable/enable clock on demand.*/
-	if (pdata->vbus) {
+	if (udc->transceiver)
+		udc->clock_gating = 1;
+	else if (pdata->vbus) {
 		udc->clock_gating = 1;
 		retval = request_threaded_irq(pdata->vbus->irq, NULL,
 				mv_udc_vbus_irq, IRQF_ONESHOT, "vbus", udc);
@@ -2354,11 +2354,9 @@
 	 * If not, it means that VBUS detection is not supported, we
 	 * have to enable vbus active all the time to let controller work.
 	 */
-	if (udc->clock_gating) {
-		if (udc->pdata->phy_deinit)
-			udc->pdata->phy_deinit(udc->phy_regs);
-		udc_clock_disable(udc);
-	} else
+	if (udc->clock_gating)
+		mv_udc_disable_internal(udc);
+	else
 		udc->vbus_active = 1;
 
 	retval = usb_add_gadget_udc(&dev->dev, &udc->gadget);
@@ -2371,7 +2369,8 @@
 	return 0;
 
 err_unregister:
-	if (udc->pdata && udc->pdata->vbus && udc->clock_gating)
+	if (udc->pdata && udc->pdata->vbus
+		&& udc->clock_gating && udc->transceiver == NULL)
 		free_irq(pdata->vbus->irq, &dev->dev);
 	device_unregister(&udc->gadget.dev);
 err_free_irq:
@@ -2387,11 +2386,9 @@
 	dma_free_coherent(&dev->dev, udc->ep_dqh_size,
 			udc->ep_dqh, udc->ep_dqh_dma);
 err_disable_clock:
-	if (udc->pdata->phy_deinit)
-		udc->pdata->phy_deinit(udc->phy_regs);
-	udc_clock_disable(udc);
+	mv_udc_disable_internal(udc);
 err_iounmap_phyreg:
-	iounmap((void *)udc->phy_regs);
+	iounmap(udc->phy_regs);
 err_iounmap_capreg:
 	iounmap(udc->cap_regs);
 err_put_clk:
@@ -2407,7 +2404,30 @@
 {
 	struct mv_udc *udc = the_controller;
 
-	udc_stop(udc);
+	/* if OTG is enabled, the following will be done in OTG driver*/
+	if (udc->transceiver)
+		return 0;
+
+	if (udc->pdata->vbus && udc->pdata->vbus->poll)
+		if (udc->pdata->vbus->poll() == VBUS_HIGH) {
+			dev_info(&udc->dev->dev, "USB cable is connected!\n");
+			return -EAGAIN;
+		}
+
+	/*
+	 * only cable is unplugged, udc can suspend.
+	 * So do not care about clock_gating == 1.
+	 */
+	if (!udc->clock_gating) {
+		udc_stop(udc);
+
+		spin_lock_irq(&udc->lock);
+		/* stop all usb activities */
+		stop_activity(udc, udc->driver);
+		spin_unlock_irq(&udc->lock);
+
+		mv_udc_disable_internal(udc);
+	}
 
 	return 0;
 }
@@ -2417,20 +2437,22 @@
 	struct mv_udc *udc = the_controller;
 	int retval;
 
-	if (udc->pdata->phy_init) {
-		retval = udc->pdata->phy_init(udc->phy_regs);
-		if (retval) {
-			dev_err(&udc->dev->dev,
-				"init phy error %d when resume back\n",
-				retval);
+	/* if OTG is enabled, the following will be done in OTG driver*/
+	if (udc->transceiver)
+		return 0;
+
+	if (!udc->clock_gating) {
+		retval = mv_udc_enable_internal(udc);
+		if (retval)
 			return retval;
+
+		if (udc->driver && udc->softconnect) {
+			udc_reset(udc);
+			ep0_reset(udc);
+			udc_start(udc);
 		}
 	}
 
-	udc_reset(udc);
-	ep0_reset(udc);
-	udc_start(udc);
-
 	return 0;
 }
 
@@ -2457,30 +2479,16 @@
 	.shutdown	= mv_udc_shutdown,
 	.driver		= {
 		.owner	= THIS_MODULE,
-		.name	= "pxa-u2o",
+		.name	= "mv-udc",
 #ifdef CONFIG_PM
 		.pm	= &mv_udc_pm_ops,
 #endif
 	},
 };
-MODULE_ALIAS("platform:pxa-u2o");
 
+module_platform_driver(udc_driver);
+MODULE_ALIAS("platform:mv-udc");
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>");
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
-
-
-static int __init init(void)
-{
-	return platform_driver_register(&udc_driver);
-}
-module_init(init);
-
-
-static void __exit cleanup(void)
-{
-	platform_driver_unregister(&udc_driver);
-}
-module_exit(cleanup);
-
diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c
index d1b7636..4c81d54 100644
--- a/drivers/usb/gadget/net2272.c
+++ b/drivers/usb/gadget/net2272.c
@@ -1459,7 +1459,7 @@
 	unsigned i;
 
 	if (!driver || !driver->unbind || !driver->setup ||
-	    driver->speed != USB_SPEED_HIGH)
+	    driver->max_speed != USB_SPEED_HIGH)
 		return -EINVAL;
 
 	dev = container_of(_gadget, struct net2272, gadget);
@@ -2235,7 +2235,7 @@
 	ret->irq = irq;
 	ret->dev = dev;
 	ret->gadget.ops = &net2272_ops;
-	ret->gadget.is_dualspeed = 1;
+	ret->gadget.max_speed = USB_SPEED_HIGH;
 
 	/* the "gadget" abstracts/virtualizes the controller */
 	dev_set_name(&ret->gadget.dev, "gadget");
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index da2b9d0..cf1f364 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -1881,7 +1881,7 @@
 	 * (dev->usb->xcvrdiag & FORCE_FULL_SPEED_MODE)
 	 * "must not be used in normal operation"
 	 */
-	if (!driver || driver->speed < USB_SPEED_HIGH
+	if (!driver || driver->max_speed < USB_SPEED_HIGH
 			|| !driver->setup)
 		return -EINVAL;
 
@@ -2698,7 +2698,7 @@
 	spin_lock_init (&dev->lock);
 	dev->pdev = pdev;
 	dev->gadget.ops = &net2280_ops;
-	dev->gadget.is_dualspeed = 1;
+	dev->gadget.max_speed = USB_SPEED_HIGH;
 
 	/* the "gadget" abstracts/virtualizes the controller */
 	dev_set_name(&dev->gadget.dev, "gadget");
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 788989a..7db5bbe 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -2110,7 +2110,7 @@
 		return -ENODEV;
 	if (!driver
 			// FIXME if otg, check:  driver->is_otg
-			|| driver->speed < USB_SPEED_FULL
+			|| driver->max_speed < USB_SPEED_FULL
 			|| !bind || !driver->setup)
 		return -EINVAL;
 
@@ -2676,6 +2676,7 @@
 	INIT_LIST_HEAD(&udc->gadget.ep_list);
 	INIT_LIST_HEAD(&udc->iso);
 	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	udc->gadget.max_speed = USB_SPEED_FULL;
 	udc->gadget.name = driver_name;
 
 	device_initialize(&udc->gadget.dev);
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
index 5048a0c..dd2313c 100644
--- a/drivers/usb/gadget/pch_udc.c
+++ b/drivers/usb/gadget/pch_udc.c
@@ -2693,7 +2693,7 @@
 	struct pch_udc_dev	*dev = pch_udc;
 	int			retval;
 
-	if (!driver || (driver->speed == USB_SPEED_UNKNOWN) || !bind ||
+	if (!driver || (driver->max_speed == USB_SPEED_UNKNOWN) || !bind ||
 	    !driver->setup || !driver->unbind || !driver->disconnect) {
 		dev_err(&dev->pdev->dev,
 			"%s: invalid driver parameter\n", __func__);
@@ -2941,7 +2941,7 @@
 	dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
 	dev->gadget.dev.release = gadget_release;
 	dev->gadget.name = KBUILD_MODNAME;
-	dev->gadget.is_dualspeed = 1;
+	dev->gadget.max_speed = USB_SPEED_HIGH;
 
 	retval = device_register(&dev->gadget.dev);
 	if (retval)
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
index 65a8834..d83134b 100644
--- a/drivers/usb/gadget/printer.c
+++ b/drivers/usb/gadget/printer.c
@@ -1141,7 +1141,7 @@
 				break;
 #ifdef CONFIG_USB_GADGET_DUALSPEED
 			case USB_DT_DEVICE_QUALIFIER:
-				if (!gadget->is_dualspeed)
+				if (!gadget_is_dualspeed(gadget))
 					break;
 				/*
 				 * assumes ep0 uses the same value for both
@@ -1155,7 +1155,7 @@
 				break;
 
 			case USB_DT_OTHER_SPEED_CONFIG:
-				if (!gadget->is_dualspeed)
+				if (!gadget_is_dualspeed(gadget))
 					break;
 				/* FALLTHROUGH */
 #endif /* CONFIG_USB_GADGET_DUALSPEED */
@@ -1535,7 +1535,7 @@
 /*-------------------------------------------------------------------------*/
 
 static struct usb_gadget_driver printer_driver = {
-	.speed		= DEVSPEED,
+	.max_speed	= DEVSPEED,
 
 	.function	= (char *) driver_desc,
 	.unbind		= printer_unbind,
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index c090a7e..dd47063 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -1264,7 +1264,7 @@
 	int			retval;
 
 	if (!driver
-			|| driver->speed < USB_SPEED_FULL
+			|| driver->max_speed < USB_SPEED_FULL
 			|| !bind
 			|| !driver->disconnect
 			|| !driver->setup)
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index 18b6b09..f4c44eb 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -1807,7 +1807,7 @@
 	struct pxa_udc *udc = the_controller;
 	int retval;
 
-	if (!driver || driver->speed < USB_SPEED_FULL || !bind
+	if (!driver || driver->max_speed < USB_SPEED_FULL || !bind
 			|| !driver->disconnect || !driver->setup)
 		return -EINVAL;
 	if (!udc)
diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c
index fc719a3..f5b8d21 100644
--- a/drivers/usb/gadget/r8a66597-udc.c
+++ b/drivers/usb/gadget/r8a66597-udc.c
@@ -1746,7 +1746,7 @@
 	struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget);
 
 	if (!driver
-			|| driver->speed < USB_SPEED_HIGH
+			|| driver->max_speed < USB_SPEED_HIGH
 			|| !driver->setup)
 		return -EINVAL;
 	if (!r8a66597)
@@ -1911,7 +1911,7 @@
 
 	r8a66597->gadget.ops = &r8a66597_gadget_ops;
 	dev_set_name(&r8a66597->gadget.dev, "gadget");
-	r8a66597->gadget.is_dualspeed = 1;
+	r8a66597->gadget.max_speed = USB_SPEED_HIGH;
 	r8a66597->gadget.dev.parent = &pdev->dev;
 	r8a66597->gadget.dev.dma_mask = pdev->dev.dma_mask;
 	r8a66597->gadget.dev.release = pdev->dev.release;
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index b314482..69295ba 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -2586,7 +2586,7 @@
 		return -EINVAL;
 	}
 
-	if (driver->speed < USB_SPEED_FULL)
+	if (driver->max_speed < USB_SPEED_FULL)
 		dev_err(hsotg->dev, "%s: bad speed\n", __func__);
 
 	if (!bind || !driver->setup) {
@@ -3362,7 +3362,7 @@
 
 	dev_set_name(&hsotg->gadget.dev, "gadget");
 
-	hsotg->gadget.is_dualspeed = 1;
+	hsotg->gadget.max_speed = USB_SPEED_HIGH;
 	hsotg->gadget.ops = &s3c_hsotg_gadget_ops;
 	hsotg->gadget.name = dev_name(dev);
 
@@ -3467,18 +3467,7 @@
 	.resume		= s3c_hsotg_resume,
 };
 
-static int __init s3c_hsotg_modinit(void)
-{
-	return platform_driver_register(&s3c_hsotg_driver);
-}
-
-static void __exit s3c_hsotg_modexit(void)
-{
-	platform_driver_unregister(&s3c_hsotg_driver);
-}
-
-module_init(s3c_hsotg_modinit);
-module_exit(s3c_hsotg_modexit);
+module_platform_driver(s3c_hsotg_driver);
 
 MODULE_DESCRIPTION("Samsung S3C USB High-speed/OtG device");
 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c
index 20a553b..df8661d 100644
--- a/drivers/usb/gadget/s3c-hsudc.c
+++ b/drivers/usb/gadget/s3c-hsudc.c
@@ -28,9 +28,10 @@
 #include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/prefetch.h>
+#include <linux/platform_data/s3c-hsudc.h>
+#include <linux/regulator/consumer.h>
 
 #include <mach/regs-s3c2443-clock.h>
-#include <plat/udc.h>
 
 #define S3C_HSUDC_REG(x)	(x)
 
@@ -87,6 +88,12 @@
 #define DATA_STATE_XMIT			(1)
 #define DATA_STATE_RECV			(2)
 
+static const char * const s3c_hsudc_supply_names[] = {
+	"vdda",		/* analog phy supply, 3.3V */
+	"vddi",		/* digital phy supply, 1.2V */
+	"vddosc",	/* oscillator supply, 1.8V - 3.3V */
+};
+
 /**
  * struct s3c_hsudc_ep - Endpoint representation used by driver.
  * @ep: USB gadget layer representation of device endpoint.
@@ -139,6 +146,7 @@
 	struct device *dev;
 	struct s3c24xx_hsudc_platdata *pd;
 	struct otg_transceiver *transceiver;
+	struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsudc_supply_names)];
 	spinlock_t lock;
 	void __iomem *regs;
 	struct resource *mem_rsrc;
@@ -153,7 +161,6 @@
 #define ep_index(_ep)		((_ep)->bEndpointAddress & \
 					USB_ENDPOINT_NUMBER_MASK)
 
-static struct s3c_hsudc *the_controller;
 static const char driver_name[] = "s3c-udc";
 static const char ep0name[] = "ep0-control";
 
@@ -282,8 +289,7 @@
  * All the endpoints are stopped and any pending transfer requests if any on
  * the endpoint are terminated.
  */
-static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc,
-			  struct usb_gadget_driver *driver)
+static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc)
 {
 	struct s3c_hsudc_ep *hsep;
 	int epnum;
@@ -295,10 +301,6 @@
 		hsep->stopped = 1;
 		s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN);
 	}
-
-	spin_unlock(&hsudc->lock);
-	driver->disconnect(&hsudc->gadget);
-	spin_lock(&hsudc->lock);
 }
 
 /**
@@ -1135,16 +1137,15 @@
 	return IRQ_HANDLED;
 }
 
-static int s3c_hsudc_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+static int s3c_hsudc_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
-	struct s3c_hsudc *hsudc = the_controller;
+	struct s3c_hsudc *hsudc = to_hsudc(gadget);
 	int ret;
 
 	if (!driver
-		|| driver->speed < USB_SPEED_FULL
-		|| !bind
-		|| !driver->unbind || !driver->disconnect || !driver->setup)
+		|| driver->max_speed < USB_SPEED_FULL
+		|| !driver->setup)
 		return -EINVAL;
 
 	if (!hsudc)
@@ -1155,21 +1156,12 @@
 
 	hsudc->driver = driver;
 	hsudc->gadget.dev.driver = &driver->driver;
-	hsudc->gadget.speed = USB_SPEED_UNKNOWN;
-	ret = device_add(&hsudc->gadget.dev);
-	if (ret) {
-		dev_err(hsudc->dev, "failed to probe gadget device");
-		return ret;
-	}
 
-	ret = bind(&hsudc->gadget);
-	if (ret) {
-		dev_err(hsudc->dev, "%s: bind failed\n", hsudc->gadget.name);
-		device_del(&hsudc->gadget.dev);
-
-		hsudc->driver = NULL;
-		hsudc->gadget.dev.driver = NULL;
-		return ret;
+	ret = regulator_bulk_enable(ARRAY_SIZE(hsudc->supplies),
+				    hsudc->supplies);
+	if (ret != 0) {
+		dev_err(hsudc->dev, "failed to enable supplies: %d\n", ret);
+		goto err_supplies;
 	}
 
 	/* connect to bus through transceiver */
@@ -1178,13 +1170,7 @@
 		if (ret) {
 			dev_err(hsudc->dev, "%s: can't bind to transceiver\n",
 					hsudc->gadget.name);
-			driver->unbind(&hsudc->gadget);
-
-			device_del(&hsudc->gadget.dev);
-
-			hsudc->driver = NULL;
-			hsudc->gadget.dev.driver = NULL;
-			return ret;
+			goto err_otg;
 		}
 	}
 
@@ -1197,34 +1183,43 @@
 		hsudc->pd->gpio_init();
 
 	return 0;
+err_otg:
+	regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
+err_supplies:
+	hsudc->driver = NULL;
+	hsudc->gadget.dev.driver = NULL;
+	return ret;
 }
 
-static int s3c_hsudc_stop(struct usb_gadget_driver *driver)
+static int s3c_hsudc_stop(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
 {
-	struct s3c_hsudc *hsudc = the_controller;
+	struct s3c_hsudc *hsudc = to_hsudc(gadget);
 	unsigned long flags;
 
 	if (!hsudc)
 		return -ENODEV;
 
-	if (!driver || driver != hsudc->driver || !driver->unbind)
+	if (!driver || driver != hsudc->driver)
 		return -EINVAL;
 
 	spin_lock_irqsave(&hsudc->lock, flags);
-	hsudc->driver = 0;
+	hsudc->driver = NULL;
+	hsudc->gadget.dev.driver = NULL;
+	hsudc->gadget.speed = USB_SPEED_UNKNOWN;
 	s3c_hsudc_uninit_phy();
 	if (hsudc->pd->gpio_uninit)
 		hsudc->pd->gpio_uninit();
-	s3c_hsudc_stop_activity(hsudc, driver);
+	s3c_hsudc_stop_activity(hsudc);
 	spin_unlock_irqrestore(&hsudc->lock, flags);
 
 	if (hsudc->transceiver)
 		(void) otg_set_peripheral(hsudc->transceiver, NULL);
 
-	driver->unbind(&hsudc->gadget);
-	device_del(&hsudc->gadget.dev);
 	disable_irq(hsudc->irq);
 
+	regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
+
 	dev_info(hsudc->dev, "unregistered gadget driver '%s'\n",
 			driver->driver.name);
 	return 0;
@@ -1242,7 +1237,7 @@
 
 static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA)
 {
-	struct s3c_hsudc *hsudc = the_controller;
+	struct s3c_hsudc *hsudc = to_hsudc(gadget);
 
 	if (!hsudc)
 		return -ENODEV;
@@ -1255,18 +1250,18 @@
 
 static struct usb_gadget_ops s3c_hsudc_gadget_ops = {
 	.get_frame	= s3c_hsudc_gadget_getframe,
-	.start		= s3c_hsudc_start,
-	.stop		= s3c_hsudc_stop,
+	.udc_start	= s3c_hsudc_start,
+	.udc_stop	= s3c_hsudc_stop,
 	.vbus_draw	= s3c_hsudc_vbus_draw,
 };
 
-static int s3c_hsudc_probe(struct platform_device *pdev)
+static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct resource *res;
 	struct s3c_hsudc *hsudc;
 	struct s3c24xx_hsudc_platdata *pd = pdev->dev.platform_data;
-	int ret;
+	int ret, i;
 
 	hsudc = kzalloc(sizeof(struct s3c_hsudc) +
 			sizeof(struct s3c_hsudc_ep) * pd->epnum,
@@ -1276,13 +1271,22 @@
 		return -ENOMEM;
 	}
 
-	the_controller = hsudc;
 	platform_set_drvdata(pdev, dev);
 	hsudc->dev = dev;
 	hsudc->pd = pdev->dev.platform_data;
 
 	hsudc->transceiver = otg_get_transceiver();
 
+	for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++)
+		hsudc->supplies[i].supply = s3c_hsudc_supply_names[i];
+
+	ret = regulator_bulk_get(dev, ARRAY_SIZE(hsudc->supplies),
+				 hsudc->supplies);
+	if (ret != 0) {
+		dev_err(dev, "failed to request supplies: %d\n", ret);
+		goto err_supplies;
+	}
+
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 		dev_err(dev, "unable to obtain driver resource data\n");
@@ -1307,10 +1311,9 @@
 
 	spin_lock_init(&hsudc->lock);
 
-	device_initialize(&hsudc->gadget.dev);
 	dev_set_name(&hsudc->gadget.dev, "gadget");
 
-	hsudc->gadget.is_dualspeed = 1;
+	hsudc->gadget.max_speed = USB_SPEED_HIGH;
 	hsudc->gadget.ops = &s3c_hsudc_gadget_ops;
 	hsudc->gadget.name = dev_name(dev);
 	hsudc->gadget.dev.parent = dev;
@@ -1319,6 +1322,7 @@
 
 	hsudc->gadget.is_otg = 0;
 	hsudc->gadget.is_a_peripheral = 0;
+	hsudc->gadget.speed = USB_SPEED_UNKNOWN;
 
 	s3c_hsudc_setup_ep(hsudc);
 
@@ -1348,12 +1352,20 @@
 	disable_irq(hsudc->irq);
 	local_irq_enable();
 
+	ret = device_register(&hsudc->gadget.dev);
+	if (ret) {
+		put_device(&hsudc->gadget.dev);
+		goto err_add_device;
+	}
+
 	ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget);
 	if (ret)
 		goto err_add_udc;
 
 	return 0;
 err_add_udc:
+	device_unregister(&hsudc->gadget.dev);
+err_add_device:
 	clk_disable(hsudc->uclk);
 	clk_put(hsudc->uclk);
 err_clk:
@@ -1362,10 +1374,13 @@
 	iounmap(hsudc->regs);
 
 err_remap:
-	release_resource(hsudc->mem_rsrc);
-	kfree(hsudc->mem_rsrc);
-
+	release_mem_region(res->start, resource_size(res));
 err_res:
+	if (hsudc->transceiver)
+		otg_put_transceiver(hsudc->transceiver);
+
+	regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
+err_supplies:
 	kfree(hsudc);
 	return ret;
 }
@@ -1377,21 +1392,10 @@
 	},
 	.probe		= s3c_hsudc_probe,
 };
-MODULE_ALIAS("platform:s3c-hsudc");
 
-static int __init s3c_hsudc_modinit(void)
-{
-	return platform_driver_register(&s3c_hsudc_driver);
-}
-
-static void __exit s3c_hsudc_modexit(void)
-{
-	platform_driver_unregister(&s3c_hsudc_driver);
-}
-
-module_init(s3c_hsudc_modinit);
-module_exit(s3c_hsudc_modexit);
+module_platform_driver(s3c_hsudc_driver);
 
 MODULE_DESCRIPTION("Samsung S3C24XX USB high-speed controller driver");
 MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c-hsudc");
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index fac4c65..3f87cb9 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -1683,9 +1683,9 @@
 	if (udc->driver)
 		return -EBUSY;
 
-	if (!bind || !driver->setup || driver->speed < USB_SPEED_FULL) {
+	if (!bind || !driver->setup || driver->max_speed < USB_SPEED_FULL) {
 		printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n",
-			bind, driver->setup, driver->speed);
+			bind, driver->setup, driver->max_speed);
 		return -EINVAL;
 	}
 #if defined(MODULE)
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
index 6939e17..0b0d12c 100644
--- a/drivers/usb/gadget/udc-core.c
+++ b/drivers/usb/gadget/udc-core.c
@@ -371,14 +371,28 @@
 }
 static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store);
 
-static ssize_t usb_udc_speed_show(struct device *dev,
+#define USB_UDC_SPEED_ATTR(name, param)					\
+ssize_t usb_udc_##param##_show(struct device *dev,			\
+		struct device_attribute *attr, char *buf)		\
+{									\
+	struct usb_udc *udc = container_of(dev, struct usb_udc, dev);	\
+	return snprintf(buf, PAGE_SIZE, "%s\n",				\
+			usb_speed_string(udc->gadget->param));		\
+}									\
+static DEVICE_ATTR(name, S_IRUSR, usb_udc_##param##_show, NULL)
+
+static USB_UDC_SPEED_ATTR(current_speed, speed);
+static USB_UDC_SPEED_ATTR(maximum_speed, max_speed);
+
+/* TODO: Scheduled for removal in 3.8. */
+static ssize_t usb_udc_is_dualspeed_show(struct device *dev,
 		struct device_attribute *attr, char *buf)
 {
 	struct usb_udc		*udc = container_of(dev, struct usb_udc, dev);
-	return snprintf(buf, PAGE_SIZE, "%s\n",
-			usb_speed_string(udc->gadget->speed));
+	return snprintf(buf, PAGE_SIZE, "%d\n",
+			gadget_is_dualspeed(udc->gadget));
 }
-static DEVICE_ATTR(speed, S_IRUGO, usb_udc_speed_show, NULL);
+static DEVICE_ATTR(is_dualspeed, S_IRUSR, usb_udc_is_dualspeed_show, NULL);
 
 #define USB_UDC_ATTR(name)					\
 ssize_t usb_udc_##name##_show(struct device *dev,		\
@@ -391,7 +405,6 @@
 }								\
 static DEVICE_ATTR(name, S_IRUGO, usb_udc_##name##_show, NULL)
 
-static USB_UDC_ATTR(is_dualspeed);
 static USB_UDC_ATTR(is_otg);
 static USB_UDC_ATTR(is_a_peripheral);
 static USB_UDC_ATTR(b_hnp_enable);
@@ -401,7 +414,8 @@
 static struct attribute *usb_udc_attrs[] = {
 	&dev_attr_srp.attr,
 	&dev_attr_soft_connect.attr,
-	&dev_attr_speed.attr,
+	&dev_attr_current_speed.attr,
+	&dev_attr_maximum_speed.attr,
 
 	&dev_attr_is_dualspeed.attr,
 	&dev_attr_is_otg.attr,
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
index 58c4d37..4d25b90 100644
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -13,82 +13,17 @@
 #include <linux/string.h>
 #include <linux/device.h>
 #include <linux/init.h>
+#include <linux/nls.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 
-#include <asm/unaligned.h>
-
-
-static int utf8_to_utf16le(const char *s, __le16 *cp, unsigned len)
-{
-	int	count = 0;
-	u8	c;
-	u16	uchar;
-
-	/* this insists on correct encodings, though not minimal ones.
-	 * BUT it currently rejects legit 4-byte UTF-8 code points,
-	 * which need surrogate pairs.  (Unicode 3.1 can use them.)
-	 */
-	while (len != 0 && (c = (u8) *s++) != 0) {
-		if (unlikely(c & 0x80)) {
-			// 2-byte sequence:
-			// 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
-			if ((c & 0xe0) == 0xc0) {
-				uchar = (c & 0x1f) << 6;
-
-				c = (u8) *s++;
-				if ((c & 0xc0) != 0x80)
-					goto fail;
-				c &= 0x3f;
-				uchar |= c;
-
-			// 3-byte sequence (most CJKV characters):
-			// zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
-			} else if ((c & 0xf0) == 0xe0) {
-				uchar = (c & 0x0f) << 12;
-
-				c = (u8) *s++;
-				if ((c & 0xc0) != 0x80)
-					goto fail;
-				c &= 0x3f;
-				uchar |= c << 6;
-
-				c = (u8) *s++;
-				if ((c & 0xc0) != 0x80)
-					goto fail;
-				c &= 0x3f;
-				uchar |= c;
-
-				/* no bogus surrogates */
-				if (0xd800 <= uchar && uchar <= 0xdfff)
-					goto fail;
-
-			// 4-byte sequence (surrogate pairs, currently rare):
-			// 11101110wwwwzzzzyy + 110111yyyyxxxxxx
-			//     = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
-			// (uuuuu = wwww + 1)
-			// FIXME accept the surrogate code points (only)
-
-			} else
-				goto fail;
-		} else
-			uchar = c;
-		put_unaligned_le16(uchar, cp++);
-		count++;
-		len--;
-	}
-	return count;
-fail:
-	return -1;
-}
-
 
 /**
  * usb_gadget_get_string - fill out a string descriptor 
  * @table: of c strings encoded using UTF-8
  * @id: string id, from low byte of wValue in get string descriptor
- * @buf: at least 256 bytes
+ * @buf: at least 256 bytes, must be 16-bit aligned
  *
  * Finds the UTF-8 string matching the ID, and converts it into a
  * string descriptor in utf16-le.
@@ -125,8 +60,8 @@
 
 	/* string descriptors have length, tag, then UTF16-LE text */
 	len = min ((size_t) 126, strlen (s->s));
-	memset (buf + 2, 0, 2 * len);	/* zero all the bytes */
-	len = utf8_to_utf16le(s->s, (__le16 *)&buf[2], len);
+	len = utf8s_to_utf16s(s->s, len, UTF16_LITTLE_ENDIAN,
+			(wchar_t *) &buf[2], 126);
 	if (len < 0)
 		return -EINVAL;
 	buf [0] = (len + 1) * 2;
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 060e0e2..a52769b 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -194,6 +194,15 @@
        help
 	 Enable support for the S5P SOC's on-chip EHCI controller.
 
+config USB_EHCI_MV
+	bool "EHCI support for Marvell on-chip controller"
+	depends on USB_EHCI_HCD
+	select USB_EHCI_ROOT_HUB_TT
+	---help---
+	  Enables support for Marvell (including PXA and MMP series) on-chip
+	  USB SPH and OTG controller. SPH is a single port host, and it can
+	  only be EHCI host. OTG is controller that can switch to host mode.
+
 config USB_W90X900_EHCI
 	bool "W90X900(W90P910) EHCI support"
 	depends on USB_EHCI_HCD && ARCH_W90X900
diff --git a/drivers/usb/host/ehci-au1xxx.c b/drivers/usb/host/ehci-au1xxx.c
index 18bafa9..bf7441a 100644
--- a/drivers/usb/host/ehci-au1xxx.c
+++ b/drivers/usb/host/ehci-au1xxx.c
@@ -23,6 +23,7 @@
 	int ret = ehci_init(hcd);
 
 	ehci->need_io_watchdog = 0;
+	ehci_reset(ehci);
 	return ret;
 }
 
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 3ff9f82..e311a51 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -48,6 +48,10 @@
 #include <asm/system.h>
 #include <asm/unaligned.h>
 
+#if defined(CONFIG_PPC_PS3)
+#include <asm/firmware.h>
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -230,12 +234,58 @@
 			  STS_HALT, STS_HALT, 16 * 125);
 }
 
+#if defined(CONFIG_USB_SUSPEND) && defined(CONFIG_PPC_PS3)
+
+/*
+ * The EHCI controller of the Cell Super Companion Chip used in the
+ * PS3 will stop the root hub after all root hub ports are suspended.
+ * When in this condition handshake will return -ETIMEDOUT.  The
+ * STS_HLT bit will not be set, so inspection of the frame index is
+ * used here to test for the condition.  If the condition is found
+ * return success to allow the USB suspend to complete.
+ */
+
+static int handshake_for_broken_root_hub(struct ehci_hcd *ehci,
+					 void __iomem *ptr, u32 mask, u32 done,
+					 int usec)
+{
+	unsigned int old_index;
+	int error;
+
+	if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
+		return -ETIMEDOUT;
+
+	old_index = ehci_read_frame_index(ehci);
+
+	error = handshake(ehci, ptr, mask, done, usec);
+
+	if (error == -ETIMEDOUT && ehci_read_frame_index(ehci) == old_index)
+		return 0;
+
+	return error;
+}
+
+#else
+
+static int handshake_for_broken_root_hub(struct ehci_hcd *ehci,
+					 void __iomem *ptr, u32 mask, u32 done,
+					 int usec)
+{
+	return -ETIMEDOUT;
+}
+
+#endif
+
 static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
 				       u32 mask, u32 done, int usec)
 {
 	int error;
 
 	error = handshake(ehci, ptr, mask, done, usec);
+	if (error == -ETIMEDOUT)
+		error = handshake_for_broken_root_hub(ehci, ptr, mask, done,
+						      usec);
+
 	if (error) {
 		ehci_halt(ehci);
 		ehci->rh_state = EHCI_RH_HALTED;
@@ -620,6 +670,7 @@
 	hw = ehci->async->hw;
 	hw->hw_next = QH_NEXT(ehci, ehci->async->qh_dma);
 	hw->hw_info1 = cpu_to_hc32(ehci, QH_HEAD);
+	hw->hw_info1 |= cpu_to_hc32(ehci, (1 << 7));	/* I = 1 */
 	hw->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
 	hw->hw_qtd_next = EHCI_LIST_END(ehci);
 	ehci->async->qh_state = QH_STATE_LINKED;
@@ -677,22 +728,13 @@
 static int ehci_run (struct usb_hcd *hcd)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	int			retval;
 	u32			temp;
 	u32			hcc_params;
 
 	hcd->uses_new_polling = 1;
 
 	/* EHCI spec section 4.1 */
-	/*
-	 * TDI driver does the ehci_reset in their reset callback.
-	 * Don't reset here, because configuration settings will
-	 * vanish.
-	 */
-	if (!ehci_is_TDI(ehci) && (retval = ehci_reset(ehci)) != 0) {
-		ehci_mem_cleanup(ehci);
-		return retval;
-	}
+
 	ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
 	ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
 
@@ -1324,11 +1366,16 @@
 #define PLATFORM_DRIVER		ehci_pxa168_driver
 #endif
 
-#ifdef CONFIG_NLM_XLR
+#ifdef CONFIG_CPU_XLR
 #include "ehci-xls.c"
 #define PLATFORM_DRIVER		ehci_xls_driver
 #endif
 
+#ifdef CONFIG_USB_EHCI_MV
+#include "ehci-mv.c"
+#define        PLATFORM_DRIVER         ehci_mv_driver
+#endif
+
 #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
     !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
     !defined(XILINX_OF_PLATFORM_DRIVER)
diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c
new file mode 100644
index 0000000..52a604f
--- /dev/null
+++ b/drivers/usb/host/ehci-mv.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ * Author: Chao Xie <chao.xie@marvell.com>
+ *        Neil Zhang <zhangwm@marvell.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/usb/otg.h>
+#include <linux/platform_data/mv_usb.h>
+
+#define CAPLENGTH_MASK         (0xff)
+
+struct ehci_hcd_mv {
+	struct usb_hcd *hcd;
+
+	/* Which mode does this ehci running OTG/Host ? */
+	int mode;
+
+	void __iomem *phy_regs;
+	void __iomem *cap_regs;
+	void __iomem *op_regs;
+
+	struct otg_transceiver *otg;
+
+	struct mv_usb_platform_data *pdata;
+
+	/* clock source and total clock number */
+	unsigned int clknum;
+	struct clk *clk[0];
+};
+
+static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv)
+{
+	unsigned int i;
+
+	for (i = 0; i < ehci_mv->clknum; i++)
+		clk_enable(ehci_mv->clk[i]);
+}
+
+static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv)
+{
+	unsigned int i;
+
+	for (i = 0; i < ehci_mv->clknum; i++)
+		clk_disable(ehci_mv->clk[i]);
+}
+
+static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv)
+{
+	int retval;
+
+	ehci_clock_enable(ehci_mv);
+	if (ehci_mv->pdata->phy_init) {
+		retval = ehci_mv->pdata->phy_init(ehci_mv->phy_regs);
+		if (retval)
+			return retval;
+	}
+
+	return 0;
+}
+
+static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv)
+{
+	if (ehci_mv->pdata->phy_deinit)
+		ehci_mv->pdata->phy_deinit(ehci_mv->phy_regs);
+	ehci_clock_disable(ehci_mv);
+}
+
+static int mv_ehci_reset(struct usb_hcd *hcd)
+{
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	struct device *dev = hcd->self.controller;
+	struct ehci_hcd_mv *ehci_mv = dev_get_drvdata(dev);
+	int retval;
+
+	if (ehci_mv == NULL) {
+		dev_err(dev, "Can not find private ehci data\n");
+		return -ENODEV;
+	}
+
+	/*
+	 * data structure init
+	 */
+	retval = ehci_init(hcd);
+	if (retval) {
+		dev_err(dev, "ehci_init failed %d\n", retval);
+		return retval;
+	}
+
+	hcd->has_tt = 1;
+	ehci->sbrn = 0x20;
+
+	retval = ehci_reset(ehci);
+	if (retval) {
+		dev_err(dev, "ehci_reset failed %d\n", retval);
+		return retval;
+	}
+
+	return 0;
+}
+
+static const struct hc_driver mv_ehci_hc_driver = {
+	.description = hcd_name,
+	.product_desc = "Marvell EHCI",
+	.hcd_priv_size = sizeof(struct ehci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq = ehci_irq,
+	.flags = HCD_MEMORY | HCD_USB2,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset = mv_ehci_reset,
+	.start = ehci_run,
+	.stop = ehci_stop,
+	.shutdown = ehci_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue = ehci_urb_enqueue,
+	.urb_dequeue = ehci_urb_dequeue,
+	.endpoint_disable = ehci_endpoint_disable,
+	.endpoint_reset = ehci_endpoint_reset,
+	.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number = ehci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data = ehci_hub_status_data,
+	.hub_control = ehci_hub_control,
+	.bus_suspend = ehci_bus_suspend,
+	.bus_resume = ehci_bus_resume,
+};
+
+static int mv_ehci_probe(struct platform_device *pdev)
+{
+	struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
+	struct usb_hcd *hcd;
+	struct ehci_hcd *ehci;
+	struct ehci_hcd_mv *ehci_mv;
+	struct resource *r;
+	int clk_i, retval = -ENODEV;
+	u32 offset;
+	size_t size;
+
+	if (!pdata) {
+		dev_err(&pdev->dev, "missing platform_data\n");
+		return -ENODEV;
+	}
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	hcd = usb_create_hcd(&mv_ehci_hc_driver, &pdev->dev, "mv ehci");
+	if (!hcd)
+		return -ENOMEM;
+
+	size = sizeof(*ehci_mv) + sizeof(struct clk *) * pdata->clknum;
+	ehci_mv = kzalloc(size, GFP_KERNEL);
+	if (ehci_mv == NULL) {
+		dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n");
+		retval = -ENOMEM;
+		goto err_put_hcd;
+	}
+
+	platform_set_drvdata(pdev, ehci_mv);
+	ehci_mv->pdata = pdata;
+	ehci_mv->hcd = hcd;
+
+	ehci_mv->clknum = pdata->clknum;
+	for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) {
+		ehci_mv->clk[clk_i] =
+		    clk_get(&pdev->dev, pdata->clkname[clk_i]);
+		if (IS_ERR(ehci_mv->clk[clk_i])) {
+			dev_err(&pdev->dev, "error get clck \"%s\"\n",
+				pdata->clkname[clk_i]);
+			retval = PTR_ERR(ehci_mv->clk[clk_i]);
+			goto err_put_clk;
+		}
+	}
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs");
+	if (r == NULL) {
+		dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
+		retval = -ENODEV;
+		goto err_put_clk;
+	}
+
+	ehci_mv->phy_regs = ioremap(r->start, resource_size(r));
+	if (ehci_mv->phy_regs == 0) {
+		dev_err(&pdev->dev, "failed to map phy I/O memory\n");
+		retval = -EFAULT;
+		goto err_put_clk;
+	}
+
+	r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "capregs");
+	if (!r) {
+		dev_err(&pdev->dev, "no I/O memory resource defined\n");
+		retval = -ENODEV;
+		goto err_iounmap_phyreg;
+	}
+
+	ehci_mv->cap_regs = ioremap(r->start, resource_size(r));
+	if (ehci_mv->cap_regs == NULL) {
+		dev_err(&pdev->dev, "failed to map I/O memory\n");
+		retval = -EFAULT;
+		goto err_iounmap_phyreg;
+	}
+
+	retval = mv_ehci_enable(ehci_mv);
+	if (retval) {
+		dev_err(&pdev->dev, "init phy error %d\n", retval);
+		goto err_iounmap_capreg;
+	}
+
+	offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK;
+	ehci_mv->op_regs =
+		(void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset);
+
+	hcd->rsrc_start = r->start;
+	hcd->rsrc_len = r->end - r->start + 1;
+	hcd->regs = ehci_mv->op_regs;
+
+	hcd->irq = platform_get_irq(pdev, 0);
+	if (!hcd->irq) {
+		dev_err(&pdev->dev, "Cannot get irq.");
+		retval = -ENODEV;
+		goto err_disable_clk;
+	}
+
+	ehci = hcd_to_ehci(hcd);
+	ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs;
+	ehci->regs = (struct ehci_regs *) ehci_mv->op_regs;
+	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+	ehci_mv->mode = pdata->mode;
+	if (ehci_mv->mode == MV_USB_MODE_OTG) {
+#ifdef CONFIG_USB_OTG_UTILS
+		ehci_mv->otg = otg_get_transceiver();
+		if (!ehci_mv->otg) {
+			dev_err(&pdev->dev,
+				"unable to find transceiver\n");
+			retval = -ENODEV;
+			goto err_disable_clk;
+		}
+
+		retval = otg_set_host(ehci_mv->otg, &hcd->self);
+		if (retval < 0) {
+			dev_err(&pdev->dev,
+				"unable to register with transceiver\n");
+			retval = -ENODEV;
+			goto err_put_transceiver;
+		}
+		/* otg will enable clock before use as host */
+		mv_ehci_disable(ehci_mv);
+#else
+		dev_info(&pdev->dev, "MV_USB_MODE_OTG "
+			 "must have CONFIG_USB_OTG_UTILS enabled\n");
+		goto err_disable_clk;
+#endif
+	} else {
+		if (pdata->set_vbus)
+			pdata->set_vbus(1);
+
+		retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
+		if (retval) {
+			dev_err(&pdev->dev,
+				"failed to add hcd with err %d\n", retval);
+			goto err_set_vbus;
+		}
+	}
+
+	if (pdata->private_init)
+		pdata->private_init(ehci_mv->op_regs, ehci_mv->phy_regs);
+
+	dev_info(&pdev->dev,
+		 "successful find EHCI device with regs 0x%p irq %d"
+		 " working in %s mode\n", hcd->regs, hcd->irq,
+		 ehci_mv->mode == MV_USB_MODE_OTG ? "OTG" : "Host");
+
+	return 0;
+
+err_set_vbus:
+	if (pdata->set_vbus)
+		pdata->set_vbus(0);
+#ifdef CONFIG_USB_OTG_UTILS
+err_put_transceiver:
+	if (ehci_mv->otg)
+		otg_put_transceiver(ehci_mv->otg);
+#endif
+err_disable_clk:
+	mv_ehci_disable(ehci_mv);
+err_iounmap_capreg:
+	iounmap(ehci_mv->cap_regs);
+err_iounmap_phyreg:
+	iounmap(ehci_mv->phy_regs);
+err_put_clk:
+	for (clk_i--; clk_i >= 0; clk_i--)
+		clk_put(ehci_mv->clk[clk_i]);
+	platform_set_drvdata(pdev, NULL);
+	kfree(ehci_mv);
+err_put_hcd:
+	usb_put_hcd(hcd);
+
+	return retval;
+}
+
+static int mv_ehci_remove(struct platform_device *pdev)
+{
+	struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev);
+	struct usb_hcd *hcd = ehci_mv->hcd;
+	int clk_i;
+
+	if (hcd->rh_registered)
+		usb_remove_hcd(hcd);
+
+	if (ehci_mv->otg) {
+		otg_set_host(ehci_mv->otg, NULL);
+		otg_put_transceiver(ehci_mv->otg);
+	}
+
+	if (ehci_mv->mode == MV_USB_MODE_HOST) {
+		if (ehci_mv->pdata->set_vbus)
+			ehci_mv->pdata->set_vbus(0);
+
+		mv_ehci_disable(ehci_mv);
+	}
+
+	iounmap(ehci_mv->cap_regs);
+	iounmap(ehci_mv->phy_regs);
+
+	for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++)
+		clk_put(ehci_mv->clk[clk_i]);
+
+	platform_set_drvdata(pdev, NULL);
+
+	kfree(ehci_mv);
+	usb_put_hcd(hcd);
+
+	return 0;
+}
+
+MODULE_ALIAS("mv-ehci");
+
+static const struct platform_device_id ehci_id_table[] = {
+	{"pxa-u2oehci", PXA_U2OEHCI},
+	{"pxa-sph", PXA_SPH},
+	{"mmp3-hsic", MMP3_HSIC},
+	{"mmp3-fsic", MMP3_FSIC},
+	{},
+};
+
+static void mv_ehci_shutdown(struct platform_device *pdev)
+{
+	struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev);
+	struct usb_hcd *hcd = ehci_mv->hcd;
+
+	if (!hcd->rh_registered)
+		return;
+
+	if (hcd->driver->shutdown)
+		hcd->driver->shutdown(hcd);
+}
+
+static struct platform_driver ehci_mv_driver = {
+	.probe = mv_ehci_probe,
+	.remove = mv_ehci_remove,
+	.shutdown = mv_ehci_shutdown,
+	.driver = {
+		   .name = "mv-ehci",
+		   .bus = &platform_bus_type,
+		   },
+	.id_table = ehci_id_table,
+};
diff --git a/drivers/usb/host/ehci-octeon.c b/drivers/usb/host/ehci-octeon.c
index ba1f513..c010488 100644
--- a/drivers/usb/host/ehci-octeon.c
+++ b/drivers/usb/host/ehci-octeon.c
@@ -155,6 +155,8 @@
 	/* cache this readonly data; minimize chip reads */
 	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
+	ehci_reset(ehci);
+
 	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (ret) {
 		dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index e39b029..e33baf9 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -228,6 +228,8 @@
 	/* cache this readonly data; minimize chip reads */
 	omap_ehci->hcs_params = readl(&omap_ehci->caps->hcs_params);
 
+	ehci_reset(omap_ehci);
+
 	ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (ret) {
 		dev_err(dev, "failed to add hcd with err %d\n", ret);
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
index 2dc32da..a20e496 100644
--- a/drivers/usb/host/ehci-ps3.c
+++ b/drivers/usb/host/ehci-ps3.c
@@ -21,6 +21,34 @@
 #include <asm/firmware.h>
 #include <asm/ps3.h>
 
+static void ps3_ehci_setup_insnreg(struct ehci_hcd *ehci)
+{
+	/* PS3 HC internal setup register offsets. */
+
+	enum ps3_ehci_hc_insnreg {
+		ps3_ehci_hc_insnreg01 = 0x084,
+		ps3_ehci_hc_insnreg02 = 0x088,
+		ps3_ehci_hc_insnreg03 = 0x08c,
+	};
+
+	/* PS3 EHCI HC errata fix 316 - The PS3 EHCI HC will reset its
+	 * internal INSNREGXX setup regs back to the chip default values
+	 * on Host Controller Reset (CMD_RESET) or Light Host Controller
+	 * Reset (CMD_LRESET).  The work-around for this is for the HC
+	 * driver to re-initialise these regs when ever the HC is reset.
+	 */
+
+	/* Set burst transfer counts to 256 out, 32 in. */
+
+	writel_be(0x01000020, (void __iomem *)ehci->regs +
+		ps3_ehci_hc_insnreg01);
+
+	/* Enable burst transfer counts. */
+
+	writel_be(0x00000001, (void __iomem *)ehci->regs +
+		ps3_ehci_hc_insnreg03);
+}
+
 static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
 {
 	int result;
@@ -49,6 +77,8 @@
 
 	ehci_reset(ehci);
 
+	ps3_ehci_setup_insnreg(ehci);
+
 	return result;
 }
 
diff --git a/drivers/usb/host/ehci-pxa168.c b/drivers/usb/host/ehci-pxa168.c
index ac0c16e..8d0e7a2 100644
--- a/drivers/usb/host/ehci-pxa168.c
+++ b/drivers/usb/host/ehci-pxa168.c
@@ -299,7 +299,7 @@
 	ehci = hcd_to_ehci(hcd);
 	ehci->caps = hcd->regs + 0x100;
 	ehci->regs = hcd->regs + 0x100 +
-		HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
 	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 	hcd->has_tt = 1;
 	ehci->sbrn = 0x20;
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 4e4066c..36ca507 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -373,6 +373,17 @@
  retry_xacterr:
 		if ((token & QTD_STS_ACTIVE) == 0) {
 
+			/* Report Data Buffer Error: non-fatal but useful */
+			if (token & QTD_STS_DBE)
+				ehci_dbg(ehci,
+					"detected DataBufferErr for urb %p ep%d%s len %d, qtd %p [qh %p]\n",
+					urb,
+					usb_endpoint_num(&urb->ep->desc),
+					usb_endpoint_dir_in(&urb->ep->desc) ? "in" : "out",
+					urb->transfer_buffer_length,
+					qtd,
+					qh);
+
 			/* on STALL, error, and short reads this urb must
 			 * complete and all its qtds must be recycled.
 			 */
@@ -647,7 +658,7 @@
 	/*
 	 * data transfer stage:  buffer setup
 	 */
-	i = urb->num_sgs;
+	i = urb->num_mapped_sgs;
 	if (len > 0 && i > 0) {
 		sg = urb->sg;
 		buf = sg_dma_address(sg);
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index 024b65c..293f741 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -14,8 +14,6 @@
 
 #include <linux/clk.h>
 #include <linux/platform_device.h>
-#include <mach/regs-pmu.h>
-#include <plat/cpu.h>
 #include <plat/ehci.h>
 #include <plat/usb-phy.h>
 
@@ -136,6 +134,8 @@
 	/* cache this readonly data; minimize chip reads */
 	ehci->hcs_params = readl(&ehci->caps->hcs_params);
 
+	ehci_reset(ehci);
+
 	err = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (err) {
 		dev_err(&pdev->dev, "Failed to add USB HCD\n");
diff --git a/drivers/usb/host/ehci-vt8500.c b/drivers/usb/host/ehci-vt8500.c
index 54d1ab8..c1eda73 100644
--- a/drivers/usb/host/ehci-vt8500.c
+++ b/drivers/usb/host/ehci-vt8500.c
@@ -132,6 +132,8 @@
 
 	ehci_port_power(ehci, 1);
 
+	ehci_reset(ehci);
+
 	ret = usb_add_hcd(hcd, pdev->resource[1].start,
 			  IRQF_SHARED);
 	if (ret == 0) {
diff --git a/drivers/usb/host/ehci-w90x900.c b/drivers/usb/host/ehci-w90x900.c
index d661cf7..3d2e26c 100644
--- a/drivers/usb/host/ehci-w90x900.c
+++ b/drivers/usb/host/ehci-w90x900.c
@@ -78,6 +78,8 @@
 	if (irq < 0)
 		goto err4;
 
+	ehci_reset(ehci);
+
 	retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
 	if (retval != 0)
 		goto err4;
diff --git a/drivers/usb/host/ehci-xls.c b/drivers/usb/host/ehci-xls.c
index b4fb511..72f0819 100644
--- a/drivers/usb/host/ehci-xls.c
+++ b/drivers/usb/host/ehci-xls.c
@@ -69,7 +69,7 @@
 	}
 
 	hcd->rsrc_start = res->start;
-	hcd->rsrc_len = res->end - res->start + 1;
+	hcd->rsrc_len = resource_size(res);
 
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
 				driver->description)) {
diff --git a/drivers/usb/host/fhci-hcd.c b/drivers/usb/host/fhci-hcd.c
index 4ed6d19..d262374 100644
--- a/drivers/usb/host/fhci-hcd.c
+++ b/drivers/usb/host/fhci-hcd.c
@@ -824,17 +824,7 @@
 	.remove		= __devexit_p(of_fhci_remove),
 };
 
-static int __init fhci_module_init(void)
-{
-	return platform_driver_register(&of_fhci_driver);
-}
-module_init(fhci_module_init);
-
-static void __exit fhci_module_exit(void)
-{
-	platform_driver_unregister(&of_fhci_driver);
-}
-module_exit(fhci_module_exit);
+module_platform_driver(of_fhci_driver);
 
 MODULE_DESCRIPTION("USB Freescale Host Controller Interface Driver");
 MODULE_AUTHOR("Shlomi Gridish <gridish@freescale.com>, "
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index 9037035..7916e56 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -297,17 +297,7 @@
 	.remove	= __devexit_p(fsl_usb2_mph_dr_of_remove),
 };
 
-static int __init fsl_usb2_mph_dr_init(void)
-{
-	return platform_driver_register(&fsl_usb2_mph_dr_driver);
-}
-module_init(fsl_usb2_mph_dr_init);
-
-static void __exit fsl_usb2_mph_dr_exit(void)
-{
-	platform_driver_unregister(&fsl_usb2_mph_dr_driver);
-}
-module_exit(fsl_usb2_mph_dr_exit);
+module_platform_driver(fsl_usb2_mph_dr_driver);
 
 MODULE_DESCRIPTION("FSL MPH DR OF devices driver");
 MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>");
diff --git a/drivers/usb/host/hwa-hc.c b/drivers/usb/host/hwa-hc.c
index 43b3ca4..104730d 100644
--- a/drivers/usb/host/hwa-hc.c
+++ b/drivers/usb/host/hwa-hc.c
@@ -776,7 +776,6 @@
 		goto error_alloc;
 	}
 	usb_hcd->wireless = 1;
-	set_bit(HCD_FLAG_SAW_IRQ, &usb_hcd->flags);
 	wusbhc = usb_hcd_to_wusbhc(usb_hcd);
 	hwahc = container_of(wusbhc, struct hwahc, wusbhc);
 	hwahc_init(hwahc);
diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c
index dbf0f15..ff471c1 100644
--- a/drivers/usb/host/imx21-hcd.c
+++ b/drivers/usb/host/imx21-hcd.c
@@ -1924,18 +1924,7 @@
 	.resume = NULL,
 };
 
-static int __init imx21_hcd_init(void)
-{
-	return platform_driver_register(&imx21_hcd_driver);
-}
-
-static void __exit imx21_hcd_cleanup(void)
-{
-	platform_driver_unregister(&imx21_hcd_driver);
-}
-
-module_init(imx21_hcd_init);
-module_exit(imx21_hcd_cleanup);
+module_platform_driver(imx21_hcd_driver);
 
 MODULE_DESCRIPTION("i.MX21 USB Host controller");
 MODULE_AUTHOR("Martin Fuzzey");
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
index 27dfab8..fc72d44 100644
--- a/drivers/usb/host/isp1760-hcd.c
+++ b/drivers/usb/host/isp1760-hcd.c
@@ -32,6 +32,13 @@
 static struct kmem_cache *qh_cachep;
 static struct kmem_cache *urb_listitem_cachep;
 
+enum queue_head_types {
+	QH_CONTROL,
+	QH_BULK,
+	QH_INTERRUPT,
+	QH_END
+};
+
 struct isp1760_hcd {
 	u32 hcs_params;
 	spinlock_t		lock;
@@ -40,7 +47,7 @@
 	struct slotinfo		int_slots[32];
 	int			int_done_map;
 	struct memory_chunk memory_pool[BLOCKS];
-	struct list_head	controlqhs, bulkqhs, interruptqhs;
+	struct list_head	qh_list[QH_END];
 
 	/* periodic schedule support */
 #define	DEFAULT_I_TDPS		1024
@@ -406,12 +413,12 @@
 {
 	struct isp1760_hcd		*priv = hcd_to_priv(hcd);
 	u32			hcc_params;
+	int i;
 
 	spin_lock_init(&priv->lock);
 
-	INIT_LIST_HEAD(&priv->interruptqhs);
-	INIT_LIST_HEAD(&priv->controlqhs);
-	INIT_LIST_HEAD(&priv->bulkqhs);
+	for (i = 0; i < QH_END; i++)
+		INIT_LIST_HEAD(&priv->qh_list[i]);
 
 	/*
 	 * hw default: 1K periodic list heads, one per frame.
@@ -930,9 +937,9 @@
 	struct isp1760_hcd *priv;
 	struct isp1760_qh *qh, *qh_next;
 	struct list_head *ep_queue;
-	struct usb_host_endpoint *ep;
 	LIST_HEAD(urb_list);
 	struct urb_listitem *urb_listitem, *urb_listitem_next;
+	int i;
 
 	if (!hcd) {
 		WARN_ON(1);
@@ -944,28 +951,13 @@
 	/*
 	 * check finished/retired xfers, transfer payloads, call urb_done()
 	 */
-	ep_queue = &priv->interruptqhs;
-	while (ep_queue) {
+	for (i = 0; i < QH_END; i++) {
+		ep_queue = &priv->qh_list[i];
 		list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list) {
-			ep = list_entry(qh->qtd_list.next, struct isp1760_qtd,
-							qtd_list)->urb->ep;
 			collect_qtds(hcd, qh, &urb_list);
-			if (list_empty(&qh->qtd_list)) {
+			if (list_empty(&qh->qtd_list))
 				list_del(&qh->qh_list);
-				if (ep->hcpriv == NULL) {
-					/* Endpoint has been disabled, so we
-					can free the associated queue head. */
-					qh_free(qh);
-				}
-			}
 		}
-
-		if (ep_queue == &priv->interruptqhs)
-			ep_queue = &priv->controlqhs;
-		else if (ep_queue == &priv->controlqhs)
-			ep_queue = &priv->bulkqhs;
-		else
-			ep_queue = NULL;
 	}
 
 	list_for_each_entry_safe(urb_listitem, urb_listitem_next, &urb_list,
@@ -998,17 +990,10 @@
 	 *
 	 * I'm sure this scheme could be improved upon!
 	 */
-	ep_queue = &priv->controlqhs;
-	while (ep_queue) {
+	for (i = 0; i < QH_END; i++) {
+		ep_queue = &priv->qh_list[i];
 		list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list)
 			enqueue_qtds(hcd, qh);
-
-		if (ep_queue == &priv->controlqhs)
-			ep_queue = &priv->interruptqhs;
-		else if (ep_queue == &priv->interruptqhs)
-			ep_queue = &priv->bulkqhs;
-		else
-			ep_queue = NULL;
 	}
 }
 
@@ -1543,16 +1528,16 @@
 
 	switch (usb_pipetype(urb->pipe)) {
 	case PIPE_CONTROL:
-		ep_queue = &priv->controlqhs;
+		ep_queue = &priv->qh_list[QH_CONTROL];
 		break;
 	case PIPE_BULK:
-		ep_queue = &priv->bulkqhs;
+		ep_queue = &priv->qh_list[QH_BULK];
 		break;
 	case PIPE_INTERRUPT:
 		if (urb->interval < 0)
 			return -EINVAL;
 		/* FIXME: Check bandwidth  */
-		ep_queue = &priv->interruptqhs;
+		ep_queue = &priv->qh_list[QH_INTERRUPT];
 		break;
 	case PIPE_ISOCHRONOUS:
 		dev_err(hcd->self.controller, "%s: isochronous USB packets "
@@ -1714,8 +1699,8 @@
 {
 	struct isp1760_hcd *priv = hcd_to_priv(hcd);
 	unsigned long spinflags;
-	struct isp1760_qh *qh;
-	struct isp1760_qtd *qtd;
+	struct isp1760_qh *qh, *qh_iter;
+	int i;
 
 	spin_lock_irqsave(&priv->lock, spinflags);
 
@@ -1723,14 +1708,17 @@
 	if (!qh)
 		goto out;
 
-	list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
-		if (qtd->status != QTD_RETIRE) {
-			dequeue_urb_from_qtd(hcd, qh, qtd);
-			qtd->urb->status = -ECONNRESET;
-		}
+	WARN_ON(!list_empty(&qh->qtd_list));
 
+	for (i = 0; i < QH_END; i++)
+		list_for_each_entry(qh_iter, &priv->qh_list[i], qh_list)
+			if (qh_iter == qh) {
+				list_del(&qh_iter->qh_list);
+				i = QH_END;
+				break;
+			}
+	qh_free(qh);
 	ep->hcpriv = NULL;
-	/* Cannot free qh here since it will be parsed by schedule_ptds() */
 
 	schedule_ptds(hcd);
 
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
index 2ac4ac2..4592dc1 100644
--- a/drivers/usb/host/isp1760-if.c
+++ b/drivers/usb/host/isp1760-if.c
@@ -47,23 +47,27 @@
 	int virq;
 	resource_size_t res_len;
 	int ret;
-	const unsigned int *prop;
 	unsigned int devflags = 0;
 	enum of_gpio_flags gpio_flags;
+	u32 bus_width = 0;
 
 	drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
 	if (!drvdata)
 		return -ENOMEM;
 
 	ret = of_address_to_resource(dp, 0, &memory);
-	if (ret)
-		return -ENXIO;
+	if (ret) {
+		ret = -ENXIO;
+		goto free_data;
+	}
 
 	res_len = resource_size(&memory);
 
 	res = request_mem_region(memory.start, res_len, dev_name(&dev->dev));
-	if (!res)
-		return -EBUSY;
+	if (!res) {
+		ret = -EBUSY;
+		goto free_data;
+	}
 
 	if (of_irq_map_one(dp, 0, &oirq)) {
 		ret = -ENODEV;
@@ -77,8 +81,8 @@
 		devflags |= ISP1760_FLAG_ISP1761;
 
 	/* Some systems wire up only 16 of the 32 data lines */
-	prop = of_get_property(dp, "bus-width", NULL);
-	if (prop && *prop == 16)
+	of_property_read_u32(dp, "bus-width", &bus_width);
+	if (bus_width == 16)
 		devflags |= ISP1760_FLAG_BUS_WIDTH_16;
 
 	if (of_get_property(dp, "port1-otg", NULL) != NULL)
@@ -125,6 +129,7 @@
 		gpio_free(drvdata->rst_gpio);
 release_reg:
 	release_mem_region(memory.start, res_len);
+free_data:
 	kfree(drvdata);
 	return ret;
 }
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index 9b66df8..40d886a 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -173,12 +173,9 @@
 	 * mark HW unaccessible, bail out if RH has been resumed. Use
 	 * the spinlock to properly synchronize with possible pending
 	 * RH suspend or resume activity.
-	 *
-	 * This is still racy as hcd->state is manipulated outside of
-	 * any locks =P But that will be a different fix.
 	 */
 	spin_lock_irqsave(&ohci->lock, flags);
-	if (hcd->state != HC_STATE_SUSPENDED) {
+	if (ohci->rh_state != OHCI_RH_SUSPENDED) {
 		rc = -EINVAL;
 		goto bail;
 	}
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index d7d3449..5179fcd 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -127,6 +127,19 @@
 	return "?";
 }
 
+static const char *rh_state_string(struct ohci_hcd *ohci)
+{
+	switch (ohci->rh_state) {
+	case OHCI_RH_HALTED:
+		return "halted";
+	case OHCI_RH_SUSPENDED:
+		return "suspended";
+	case OHCI_RH_RUNNING:
+		return "running";
+	}
+	return "?";
+}
+
 // dump control and status registers
 static void
 ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size)
@@ -136,9 +149,10 @@
 
 	temp = ohci_readl (controller, &regs->revision) & 0xff;
 	ohci_dbg_sw (controller, next, size,
-		"OHCI %d.%d, %s legacy support registers\n",
+		"OHCI %d.%d, %s legacy support registers, rh state %s\n",
 		0x03 & (temp >> 4), (temp & 0x0f),
-		(temp & 0x0100) ? "with" : "NO");
+		(temp & 0x0100) ? "with" : "NO",
+		rh_state_string(controller));
 
 	temp = ohci_readl (controller, &regs->control);
 	ohci_dbg_sw (controller, next, size,
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
index dc45d48..3d63574 100644
--- a/drivers/usb/host/ohci-ep93xx.c
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -179,8 +179,6 @@
 	ohci->next_statechange = jiffies;
 
 	ep93xx_stop_hc(&pdev->dev);
-	hcd->state = HC_STATE_SUSPENDED;
-
 	return 0;
 }
 
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index b263919..4fa5d8c 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -209,7 +209,7 @@
 		retval = -ENODEV;
 		goto fail;
 	}
-	if (!HC_IS_RUNNING(hcd->state)) {
+	if (ohci->rh_state != OHCI_RH_RUNNING) {
 		retval = -ENODEV;
 		goto fail;
 	}
@@ -274,7 +274,7 @@
 	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
 	if (rc) {
 		;	/* Do nothing */
-	} else if (HC_IS_RUNNING(hcd->state)) {
+	} else if (ohci->rh_state == OHCI_RH_RUNNING) {
 		urb_priv_t  *urb_priv;
 
 		/* Unless an IRQ completed the unlink while it was being
@@ -321,7 +321,7 @@
 rescan:
 	spin_lock_irqsave (&ohci->lock, flags);
 
-	if (!HC_IS_RUNNING (hcd->state)) {
+	if (ohci->rh_state != OHCI_RH_RUNNING) {
 sanitize:
 		ed->state = ED_IDLE;
 		if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
@@ -377,6 +377,7 @@
 	ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
 	ohci->hc_control &= OHCI_CTRL_RWC;
 	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+	ohci->rh_state = OHCI_RH_HALTED;
 }
 
 /* ohci_shutdown forcibly disables IRQs and DMA, helping kexec and
@@ -500,7 +501,7 @@
 	if (distrust_firmware)
 		ohci->flags |= OHCI_QUIRK_HUB_POWER;
 
-	disable (ohci);
+	ohci->rh_state = OHCI_RH_HALTED;
 	ohci->regs = hcd->regs;
 
 	/* REVISIT this BIOS handshake is now moved into PCI "quirks", and
@@ -575,7 +576,7 @@
 	int			first = ohci->fminterval == 0;
 	struct usb_hcd		*hcd = ohci_to_hcd(ohci);
 
-	disable (ohci);
+	ohci->rh_state = OHCI_RH_HALTED;
 
 	/* boot firmware should have set this up (5.1.1.3.1) */
 	if (first) {
@@ -688,7 +689,7 @@
 	ohci->hc_control &= OHCI_CTRL_RWC;
 	ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
 	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
-	hcd->state = HC_STATE_RUNNING;
+	ohci->rh_state = OHCI_RH_RUNNING;
 
 	/* wake on ConnectStatusChange, matching external hubs */
 	ohci_writel (ohci, RH_HS_DRWE, &ohci->regs->roothub.status);
@@ -725,7 +726,6 @@
 
 	// POTPGT delay is bits 24-31, in 2 ms units.
 	mdelay ((val >> 23) & 0x1fe);
-	hcd->state = HC_STATE_RUNNING;
 
 	if (quirk_zfmicro(ohci)) {
 		/* Create timer to watch for bad queue state on ZF Micro */
@@ -761,7 +761,7 @@
 	 * of dead, unclocked, or unplugged (CardBus...) devices
 	 */
 	if (ints == ~(u32)0) {
-		disable (ohci);
+		ohci->rh_state = OHCI_RH_HALTED;
 		ohci_dbg (ohci, "device removed!\n");
 		usb_hc_died(hcd);
 		return IRQ_HANDLED;
@@ -771,7 +771,7 @@
 	ints &= ohci_readl(ohci, &regs->intrenable);
 
 	/* interrupt for some other device? */
-	if (ints == 0 || unlikely(hcd->state == HC_STATE_HALT))
+	if (ints == 0 || unlikely(ohci->rh_state == OHCI_RH_HALTED))
 		return IRQ_NOTMINE;
 
 	if (ints & OHCI_INTR_UE) {
@@ -786,8 +786,8 @@
 
 			schedule_work (&ohci->nec_work);
 		} else {
-			disable (ohci);
 			ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
+			ohci->rh_state = OHCI_RH_HALTED;
 			usb_hc_died(hcd);
 		}
 
@@ -871,11 +871,11 @@
 	if ((ints & OHCI_INTR_SF) != 0
 			&& !ohci->ed_rm_list
 			&& !ohci->ed_to_check
-			&& HC_IS_RUNNING(hcd->state))
+			&& ohci->rh_state == OHCI_RH_RUNNING)
 		ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);
 	spin_unlock (&ohci->lock);
 
-	if (HC_IS_RUNNING(hcd->state)) {
+	if (ohci->rh_state == OHCI_RH_RUNNING) {
 		ohci_writel (ohci, ints, &regs->intrstatus);
 		ohci_writel (ohci, OHCI_INTR_MIE, &regs->intrenable);
 		// flush those writes
@@ -929,7 +929,7 @@
 	struct urb_priv *priv;
 
 	spin_lock_irq(&ohci->lock);
-	disable (ohci);
+	ohci->rh_state = OHCI_RH_HALTED;
 
 	/* Recycle any "live" eds/tds (and urbs). */
 	if (!list_empty (&ohci->pending))
@@ -1111,7 +1111,7 @@
 #define PLATFORM_DRIVER		ohci_hcd_ath79_driver
 #endif
 
-#ifdef CONFIG_NLM_XLR
+#ifdef CONFIG_CPU_XLR
 #include "ohci-xls.c"
 #define PLATFORM_DRIVER		ohci_xls_driver
 #endif
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 2f00040..836772d 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -111,6 +111,7 @@
 	if (!autostop) {
 		ohci->next_statechange = jiffies + msecs_to_jiffies (5);
 		ohci->autostop = 0;
+		ohci->rh_state = OHCI_RH_SUSPENDED;
 	}
 
 done:
@@ -140,7 +141,7 @@
 
 	if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
 		/* this can happen after resuming a swsusp snapshot */
-		if (hcd->state == HC_STATE_RESUMING) {
+		if (ohci->rh_state != OHCI_RH_RUNNING) {
 			ohci_dbg (ohci, "BIOS/SMM active, control %03x\n",
 					ohci->hc_control);
 			status = -EBUSY;
@@ -274,6 +275,7 @@
 		(void) ohci_readl (ohci, &ohci->regs->control);
 	}
 
+	ohci->rh_state = OHCI_RH_RUNNING;
 	return 0;
 }
 
@@ -336,11 +338,8 @@
 	/* If needed, reinitialize and suspend the root hub */
 	if (need_reinit) {
 		spin_lock_irq(&ohci->lock);
-		hcd->state = HC_STATE_RESUMING;
 		ohci_rh_resume(ohci);
-		hcd->state = HC_STATE_QUIESCING;
 		ohci_rh_suspend(ohci, 0);
-		hcd->state = HC_STATE_SUSPENDED;
 		spin_unlock_irq(&ohci->lock);
 	}
 
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index e4b8782..db39686 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -516,7 +516,6 @@
 	ohci->next_statechange = jiffies;
 
 	omap_ohci_clock_power(0);
-	ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
 	return 0;
 }
 
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index bc01b06..6109810 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -308,12 +308,9 @@
 	 * mark HW unaccessible, bail out if RH has been resumed. Use
 	 * the spinlock to properly synchronize with possible pending
 	 * RH suspend or resume activity.
-	 *
-	 * This is still racy as hcd->state is manipulated outside of
-	 * any locks =P But that will be a different fix.
 	 */
 	spin_lock_irqsave (&ohci->lock, flags);
-	if (hcd->state != HC_STATE_SUSPENDED) {
+	if (ohci->rh_state != OHCI_RH_SUSPENDED) {
 		rc = -EINVAL;
 		goto bail;
 	}
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 29dfefe..6313e44 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -502,8 +502,6 @@
 	ohci->ohci.next_statechange = jiffies;
 
 	pxa27x_stop_hc(ohci, dev);
-	hcd->state = HC_STATE_SUSPENDED;
-
 	return 0;
 }
 
diff --git a/drivers/usb/host/ohci-q.c b/drivers/usb/host/ohci-q.c
index 15dc51d..c5a1ea9 100644
--- a/drivers/usb/host/ohci-q.c
+++ b/drivers/usb/host/ohci-q.c
@@ -912,7 +912,7 @@
 		/* only take off EDs that the HC isn't using, accounting for
 		 * frame counter wraps and EDs with partially retired TDs
 		 */
-		if (likely (HC_IS_RUNNING(ohci_to_hcd(ohci)->state))) {
+		if (likely(ohci->rh_state == OHCI_RH_RUNNING)) {
 			if (tick_before (tick, ed->tick)) {
 skip_ed:
 				last = &ed->ed_next;
@@ -1012,7 +1012,7 @@
 
 		/* but if there's work queued, reschedule */
 		if (!list_empty (&ed->td_list)) {
-			if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state))
+			if (ohci->rh_state == OHCI_RH_RUNNING)
 				ed_schedule (ohci, ed);
 		}
 
@@ -1021,9 +1021,7 @@
 	}
 
 	/* maybe reenable control and bulk lists */
-	if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state)
-			&& ohci_to_hcd(ohci)->state != HC_STATE_QUIESCING
-			&& !ohci->ed_rm_list) {
+	if (ohci->rh_state == OHCI_RH_RUNNING && !ohci->ed_rm_list) {
 		u32	command = 0, control = 0;
 
 		if (ohci->ed_controltail) {
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index a1877c4..56dcf06 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -486,15 +486,66 @@
 	return 0;
 }
 
+#ifdef CONFIG_PM
+static int ohci_hcd_s3c2410_drv_suspend(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+	struct platform_device *pdev = to_platform_device(dev);
+	unsigned long flags;
+	int rc = 0;
+
+	/*
+	 * Root hub was already suspended. Disable irq emission and
+	 * mark HW unaccessible, bail out if RH has been resumed. Use
+	 * the spinlock to properly synchronize with possible pending
+	 * RH suspend or resume activity.
+	 */
+	spin_lock_irqsave(&ohci->lock, flags);
+	if (ohci->rh_state != OHCI_RH_SUSPENDED) {
+		rc = -EINVAL;
+		goto bail;
+	}
+
+	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+	s3c2410_stop_hc(pdev);
+bail:
+	spin_unlock_irqrestore(&ohci->lock, flags);
+
+	return rc;
+}
+
+static int ohci_hcd_s3c2410_drv_resume(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct platform_device *pdev = to_platform_device(dev);
+
+	s3c2410_start_hc(pdev, hcd);
+
+	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+	ohci_finish_controller_resume(hcd);
+
+	return 0;
+}
+#else
+#define ohci_hcd_s3c2410_drv_suspend	NULL
+#define ohci_hcd_s3c2410_drv_resume	NULL
+#endif
+
+static const struct dev_pm_ops ohci_hcd_s3c2410_pm_ops = {
+	.suspend	= ohci_hcd_s3c2410_drv_suspend,
+	.resume		= ohci_hcd_s3c2410_drv_resume,
+};
+
 static struct platform_driver ohci_hcd_s3c2410_driver = {
 	.probe		= ohci_hcd_s3c2410_drv_probe,
 	.remove		= __devexit_p(ohci_hcd_s3c2410_drv_remove),
 	.shutdown	= usb_hcd_platform_shutdown,
-	/*.suspend	= ohci_hcd_s3c2410_drv_suspend, */
-	/*.resume	= ohci_hcd_s3c2410_drv_resume, */
 	.driver		= {
 		.owner	= THIS_MODULE,
 		.name	= "s3c2410-ohci",
+		.pm	= &ohci_hcd_s3c2410_pm_ops,
 	},
 };
 
diff --git a/drivers/usb/host/ohci-sh.c b/drivers/usb/host/ohci-sh.c
index afc4eb6..84686d9 100644
--- a/drivers/usb/host/ohci-sh.c
+++ b/drivers/usb/host/ohci-sh.c
@@ -29,7 +29,6 @@
 	ohci_hcd_init(ohci);
 	ohci_init(ohci);
 	ohci_run(ohci);
-	hcd->state = HC_STATE_RUNNING;
 	return 0;
 }
 
diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c
index 968cea2..5596ac2 100644
--- a/drivers/usb/host/ohci-sm501.c
+++ b/drivers/usb/host/ohci-sm501.c
@@ -224,7 +224,6 @@
 	ohci->next_statechange = jiffies;
 
 	sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 0);
-	ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
 	return 0;
 }
 
diff --git a/drivers/usb/host/ohci-spear.c b/drivers/usb/host/ohci-spear.c
index 6987465..95c1648 100644
--- a/drivers/usb/host/ohci-spear.c
+++ b/drivers/usb/host/ohci-spear.c
@@ -203,7 +203,6 @@
 	ohci->next_statechange = jiffies;
 
 	spear_stop_ohci(ohci_p);
-	ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
 	return 0;
 }
 
diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c
index 06331d9..120bfe6 100644
--- a/drivers/usb/host/ohci-tmio.c
+++ b/drivers/usb/host/ohci-tmio.c
@@ -318,9 +318,6 @@
 		if (ret)
 			return ret;
 	}
-
-	hcd->state = HC_STATE_SUSPENDED;
-
 	return 0;
 }
 
diff --git a/drivers/usb/host/ohci-xls.c b/drivers/usb/host/ohci-xls.c
index a3a9c6f..a224786 100644
--- a/drivers/usb/host/ohci-xls.c
+++ b/drivers/usb/host/ohci-xls.c
@@ -40,7 +40,7 @@
 		goto err1;
 	}
 	hcd->rsrc_start = res->start;
-	hcd->rsrc_len = res->end - res->start + 1;
+	hcd->rsrc_len = resource_size(res);
 
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
 			driver->description)) {
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 0795b93..8ff6f7e 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -344,6 +344,12 @@
  * a subset of what the full implementation needs. (Linus)
  */
 
+enum ohci_rh_state {
+	OHCI_RH_HALTED,
+	OHCI_RH_SUSPENDED,
+	OHCI_RH_RUNNING
+};
+
 struct ohci_hcd {
 	spinlock_t		lock;
 
@@ -384,6 +390,7 @@
 	/*
 	 * driver state
 	 */
+	enum ohci_rh_state	rh_state;
 	int			num_ports;
 	int			load [NUM_INTS];
 	u32			hc_control;	/* copy of hc control reg */
@@ -679,11 +686,6 @@
 
 /*-------------------------------------------------------------------------*/
 
-static inline void disable (struct ohci_hcd *ohci)
-{
-	ohci_to_hcd(ohci)->state = HC_STATE_HALT;
-}
-
 #define	FI			0x2edf		/* 12000 bits per frame (-1) */
 #define	FSMP(fi)		(0x7fff & ((6 * ((fi) - 210)) / 7))
 #define	FIT			(1 << 31)
@@ -707,7 +709,7 @@
 #define read_roothub(hc, register, mask) ({ \
 	u32 temp = ohci_readl (hc, &hc->regs->roothub.register); \
 	if (temp == -1) \
-		disable (hc); \
+		hc->rh_state = OHCI_RH_HALTED; \
 	else if (hc->flags & OHCI_QUIRK_AMD756) \
 		while (temp & mask) \
 			temp = ohci_readl (hc, &hc->regs->roothub.register); \
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index dcd8898..6f62de5 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -3951,24 +3951,7 @@
 	}
 };
 
-static int __init oxu_module_init(void)
-{
-	int retval = 0;
-
-	retval = platform_driver_register(&oxu_driver);
-	if (retval < 0)
-		return retval;
-
-	return retval;
-}
-
-static void __exit oxu_module_cleanup(void)
-{
-	platform_driver_unregister(&oxu_driver);
-}
-
-module_init(oxu_module_init);
-module_exit(oxu_module_cleanup);
+module_platform_driver(oxu_driver);
 
 MODULE_DESCRIPTION("Oxford OXU210HP HCD driver - ver. " DRIVER_VERSION);
 MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index f6ca80e..d2c6f5a 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -943,7 +943,7 @@
 	if (usb_pipein(urb->pipe))
 		status |= TD_CTRL_SPD;
 
-	i = urb->num_sgs;
+	i = urb->num_mapped_sgs;
 	if (len > 0 && i > 0) {
 		sg = urb->sg;
 		data = sg_dma_address(sg);
diff --git a/drivers/usb/host/whci/qset.c b/drivers/usb/host/whci/qset.c
index a403b53..76083ae 100644
--- a/drivers/usb/host/whci/qset.c
+++ b/drivers/usb/host/whci/qset.c
@@ -443,7 +443,7 @@
 
 	remaining = urb->transfer_buffer_length;
 
-	for_each_sg(urb->sg, sg, urb->num_sgs, i) {
+	for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
 		dma_addr_t dma_addr;
 		size_t dma_remaining;
 		dma_addr_t sp, ep;
@@ -561,7 +561,7 @@
 
 	remaining = urb->transfer_buffer_length;
 
-	for_each_sg(urb->sg, sg, urb->num_sgs, i) {
+	for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
 		size_t len;
 		size_t sg_remaining;
 		void *orig;
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 430e88f..35e257f 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -57,17 +57,15 @@
 	desc->bHubContrCurrent = 0;
 
 	desc->bNbrPorts = ports;
-	/* Ugh, these should be #defines, FIXME */
-	/* Using table 11-13 in USB 2.0 spec. */
 	temp = 0;
-	/* Bits 1:0 - support port power switching, or power always on */
+	/* Bits 1:0 - support per-port power switching, or power always on */
 	if (HCC_PPC(xhci->hcc_params))
-		temp |= 0x0001;
+		temp |= HUB_CHAR_INDV_PORT_LPSM;
 	else
-		temp |= 0x0002;
+		temp |= HUB_CHAR_NO_LPSM;
 	/* Bit  2 - root hubs are not part of a compound device */
 	/* Bits 4:3 - individual port over current protection */
-	temp |= 0x0008;
+	temp |= HUB_CHAR_INDV_PORT_OCPM;
 	/* Bits 6:5 - no TTs in root ports */
 	/* Bit  7 - no port indicators */
 	desc->wHubCharacteristics = cpu_to_le16(temp);
@@ -86,9 +84,9 @@
 	ports = xhci->num_usb2_ports;
 
 	xhci_common_hub_descriptor(xhci, desc, ports);
-	desc->bDescriptorType = 0x29;
+	desc->bDescriptorType = USB_DT_HUB;
 	temp = 1 + (ports / 8);
-	desc->bDescLength = 7 + 2 * temp;
+	desc->bDescLength = USB_DT_HUB_NONVAR_SIZE + 2 * temp;
 
 	/* The Device Removable bits are reported on a byte granularity.
 	 * If the port doesn't exist within that byte, the bit is set to 0.
@@ -137,8 +135,8 @@
 
 	ports = xhci->num_usb3_ports;
 	xhci_common_hub_descriptor(xhci, desc, ports);
-	desc->bDescriptorType = 0x2a;
-	desc->bDescLength = 12;
+	desc->bDescriptorType = USB_DT_SS_HUB;
+	desc->bDescLength = USB_DT_SS_HUB_SIZE;
 
 	/* header decode latency should be zero for roothubs,
 	 * see section 4.23.5.2.
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 0e4b25f..36cbe22 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -42,15 +42,12 @@
 	seg = kzalloc(sizeof *seg, flags);
 	if (!seg)
 		return NULL;
-	xhci_dbg(xhci, "Allocating priv segment structure at %p\n", seg);
 
 	seg->trbs = dma_pool_alloc(xhci->segment_pool, flags, &dma);
 	if (!seg->trbs) {
 		kfree(seg);
 		return NULL;
 	}
-	xhci_dbg(xhci, "// Allocating segment at %p (virtual) 0x%llx (DMA)\n",
-			seg->trbs, (unsigned long long)dma);
 
 	memset(seg->trbs, 0, SEGMENT_SIZE);
 	seg->dma = dma;
@@ -62,12 +59,9 @@
 static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg)
 {
 	if (seg->trbs) {
-		xhci_dbg(xhci, "Freeing DMA segment at %p (virtual) 0x%llx (DMA)\n",
-				seg->trbs, (unsigned long long)seg->dma);
 		dma_pool_free(xhci->segment_pool, seg->trbs, seg->dma);
 		seg->trbs = NULL;
 	}
-	xhci_dbg(xhci, "Freeing priv segment structure at %p\n", seg);
 	kfree(seg);
 }
 
@@ -101,9 +95,6 @@
 			val |= TRB_CHAIN;
 		prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val);
 	}
-	xhci_dbg(xhci, "Linking segment 0x%llx to segment 0x%llx (DMA)\n",
-			(unsigned long long)prev->dma,
-			(unsigned long long)next->dma);
 }
 
 /* XXX: Do we need the hcd structure in all these functions? */
@@ -117,7 +108,6 @@
 	if (ring->first_seg) {
 		first_seg = ring->first_seg;
 		seg = first_seg->next;
-		xhci_dbg(xhci, "Freeing ring at %p\n", ring);
 		while (seg != first_seg) {
 			struct xhci_segment *next = seg->next;
 			xhci_segment_free(xhci, seg);
@@ -160,7 +150,6 @@
 	struct xhci_segment	*prev;
 
 	ring = kzalloc(sizeof *(ring), flags);
-	xhci_dbg(xhci, "Allocating ring at %p\n", ring);
 	if (!ring)
 		return NULL;
 
@@ -191,9 +180,6 @@
 		/* See section 4.9.2.1 and 6.4.4.1 */
 		prev->trbs[TRBS_PER_SEGMENT-1].link.control |=
 			cpu_to_le32(LINK_TOGGLE);
-		xhci_dbg(xhci, "Wrote link toggle flag to"
-				" segment %p (virtual), 0x%llx (DMA)\n",
-				prev, (unsigned long long)prev->dma);
 	}
 	xhci_initialize_ring_info(ring);
 	return ring;
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 9f1d4b1..b90e138 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -155,10 +155,6 @@
 	while (last_trb(xhci, ring, ring->deq_seg, next)) {
 		if (consumer && last_trb_on_last_seg(xhci, ring, ring->deq_seg, next)) {
 			ring->cycle_state = (ring->cycle_state ? 0 : 1);
-			if (!in_interrupt())
-				xhci_dbg(xhci, "Toggle cycle state for ring %p = %i\n",
-						ring,
-						(unsigned int) ring->cycle_state);
 		}
 		ring->deq_seg = ring->deq_seg->next;
 		ring->dequeue = ring->deq_seg->trbs;
@@ -231,10 +227,6 @@
 			/* Toggle the cycle bit after the last ring segment. */
 			if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
 				ring->cycle_state = (ring->cycle_state ? 0 : 1);
-				if (!in_interrupt())
-					xhci_dbg(xhci, "Toggle cycle state for ring %p = %i\n",
-							ring,
-							(unsigned int) ring->cycle_state);
 			}
 		}
 		ring->enq_seg = ring->enq_seg->next;
@@ -560,12 +552,9 @@
 					cpu_to_le32(TRB_CYCLE);
 			cur_trb->generic.field[3] |= cpu_to_le32(
 				TRB_TYPE(TRB_TR_NOOP));
-			xhci_dbg(xhci, "Cancel TRB %p (0x%llx dma) "
-					"in seg %p (0x%llx dma)\n",
-					cur_trb,
-					(unsigned long long)xhci_trb_virt_to_dma(cur_seg, cur_trb),
-					cur_seg,
-					(unsigned long long)cur_seg->dma);
+			xhci_dbg(xhci, "TRB to noop at offset 0x%llx\n",
+					(unsigned long long)
+					xhci_trb_virt_to_dma(cur_seg, cur_trb));
 		}
 		if (cur_trb == cur_td->last_trb)
 			break;
@@ -705,9 +694,9 @@
 	 */
 	list_for_each(entry, &ep->cancelled_td_list) {
 		cur_td = list_entry(entry, struct xhci_td, cancelled_td_list);
-		xhci_dbg(xhci, "Cancelling TD starting at %p, 0x%llx (dma).\n",
-				cur_td->first_trb,
-				(unsigned long long)xhci_trb_virt_to_dma(cur_td->start_seg, cur_td->first_trb));
+		xhci_dbg(xhci, "Removing canceled TD starting at 0x%llx (dma).\n",
+				(unsigned long long)xhci_trb_virt_to_dma(
+					cur_td->start_seg, cur_td->first_trb));
 		ep_ring = xhci_urb_to_transfer_ring(xhci, cur_td->urb);
 		if (!ep_ring) {
 			/* This shouldn't happen unless a driver is mucking
@@ -1627,7 +1616,6 @@
 	ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
 	trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
 
-	xhci_debug_trb(xhci, xhci->event_ring->dequeue);
 	switch (trb_comp_code) {
 	case COMP_SUCCESS:
 		if (event_trb == ep_ring->dequeue) {
@@ -1643,7 +1631,6 @@
 		}
 		break;
 	case COMP_SHORT_TX:
-		xhci_warn(xhci, "WARN: short transfer on control ep\n");
 		if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
 			*status = -EREMOTEIO;
 		else
@@ -1946,6 +1933,16 @@
 	xdev = xhci->devs[slot_id];
 	if (!xdev) {
 		xhci_err(xhci, "ERROR Transfer event pointed to bad slot\n");
+		xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n",
+			 (unsigned long long) xhci_trb_virt_to_dma(
+				 xhci->event_ring->deq_seg,
+				 xhci->event_ring->dequeue),
+			 lower_32_bits(le64_to_cpu(event->buffer)),
+			 upper_32_bits(le64_to_cpu(event->buffer)),
+			 le32_to_cpu(event->transfer_len),
+			 le32_to_cpu(event->flags));
+		xhci_dbg(xhci, "Event ring:\n");
+		xhci_debug_segment(xhci, xhci->event_ring->deq_seg);
 		return -ENODEV;
 	}
 
@@ -1959,6 +1956,16 @@
 	    EP_STATE_DISABLED) {
 		xhci_err(xhci, "ERROR Transfer event for disabled endpoint "
 				"or incorrect stream ring\n");
+		xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n",
+			 (unsigned long long) xhci_trb_virt_to_dma(
+				 xhci->event_ring->deq_seg,
+				 xhci->event_ring->dequeue),
+			 lower_32_bits(le64_to_cpu(event->buffer)),
+			 upper_32_bits(le64_to_cpu(event->buffer)),
+			 le32_to_cpu(event->transfer_len),
+			 le32_to_cpu(event->flags));
+		xhci_dbg(xhci, "Event ring:\n");
+		xhci_debug_segment(xhci, xhci->event_ring->deq_seg);
 		return -ENODEV;
 	}
 
@@ -1985,7 +1992,7 @@
 		xhci_dbg(xhci, "Stopped on No-op or Link TRB\n");
 		break;
 	case COMP_STALL:
-		xhci_warn(xhci, "WARN: Stalled endpoint\n");
+		xhci_dbg(xhci, "Stalled endpoint\n");
 		ep->ep_state |= EP_HALTED;
 		status = -EPIPE;
 		break;
@@ -1995,11 +2002,11 @@
 		break;
 	case COMP_SPLIT_ERR:
 	case COMP_TX_ERR:
-		xhci_warn(xhci, "WARN: transfer error on endpoint\n");
+		xhci_dbg(xhci, "Transfer error on endpoint\n");
 		status = -EPROTO;
 		break;
 	case COMP_BABBLE:
-		xhci_warn(xhci, "WARN: babble error on endpoint\n");
+		xhci_dbg(xhci, "Babble error on endpoint\n");
 		status = -EOVERFLOW;
 		break;
 	case COMP_DB_ERR:
@@ -2390,17 +2397,7 @@
 
 irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd)
 {
-	irqreturn_t ret;
-	struct xhci_hcd *xhci;
-
-	xhci = hcd_to_xhci(hcd);
-	set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
-	if (xhci->shared_hcd)
-		set_bit(HCD_FLAG_SAW_IRQ, &xhci->shared_hcd->flags);
-
-	ret = xhci_irq(hcd);
-
-	return ret;
+	return xhci_irq(hcd);
 }
 
 /****		Endpoint Ring Operations	****/
@@ -2488,11 +2485,6 @@
 			/* Toggle the cycle bit after the last ring segment. */
 			if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
 				ring->cycle_state = (ring->cycle_state ? 0 : 1);
-				if (!in_interrupt()) {
-					xhci_dbg(xhci, "queue_trb: Toggle cycle "
-						"state for ring %p = %i\n",
-						ring, (unsigned int)ring->cycle_state);
-				}
 			}
 			ring->enq_seg = ring->enq_seg->next;
 			ring->enqueue = ring->enq_seg->trbs;
@@ -2561,13 +2553,11 @@
 	struct scatterlist *sg;
 
 	sg = NULL;
-	num_sgs = urb->num_sgs;
+	num_sgs = urb->num_mapped_sgs;
 	temp = urb->transfer_buffer_length;
 
-	xhci_dbg(xhci, "count sg list trbs: \n");
 	num_trbs = 0;
 	for_each_sg(urb->sg, sg, num_sgs, i) {
-		unsigned int previous_total_trbs = num_trbs;
 		unsigned int len = sg_dma_len(sg);
 
 		/* Scatter gather list entries may cross 64KB boundaries */
@@ -2582,22 +2572,11 @@
 			num_trbs++;
 			running_total += TRB_MAX_BUFF_SIZE;
 		}
-		xhci_dbg(xhci, " sg #%d: dma = %#llx, len = %#x (%d), num_trbs = %d\n",
-				i, (unsigned long long)sg_dma_address(sg),
-				len, len, num_trbs - previous_total_trbs);
-
 		len = min_t(int, len, temp);
 		temp -= len;
 		if (temp == 0)
 			break;
 	}
-	xhci_dbg(xhci, "\n");
-	if (!in_interrupt())
-		xhci_dbg(xhci, "ep %#x - urb len = %d, sglist used, "
-				"num_trbs = %d\n",
-				urb->ep->desc.bEndpointAddress,
-				urb->transfer_buffer_length,
-				num_trbs);
 	return num_trbs;
 }
 
@@ -2745,7 +2724,7 @@
 		return -EINVAL;
 
 	num_trbs = count_sg_trbs_needed(xhci, urb);
-	num_sgs = urb->num_sgs;
+	num_sgs = urb->num_mapped_sgs;
 	total_packet_count = roundup(urb->transfer_buffer_length,
 			usb_endpoint_maxp(&urb->ep->desc));
 
@@ -2783,8 +2762,6 @@
 	trb_buff_len = min_t(int, trb_buff_len, this_sg_len);
 	if (trb_buff_len > urb->transfer_buffer_length)
 		trb_buff_len = urb->transfer_buffer_length;
-	xhci_dbg(xhci, "First length to xfer from 1st sglist entry = %u\n",
-			trb_buff_len);
 
 	first_trb = true;
 	/* Queue the first TRB, even if it's zero-length */
@@ -2816,11 +2793,6 @@
 		if (usb_urb_dir_in(urb))
 			field |= TRB_ISP;
 
-		xhci_dbg(xhci, " sg entry: dma = %#x, len = %#x (%d), "
-				"64KB boundary at %#x, end dma = %#x\n",
-				(unsigned int) addr, trb_buff_len, trb_buff_len,
-				(unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1),
-				(unsigned int) addr + trb_buff_len);
 		if (TRB_MAX_BUFF_SIZE -
 				(addr & (TRB_MAX_BUFF_SIZE - 1)) < trb_buff_len) {
 			xhci_warn(xhci, "WARN: sg dma xfer crosses 64KB boundaries!\n");
@@ -2926,15 +2898,6 @@
 	}
 	/* FIXME: this doesn't deal with URB_ZERO_PACKET - need one more */
 
-	if (!in_interrupt())
-		xhci_dbg(xhci, "ep %#x - urb len = %#x (%d), "
-				"addr = %#llx, num_trbs = %d\n",
-				urb->ep->desc.bEndpointAddress,
-				urb->transfer_buffer_length,
-				urb->transfer_buffer_length,
-				(unsigned long long)urb->transfer_dma,
-				num_trbs);
-
 	ret = prepare_transfer(xhci, xhci->devs[slot_id],
 			ep_index, urb->stream_id,
 			num_trbs, urb, 0, false, mem_flags);
@@ -3055,9 +3018,6 @@
 	if (!urb->setup_packet)
 		return -EINVAL;
 
-	if (!in_interrupt())
-		xhci_dbg(xhci, "Queueing ctrl tx for slot id %d, ep %d\n",
-				slot_id, ep_index);
 	/* 1 TRB for setup, 1 for status */
 	num_trbs = 2;
 	/*
@@ -3249,15 +3209,6 @@
 		return -EINVAL;
 	}
 
-	if (!in_interrupt())
-		xhci_dbg(xhci, "ep %#x - urb len = %#x (%d),"
-				" addr = %#llx, num_tds = %d\n",
-				urb->ep->desc.bEndpointAddress,
-				urb->transfer_buffer_length,
-				urb->transfer_buffer_length,
-				(unsigned long long)urb->transfer_dma,
-				num_tds);
-
 	start_addr = (u64) urb->transfer_dma;
 	start_trb = &ep_ring->enqueue->generic;
 	start_cycle = ep_ring->cycle_state;
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index a1afb7c..6bbe3c3 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -200,14 +200,14 @@
 
 	ret = pci_enable_msi(pdev);
 	if (ret) {
-		xhci_err(xhci, "failed to allocate MSI entry\n");
+		xhci_dbg(xhci, "failed to allocate MSI entry\n");
 		return ret;
 	}
 
 	ret = request_irq(pdev->irq, (irq_handler_t)xhci_msi_irq,
 				0, "xhci_hcd", xhci_to_hcd(xhci));
 	if (ret) {
-		xhci_err(xhci, "disable MSI interrupt\n");
+		xhci_dbg(xhci, "disable MSI interrupt\n");
 		pci_disable_msi(pdev);
 	}
 
@@ -270,7 +270,7 @@
 
 	ret = pci_enable_msix(pdev, xhci->msix_entries, xhci->msix_count);
 	if (ret) {
-		xhci_err(xhci, "Failed to enable MSI-X\n");
+		xhci_dbg(xhci, "Failed to enable MSI-X\n");
 		goto free_entries;
 	}
 
@@ -286,7 +286,7 @@
 	return ret;
 
 disable_msix:
-	xhci_err(xhci, "disable MSI-X interrupt\n");
+	xhci_dbg(xhci, "disable MSI-X interrupt\n");
 	xhci_free_irq(xhci);
 	pci_disable_msix(pdev);
 free_entries:
@@ -1333,9 +1333,6 @@
 		goto done;
 	}
 
-	xhci_dbg(xhci, "Cancel URB %p\n", urb);
-	xhci_dbg(xhci, "Event ring:\n");
-	xhci_debug_ring(xhci, xhci->event_ring);
 	ep_index = xhci_get_endpoint_index(&urb->ep->desc);
 	ep = &xhci->devs[urb->dev->slot_id]->eps[ep_index];
 	ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
@@ -1344,12 +1341,18 @@
 		goto done;
 	}
 
-	xhci_dbg(xhci, "Endpoint ring:\n");
-	xhci_debug_ring(xhci, ep_ring);
-
 	urb_priv = urb->hcpriv;
+	i = urb_priv->td_cnt;
+	if (i < urb_priv->length)
+		xhci_dbg(xhci, "Cancel URB %p, dev %s, ep 0x%x, "
+				"starting at offset 0x%llx\n",
+				urb, urb->dev->devpath,
+				urb->ep->desc.bEndpointAddress,
+				(unsigned long long) xhci_trb_virt_to_dma(
+					urb_priv->td[i]->start_seg,
+					urb_priv->td[i]->first_trb));
 
-	for (i = urb_priv->td_cnt; i < urb_priv->length; i++) {
+	for (; i < urb_priv->length; i++) {
 		td = urb_priv->td[i];
 		list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list);
 	}
@@ -1620,6 +1623,7 @@
 		/* FIXME: can we allocate more resources for the HC? */
 		break;
 	case COMP_BW_ERR:
+	case COMP_2ND_BW_ERR:
 		dev_warn(&udev->dev, "Not enough bandwidth "
 				"for new device state.\n");
 		ret = -ENOSPC;
@@ -2796,8 +2800,7 @@
 		if (ret < 0)
 			return ret;
 
-		max_streams = USB_SS_MAX_STREAMS(
-				eps[i]->ss_ep_comp.bmAttributes);
+		max_streams = usb_ss_max_streams(&eps[i]->ss_ep_comp);
 		if (max_streams < (*num_streams - 1)) {
 			xhci_dbg(xhci, "Ep 0x%x only supports %u stream IDs.\n",
 					eps[i]->desc.bEndpointAddress,
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 3c8fbd2..fb99c83 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1033,7 +1033,6 @@
 /* Invalid Stream ID Error */
 #define COMP_STRID_ERR	34
 /* Secondary Bandwidth Error - may be returned by a Configure Endpoint cmd */
-/* FIXME - check for this */
 #define COMP_2ND_BW_ERR	35
 /* Split Transaction Error */
 #define	COMP_SPLIT_ERR	36
@@ -1356,7 +1355,7 @@
 		return 1;
 }
 
-/* There is one ehci_hci structure per controller */
+/* There is one xhci_hcd structure per controller */
 struct xhci_hcd {
 	struct usb_hcd *main_hcd;
 	struct usb_hcd *shared_hcd;
diff --git a/drivers/usb/misc/isight_firmware.c b/drivers/usb/misc/isight_firmware.c
index 1dc7e95..1c61830 100644
--- a/drivers/usb/misc/isight_firmware.c
+++ b/drivers/usb/misc/isight_firmware.c
@@ -55,8 +55,9 @@
 
 	ptr = firmware->data;
 
+	buf[0] = 0x01;
 	if (usb_control_msg
-	    (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\1", 1,
+	    (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, buf, 1,
 	     300) != 1) {
 		printk(KERN_ERR
 		       "Failed to initialise isight firmware loader\n");
@@ -100,8 +101,9 @@
 		}
 	}
 
+	buf[0] = 0x00;
 	if (usb_control_msg
-	    (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\0", 1,
+	    (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, buf, 1,
 	     300) != 1) {
 		printk(KERN_ERR "isight firmware loading completion failed\n");
 		ret = -ENODEV;
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index bd6d008..959145b 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -1765,7 +1765,6 @@
  * off just killing the userspace task and waiting for it to exit.
  */
 
-/* No BKL needed */
 static int
 usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
 {
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index 07a0346..f70cab3 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -5,14 +5,13 @@
 
 # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller
 config USB_MUSB_HDRC
+	tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
 	depends on USB && USB_GADGET
-	depends on (ARM || (BF54x && !BF544) || (BF52x && !BF522 && !BF523))
 	select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN)
 	select TWL4030_USB if MACH_OMAP_3430SDP
 	select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA
 	select USB_OTG_UTILS
 	select USB_GADGET_DUALSPEED
-	tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
 	help
 	  Say Y here if your system has a dual role high speed USB
 	  controller based on the Mentor Graphics silicon IP.  Then
@@ -31,9 +30,10 @@
 	  To compile this driver as a module, choose M here; the
 	  module will be called "musb-hdrc".
 
+if USB_MUSB_HDRC
+
 choice
 	prompt "Platform Glue Layer"
-	depends on USB_MUSB_HDRC
 
 config USB_MUSB_DAVINCI
 	tristate "DaVinci"
@@ -45,7 +45,6 @@
 
 config USB_MUSB_TUSB6010
 	tristate "TUSB6010"
-	depends on ARCH_OMAP
 
 config USB_MUSB_OMAP2PLUS
 	tristate "OMAP2430 and onwards"
@@ -65,46 +64,54 @@
 
 endchoice
 
-config MUSB_PIO_ONLY
-	bool 'Disable DMA (always use PIO)'
-	depends on USB_MUSB_HDRC
-	default USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X
+choice
+	prompt 'MUSB DMA mode'
+	default USB_UX500_DMA if USB_MUSB_UX500
+	default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN
+	default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI
+	default USB_TUSB_OMAP_DMA if USB_MUSB_TUSB6010
+	default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X
 	help
-	  All data is copied between memory and FIFO by the CPU.
-	  DMA controllers are ignored.
-
-	  Do not select 'n' here unless DMA support for your SOC or board
-	  is unavailable (or unstable).  When DMA is enabled at compile time,
-	  you can still disable it at run time using the "use_dma=n" module
-	  parameter.
+	  Unfortunately, only one option can be enabled here. Ideally one
+	  should be able to build all these drivers into one kernel to
+	  allow using DMA on multiplatform kernels.
 
 config USB_UX500_DMA
-	bool
-	depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
-	default USB_MUSB_UX500
+	bool 'ST Ericsson U8500 and U5500'
+	depends on USB_MUSB_UX500
 	help
 	  Enable DMA transfers on UX500 platforms.
 
 config USB_INVENTRA_DMA
-	bool
-	depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
-	default USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN
+	bool 'Inventra'
+	depends on USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN
 	help
 	  Enable DMA transfers using Mentor's engine.
 
 config USB_TI_CPPI_DMA
-	bool
-	depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
-	default USB_MUSB_DAVINCI
+	bool 'TI CPPI (Davinci)'
+	depends on USB_MUSB_DAVINCI
 	help
 	  Enable DMA transfers when TI CPPI DMA is available.
 
 config USB_TUSB_OMAP_DMA
-	bool
-	depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
+	bool 'TUSB 6010'
 	depends on USB_MUSB_TUSB6010
 	depends on ARCH_OMAP
-	default y
 	help
 	  Enable DMA transfers on TUSB 6010 when OMAP DMA is available.
 
+config MUSB_PIO_ONLY
+	bool 'Disable DMA (always use PIO)'
+	help
+	  All data is copied between memory and FIFO by the CPU.
+	  DMA controllers are ignored.
+
+	  Do not choose this unless DMA support for your SOC or board
+	  is unavailable (or unstable).  When DMA is enabled at compile time,
+	  you can still disable it at run time using the "use_dma=n" module
+	  parameter.
+
+endchoice
+
+endif # USB_MUSB_HDRC
diff --git a/drivers/usb/musb/Makefile b/drivers/usb/musb/Makefile
index d8fd9d0..88bfb9d 100644
--- a/drivers/usb/musb/Makefile
+++ b/drivers/usb/musb/Makefile
@@ -24,25 +24,7 @@
 # PIO only, or DMA (several potential schemes).
 # though PIO is always there to back up DMA, and for ep0
 
-ifneq ($(CONFIG_MUSB_PIO_ONLY),y)
-
-  ifeq ($(CONFIG_USB_INVENTRA_DMA),y)
-    musb_hdrc-y			+= musbhsdma.o
-
-  else
-    ifeq ($(CONFIG_USB_TI_CPPI_DMA),y)
-      musb_hdrc-y		+= cppi_dma.o
-
-    else
-      ifeq ($(CONFIG_USB_TUSB_OMAP_DMA),y)
-	musb_hdrc-y		+= tusb6010_omap.o
-
-      else
-        ifeq ($(CONFIG_USB_UX500_DMA),y)
-	  musb_hdrc-y		+= ux500_dma.o
-
-        endif
-      endif
-    endif
-  endif
-endif
+musb_hdrc-$(CONFIG_USB_INVENTRA_DMA)		+= musbhsdma.o
+musb_hdrc-$(CONFIG_USB_TI_CPPI_DMA)		+= cppi_dma.o
+musb_hdrc-$(CONFIG_USB_TUSB_OMAP_DMA)		+= tusb6010_omap.o
+musb_hdrc-$(CONFIG_USB_UX500_DMA)		+= ux500_dma.o
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index b63ab15..f6ff792 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -661,7 +661,6 @@
 
 		handled = IRQ_HANDLED;
 		musb->is_active = 1;
-		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
 
 		musb->ep0_stage = MUSB_EP0_START;
 
@@ -1432,7 +1431,7 @@
 		struct musb_hw_ep	*hw_ep = musb->endpoints + i;
 
 		hw_ep->fifo = MUSB_FIFO_OFFSET(i) + mbase;
-#ifdef CONFIG_USB_MUSB_TUSB6010
+#if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE)
 		hw_ep->fifo_async = musb->async + 0x400 + MUSB_FIFO_OFFSET(i);
 		hw_ep->fifo_sync = musb->sync + 0x400 + MUSB_FIFO_OFFSET(i);
 		hw_ep->fifo_sync_va =
@@ -1631,6 +1630,7 @@
 		}
 	}
 }
+EXPORT_SYMBOL_GPL(musb_dma_completion);
 
 #else
 #define use_dma			0
@@ -2012,8 +2012,6 @@
 	if (status < 0)
 		goto fail3;
 
-	pm_runtime_put(musb->controller);
-
 	status = musb_init_debugfs(musb);
 	if (status < 0)
 		goto fail4;
@@ -2158,6 +2156,7 @@
 		if (!epio)
 			continue;
 
+		musb_writeb(musb_base, MUSB_INDEX, i);
 		musb->context.index_regs[i].txmaxp =
 			musb_readw(epio, MUSB_TXMAXP);
 		musb->context.index_regs[i].txcsr =
@@ -2233,6 +2232,7 @@
 		if (!epio)
 			continue;
 
+		musb_writeb(musb_base, MUSB_INDEX, i);
 		musb_writew(epio, MUSB_TXMAXP,
 			musb->context.index_regs[i].txmaxp);
 		musb_writew(epio, MUSB_TXCSR,
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index b3c065a..3d28fb8 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -40,7 +40,6 @@
 #include <linux/interrupt.h>
 #include <linux/errno.h>
 #include <linux/timer.h>
-#include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
@@ -311,6 +310,7 @@
 	u8 index, testmode;
 
 	u8 devctl, busctl, misc;
+	u32 otg_interfsel;
 
 	struct musb_csr_regs index_regs[MUSB_C_NUM_EPS];
 };
@@ -327,6 +327,7 @@
 
 	irqreturn_t		(*isr)(int, void *);
 	struct work_struct	irq_work;
+	struct work_struct	otg_notifier_work;
 	u16			hwvers;
 
 /* this hub status bit is reserved by USB 2.0 and not seen by usbcore */
@@ -372,6 +373,7 @@
 	u16			int_tx;
 
 	struct otg_transceiver	*xceiv;
+	u8			xceiv_event;
 
 	int nIrq;
 	unsigned		irq_wake:1;
diff --git a/drivers/usb/musb/musb_debug.h b/drivers/usb/musb/musb_debug.h
index 742eada..27ba8f7 100644
--- a/drivers/usb/musb/musb_debug.h
+++ b/drivers/usb/musb/musb_debug.h
@@ -43,8 +43,8 @@
 #define ERR(fmt, args...) yprintk(KERN_ERR, fmt, ## args)
 
 #ifdef CONFIG_DEBUG_FS
-extern int musb_init_debugfs(struct musb *musb);
-extern void musb_exit_debugfs(struct musb *musb);
+int musb_init_debugfs(struct musb *musb);
+void musb_exit_debugfs(struct musb *musb);
 #else
 static inline int musb_init_debugfs(struct musb *musb)
 {
diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c
index 61f4ee4..13d9af9 100644
--- a/drivers/usb/musb/musb_debugfs.c
+++ b/drivers/usb/musb/musb_debugfs.c
@@ -33,11 +33,7 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/init.h>
-#include <linux/list.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 
@@ -46,10 +42,6 @@
 #include "musb_core.h"
 #include "musb_debug.h"
 
-#ifdef CONFIG_ARCH_DAVINCI
-#include "davinci.h"
-#endif
-
 struct musb_register_map {
 	char			*name;
 	unsigned		offset;
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 922148f..ac3d2ee 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -40,8 +40,6 @@
 #include <linux/smp.h>
 #include <linux/spinlock.h>
 #include <linux/delay.h>
-#include <linux/moduleparam.h>
-#include <linux/stat.h>
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 
@@ -1844,7 +1842,7 @@
 	 */
 
 	musb->g.ops = &musb_gadget_operations;
-	musb->g.is_dualspeed = 1;
+	musb->g.max_speed = USB_SPEED_HIGH;
 	musb->g.speed = USB_SPEED_UNKNOWN;
 
 	/* this "gadget" abstracts/virtualizes the controller */
@@ -1903,7 +1901,7 @@
 	unsigned long		flags;
 	int			retval = -EINVAL;
 
-	if (driver->speed < USB_SPEED_HIGH)
+	if (driver->max_speed < USB_SPEED_HIGH)
 		goto err0;
 
 	pm_runtime_get_sync(musb->controller);
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index 6a0d046..e40d764 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -37,7 +37,6 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/spinlock.h>
-#include <linux/init.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
 
diff --git a/drivers/usb/musb/musb_io.h b/drivers/usb/musb/musb_io.h
index 03c6ccd..e61aa95 100644
--- a/drivers/usb/musb/musb_io.h
+++ b/drivers/usb/musb/musb_io.h
@@ -74,7 +74,7 @@
 	{ __raw_writel(data, addr + offset); }
 
 
-#ifdef CONFIG_USB_MUSB_TUSB6010
+#if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE)
 
 /*
  * TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum.
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index ba85f27..c27bbbf 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -29,7 +29,6 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/list.h>
-#include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
@@ -228,21 +227,25 @@
 		unsigned long event, void *unused)
 {
 	struct musb	*musb = container_of(nb, struct musb, nb);
+
+	musb->xceiv_event = event;
+	schedule_work(&musb->otg_notifier_work);
+
+	return 0;
+}
+
+static void musb_otg_notifier_work(struct work_struct *data_notifier_work)
+{
+	struct musb *musb = container_of(data_notifier_work, struct musb, otg_notifier_work);
 	struct device *dev = musb->controller;
 	struct musb_hdrc_platform_data *pdata = dev->platform_data;
 	struct omap_musb_board_data *data = pdata->board_data;
 
-	switch (event) {
+	switch (musb->xceiv_event) {
 	case USB_EVENT_ID:
 		dev_dbg(musb->controller, "ID GND\n");
 
-		if (is_otg_enabled(musb)) {
-			if (musb->gadget_driver) {
-				pm_runtime_get_sync(musb->controller);
-				otg_init(musb->xceiv);
-				omap2430_musb_set_vbus(musb, 1);
-			}
-		} else {
+		if (!is_otg_enabled(musb) || musb->gadget_driver) {
 			pm_runtime_get_sync(musb->controller);
 			otg_init(musb->xceiv);
 			omap2430_musb_set_vbus(musb, 1);
@@ -274,10 +277,7 @@
 		break;
 	default:
 		dev_dbg(musb->controller, "ID float\n");
-		return NOTIFY_DONE;
 	}
-
-	return NOTIFY_OK;
 }
 
 static int omap2430_musb_init(struct musb *musb)
@@ -297,6 +297,8 @@
 		return -ENODEV;
 	}
 
+	INIT_WORK(&musb->otg_notifier_work, musb_otg_notifier_work);
+
 	status = pm_runtime_get_sync(dev);
 	if (status < 0) {
 		dev_err(dev, "pm_runtime_get_sync FAILED");
@@ -334,7 +336,6 @@
 	return 0;
 
 err1:
-	pm_runtime_disable(dev);
 	return status;
 }
 
@@ -350,20 +351,19 @@
 
 	case USB_EVENT_ID:
 		otg_init(musb->xceiv);
-		if (data->interface_type == MUSB_INTERFACE_UTMI) {
-			devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
-			/* start the session */
-			devctl |= MUSB_DEVCTL_SESSION;
-			musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
-			while (musb_readb(musb->mregs, MUSB_DEVCTL) &
-						MUSB_DEVCTL_BDEVICE) {
-				cpu_relax();
+		if (data->interface_type != MUSB_INTERFACE_UTMI)
+			break;
+		devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+		/* start the session */
+		devctl |= MUSB_DEVCTL_SESSION;
+		musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+		while (musb_readb(musb->mregs, MUSB_DEVCTL) &
+				MUSB_DEVCTL_BDEVICE) {
+			cpu_relax();
 
-				if (time_after(jiffies, timeout)) {
-					dev_err(musb->controller,
-					"configured as A device timeout");
-					break;
-				}
+			if (time_after(jiffies, timeout)) {
+				dev_err(dev, "configured as A device timeout");
+				break;
 			}
 		}
 		break;
@@ -478,7 +478,6 @@
 	platform_device_del(glue->musb);
 	platform_device_put(glue->musb);
 	pm_runtime_put(&pdev->dev);
-	pm_runtime_disable(&pdev->dev);
 	kfree(glue);
 
 	return 0;
@@ -491,6 +490,9 @@
 	struct omap2430_glue		*glue = dev_get_drvdata(dev);
 	struct musb			*musb = glue_to_musb(glue);
 
+	musb->context.otg_interfsel = musb_readl(musb->mregs,
+						OTG_INTERFSEL);
+
 	omap2430_low_level_exit(musb);
 	otg_set_suspend(musb->xceiv, 1);
 
@@ -503,6 +505,9 @@
 	struct musb			*musb = glue_to_musb(glue);
 
 	omap2430_low_level_init(musb);
+	musb_writel(musb->mregs, OTG_INTERFSEL,
+					musb->context.otg_interfsel);
+
 	otg_set_suspend(musb->xceiv, 0);
 
 	return 0;
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index ec14801..1f40561 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -56,6 +56,7 @@
 
 	return rev;
 }
+EXPORT_SYMBOL_GPL(tusb_get_revision);
 
 static int tusb_print_revision(struct musb *musb)
 {
diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c
index ef4333f..a163632 100644
--- a/drivers/usb/musb/ux500_dma.c
+++ b/drivers/usb/musb/ux500_dma.c
@@ -37,7 +37,6 @@
 	struct dma_channel channel;
 	struct ux500_dma_controller *controller;
 	struct musb_hw_ep *hw_ep;
-	struct work_struct channel_work;
 	struct dma_chan *dma_chan;
 	unsigned int cur_len;
 	dma_cookie_t cookie;
@@ -56,31 +55,11 @@
 	dma_addr_t phy_base;
 };
 
-/* Work function invoked from DMA callback to handle tx transfers. */
-static void ux500_tx_work(struct work_struct *data)
-{
-	struct ux500_dma_channel *ux500_channel = container_of(data,
-		struct ux500_dma_channel, channel_work);
-	struct musb_hw_ep       *hw_ep = ux500_channel->hw_ep;
-	struct musb *musb = hw_ep->musb;
-	unsigned long flags;
-
-	dev_dbg(musb->controller, "DMA tx transfer done on hw_ep=%d\n",
-		hw_ep->epnum);
-
-	spin_lock_irqsave(&musb->lock, flags);
-	ux500_channel->channel.actual_len = ux500_channel->cur_len;
-	ux500_channel->channel.status = MUSB_DMA_STATUS_FREE;
-	musb_dma_completion(musb, hw_ep->epnum,
-				ux500_channel->is_tx);
-	spin_unlock_irqrestore(&musb->lock, flags);
-}
-
 /* Work function invoked from DMA callback to handle rx transfers. */
-static void ux500_rx_work(struct work_struct *data)
+void ux500_dma_callback(void *private_data)
 {
-	struct ux500_dma_channel *ux500_channel = container_of(data,
-		struct ux500_dma_channel, channel_work);
+	struct dma_channel *channel = private_data;
+	struct ux500_dma_channel *ux500_channel = channel->private_data;
 	struct musb_hw_ep       *hw_ep = ux500_channel->hw_ep;
 	struct musb *musb = hw_ep->musb;
 	unsigned long flags;
@@ -94,14 +73,7 @@
 	musb_dma_completion(musb, hw_ep->epnum,
 		ux500_channel->is_tx);
 	spin_unlock_irqrestore(&musb->lock, flags);
-}
 
-void ux500_dma_callback(void *private_data)
-{
-	struct dma_channel *channel = (struct dma_channel *)private_data;
-	struct ux500_dma_channel *ux500_channel = channel->private_data;
-
-	schedule_work(&ux500_channel->channel_work);
 }
 
 static bool ux500_configure_channel(struct dma_channel *channel,
@@ -330,7 +302,6 @@
 	void **param_array;
 	struct ux500_dma_channel *channel_array;
 	u32 ch_count;
-	void (*musb_channel_work)(struct work_struct *);
 	dma_cap_mask_t mask;
 
 	if ((data->num_rx_channels > UX500_MUSB_DMA_NUM_RX_CHANNELS) ||
@@ -347,7 +318,6 @@
 	channel_array = controller->rx_channel;
 	ch_count = data->num_rx_channels;
 	param_array = data->dma_rx_param_array;
-	musb_channel_work = ux500_rx_work;
 
 	for (dir = 0; dir < 2; dir++) {
 		for (ch_num = 0; ch_num < ch_count; ch_num++) {
@@ -374,15 +344,12 @@
 				return -EBUSY;
 			}
 
-			INIT_WORK(&ux500_channel->channel_work,
-				musb_channel_work);
 		}
 
 		/* Prepare the loop for TX channels */
 		channel_array = controller->tx_channel;
 		ch_count = data->num_tx_channels;
 		param_array = data->dma_tx_param_array;
-		musb_channel_work = ux500_tx_work;
 		is_tx = 1;
 	}
 
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
index c66481a..2a25955 100644
--- a/drivers/usb/otg/Kconfig
+++ b/drivers/usb/otg/Kconfig
@@ -82,9 +82,9 @@
 	tristate "NOP USB Transceiver Driver"
 	select USB_OTG_UTILS
 	help
-	 this driver is to be used by all the usb transceiver which are either
-	 built-in with usb ip or which are autonomous and doesn't require any
-	 phy programming such as ISP1x04 etc.
+	  This driver is to be used by all the usb transceiver which are either
+	  built-in with usb ip or which are autonomous and doesn't require any
+	  phy programming such as ISP1x04 etc.
 
 config USB_LANGWELL_OTG
 	tristate "Intel Langwell USB OTG dual-role support"
@@ -114,13 +114,13 @@
 	  has an external PHY.
 
 config AB8500_USB
-        tristate "AB8500 USB Transceiver Driver"
-        depends on AB8500_CORE
-        select USB_OTG_UTILS
-        help
-          Enable this to support the USB OTG transceiver in AB8500 chip.
-          This transceiver supports high and full speed devices plus,
-          in host mode, low speed.
+	tristate "AB8500 USB Transceiver Driver"
+	depends on AB8500_CORE
+	select USB_OTG_UTILS
+	help
+	  Enable this to support the USB OTG transceiver in AB8500 chip.
+	  This transceiver supports high and full speed devices plus,
+	  in host mode, low speed.
 
 config FSL_USB2_OTG
 	bool "Freescale USB OTG Transceiver Driver"
@@ -130,4 +130,16 @@
 	help
 	  Enable this to support Freescale USB OTG transceiver.
 
+config USB_MV_OTG
+	tristate "Marvell USB OTG support"
+	depends on USB_MV_UDC
+	select USB_OTG
+	select USB_OTG_UTILS
+	help
+	  Say Y here if you want to build Marvell USB OTG transciever
+	  driver in kernel (including PXA and MMP series). This driver
+	  implements role switch between EHCI host driver and gadget driver.
+
+	  To compile this driver as a module, choose M here.
+
 endif # USB || OTG
diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile
index 566655c..b2c5a95 100644
--- a/drivers/usb/otg/Makefile
+++ b/drivers/usb/otg/Makefile
@@ -21,3 +21,4 @@
 obj-$(CONFIG_AB8500_USB)	+= ab8500-usb.o
 fsl_usb2_otg-objs		:= fsl_otg.o otg_fsm.o
 obj-$(CONFIG_FSL_USB2_OTG)	+= fsl_usb2_otg.o
+obj-$(CONFIG_USB_MV_OTG)	+= mv_otg.o
diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/otg/fsl_otg.c
index 2d9cc44..a190850 100644
--- a/drivers/usb/otg/fsl_otg.c
+++ b/drivers/usb/otg/fsl_otg.c
@@ -1151,18 +1151,7 @@
 	},
 };
 
-static int __init fsl_usb_otg_init(void)
-{
-	pr_info(DRIVER_INFO "\n");
-	return platform_driver_register(&fsl_otg_driver);
-}
-module_init(fsl_usb_otg_init);
-
-static void __exit fsl_usb_otg_exit(void)
-{
-	platform_driver_unregister(&fsl_otg_driver);
-}
-module_exit(fsl_usb_otg_exit);
+module_platform_driver(fsl_otg_driver);
 
 MODULE_DESCRIPTION(DRIVER_INFO);
 MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/otg/mv_otg.c
new file mode 100644
index 0000000..db0d4fc
--- /dev/null
+++ b/drivers/usb/otg/mv_otg.c
@@ -0,0 +1,957 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ * Author: Chao Xie <chao.xie@marvell.com>
+ *	   Neil Zhang <zhangwm@marvell.com>
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/device.h>
+#include <linux/proc_fs.h>
+#include <linux/clk.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/hcd.h>
+#include <linux/platform_data/mv_usb.h>
+
+#include "mv_otg.h"
+
+#define	DRIVER_DESC	"Marvell USB OTG transceiver driver"
+#define	DRIVER_VERSION	"Jan 20, 2010"
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+static const char driver_name[] = "mv-otg";
+
+static char *state_string[] = {
+	"undefined",
+	"b_idle",
+	"b_srp_init",
+	"b_peripheral",
+	"b_wait_acon",
+	"b_host",
+	"a_idle",
+	"a_wait_vrise",
+	"a_wait_bcon",
+	"a_host",
+	"a_suspend",
+	"a_peripheral",
+	"a_wait_vfall",
+	"a_vbus_err"
+};
+
+static int mv_otg_set_vbus(struct otg_transceiver *otg, bool on)
+{
+	struct mv_otg *mvotg = container_of(otg, struct mv_otg, otg);
+	if (mvotg->pdata->set_vbus == NULL)
+		return -ENODEV;
+
+	return mvotg->pdata->set_vbus(on);
+}
+
+static int mv_otg_set_host(struct otg_transceiver *otg,
+			   struct usb_bus *host)
+{
+	otg->host = host;
+
+	return 0;
+}
+
+static int mv_otg_set_peripheral(struct otg_transceiver *otg,
+				 struct usb_gadget *gadget)
+{
+	otg->gadget = gadget;
+
+	return 0;
+}
+
+static void mv_otg_run_state_machine(struct mv_otg *mvotg,
+				     unsigned long delay)
+{
+	dev_dbg(&mvotg->pdev->dev, "transceiver is updated\n");
+	if (!mvotg->qwork)
+		return;
+
+	queue_delayed_work(mvotg->qwork, &mvotg->work, delay);
+}
+
+static void mv_otg_timer_await_bcon(unsigned long data)
+{
+	struct mv_otg *mvotg = (struct mv_otg *) data;
+
+	mvotg->otg_ctrl.a_wait_bcon_timeout = 1;
+
+	dev_info(&mvotg->pdev->dev, "B Device No Response!\n");
+
+	if (spin_trylock(&mvotg->wq_lock)) {
+		mv_otg_run_state_machine(mvotg, 0);
+		spin_unlock(&mvotg->wq_lock);
+	}
+}
+
+static int mv_otg_cancel_timer(struct mv_otg *mvotg, unsigned int id)
+{
+	struct timer_list *timer;
+
+	if (id >= OTG_TIMER_NUM)
+		return -EINVAL;
+
+	timer = &mvotg->otg_ctrl.timer[id];
+
+	if (timer_pending(timer))
+		del_timer(timer);
+
+	return 0;
+}
+
+static int mv_otg_set_timer(struct mv_otg *mvotg, unsigned int id,
+			    unsigned long interval,
+			    void (*callback) (unsigned long))
+{
+	struct timer_list *timer;
+
+	if (id >= OTG_TIMER_NUM)
+		return -EINVAL;
+
+	timer = &mvotg->otg_ctrl.timer[id];
+	if (timer_pending(timer)) {
+		dev_err(&mvotg->pdev->dev, "Timer%d is already running\n", id);
+		return -EBUSY;
+	}
+
+	init_timer(timer);
+	timer->data = (unsigned long) mvotg;
+	timer->function = callback;
+	timer->expires = jiffies + interval;
+	add_timer(timer);
+
+	return 0;
+}
+
+static int mv_otg_reset(struct mv_otg *mvotg)
+{
+	unsigned int loops;
+	u32 tmp;
+
+	/* Stop the controller */
+	tmp = readl(&mvotg->op_regs->usbcmd);
+	tmp &= ~USBCMD_RUN_STOP;
+	writel(tmp, &mvotg->op_regs->usbcmd);
+
+	/* Reset the controller to get default values */
+	writel(USBCMD_CTRL_RESET, &mvotg->op_regs->usbcmd);
+
+	loops = 500;
+	while (readl(&mvotg->op_regs->usbcmd) & USBCMD_CTRL_RESET) {
+		if (loops == 0) {
+			dev_err(&mvotg->pdev->dev,
+				"Wait for RESET completed TIMEOUT\n");
+			return -ETIMEDOUT;
+		}
+		loops--;
+		udelay(20);
+	}
+
+	writel(0x0, &mvotg->op_regs->usbintr);
+	tmp = readl(&mvotg->op_regs->usbsts);
+	writel(tmp, &mvotg->op_regs->usbsts);
+
+	return 0;
+}
+
+static void mv_otg_init_irq(struct mv_otg *mvotg)
+{
+	u32 otgsc;
+
+	mvotg->irq_en = OTGSC_INTR_A_SESSION_VALID
+	    | OTGSC_INTR_A_VBUS_VALID;
+	mvotg->irq_status = OTGSC_INTSTS_A_SESSION_VALID
+	    | OTGSC_INTSTS_A_VBUS_VALID;
+
+	if (mvotg->pdata->vbus == NULL) {
+		mvotg->irq_en |= OTGSC_INTR_B_SESSION_VALID
+		    | OTGSC_INTR_B_SESSION_END;
+		mvotg->irq_status |= OTGSC_INTSTS_B_SESSION_VALID
+		    | OTGSC_INTSTS_B_SESSION_END;
+	}
+
+	if (mvotg->pdata->id == NULL) {
+		mvotg->irq_en |= OTGSC_INTR_USB_ID;
+		mvotg->irq_status |= OTGSC_INTSTS_USB_ID;
+	}
+
+	otgsc = readl(&mvotg->op_regs->otgsc);
+	otgsc |= mvotg->irq_en;
+	writel(otgsc, &mvotg->op_regs->otgsc);
+}
+
+static void mv_otg_start_host(struct mv_otg *mvotg, int on)
+{
+	struct otg_transceiver *otg = &mvotg->otg;
+	struct usb_hcd *hcd;
+
+	if (!otg->host)
+		return;
+
+	dev_info(&mvotg->pdev->dev, "%s host\n", on ? "start" : "stop");
+
+	hcd = bus_to_hcd(otg->host);
+
+	if (on)
+		usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
+	else
+		usb_remove_hcd(hcd);
+}
+
+static void mv_otg_start_periphrals(struct mv_otg *mvotg, int on)
+{
+	struct otg_transceiver *otg = &mvotg->otg;
+
+	if (!otg->gadget)
+		return;
+
+	dev_info(otg->dev, "gadget %s\n", on ? "on" : "off");
+
+	if (on)
+		usb_gadget_vbus_connect(otg->gadget);
+	else
+		usb_gadget_vbus_disconnect(otg->gadget);
+}
+
+static void otg_clock_enable(struct mv_otg *mvotg)
+{
+	unsigned int i;
+
+	for (i = 0; i < mvotg->clknum; i++)
+		clk_enable(mvotg->clk[i]);
+}
+
+static void otg_clock_disable(struct mv_otg *mvotg)
+{
+	unsigned int i;
+
+	for (i = 0; i < mvotg->clknum; i++)
+		clk_disable(mvotg->clk[i]);
+}
+
+static int mv_otg_enable_internal(struct mv_otg *mvotg)
+{
+	int retval = 0;
+
+	if (mvotg->active)
+		return 0;
+
+	dev_dbg(&mvotg->pdev->dev, "otg enabled\n");
+
+	otg_clock_enable(mvotg);
+	if (mvotg->pdata->phy_init) {
+		retval = mvotg->pdata->phy_init(mvotg->phy_regs);
+		if (retval) {
+			dev_err(&mvotg->pdev->dev,
+				"init phy error %d\n", retval);
+			otg_clock_disable(mvotg);
+			return retval;
+		}
+	}
+	mvotg->active = 1;
+
+	return 0;
+
+}
+
+static int mv_otg_enable(struct mv_otg *mvotg)
+{
+	if (mvotg->clock_gating)
+		return mv_otg_enable_internal(mvotg);
+
+	return 0;
+}
+
+static void mv_otg_disable_internal(struct mv_otg *mvotg)
+{
+	if (mvotg->active) {
+		dev_dbg(&mvotg->pdev->dev, "otg disabled\n");
+		if (mvotg->pdata->phy_deinit)
+			mvotg->pdata->phy_deinit(mvotg->phy_regs);
+		otg_clock_disable(mvotg);
+		mvotg->active = 0;
+	}
+}
+
+static void mv_otg_disable(struct mv_otg *mvotg)
+{
+	if (mvotg->clock_gating)
+		mv_otg_disable_internal(mvotg);
+}
+
+static void mv_otg_update_inputs(struct mv_otg *mvotg)
+{
+	struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl;
+	u32 otgsc;
+
+	otgsc = readl(&mvotg->op_regs->otgsc);
+
+	if (mvotg->pdata->vbus) {
+		if (mvotg->pdata->vbus->poll() == VBUS_HIGH) {
+			otg_ctrl->b_sess_vld = 1;
+			otg_ctrl->b_sess_end = 0;
+		} else {
+			otg_ctrl->b_sess_vld = 0;
+			otg_ctrl->b_sess_end = 1;
+		}
+	} else {
+		otg_ctrl->b_sess_vld = !!(otgsc & OTGSC_STS_B_SESSION_VALID);
+		otg_ctrl->b_sess_end = !!(otgsc & OTGSC_STS_B_SESSION_END);
+	}
+
+	if (mvotg->pdata->id)
+		otg_ctrl->id = !!mvotg->pdata->id->poll();
+	else
+		otg_ctrl->id = !!(otgsc & OTGSC_STS_USB_ID);
+
+	if (mvotg->pdata->otg_force_a_bus_req && !otg_ctrl->id)
+		otg_ctrl->a_bus_req = 1;
+
+	otg_ctrl->a_sess_vld = !!(otgsc & OTGSC_STS_A_SESSION_VALID);
+	otg_ctrl->a_vbus_vld = !!(otgsc & OTGSC_STS_A_VBUS_VALID);
+
+	dev_dbg(&mvotg->pdev->dev, "%s: ", __func__);
+	dev_dbg(&mvotg->pdev->dev, "id %d\n", otg_ctrl->id);
+	dev_dbg(&mvotg->pdev->dev, "b_sess_vld %d\n", otg_ctrl->b_sess_vld);
+	dev_dbg(&mvotg->pdev->dev, "b_sess_end %d\n", otg_ctrl->b_sess_end);
+	dev_dbg(&mvotg->pdev->dev, "a_vbus_vld %d\n", otg_ctrl->a_vbus_vld);
+	dev_dbg(&mvotg->pdev->dev, "a_sess_vld %d\n", otg_ctrl->a_sess_vld);
+}
+
+static void mv_otg_update_state(struct mv_otg *mvotg)
+{
+	struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl;
+	struct otg_transceiver *otg = &mvotg->otg;
+	int old_state = otg->state;
+
+	switch (old_state) {
+	case OTG_STATE_UNDEFINED:
+		otg->state = OTG_STATE_B_IDLE;
+		/* FALL THROUGH */
+	case OTG_STATE_B_IDLE:
+		if (otg_ctrl->id == 0)
+			otg->state = OTG_STATE_A_IDLE;
+		else if (otg_ctrl->b_sess_vld)
+			otg->state = OTG_STATE_B_PERIPHERAL;
+		break;
+	case OTG_STATE_B_PERIPHERAL:
+		if (!otg_ctrl->b_sess_vld || otg_ctrl->id == 0)
+			otg->state = OTG_STATE_B_IDLE;
+		break;
+	case OTG_STATE_A_IDLE:
+		if (otg_ctrl->id)
+			otg->state = OTG_STATE_B_IDLE;
+		else if (!(otg_ctrl->a_bus_drop) &&
+			 (otg_ctrl->a_bus_req || otg_ctrl->a_srp_det))
+			otg->state = OTG_STATE_A_WAIT_VRISE;
+		break;
+	case OTG_STATE_A_WAIT_VRISE:
+		if (otg_ctrl->a_vbus_vld)
+			otg->state = OTG_STATE_A_WAIT_BCON;
+		break;
+	case OTG_STATE_A_WAIT_BCON:
+		if (otg_ctrl->id || otg_ctrl->a_bus_drop
+		    || otg_ctrl->a_wait_bcon_timeout) {
+			mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
+			mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
+			otg->state = OTG_STATE_A_WAIT_VFALL;
+			otg_ctrl->a_bus_req = 0;
+		} else if (!otg_ctrl->a_vbus_vld) {
+			mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
+			mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
+			otg->state = OTG_STATE_A_VBUS_ERR;
+		} else if (otg_ctrl->b_conn) {
+			mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
+			mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
+			otg->state = OTG_STATE_A_HOST;
+		}
+		break;
+	case OTG_STATE_A_HOST:
+		if (otg_ctrl->id || !otg_ctrl->b_conn
+		    || otg_ctrl->a_bus_drop)
+			otg->state = OTG_STATE_A_WAIT_BCON;
+		else if (!otg_ctrl->a_vbus_vld)
+			otg->state = OTG_STATE_A_VBUS_ERR;
+		break;
+	case OTG_STATE_A_WAIT_VFALL:
+		if (otg_ctrl->id
+		    || (!otg_ctrl->b_conn && otg_ctrl->a_sess_vld)
+		    || otg_ctrl->a_bus_req)
+			otg->state = OTG_STATE_A_IDLE;
+		break;
+	case OTG_STATE_A_VBUS_ERR:
+		if (otg_ctrl->id || otg_ctrl->a_clr_err
+		    || otg_ctrl->a_bus_drop) {
+			otg_ctrl->a_clr_err = 0;
+			otg->state = OTG_STATE_A_WAIT_VFALL;
+		}
+		break;
+	default:
+		break;
+	}
+}
+
+static void mv_otg_work(struct work_struct *work)
+{
+	struct mv_otg *mvotg;
+	struct otg_transceiver *otg;
+	int old_state;
+
+	mvotg = container_of((struct delayed_work *)work, struct mv_otg, work);
+
+run:
+	/* work queue is single thread, or we need spin_lock to protect */
+	otg = &mvotg->otg;
+	old_state = otg->state;
+
+	if (!mvotg->active)
+		return;
+
+	mv_otg_update_inputs(mvotg);
+	mv_otg_update_state(mvotg);
+
+	if (old_state != otg->state) {
+		dev_info(&mvotg->pdev->dev, "change from state %s to %s\n",
+			 state_string[old_state],
+			 state_string[otg->state]);
+
+		switch (otg->state) {
+		case OTG_STATE_B_IDLE:
+			mvotg->otg.default_a = 0;
+			if (old_state == OTG_STATE_B_PERIPHERAL)
+				mv_otg_start_periphrals(mvotg, 0);
+			mv_otg_reset(mvotg);
+			mv_otg_disable(mvotg);
+			break;
+		case OTG_STATE_B_PERIPHERAL:
+			mv_otg_enable(mvotg);
+			mv_otg_start_periphrals(mvotg, 1);
+			break;
+		case OTG_STATE_A_IDLE:
+			mvotg->otg.default_a = 1;
+			mv_otg_enable(mvotg);
+			if (old_state == OTG_STATE_A_WAIT_VFALL)
+				mv_otg_start_host(mvotg, 0);
+			mv_otg_reset(mvotg);
+			break;
+		case OTG_STATE_A_WAIT_VRISE:
+			mv_otg_set_vbus(&mvotg->otg, 1);
+			break;
+		case OTG_STATE_A_WAIT_BCON:
+			if (old_state != OTG_STATE_A_HOST)
+				mv_otg_start_host(mvotg, 1);
+			mv_otg_set_timer(mvotg, A_WAIT_BCON_TIMER,
+					 T_A_WAIT_BCON,
+					 mv_otg_timer_await_bcon);
+			/*
+			 * Now, we directly enter A_HOST. So set b_conn = 1
+			 * here. In fact, it need host driver to notify us.
+			 */
+			mvotg->otg_ctrl.b_conn = 1;
+			break;
+		case OTG_STATE_A_HOST:
+			break;
+		case OTG_STATE_A_WAIT_VFALL:
+			/*
+			 * Now, we has exited A_HOST. So set b_conn = 0
+			 * here. In fact, it need host driver to notify us.
+			 */
+			mvotg->otg_ctrl.b_conn = 0;
+			mv_otg_set_vbus(&mvotg->otg, 0);
+			break;
+		case OTG_STATE_A_VBUS_ERR:
+			break;
+		default:
+			break;
+		}
+		goto run;
+	}
+}
+
+static irqreturn_t mv_otg_irq(int irq, void *dev)
+{
+	struct mv_otg *mvotg = dev;
+	u32 otgsc;
+
+	otgsc = readl(&mvotg->op_regs->otgsc);
+	writel(otgsc, &mvotg->op_regs->otgsc);
+
+	/*
+	 * if we have vbus, then the vbus detection for B-device
+	 * will be done by mv_otg_inputs_irq().
+	 */
+	if (mvotg->pdata->vbus)
+		if ((otgsc & OTGSC_STS_USB_ID) &&
+		    !(otgsc & OTGSC_INTSTS_USB_ID))
+			return IRQ_NONE;
+
+	if ((otgsc & mvotg->irq_status) == 0)
+		return IRQ_NONE;
+
+	mv_otg_run_state_machine(mvotg, 0);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t mv_otg_inputs_irq(int irq, void *dev)
+{
+	struct mv_otg *mvotg = dev;
+
+	/* The clock may disabled at this time */
+	if (!mvotg->active) {
+		mv_otg_enable(mvotg);
+		mv_otg_init_irq(mvotg);
+	}
+
+	mv_otg_run_state_machine(mvotg, 0);
+
+	return IRQ_HANDLED;
+}
+
+static ssize_t
+get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct mv_otg *mvotg = dev_get_drvdata(dev);
+	return scnprintf(buf, PAGE_SIZE, "%d\n",
+			 mvotg->otg_ctrl.a_bus_req);
+}
+
+static ssize_t
+set_a_bus_req(struct device *dev, struct device_attribute *attr,
+	      const char *buf, size_t count)
+{
+	struct mv_otg *mvotg = dev_get_drvdata(dev);
+
+	if (count > 2)
+		return -1;
+
+	/* We will use this interface to change to A device */
+	if (mvotg->otg.state != OTG_STATE_B_IDLE
+	    && mvotg->otg.state != OTG_STATE_A_IDLE)
+		return -1;
+
+	/* The clock may disabled and we need to set irq for ID detected */
+	mv_otg_enable(mvotg);
+	mv_otg_init_irq(mvotg);
+
+	if (buf[0] == '1') {
+		mvotg->otg_ctrl.a_bus_req = 1;
+		mvotg->otg_ctrl.a_bus_drop = 0;
+		dev_dbg(&mvotg->pdev->dev,
+			"User request: a_bus_req = 1\n");
+
+		if (spin_trylock(&mvotg->wq_lock)) {
+			mv_otg_run_state_machine(mvotg, 0);
+			spin_unlock(&mvotg->wq_lock);
+		}
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req,
+		   set_a_bus_req);
+
+static ssize_t
+set_a_clr_err(struct device *dev, struct device_attribute *attr,
+	      const char *buf, size_t count)
+{
+	struct mv_otg *mvotg = dev_get_drvdata(dev);
+	if (!mvotg->otg.default_a)
+		return -1;
+
+	if (count > 2)
+		return -1;
+
+	if (buf[0] == '1') {
+		mvotg->otg_ctrl.a_clr_err = 1;
+		dev_dbg(&mvotg->pdev->dev,
+			"User request: a_clr_err = 1\n");
+	}
+
+	if (spin_trylock(&mvotg->wq_lock)) {
+		mv_otg_run_state_machine(mvotg, 0);
+		spin_unlock(&mvotg->wq_lock);
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err);
+
+static ssize_t
+get_a_bus_drop(struct device *dev, struct device_attribute *attr,
+	       char *buf)
+{
+	struct mv_otg *mvotg = dev_get_drvdata(dev);
+	return scnprintf(buf, PAGE_SIZE, "%d\n",
+			 mvotg->otg_ctrl.a_bus_drop);
+}
+
+static ssize_t
+set_a_bus_drop(struct device *dev, struct device_attribute *attr,
+	       const char *buf, size_t count)
+{
+	struct mv_otg *mvotg = dev_get_drvdata(dev);
+	if (!mvotg->otg.default_a)
+		return -1;
+
+	if (count > 2)
+		return -1;
+
+	if (buf[0] == '0') {
+		mvotg->otg_ctrl.a_bus_drop = 0;
+		dev_dbg(&mvotg->pdev->dev,
+			"User request: a_bus_drop = 0\n");
+	} else if (buf[0] == '1') {
+		mvotg->otg_ctrl.a_bus_drop = 1;
+		mvotg->otg_ctrl.a_bus_req = 0;
+		dev_dbg(&mvotg->pdev->dev,
+			"User request: a_bus_drop = 1\n");
+		dev_dbg(&mvotg->pdev->dev,
+			"User request: and a_bus_req = 0\n");
+	}
+
+	if (spin_trylock(&mvotg->wq_lock)) {
+		mv_otg_run_state_machine(mvotg, 0);
+		spin_unlock(&mvotg->wq_lock);
+	}
+
+	return count;
+}
+
+static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR,
+		   get_a_bus_drop, set_a_bus_drop);
+
+static struct attribute *inputs_attrs[] = {
+	&dev_attr_a_bus_req.attr,
+	&dev_attr_a_clr_err.attr,
+	&dev_attr_a_bus_drop.attr,
+	NULL,
+};
+
+static struct attribute_group inputs_attr_group = {
+	.name = "inputs",
+	.attrs = inputs_attrs,
+};
+
+int mv_otg_remove(struct platform_device *pdev)
+{
+	struct mv_otg *mvotg = platform_get_drvdata(pdev);
+	int clk_i;
+
+	sysfs_remove_group(&mvotg->pdev->dev.kobj, &inputs_attr_group);
+
+	if (mvotg->irq)
+		free_irq(mvotg->irq, mvotg);
+
+	if (mvotg->pdata->vbus)
+		free_irq(mvotg->pdata->vbus->irq, mvotg);
+	if (mvotg->pdata->id)
+		free_irq(mvotg->pdata->id->irq, mvotg);
+
+	if (mvotg->qwork) {
+		flush_workqueue(mvotg->qwork);
+		destroy_workqueue(mvotg->qwork);
+	}
+
+	mv_otg_disable(mvotg);
+
+	if (mvotg->cap_regs)
+		iounmap(mvotg->cap_regs);
+
+	if (mvotg->phy_regs)
+		iounmap(mvotg->phy_regs);
+
+	for (clk_i = 0; clk_i <= mvotg->clknum; clk_i++)
+		clk_put(mvotg->clk[clk_i]);
+
+	otg_set_transceiver(NULL);
+	platform_set_drvdata(pdev, NULL);
+
+	kfree(mvotg);
+
+	return 0;
+}
+
+static int mv_otg_probe(struct platform_device *pdev)
+{
+	struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
+	struct mv_otg *mvotg;
+	struct resource *r;
+	int retval = 0, clk_i, i;
+	size_t size;
+
+	if (pdata == NULL) {
+		dev_err(&pdev->dev, "failed to get platform data\n");
+		return -ENODEV;
+	}
+
+	size = sizeof(*mvotg) + sizeof(struct clk *) * pdata->clknum;
+	mvotg = kzalloc(size, GFP_KERNEL);
+	if (!mvotg) {
+		dev_err(&pdev->dev, "failed to allocate memory!\n");
+		return -ENOMEM;
+	}
+
+	platform_set_drvdata(pdev, mvotg);
+
+	mvotg->pdev = pdev;
+	mvotg->pdata = pdata;
+
+	mvotg->clknum = pdata->clknum;
+	for (clk_i = 0; clk_i < mvotg->clknum; clk_i++) {
+		mvotg->clk[clk_i] = clk_get(&pdev->dev, pdata->clkname[clk_i]);
+		if (IS_ERR(mvotg->clk[clk_i])) {
+			retval = PTR_ERR(mvotg->clk[clk_i]);
+			goto err_put_clk;
+		}
+	}
+
+	mvotg->qwork = create_singlethread_workqueue("mv_otg_queue");
+	if (!mvotg->qwork) {
+		dev_dbg(&pdev->dev, "cannot create workqueue for OTG\n");
+		retval = -ENOMEM;
+		goto err_put_clk;
+	}
+
+	INIT_DELAYED_WORK(&mvotg->work, mv_otg_work);
+
+	/* OTG common part */
+	mvotg->pdev = pdev;
+	mvotg->otg.dev = &pdev->dev;
+	mvotg->otg.label = driver_name;
+	mvotg->otg.set_host = mv_otg_set_host;
+	mvotg->otg.set_peripheral = mv_otg_set_peripheral;
+	mvotg->otg.set_vbus = mv_otg_set_vbus;
+	mvotg->otg.state = OTG_STATE_UNDEFINED;
+
+	for (i = 0; i < OTG_TIMER_NUM; i++)
+		init_timer(&mvotg->otg_ctrl.timer[i]);
+
+	r = platform_get_resource_byname(mvotg->pdev,
+					 IORESOURCE_MEM, "phyregs");
+	if (r == NULL) {
+		dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
+		retval = -ENODEV;
+		goto err_destroy_workqueue;
+	}
+
+	mvotg->phy_regs = ioremap(r->start, resource_size(r));
+	if (mvotg->phy_regs == NULL) {
+		dev_err(&pdev->dev, "failed to map phy I/O memory\n");
+		retval = -EFAULT;
+		goto err_destroy_workqueue;
+	}
+
+	r = platform_get_resource_byname(mvotg->pdev,
+					 IORESOURCE_MEM, "capregs");
+	if (r == NULL) {
+		dev_err(&pdev->dev, "no I/O memory resource defined\n");
+		retval = -ENODEV;
+		goto err_unmap_phyreg;
+	}
+
+	mvotg->cap_regs = ioremap(r->start, resource_size(r));
+	if (mvotg->cap_regs == NULL) {
+		dev_err(&pdev->dev, "failed to map I/O memory\n");
+		retval = -EFAULT;
+		goto err_unmap_phyreg;
+	}
+
+	/* we will acces controller register, so enable the udc controller */
+	retval = mv_otg_enable_internal(mvotg);
+	if (retval) {
+		dev_err(&pdev->dev, "mv otg enable error %d\n", retval);
+		goto err_unmap_capreg;
+	}
+
+	mvotg->op_regs =
+		(struct mv_otg_regs __iomem *) ((unsigned long) mvotg->cap_regs
+			+ (readl(mvotg->cap_regs) & CAPLENGTH_MASK));
+
+	if (pdata->id) {
+		retval = request_threaded_irq(pdata->id->irq, NULL,
+					      mv_otg_inputs_irq,
+					      IRQF_ONESHOT, "id", mvotg);
+		if (retval) {
+			dev_info(&pdev->dev,
+				 "Failed to request irq for ID\n");
+			pdata->id = NULL;
+		}
+	}
+
+	if (pdata->vbus) {
+		mvotg->clock_gating = 1;
+		retval = request_threaded_irq(pdata->vbus->irq, NULL,
+					      mv_otg_inputs_irq,
+					      IRQF_ONESHOT, "vbus", mvotg);
+		if (retval) {
+			dev_info(&pdev->dev,
+				 "Failed to request irq for VBUS, "
+				 "disable clock gating\n");
+			mvotg->clock_gating = 0;
+			pdata->vbus = NULL;
+		}
+	}
+
+	if (pdata->disable_otg_clock_gating)
+		mvotg->clock_gating = 0;
+
+	mv_otg_reset(mvotg);
+	mv_otg_init_irq(mvotg);
+
+	r = platform_get_resource(mvotg->pdev, IORESOURCE_IRQ, 0);
+	if (r == NULL) {
+		dev_err(&pdev->dev, "no IRQ resource defined\n");
+		retval = -ENODEV;
+		goto err_disable_clk;
+	}
+
+	mvotg->irq = r->start;
+	if (request_irq(mvotg->irq, mv_otg_irq, IRQF_SHARED,
+			driver_name, mvotg)) {
+		dev_err(&pdev->dev, "Request irq %d for OTG failed\n",
+			mvotg->irq);
+		mvotg->irq = 0;
+		retval = -ENODEV;
+		goto err_disable_clk;
+	}
+
+	retval = otg_set_transceiver(&mvotg->otg);
+	if (retval < 0) {
+		dev_err(&pdev->dev, "can't register transceiver, %d\n",
+			retval);
+		goto err_free_irq;
+	}
+
+	retval = sysfs_create_group(&pdev->dev.kobj, &inputs_attr_group);
+	if (retval < 0) {
+		dev_dbg(&pdev->dev,
+			"Can't register sysfs attr group: %d\n", retval);
+		goto err_set_transceiver;
+	}
+
+	spin_lock_init(&mvotg->wq_lock);
+	if (spin_trylock(&mvotg->wq_lock)) {
+		mv_otg_run_state_machine(mvotg, 2 * HZ);
+		spin_unlock(&mvotg->wq_lock);
+	}
+
+	dev_info(&pdev->dev,
+		 "successful probe OTG device %s clock gating.\n",
+		 mvotg->clock_gating ? "with" : "without");
+
+	return 0;
+
+err_set_transceiver:
+	otg_set_transceiver(NULL);
+err_free_irq:
+	free_irq(mvotg->irq, mvotg);
+err_disable_clk:
+	if (pdata->vbus)
+		free_irq(pdata->vbus->irq, mvotg);
+	if (pdata->id)
+		free_irq(pdata->id->irq, mvotg);
+	mv_otg_disable_internal(mvotg);
+err_unmap_capreg:
+	iounmap(mvotg->cap_regs);
+err_unmap_phyreg:
+	iounmap(mvotg->phy_regs);
+err_destroy_workqueue:
+	flush_workqueue(mvotg->qwork);
+	destroy_workqueue(mvotg->qwork);
+err_put_clk:
+	for (clk_i--; clk_i >= 0; clk_i--)
+		clk_put(mvotg->clk[clk_i]);
+
+	platform_set_drvdata(pdev, NULL);
+	kfree(mvotg);
+
+	return retval;
+}
+
+#ifdef CONFIG_PM
+static int mv_otg_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct mv_otg *mvotg = platform_get_drvdata(pdev);
+
+	if (mvotg->otg.state != OTG_STATE_B_IDLE) {
+		dev_info(&pdev->dev,
+			 "OTG state is not B_IDLE, it is %d!\n",
+			 mvotg->otg.state);
+		return -EAGAIN;
+	}
+
+	if (!mvotg->clock_gating)
+		mv_otg_disable_internal(mvotg);
+
+	return 0;
+}
+
+static int mv_otg_resume(struct platform_device *pdev)
+{
+	struct mv_otg *mvotg = platform_get_drvdata(pdev);
+	u32 otgsc;
+
+	if (!mvotg->clock_gating) {
+		mv_otg_enable_internal(mvotg);
+
+		otgsc = readl(&mvotg->op_regs->otgsc);
+		otgsc |= mvotg->irq_en;
+		writel(otgsc, &mvotg->op_regs->otgsc);
+
+		if (spin_trylock(&mvotg->wq_lock)) {
+			mv_otg_run_state_machine(mvotg, 0);
+			spin_unlock(&mvotg->wq_lock);
+		}
+	}
+	return 0;
+}
+#endif
+
+static struct platform_driver mv_otg_driver = {
+	.probe = mv_otg_probe,
+	.remove = __exit_p(mv_otg_remove),
+	.driver = {
+		   .owner = THIS_MODULE,
+		   .name = driver_name,
+		   },
+#ifdef CONFIG_PM
+	.suspend = mv_otg_suspend,
+	.resume = mv_otg_resume,
+#endif
+};
+
+static int __init mv_otg_init(void)
+{
+	return platform_driver_register(&mv_otg_driver);
+}
+
+static void __exit mv_otg_exit(void)
+{
+	platform_driver_unregister(&mv_otg_driver);
+}
+
+module_init(mv_otg_init);
+module_exit(mv_otg_exit);
diff --git a/drivers/usb/otg/mv_otg.h b/drivers/usb/otg/mv_otg.h
new file mode 100644
index 0000000..be6ca14
--- /dev/null
+++ b/drivers/usb/otg/mv_otg.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
+
+#ifndef	__MV_USB_OTG_CONTROLLER__
+#define	__MV_USB_OTG_CONTROLLER__
+
+#include <linux/types.h>
+
+/* Command Register Bit Masks */
+#define USBCMD_RUN_STOP			(0x00000001)
+#define USBCMD_CTRL_RESET		(0x00000002)
+
+/* otgsc Register Bit Masks */
+#define OTGSC_CTRL_VUSB_DISCHARGE		0x00000001
+#define OTGSC_CTRL_VUSB_CHARGE			0x00000002
+#define OTGSC_CTRL_OTG_TERM			0x00000008
+#define OTGSC_CTRL_DATA_PULSING			0x00000010
+#define OTGSC_STS_USB_ID			0x00000100
+#define OTGSC_STS_A_VBUS_VALID			0x00000200
+#define OTGSC_STS_A_SESSION_VALID		0x00000400
+#define OTGSC_STS_B_SESSION_VALID		0x00000800
+#define OTGSC_STS_B_SESSION_END			0x00001000
+#define OTGSC_STS_1MS_TOGGLE			0x00002000
+#define OTGSC_STS_DATA_PULSING			0x00004000
+#define OTGSC_INTSTS_USB_ID			0x00010000
+#define OTGSC_INTSTS_A_VBUS_VALID		0x00020000
+#define OTGSC_INTSTS_A_SESSION_VALID		0x00040000
+#define OTGSC_INTSTS_B_SESSION_VALID		0x00080000
+#define OTGSC_INTSTS_B_SESSION_END		0x00100000
+#define OTGSC_INTSTS_1MS			0x00200000
+#define OTGSC_INTSTS_DATA_PULSING		0x00400000
+#define OTGSC_INTR_USB_ID			0x01000000
+#define OTGSC_INTR_A_VBUS_VALID			0x02000000
+#define OTGSC_INTR_A_SESSION_VALID		0x04000000
+#define OTGSC_INTR_B_SESSION_VALID		0x08000000
+#define OTGSC_INTR_B_SESSION_END		0x10000000
+#define OTGSC_INTR_1MS_TIMER			0x20000000
+#define OTGSC_INTR_DATA_PULSING			0x40000000
+
+#define CAPLENGTH_MASK		(0xff)
+
+/* Timer's interval, unit 10ms */
+#define T_A_WAIT_VRISE		100
+#define T_A_WAIT_BCON		2000
+#define T_A_AIDL_BDIS		100
+#define T_A_BIDL_ADIS		20
+#define T_B_ASE0_BRST		400
+#define T_B_SE0_SRP		300
+#define T_B_SRP_FAIL		2000
+#define T_B_DATA_PLS		10
+#define T_B_SRP_INIT		100
+#define T_A_SRP_RSPNS		10
+#define T_A_DRV_RSM		5
+
+enum otg_function {
+	OTG_B_DEVICE = 0,
+	OTG_A_DEVICE
+};
+
+enum mv_otg_timer {
+	A_WAIT_BCON_TIMER = 0,
+	OTG_TIMER_NUM
+};
+
+/* PXA OTG state machine */
+struct mv_otg_ctrl {
+	/* internal variables */
+	u8 a_set_b_hnp_en;	/* A-Device set b_hnp_en */
+	u8 b_srp_done;
+	u8 b_hnp_en;
+
+	/* OTG inputs */
+	u8 a_bus_drop;
+	u8 a_bus_req;
+	u8 a_clr_err;
+	u8 a_bus_resume;
+	u8 a_bus_suspend;
+	u8 a_conn;
+	u8 a_sess_vld;
+	u8 a_srp_det;
+	u8 a_vbus_vld;
+	u8 b_bus_req;		/* B-Device Require Bus */
+	u8 b_bus_resume;
+	u8 b_bus_suspend;
+	u8 b_conn;
+	u8 b_se0_srp;
+	u8 b_sess_end;
+	u8 b_sess_vld;
+	u8 id;
+	u8 a_suspend_req;
+
+	/*Timer event */
+	u8 a_aidl_bdis_timeout;
+	u8 b_ase0_brst_timeout;
+	u8 a_bidl_adis_timeout;
+	u8 a_wait_bcon_timeout;
+
+	struct timer_list timer[OTG_TIMER_NUM];
+};
+
+#define VUSBHS_MAX_PORTS	8
+
+struct mv_otg_regs {
+	u32 usbcmd;		/* Command register */
+	u32 usbsts;		/* Status register */
+	u32 usbintr;		/* Interrupt enable */
+	u32 frindex;		/* Frame index */
+	u32 reserved1[1];
+	u32 deviceaddr;		/* Device Address */
+	u32 eplistaddr;		/* Endpoint List Address */
+	u32 ttctrl;		/* HOST TT status and control */
+	u32 burstsize;		/* Programmable Burst Size */
+	u32 txfilltuning;	/* Host Transmit Pre-Buffer Packet Tuning */
+	u32 reserved[4];
+	u32 epnak;		/* Endpoint NAK */
+	u32 epnaken;		/* Endpoint NAK Enable */
+	u32 configflag;		/* Configured Flag register */
+	u32 portsc[VUSBHS_MAX_PORTS];	/* Port Status/Control x, x = 1..8 */
+	u32 otgsc;
+	u32 usbmode;		/* USB Host/Device mode */
+	u32 epsetupstat;	/* Endpoint Setup Status */
+	u32 epprime;		/* Endpoint Initialize */
+	u32 epflush;		/* Endpoint De-initialize */
+	u32 epstatus;		/* Endpoint Status */
+	u32 epcomplete;		/* Endpoint Interrupt On Complete */
+	u32 epctrlx[16];	/* Endpoint Control, where x = 0.. 15 */
+	u32 mcr;		/* Mux Control */
+	u32 isr;		/* Interrupt Status */
+	u32 ier;		/* Interrupt Enable */
+};
+
+struct mv_otg {
+	struct otg_transceiver otg;
+	struct mv_otg_ctrl otg_ctrl;
+
+	/* base address */
+	void __iomem *phy_regs;
+	void __iomem *cap_regs;
+	struct mv_otg_regs __iomem *op_regs;
+
+	struct platform_device *pdev;
+	int irq;
+	u32 irq_status;
+	u32 irq_en;
+
+	struct delayed_work work;
+	struct workqueue_struct *qwork;
+
+	spinlock_t wq_lock;
+
+	struct mv_usb_platform_data *pdata;
+
+	unsigned int active;
+	unsigned int clock_gating;
+	unsigned int clknum;
+	struct clk *clk[0];
+};
+
+#endif
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index 08c679c..e9a5b1d 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -95,25 +95,15 @@
 /*
  *		syscfg functions
  */
-void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable)
+static void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable)
 {
 	usbhs_bset(priv, SYSCFG, SCKE, enable ? SCKE : 0);
 }
 
-void usbhs_sys_hispeed_ctrl(struct usbhs_priv *priv, int enable)
-{
-	usbhs_bset(priv, SYSCFG, HSE, enable ? HSE : 0);
-}
-
-void usbhs_sys_usb_ctrl(struct usbhs_priv *priv, int enable)
-{
-	usbhs_bset(priv, SYSCFG, USBE, enable ? USBE : 0);
-}
-
 void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable)
 {
-	u16 mask = DCFM | DRPD | DPRPU;
-	u16 val  = DCFM | DRPD;
+	u16 mask = DCFM | DRPD | DPRPU | HSE | USBE;
+	u16 val  = DCFM | DRPD | HSE | USBE;
 	int has_otg = usbhs_get_dparam(priv, has_otg);
 
 	if (has_otg)
@@ -130,8 +120,8 @@
 
 void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable)
 {
-	u16 mask = DCFM | DRPD | DPRPU;
-	u16 val  = DPRPU;
+	u16 mask = DCFM | DRPD | DPRPU | HSE | USBE;
+	u16 val  = DPRPU | HSE | USBE;
 
 	/*
 	 * if enable
@@ -142,6 +132,11 @@
 	usbhs_bset(priv, SYSCFG, mask, enable ? val : 0);
 }
 
+void usbhs_sys_set_test_mode(struct usbhs_priv *priv, u16 mode)
+{
+	usbhs_write(priv, TESTMODE, mode);
+}
+
 /*
  *		frame functions
  */
@@ -229,7 +224,7 @@
 /*
  *		device configuration
  */
-int usbhs_set_device_speed(struct usbhs_priv *priv, int devnum,
+int usbhs_set_device_config(struct usbhs_priv *priv, int devnum,
 			   u16 upphub, u16 hubport, u16 speed)
 {
 	struct device *dev = usbhs_priv_to_dev(priv);
@@ -301,18 +296,25 @@
  */
 static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable)
 {
+	struct platform_device *pdev = usbhs_priv_to_pdev(priv);
 	struct device *dev = usbhs_priv_to_dev(priv);
 
 	if (enable) {
 		/* enable PM */
 		pm_runtime_get_sync(dev);
 
+		/* enable platform power */
+		usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable);
+
 		/* USB on */
 		usbhs_sys_clock_ctrl(priv, enable);
 	} else {
 		/* USB off */
 		usbhs_sys_clock_ctrl(priv, enable);
 
+		/* disable platform power */
+		usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable);
+
 		/* disable PM */
 		pm_runtime_put_sync(dev);
 	}
@@ -388,7 +390,7 @@
 	usbhsc_hotplug(priv);
 }
 
-int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev)
+static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev)
 {
 	struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
 	int delay = usbhs_get_dparam(priv, detection_delay);
@@ -398,7 +400,8 @@
 	 * To make sure safety context,
 	 * use workqueue for usbhs_notify_hotplug
 	 */
-	schedule_delayed_work(&priv->notify_hotplug_work, delay);
+	schedule_delayed_work(&priv->notify_hotplug_work,
+			      msecs_to_jiffies(delay));
 	return 0;
 }
 
@@ -637,18 +640,7 @@
 	.remove		= __devexit_p(usbhs_remove),
 };
 
-static int __init usbhs_init(void)
-{
-	return platform_driver_register(&renesas_usbhs_driver);
-}
-
-static void __exit usbhs_exit(void)
-{
-	platform_driver_unregister(&renesas_usbhs_driver);
-}
-
-module_init(usbhs_init);
-module_exit(usbhs_exit);
+module_platform_driver(renesas_usbhs_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Renesas USB driver");
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h
index 8729da5..d79b3e2 100644
--- a/drivers/usb/renesas_usbhs/common.h
+++ b/drivers/usb/renesas_usbhs/common.h
@@ -33,6 +33,7 @@
 #define SYSCFG		0x0000
 #define BUSWAIT		0x0002
 #define DVSTCTR		0x0008
+#define TESTMODE	0x000C
 #define CFIFO		0x0014
 #define CFIFOSEL	0x0020
 #define CFIFOCTR	0x0022
@@ -275,19 +276,15 @@
 void usbhs_write(struct usbhs_priv *priv, u32 reg, u16 data);
 void usbhs_bset(struct usbhs_priv *priv, u32 reg, u16 mask, u16 data);
 
-int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev);
-
 #define usbhs_lock(p, f) spin_lock_irqsave(usbhs_priv_to_lock(p), f)
 #define usbhs_unlock(p, f) spin_unlock_irqrestore(usbhs_priv_to_lock(p), f)
 
 /*
  * sysconfig
  */
-void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable);
-void usbhs_sys_hispeed_ctrl(struct usbhs_priv *priv, int enable);
-void usbhs_sys_usb_ctrl(struct usbhs_priv *priv, int enable);
 void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable);
 void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable);
+void usbhs_sys_set_test_mode(struct usbhs_priv *priv, u16 mode);
 
 /*
  * usb request
@@ -311,7 +308,7 @@
 /*
  * device config
  */
-int usbhs_set_device_speed(struct usbhs_priv *priv, int devnum, u16 upphub,
+int usbhs_set_device_config(struct usbhs_priv *priv, int devnum, u16 upphub,
 			   u16 hubport, u16 speed);
 
 /*
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index ffdf5d1..b51fcd8 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -56,7 +56,7 @@
 void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
 		    void (*done)(struct usbhs_priv *priv,
 				 struct usbhs_pkt *pkt),
-		    void *buf, int len, int zero)
+		    void *buf, int len, int zero, int sequence)
 {
 	struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
 	struct device *dev = usbhs_priv_to_dev(priv);
@@ -90,6 +90,7 @@
 	pkt->zero	= zero;
 	pkt->actual	= 0;
 	pkt->done	= done;
+	pkt->sequence	= sequence;
 
 	usbhs_unlock(priv, flags);
 	/********************  spin unlock ******************/
@@ -481,6 +482,9 @@
 	int i, ret, len;
 	int is_short;
 
+	usbhs_pipe_data_sequence(pipe, pkt->sequence);
+	pkt->sequence = -1; /* -1 sequence will be ignored */
+
 	ret = usbhsf_fifo_select(pipe, fifo, 1);
 	if (ret < 0)
 		return 0;
@@ -584,6 +588,8 @@
 	/*
 	 * pipe enable to prepare packet receive
 	 */
+	usbhs_pipe_data_sequence(pipe, pkt->sequence);
+	pkt->sequence = -1; /* -1 sequence will be ignored */
 
 	usbhs_pipe_enable(pipe);
 	usbhsf_rx_irq_ctrl(pipe, 1);
@@ -641,6 +647,7 @@
 	 * "Operation" - "FIFO Buffer Memory" - "FIFO Port Function"
 	 */
 	if (0 == rcv_len) {
+		pkt->zero = 1;
 		usbhsf_fifo_clear(pipe, fifo);
 		goto usbhs_fifo_read_end;
 	}
diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h
index 32a7b24..f68609c 100644
--- a/drivers/usb/renesas_usbhs/fifo.h
+++ b/drivers/usb/renesas_usbhs/fifo.h
@@ -59,6 +59,7 @@
 	int trans;
 	int actual;
 	int zero;
+	int sequence;
 };
 
 struct usbhs_pkt_handle {
@@ -95,7 +96,7 @@
 void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
 		    void (*done)(struct usbhs_priv *priv,
 				 struct usbhs_pkt *pkt),
-		    void *buf, int len, int zero);
+		    void *buf, int len, int zero, int sequence);
 struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt);
 void usbhs_pkt_start(struct usbhs_pipe *pipe);
 
diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c
index ad96a38..1b97fb1 100644
--- a/drivers/usb/renesas_usbhs/mod.c
+++ b/drivers/usb/renesas_usbhs/mod.c
@@ -50,7 +50,9 @@
 {
 	struct platform_device *pdev = usbhs_priv_to_pdev(priv);
 
-	return usbhsc_drvcllbck_notify_hotplug(pdev);
+	renesas_usbhs_call_notify_hotplug(pdev);
+
+	return 0;
 }
 
 void usbhs_mod_autonomy_mode(struct usbhs_priv *priv)
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 7f4e803..528691d5f 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -14,6 +14,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
+#include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/io.h>
 #include <linux/module.h>
@@ -44,7 +45,6 @@
 struct usbhsg_gpriv {
 	struct usb_gadget	 gadget;
 	struct usbhs_mod	 mod;
-	struct list_head	 link;
 
 	struct usbhsg_uep	*uep;
 	int			 uep_size;
@@ -114,16 +114,6 @@
 #define usbhsg_status_clr(gp, b) (gp->status &= ~b)
 #define usbhsg_status_has(gp, b) (gp->status &   b)
 
-/* controller */
-LIST_HEAD(the_controller_link);
-
-#define usbhsg_for_each_controller(gpriv)\
-	list_for_each_entry(gpriv, &the_controller_link, link)
-#define usbhsg_controller_register(gpriv)\
-	list_add_tail(&(gpriv)->link, &the_controller_link)
-#define usbhsg_controller_unregister(gpriv)\
-	list_del_init(&(gpriv)->link)
-
 /*
  *		queue push/pop
  */
@@ -164,7 +154,7 @@
 	req->actual = 0;
 	req->status = -EINPROGRESS;
 	usbhs_pkt_push(pipe, pkt, usbhsg_queue_done,
-		       req->buf, req->length, req->zero);
+		       req->buf, req->length, req->zero, -1);
 	usbhs_pkt_start(pipe);
 
 	dev_dbg(dev, "pipe %d : queue push (%d)\n",
@@ -195,7 +185,7 @@
 	}
 
 	if (dma_mapping_error(dev, pkt->dma)) {
-		dev_err(dev, "dma mapping error %x\n", pkt->dma);
+		dev_err(dev, "dma mapping error %llx\n", (u64)pkt->dma);
 		return -EIO;
 	}
 
@@ -271,6 +261,8 @@
 
 	usbhsg_recip_handler_std_control_done(priv, uep, ctrl);
 
+	usbhs_pkt_start(pipe);
+
 	return 0;
 }
 
@@ -282,6 +274,145 @@
 };
 
 /*
+ *		USB_TYPE_STANDARD / set feature functions
+ */
+static int usbhsg_recip_handler_std_set_device(struct usbhs_priv *priv,
+						 struct usbhsg_uep *uep,
+						 struct usb_ctrlrequest *ctrl)
+{
+	switch (le16_to_cpu(ctrl->wValue)) {
+	case USB_DEVICE_TEST_MODE:
+		usbhsg_recip_handler_std_control_done(priv, uep, ctrl);
+		udelay(100);
+		usbhs_sys_set_test_mode(priv, le16_to_cpu(ctrl->wIndex >> 8));
+		break;
+	default:
+		usbhsg_recip_handler_std_control_done(priv, uep, ctrl);
+		break;
+	}
+
+	return 0;
+}
+
+static int usbhsg_recip_handler_std_set_endpoint(struct usbhs_priv *priv,
+						 struct usbhsg_uep *uep,
+						 struct usb_ctrlrequest *ctrl)
+{
+	struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
+
+	usbhs_pipe_stall(pipe);
+
+	usbhsg_recip_handler_std_control_done(priv, uep, ctrl);
+
+	return 0;
+}
+
+struct usbhsg_recip_handle req_set_feature = {
+	.name		= "set feature",
+	.device		= usbhsg_recip_handler_std_set_device,
+	.interface	= usbhsg_recip_handler_std_control_done,
+	.endpoint	= usbhsg_recip_handler_std_set_endpoint,
+};
+
+/*
+ *		USB_TYPE_STANDARD / get status functions
+ */
+static void __usbhsg_recip_send_complete(struct usb_ep *ep,
+					 struct usb_request *req)
+{
+	struct usbhsg_request *ureq = usbhsg_req_to_ureq(req);
+
+	/* free allocated recip-buffer/usb_request */
+	kfree(ureq->pkt.buf);
+	usb_ep_free_request(ep, req);
+}
+
+static void __usbhsg_recip_send_status(struct usbhsg_gpriv *gpriv,
+				       unsigned short status)
+{
+	struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv);
+	struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(dcp);
+	struct device *dev = usbhsg_gpriv_to_dev(gpriv);
+	struct usb_request *req;
+	unsigned short *buf;
+
+	/* alloc new usb_request for recip */
+	req = usb_ep_alloc_request(&dcp->ep, GFP_ATOMIC);
+	if (!req) {
+		dev_err(dev, "recip request allocation fail\n");
+		return;
+	}
+
+	/* alloc recip data buffer */
+	buf = kmalloc(sizeof(*buf), GFP_ATOMIC);
+	if (!buf) {
+		usb_ep_free_request(&dcp->ep, req);
+		dev_err(dev, "recip data allocation fail\n");
+		return;
+	}
+
+	/* recip data is status */
+	*buf = cpu_to_le16(status);
+
+	/* allocated usb_request/buffer will be freed */
+	req->complete	= __usbhsg_recip_send_complete;
+	req->buf	= buf;
+	req->length	= sizeof(*buf);
+	req->zero	= 0;
+
+	/* push packet */
+	pipe->handler = &usbhs_fifo_pio_push_handler;
+	usbhsg_queue_push(dcp, usbhsg_req_to_ureq(req));
+}
+
+static int usbhsg_recip_handler_std_get_device(struct usbhs_priv *priv,
+					       struct usbhsg_uep *uep,
+					       struct usb_ctrlrequest *ctrl)
+{
+	struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
+	unsigned short status = 1 << USB_DEVICE_SELF_POWERED;
+
+	__usbhsg_recip_send_status(gpriv, status);
+
+	return 0;
+}
+
+static int usbhsg_recip_handler_std_get_interface(struct usbhs_priv *priv,
+						  struct usbhsg_uep *uep,
+						  struct usb_ctrlrequest *ctrl)
+{
+	struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
+	unsigned short status = 0;
+
+	__usbhsg_recip_send_status(gpriv, status);
+
+	return 0;
+}
+
+static int usbhsg_recip_handler_std_get_endpoint(struct usbhs_priv *priv,
+						 struct usbhsg_uep *uep,
+						 struct usb_ctrlrequest *ctrl)
+{
+	struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
+	struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
+	unsigned short status = 0;
+
+	if (usbhs_pipe_is_stall(pipe))
+		status = 1 << USB_ENDPOINT_HALT;
+
+	__usbhsg_recip_send_status(gpriv, status);
+
+	return 0;
+}
+
+struct usbhsg_recip_handle req_get_status = {
+	.name		= "get status",
+	.device		= usbhsg_recip_handler_std_get_device,
+	.interface	= usbhsg_recip_handler_std_get_interface,
+	.endpoint	= usbhsg_recip_handler_std_get_endpoint,
+};
+
+/*
  *		USB_TYPE handler
  */
 static int usbhsg_recip_run_handle(struct usbhs_priv *priv,
@@ -303,8 +434,7 @@
 	pipe = usbhsg_uep_to_pipe(uep);
 	if (!pipe) {
 		dev_err(dev, "wrong recip request\n");
-		ret = -EINVAL;
-		goto usbhsg_recip_run_handle_end;
+		return -EINVAL;
 	}
 
 	switch (recip) {
@@ -327,20 +457,10 @@
 	}
 
 	if (func) {
-		unsigned long flags;
-
 		dev_dbg(dev, "%s (pipe %d :%s)\n", handler->name, nth, msg);
-
-		/********************  spin lock ********************/
-		usbhs_lock(priv, flags);
 		ret = func(priv, uep, ctrl);
-		usbhs_unlock(priv, flags);
-		/********************  spin unlock ******************/
 	}
 
-usbhsg_recip_run_handle_end:
-	usbhs_pkt_start(pipe);
-
 	return ret;
 }
 
@@ -412,6 +532,12 @@
 		case USB_REQ_CLEAR_FEATURE:
 			recip_handler = &req_clear_feature;
 			break;
+		case USB_REQ_SET_FEATURE:
+			recip_handler = &req_set_feature;
+			break;
+		case USB_REQ_GET_STATUS:
+			recip_handler = &req_get_status;
+			break;
 		}
 	}
 
@@ -439,14 +565,16 @@
 	struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
 	struct usbhs_pkt *pkt;
 
-	usbhs_pipe_disable(pipe);
-
 	while (1) {
 		pkt = usbhs_pkt_pop(pipe, NULL);
 		if (!pkt)
 			break;
+
+		usbhsg_queue_pop(uep, usbhsg_pkt_to_ureq(pkt), -ECONNRESET);
 	}
 
+	usbhs_pipe_disable(pipe);
+
 	return 0;
 }
 
@@ -681,9 +809,7 @@
 	 * - function
 	 * - usb module
 	 */
-	usbhs_sys_hispeed_ctrl(priv, 1);
 	usbhs_sys_function_ctrl(priv, 1);
-	usbhs_sys_usb_ctrl(priv, 1);
 
 	/*
 	 * enable irq callback
@@ -731,9 +857,8 @@
 	gpriv->gadget.speed = USB_SPEED_UNKNOWN;
 
 	/* disable sys */
-	usbhs_sys_hispeed_ctrl(priv, 0);
+	usbhs_sys_set_test_mode(priv, 0);
 	usbhs_sys_function_ctrl(priv, 0);
-	usbhs_sys_usb_ctrl(priv, 0);
 
 	usbhsg_pipe_disable(dcp);
 
@@ -755,7 +880,7 @@
 
 	if (!driver		||
 	    !driver->setup	||
-	    driver->speed < USB_SPEED_FULL)
+	    driver->max_speed < USB_SPEED_FULL)
 		return -EINVAL;
 
 	/* first hook up the driver ... */
@@ -866,7 +991,7 @@
 	gpriv->gadget.dev.parent	= dev;
 	gpriv->gadget.name		= "renesas_usbhs_udc";
 	gpriv->gadget.ops		= &usbhsg_gadget_ops;
-	gpriv->gadget.is_dualspeed	= 1;
+	gpriv->gadget.max_speed		= USB_SPEED_HIGH;
 	ret = device_register(&gpriv->gadget.dev);
 	if (ret < 0)
 		goto err_add_udc;
@@ -896,8 +1021,6 @@
 		}
 	}
 
-	usbhsg_controller_register(gpriv);
-
 	ret = usb_add_gadget_udc(dev, &gpriv->gadget);
 	if (ret)
 		goto err_register;
@@ -926,8 +1049,6 @@
 
 	device_unregister(&gpriv->gadget.dev);
 
-	usbhsg_controller_unregister(gpriv);
-
 	kfree(gpriv->uep);
 	kfree(gpriv);
 }
diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c
index 7955de5..1834cf5 100644
--- a/drivers/usb/renesas_usbhs/mod_host.c
+++ b/drivers/usb/renesas_usbhs/mod_host.c
@@ -45,36 +45,34 @@
  *
  * +--------+					pipes are reused for each uep.
  * | udev 1 |-+- [uep 0 (dcp) ] --+		pipe will be switched when
- * +--------+ |			  |		target device was changed
+ * +--------+ |			  |		other device requested
  *	      +- [uep 1 (bulk)]	--|---+		   +--------------+
  *	      |			  +--------------> | pipe0 (dcp)  |
- *	      +- [uep 2 (bulk)]	--|---|---+	   +--------------+
- *				  |   |	  |	   | pipe1 (isoc) |
- * +--------+			  |   |	  |	   +--------------+
- * | udev 2 |-+- [uep 0 (dcp) ]	--+   +-- |------> | pipe2 (bulk) |
- * +--------+ |			  |   |	  |	   +--------------+
- *	      +- [uep 1 (int) ]	--|-+ |	  +------> | pipe3 (bulk) |
- *				  | | |	  |	   +--------------+
- * +--------+			  | +-|---|------> | pipe4 (int)  |
- * | udev 3 |-+- [uep 0 (dcp) ]	--+   |	  |	   +--------------+
- * +--------+ |			      |	  |	   | ....	  |
- *	      +- [uep 1 (bulk)]	------+	  |	   | ....	  |
+ *	      +- [uep 2 (bulk)]	-@    |		   +--------------+
+ *				      |		   | pipe1 (isoc) |
+ * +--------+			      |		   +--------------+
+ * | udev 2 |-+- [uep 0 (dcp) ]	-@    +----------> | pipe2 (bulk) |
+ * +--------+ |					   +--------------+
+ *	      +- [uep 1 (int) ]	----+	  +------> | pipe3 (bulk) |
+ *				    |	  |	   +--------------+
+ * +--------+			    +-----|------> | pipe4 (int)  |
+ * | udev 3 |-+- [uep 0 (dcp) ]	-@	  |	   +--------------+
+ * +--------+ |				  |	   | ....	  |
+ *	      +- [uep 1 (bulk)]	-@	  |	   | ....	  |
  *	      |				  |
  *	      +- [uep 2 (bulk)]-----------+
+ *
+ * @ :	uep requested free pipe, but all have been used.
+ *	now it is waiting for free pipe
  */
 
 
 /*
  *		struct
  */
-struct usbhsh_pipe_info {
-	unsigned int		usr_cnt; /* see usbhsh_endpoint_alloc() */
-};
-
 struct usbhsh_request {
 	struct urb		*urb;
 	struct usbhs_pkt	pkt;
-	struct list_head	ureq_link; /* see hpriv :: ureq_link_xxx */
 };
 
 struct usbhsh_device {
@@ -83,11 +81,10 @@
 };
 
 struct usbhsh_ep {
-	struct usbhs_pipe	*pipe;
+	struct usbhs_pipe	*pipe;   /* attached pipe */
 	struct usbhsh_device	*udev;   /* attached udev */
+	struct usb_host_endpoint *ep;
 	struct list_head	ep_list; /* list to usbhsh_device */
-
-	int maxp;
 };
 
 #define USBHSH_DEVICE_MAX	10 /* see DEVADDn / DCPMAXP / PIPEMAXP */
@@ -98,16 +95,9 @@
 
 	struct usbhsh_device	udev[USBHSH_DEVICE_MAX];
 
-	struct usbhsh_pipe_info	*pipe_info;
-	int			 pipe_size;
-
 	u32	port_stat;	/* USB_PORT_STAT_xxx */
 
 	struct completion	setup_ack_done;
-
-	/* see usbhsh_req_alloc/free */
-	struct list_head	ureq_link_active;
-	struct list_head	ureq_link_free;
 };
 
 
@@ -119,17 +109,6 @@
 #define usbhsh_priv_to_hpriv(priv) \
 	container_of(usbhs_mod_get(priv, USBHS_HOST), struct usbhsh_hpriv, mod)
 
-#define __usbhsh_for_each_hpipe(start, pos, h, i)	\
-	for (i = start, pos = (h)->hpipe + i;		\
-	     i < (h)->hpipe_size;			\
-	     i++, pos = (h)->hpipe + i)
-
-#define usbhsh_for_each_hpipe(pos, hpriv, i)	\
-	__usbhsh_for_each_hpipe(1, pos, hpriv, i)
-
-#define usbhsh_for_each_hpipe_with_dcp(pos, hpriv, i)	\
-	__usbhsh_for_each_hpipe(0, pos, hpriv, i)
-
 #define __usbhsh_for_each_udev(start, pos, h, i)	\
 	for (i = start, pos = (h)->udev + i;		\
 	     i < USBHSH_DEVICE_MAX;			\
@@ -152,15 +131,20 @@
 #define usbhsh_ep_to_uep(u)	((u)->hcpriv)
 #define usbhsh_uep_to_pipe(u)	((u)->pipe)
 #define usbhsh_uep_to_udev(u)	((u)->udev)
+#define usbhsh_uep_to_ep(u)	((u)->ep)
+
 #define usbhsh_urb_to_ureq(u)	((u)->hcpriv)
 #define usbhsh_urb_to_usbv(u)	((u)->dev)
 
 #define usbhsh_usbv_to_udev(d)	dev_get_drvdata(&(d)->dev)
 
 #define usbhsh_udev_to_usbv(h)	((h)->usbv)
+#define usbhsh_udev_is_used(h)	usbhsh_udev_to_usbv(h)
 
-#define usbhsh_pipe_info(p)	((p)->mod_private)
+#define usbhsh_pipe_to_uep(p)	((p)->mod_private)
 
+#define usbhsh_device_parent(d)		(usbhsh_usbv_to_udev((d)->usbv->parent))
+#define usbhsh_device_hubport(d)	((d)->usbv->portnum)
 #define usbhsh_device_number(h, d)	((int)((d) - (h)->udev))
 #define usbhsh_device_nth(h, d)		((h)->udev + d)
 #define usbhsh_device0(h)		usbhsh_device_nth(h, 0)
@@ -170,38 +154,13 @@
 #define usbhsh_port_stat_clear(h, s)	((h)->port_stat &= ~(s))
 #define usbhsh_port_stat_get(h)		((h)->port_stat)
 
-#define usbhsh_pkt_to_req(p)	\
+#define usbhsh_pkt_to_ureq(p)	\
 	container_of((void *)p, struct usbhsh_request, pkt)
 
 /*
  *		req alloc/free
  */
-static void usbhsh_req_list_init(struct usbhsh_hpriv *hpriv)
-{
-	INIT_LIST_HEAD(&hpriv->ureq_link_active);
-	INIT_LIST_HEAD(&hpriv->ureq_link_free);
-}
-
-static void usbhsh_req_list_quit(struct usbhsh_hpriv *hpriv)
-{
-	struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
-	struct device *dev = usbhsh_hcd_to_dev(hcd);
-	struct usbhsh_request *ureq, *next;
-
-	/* kfree all active ureq */
-	list_for_each_entry_safe(ureq, next,
-				 &hpriv->ureq_link_active,
-				 ureq_link) {
-		dev_err(dev, "active ureq (%p) is force freed\n", ureq);
-		kfree(ureq);
-	}
-
-	/* kfree all free ureq */
-	list_for_each_entry_safe(ureq, next, &hpriv->ureq_link_free, ureq_link)
-		kfree(ureq);
-}
-
-static struct usbhsh_request *usbhsh_req_alloc(struct usbhsh_hpriv *hpriv,
+static struct usbhsh_request *usbhsh_ureq_alloc(struct usbhsh_hpriv *hpriv,
 					       struct urb *urb,
 					       gfp_t mem_flags)
 {
@@ -209,117 +168,414 @@
 	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
 	struct device *dev = usbhs_priv_to_dev(priv);
 
-	if (list_empty(&hpriv->ureq_link_free)) {
-		/*
-		 * create new one if there is no free ureq
-		 */
-		ureq = kzalloc(sizeof(struct usbhsh_request), mem_flags);
-		if (ureq)
-			INIT_LIST_HEAD(&ureq->ureq_link);
-	} else {
-		/*
-		 * reuse "free" ureq if exist
-		 */
-		ureq = list_entry(hpriv->ureq_link_free.next,
-				  struct usbhsh_request,
-				  ureq_link);
-		if (ureq)
-			list_del_init(&ureq->ureq_link);
-	}
-
+	ureq = kzalloc(sizeof(struct usbhsh_request), mem_flags);
 	if (!ureq) {
 		dev_err(dev, "ureq alloc fail\n");
 		return NULL;
 	}
 
 	usbhs_pkt_init(&ureq->pkt);
-
-	/*
-	 * push it to "active" list
-	 */
-	list_add_tail(&ureq->ureq_link, &hpriv->ureq_link_active);
 	ureq->urb = urb;
+	usbhsh_urb_to_ureq(urb) = ureq;
 
 	return ureq;
 }
 
-static void usbhsh_req_free(struct usbhsh_hpriv *hpriv,
+static void usbhsh_ureq_free(struct usbhsh_hpriv *hpriv,
 			    struct usbhsh_request *ureq)
 {
-	struct usbhs_pkt *pkt = &ureq->pkt;
+	usbhsh_urb_to_ureq(ureq->urb) = NULL;
+	ureq->urb = NULL;
 
-	usbhs_pkt_init(pkt);
+	kfree(ureq);
+}
+
+/*
+ *		status
+ */
+static int usbhsh_is_running(struct usbhsh_hpriv *hpriv)
+{
+	/*
+	 * we can decide some device is attached or not
+	 * by checking mod.irq_attch
+	 * see
+	 *	usbhsh_irq_attch()
+	 *	usbhsh_irq_dtch()
+	 */
+	return (hpriv->mod.irq_attch == NULL);
+}
+
+/*
+ *		pipe control
+ */
+static void usbhsh_endpoint_sequence_save(struct usbhsh_hpriv *hpriv,
+					  struct urb *urb,
+					  struct usbhs_pkt *pkt)
+{
+	int len = urb->actual_length;
+	int maxp = usb_endpoint_maxp(&urb->ep->desc);
+	int t = 0;
+
+	/* DCP is out of sequence control */
+	if (usb_pipecontrol(urb->pipe))
+		return;
 
 	/*
-	 * removed from "active" list,
-	 * and push it to "free" list
+	 * renesas_usbhs pipe has a limitation in a number.
+	 * So, driver should re-use the limited pipe for each device/endpoint.
+	 * DATA0/1 sequence should be saved for it.
+	 * see [image of mod_host]
+	 *     [HARDWARE LIMITATION]
 	 */
-	ureq->urb = NULL;
-	list_del_init(&ureq->ureq_link);
-	list_add_tail(&ureq->ureq_link, &hpriv->ureq_link_free);
+
+	/*
+	 * next sequence depends on actual_length
+	 *
+	 * ex) actual_length = 1147, maxp = 512
+	 * data0 : 512
+	 * data1 : 512
+	 * data0 : 123
+	 * data1 is the next sequence
+	 */
+	t = len / maxp;
+	if (len % maxp)
+		t++;
+	if (pkt->zero)
+		t++;
+	t %= 2;
+
+	if (t)
+		usb_dotoggle(urb->dev,
+			     usb_pipeendpoint(urb->pipe),
+			     usb_pipeout(urb->pipe));
+}
+
+static struct usbhsh_device *usbhsh_device_get(struct usbhsh_hpriv *hpriv,
+					       struct urb *urb);
+
+static int usbhsh_pipe_attach(struct usbhsh_hpriv *hpriv,
+			      struct urb *urb)
+{
+	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+	struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep);
+	struct usbhsh_device *udev = usbhsh_device_get(hpriv, urb);
+	struct usbhs_pipe *pipe;
+	struct usb_endpoint_descriptor *desc = &urb->ep->desc;
+	struct device *dev = usbhs_priv_to_dev(priv);
+	unsigned long flags;
+	int dir_in_req = !!usb_pipein(urb->pipe);
+	int is_dcp = usb_endpoint_xfer_control(desc);
+	int i, dir_in;
+	int ret = -EBUSY;
+
+	/********************  spin lock ********************/
+	usbhs_lock(priv, flags);
+
+	if (unlikely(usbhsh_uep_to_pipe(uep))) {
+		dev_err(dev, "uep already has pipe\n");
+		goto usbhsh_pipe_attach_done;
+	}
+
+	usbhs_for_each_pipe_with_dcp(pipe, priv, i) {
+
+		/* check pipe type */
+		if (!usbhs_pipe_type_is(pipe, usb_endpoint_type(desc)))
+			continue;
+
+		/* check pipe direction if normal pipe */
+		if (!is_dcp) {
+			dir_in = !!usbhs_pipe_is_dir_in(pipe);
+			if (0 != (dir_in - dir_in_req))
+				continue;
+		}
+
+		/* check pipe is free */
+		if (usbhsh_pipe_to_uep(pipe))
+			continue;
+
+		/*
+		 * attach pipe to uep
+		 *
+		 * usbhs_pipe_config_update() should be called after
+		 * usbhs_set_device_config()
+		 * see
+		 *  DCPMAXP/PIPEMAXP
+		 */
+		usbhsh_uep_to_pipe(uep)		= pipe;
+		usbhsh_pipe_to_uep(pipe)	= uep;
+
+		usbhs_pipe_config_update(pipe,
+					 usbhsh_device_number(hpriv, udev),
+					 usb_endpoint_num(desc),
+					 usb_endpoint_maxp(desc));
+
+		dev_dbg(dev, "%s [%d-%d(%s:%s)]\n", __func__,
+			usbhsh_device_number(hpriv, udev),
+			usb_endpoint_num(desc),
+			usbhs_pipe_name(pipe),
+			dir_in_req ? "in" : "out");
+
+		ret = 0;
+		break;
+	}
+
+usbhsh_pipe_attach_done:
+	usbhs_unlock(priv, flags);
+	/********************  spin unlock ******************/
+
+	return ret;
+}
+
+static void usbhsh_pipe_detach(struct usbhsh_hpriv *hpriv,
+			       struct usbhsh_ep *uep)
+{
+	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+	struct usbhs_pipe *pipe;
+	struct device *dev = usbhs_priv_to_dev(priv);
+	unsigned long flags;
+
+	/********************  spin lock ********************/
+	usbhs_lock(priv, flags);
+
+	pipe = usbhsh_uep_to_pipe(uep);
+
+	if (unlikely(!pipe)) {
+		dev_err(dev, "uep doens't have pipe\n");
+	} else {
+		struct usb_host_endpoint *ep = usbhsh_uep_to_ep(uep);
+		struct usbhsh_device *udev = usbhsh_uep_to_udev(uep);
+
+		/* detach pipe from uep */
+		usbhsh_uep_to_pipe(uep)		= NULL;
+		usbhsh_pipe_to_uep(pipe)	= NULL;
+
+		dev_dbg(dev, "%s [%d-%d(%s)]\n", __func__,
+			usbhsh_device_number(hpriv, udev),
+			usb_endpoint_num(&ep->desc),
+			usbhs_pipe_name(pipe));
+	}
+
+	usbhs_unlock(priv, flags);
+	/********************  spin unlock ******************/
+}
+
+/*
+ *		endpoint control
+ */
+static int usbhsh_endpoint_attach(struct usbhsh_hpriv *hpriv,
+				  struct urb *urb,
+				  gfp_t mem_flags)
+{
+	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+	struct usbhsh_device *udev = usbhsh_device_get(hpriv, urb);
+	struct usb_host_endpoint *ep = urb->ep;
+	struct usbhsh_ep *uep;
+	struct device *dev = usbhs_priv_to_dev(priv);
+	struct usb_endpoint_descriptor *desc = &ep->desc;
+	unsigned long flags;
+
+	uep = kzalloc(sizeof(struct usbhsh_ep), mem_flags);
+	if (!uep) {
+		dev_err(dev, "usbhsh_ep alloc fail\n");
+		return -ENOMEM;
+	}
+
+	/********************  spin lock ********************/
+	usbhs_lock(priv, flags);
+
+	/*
+	 * init endpoint
+	 */
+	INIT_LIST_HEAD(&uep->ep_list);
+	list_add_tail(&uep->ep_list, &udev->ep_list_head);
+
+	usbhsh_uep_to_udev(uep)	= udev;
+	usbhsh_uep_to_ep(uep)	= ep;
+	usbhsh_ep_to_uep(ep)	= uep;
+
+	usbhs_unlock(priv, flags);
+	/********************  spin unlock ******************/
+
+	dev_dbg(dev, "%s [%d-%d]\n", __func__,
+		usbhsh_device_number(hpriv, udev),
+		usb_endpoint_num(desc));
+
+	return 0;
+}
+
+static void usbhsh_endpoint_detach(struct usbhsh_hpriv *hpriv,
+				   struct usb_host_endpoint *ep)
+{
+	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+	struct device *dev = usbhs_priv_to_dev(priv);
+	struct usbhsh_ep *uep = usbhsh_ep_to_uep(ep);
+	unsigned long flags;
+
+	if (!uep)
+		return;
+
+	dev_dbg(dev, "%s [%d-%d]\n", __func__,
+		usbhsh_device_number(hpriv, usbhsh_uep_to_udev(uep)),
+		usb_endpoint_num(&ep->desc));
+
+	if (usbhsh_uep_to_pipe(uep))
+		usbhsh_pipe_detach(hpriv, uep);
+
+	/********************  spin lock ********************/
+	usbhs_lock(priv, flags);
+
+	/* remove this endpoint from udev */
+	list_del_init(&uep->ep_list);
+
+	usbhsh_uep_to_udev(uep)	= NULL;
+	usbhsh_uep_to_ep(uep)	= NULL;
+	usbhsh_ep_to_uep(ep)	= NULL;
+
+	usbhs_unlock(priv, flags);
+	/********************  spin unlock ******************/
+
+	kfree(uep);
+}
+
+static void usbhsh_endpoint_detach_all(struct usbhsh_hpriv *hpriv,
+				       struct usbhsh_device *udev)
+{
+	struct usbhsh_ep *uep, *next;
+
+	list_for_each_entry_safe(uep, next, &udev->ep_list_head, ep_list)
+		usbhsh_endpoint_detach(hpriv, usbhsh_uep_to_ep(uep));
 }
 
 /*
  *		device control
  */
+static int usbhsh_connected_to_rhdev(struct usb_hcd *hcd,
+				     struct usbhsh_device *udev)
+{
+	struct usb_device *usbv = usbhsh_udev_to_usbv(udev);
+
+	return hcd->self.root_hub == usbv->parent;
+}
 
 static int usbhsh_device_has_endpoint(struct usbhsh_device *udev)
 {
 	return !list_empty(&udev->ep_list_head);
 }
 
-static struct usbhsh_device *usbhsh_device_alloc(struct usbhsh_hpriv *hpriv,
+static struct usbhsh_device *usbhsh_device_get(struct usbhsh_hpriv *hpriv,
+					       struct urb *urb)
+{
+	struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
+	struct usbhsh_device *udev = usbhsh_usbv_to_udev(usbv);
+
+	/* usbhsh_device_attach() is still not called */
+	if (!udev)
+		return NULL;
+
+	/* if it is device0, return it */
+	if (0 == usb_pipedevice(urb->pipe))
+		return usbhsh_device0(hpriv);
+
+	/* return attached device */
+	return udev;
+}
+
+static struct usbhsh_device *usbhsh_device_attach(struct usbhsh_hpriv *hpriv,
 						 struct urb *urb)
 {
 	struct usbhsh_device *udev = NULL;
+	struct usbhsh_device *udev0 = usbhsh_device0(hpriv);
+	struct usbhsh_device *pos;
 	struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
 	struct device *dev = usbhsh_hcd_to_dev(hcd);
 	struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
 	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+	unsigned long flags;
+	u16 upphub, hubport;
 	int i;
 
 	/*
-	 * device 0
+	 * This function should be called only while urb is pointing to device0.
+	 * It will attach unused usbhsh_device to urb (usbv),
+	 * and initialize device0.
+	 * You can use usbhsh_device_get() to get "current" udev,
+	 * and usbhsh_usbv_to_udev() is for "attached" udev.
 	 */
-	if (0 == usb_pipedevice(urb->pipe)) {
-		udev = usbhsh_device0(hpriv);
-		goto usbhsh_device_find;
+	if (0 != usb_pipedevice(urb->pipe)) {
+		dev_err(dev, "%s fail: urb isn't pointing device0\n", __func__);
+		return NULL;
 	}
 
+	/********************  spin lock ********************/
+	usbhs_lock(priv, flags);
+
 	/*
 	 * find unused device
 	 */
-	usbhsh_for_each_udev(udev, hpriv, i) {
-		if (usbhsh_udev_to_usbv(udev))
+	usbhsh_for_each_udev(pos, hpriv, i) {
+		if (usbhsh_udev_is_used(pos))
 			continue;
-		goto usbhsh_device_find;
+		udev = pos;
+		break;
 	}
 
-	dev_err(dev, "no free usbhsh_device\n");
+	if (udev) {
+		/*
+		 * usbhsh_usbv_to_udev()
+		 * usbhsh_udev_to_usbv()
+		 * will be enable
+		 */
+		dev_set_drvdata(&usbv->dev, udev);
+		udev->usbv = usbv;
+	}
 
-	return NULL;
+	usbhs_unlock(priv, flags);
+	/********************  spin unlock ******************/
 
-usbhsh_device_find:
-	if (usbhsh_device_has_endpoint(udev))
+	if (!udev) {
+		dev_err(dev, "no free usbhsh_device\n");
+		return NULL;
+	}
+
+	if (usbhsh_device_has_endpoint(udev)) {
 		dev_warn(dev, "udev have old endpoint\n");
+		usbhsh_endpoint_detach_all(hpriv, udev);
+	}
+
+	if (usbhsh_device_has_endpoint(udev0)) {
+		dev_warn(dev, "udev0 have old endpoint\n");
+		usbhsh_endpoint_detach_all(hpriv, udev0);
+	}
 
 	/* uep will be attached */
+	INIT_LIST_HEAD(&udev0->ep_list_head);
 	INIT_LIST_HEAD(&udev->ep_list_head);
 
 	/*
-	 * usbhsh_usbv_to_udev()
-	 * usbhsh_udev_to_usbv()
-	 * will be enable
+	 * set device0 config
 	 */
-	dev_set_drvdata(&usbv->dev, udev);
-	udev->usbv = usbv;
+	usbhs_set_device_config(priv,
+				0, 0, 0, usbv->speed);
 
-	/* set device config */
-	usbhs_set_device_speed(priv,
+	/*
+	 * set new device config
+	 */
+	upphub	= 0;
+	hubport	= 0;
+	if (!usbhsh_connected_to_rhdev(hcd, udev)) {
+		/* if udev is not connected to rhdev, it means parent is Hub */
+		struct usbhsh_device *parent = usbhsh_device_parent(udev);
+
+		upphub	= usbhsh_device_number(hpriv, parent);
+		hubport	= usbhsh_device_hubport(udev);
+
+		dev_dbg(dev, "%s connecte to Hub [%d:%d](%p)\n", __func__,
+			upphub, hubport, parent);
+	}
+
+	usbhs_set_device_config(priv,
 			       usbhsh_device_number(hpriv, udev),
-			       usbhsh_device_number(hpriv, udev),
-			       0, /* FIXME no parent */
-			       usbv->speed);
+			       upphub, hubport, usbv->speed);
 
 	dev_dbg(dev, "%s [%d](%p)\n", __func__,
 		usbhsh_device_number(hpriv, udev), udev);
@@ -327,18 +583,34 @@
 	return udev;
 }
 
-static void usbhsh_device_free(struct usbhsh_hpriv *hpriv,
+static void usbhsh_device_detach(struct usbhsh_hpriv *hpriv,
 			       struct usbhsh_device *udev)
 {
 	struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
+	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
 	struct device *dev = usbhsh_hcd_to_dev(hcd);
 	struct usb_device *usbv = usbhsh_udev_to_usbv(udev);
+	unsigned long flags;
 
 	dev_dbg(dev, "%s [%d](%p)\n", __func__,
 		usbhsh_device_number(hpriv, udev), udev);
 
-	if (usbhsh_device_has_endpoint(udev))
+	if (usbhsh_device_has_endpoint(udev)) {
 		dev_warn(dev, "udev still have endpoint\n");
+		usbhsh_endpoint_detach_all(hpriv, udev);
+	}
+
+	/*
+	 * There is nothing to do if it is device0.
+	 * see
+	 *  usbhsh_device_attach()
+	 *  usbhsh_device_get()
+	 */
+	if (0 == usbhsh_device_number(hpriv, udev))
+		return;
+
+	/********************  spin lock ********************/
+	usbhs_lock(priv, flags);
 
 	/*
 	 * usbhsh_usbv_to_udev()
@@ -347,132 +619,9 @@
 	 */
 	dev_set_drvdata(&usbv->dev, NULL);
 	udev->usbv = NULL;
-}
 
-/*
- *		end-point control
- */
-struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv,
-					struct usbhsh_device *udev,
-					struct usb_host_endpoint *ep,
-					int dir_in_req,
-					gfp_t mem_flags)
-{
-	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
-	struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
-	struct usbhsh_ep *uep;
-	struct usbhsh_pipe_info *info;
-	struct usbhs_pipe *pipe, *best_pipe;
-	struct device *dev = usbhsh_hcd_to_dev(hcd);
-	struct usb_endpoint_descriptor *desc = &ep->desc;
-	int type, i, dir_in;
-	unsigned int min_usr;
-
-	dir_in_req = !!dir_in_req;
-
-	uep = kzalloc(sizeof(struct usbhsh_ep), mem_flags);
-	if (!uep) {
-		dev_err(dev, "usbhsh_ep alloc fail\n");
-		return NULL;
-	}
-
-	if (usb_endpoint_xfer_control(desc)) {
-		best_pipe = usbhsh_hpriv_to_dcp(hpriv);
-		goto usbhsh_endpoint_alloc_find_pipe;
-	}
-
-	/*
-	 * find best pipe for endpoint
-	 * see
-	 *	HARDWARE LIMITATION
-	 */
-	type = usb_endpoint_type(desc);
-	min_usr = ~0;
-	best_pipe = NULL;
-	usbhs_for_each_pipe(pipe, priv, i) {
-		if (!usbhs_pipe_type_is(pipe, type))
-			continue;
-
-		dir_in = !!usbhs_pipe_is_dir_in(pipe);
-		if (0 != (dir_in - dir_in_req))
-			continue;
-
-		info = usbhsh_pipe_info(pipe);
-
-		if (min_usr > info->usr_cnt) {
-			min_usr		= info->usr_cnt;
-			best_pipe	= pipe;
-		}
-	}
-
-	if (unlikely(!best_pipe)) {
-		dev_err(dev, "couldn't find best pipe\n");
-		kfree(uep);
-		return NULL;
-	}
-usbhsh_endpoint_alloc_find_pipe:
-	/*
-	 * init uep
-	 */
-	uep->pipe	= best_pipe;
-	uep->maxp	= usb_endpoint_maxp(desc);
-	usbhsh_uep_to_udev(uep)	= udev;
-	usbhsh_ep_to_uep(ep)	= uep;
-
-	/*
-	 * update pipe user count
-	 */
-	info = usbhsh_pipe_info(best_pipe);
-	info->usr_cnt++;
-
-	/* init this endpoint, and attach it to udev */
-	INIT_LIST_HEAD(&uep->ep_list);
-	list_add_tail(&uep->ep_list, &udev->ep_list_head);
-
-	/*
-	 * usbhs_pipe_config_update() should be called after
-	 * usbhs_device_config()
-	 * see
-	 *  DCPMAXP/PIPEMAXP
-	 */
-	usbhs_pipe_sequence_data0(uep->pipe);
-	usbhs_pipe_config_update(uep->pipe,
-				 usbhsh_device_number(hpriv, udev),
-				 usb_endpoint_num(desc),
-				 uep->maxp);
-
-	dev_dbg(dev, "%s [%d-%s](%p)\n", __func__,
-		usbhsh_device_number(hpriv, udev),
-		usbhs_pipe_name(uep->pipe), uep);
-
-	return uep;
-}
-
-void usbhsh_endpoint_free(struct usbhsh_hpriv *hpriv,
-			  struct usb_host_endpoint *ep)
-{
-	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
-	struct device *dev = usbhs_priv_to_dev(priv);
-	struct usbhsh_ep *uep = usbhsh_ep_to_uep(ep);
-	struct usbhsh_pipe_info *info;
-
-	if (!uep)
-		return;
-
-	dev_dbg(dev, "%s [%d-%s](%p)\n", __func__,
-		usbhsh_device_number(hpriv, usbhsh_uep_to_udev(uep)),
-		usbhs_pipe_name(uep->pipe), uep);
-
-	info = usbhsh_pipe_info(uep->pipe);
-	info->usr_cnt--;
-
-	/* remove this endpoint from udev */
-	list_del_init(&uep->ep_list);
-
-	usbhsh_uep_to_udev(uep) = NULL;
-	usbhsh_ep_to_uep(ep) = NULL;
-
-	kfree(uep);
+	usbhs_unlock(priv, flags);
+	/********************  spin unlock ******************/
 }
 
 /*
@@ -480,11 +629,12 @@
  */
 static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt)
 {
-	struct usbhsh_request *ureq = usbhsh_pkt_to_req(pkt);
+	struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt);
 	struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);
 	struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
 	struct urb *urb = ureq->urb;
 	struct device *dev = usbhs_priv_to_dev(priv);
+	int status = 0;
 
 	dev_dbg(dev, "%s\n", __func__);
 
@@ -493,29 +643,43 @@
 		return;
 	}
 
+	if (!usbhsh_is_running(hpriv))
+		status = -ESHUTDOWN;
+
 	urb->actual_length = pkt->actual;
-	usbhsh_req_free(hpriv, ureq);
-	usbhsh_urb_to_ureq(urb) = NULL;
+	usbhsh_ureq_free(hpriv, ureq);
+
+	usbhsh_endpoint_sequence_save(hpriv, urb, pkt);
+	usbhsh_pipe_detach(hpriv, usbhsh_ep_to_uep(urb->ep));
 
 	usb_hcd_unlink_urb_from_ep(hcd, urb);
-	usb_hcd_giveback_urb(hcd, urb, 0);
+	usb_hcd_giveback_urb(hcd, urb, status);
 }
 
 static int usbhsh_queue_push(struct usb_hcd *hcd,
-			     struct usbhs_pipe *pipe,
-			     struct urb *urb)
+			     struct urb *urb,
+			     gfp_t mem_flags)
 {
-	struct usbhsh_request *ureq = usbhsh_urb_to_ureq(urb);
-	struct usbhs_pkt *pkt = &ureq->pkt;
+	struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd);
+	struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep);
+	struct usbhs_pipe *pipe = usbhsh_uep_to_pipe(uep);
 	struct device *dev = usbhsh_hcd_to_dev(hcd);
+	struct usbhsh_request *ureq;
 	void *buf;
-	int len;
+	int len, sequence;
 
 	if (usb_pipeisoc(urb->pipe)) {
 		dev_err(dev, "pipe iso is not supported now\n");
 		return -EIO;
 	}
 
+	/* this ureq will be freed on usbhsh_queue_done() */
+	ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags);
+	if (unlikely(!ureq)) {
+		dev_err(dev, "ureq alloc fail\n");
+		return -ENOMEM;
+	}
+
 	if (usb_pipein(urb->pipe))
 		pipe->handler = &usbhs_fifo_pio_pop_handler;
 	else
@@ -524,25 +688,59 @@
 	buf = (void *)(urb->transfer_buffer + urb->actual_length);
 	len = urb->transfer_buffer_length - urb->actual_length;
 
+	sequence = usb_gettoggle(urb->dev,
+				 usb_pipeendpoint(urb->pipe),
+				 usb_pipeout(urb->pipe));
+
 	dev_dbg(dev, "%s\n", __func__);
-	usbhs_pkt_push(pipe, pkt, usbhsh_queue_done,
-		       buf, len, (urb->transfer_flags & URB_ZERO_PACKET));
+	usbhs_pkt_push(pipe, &ureq->pkt, usbhsh_queue_done,
+		       buf, len, (urb->transfer_flags & URB_ZERO_PACKET),
+		       sequence);
+
 	usbhs_pkt_start(pipe);
 
 	return 0;
 }
 
+static void usbhsh_queue_force_pop(struct usbhs_priv *priv,
+				   struct usbhs_pipe *pipe)
+{
+	struct usbhs_pkt *pkt;
+
+	while (1) {
+		pkt = usbhs_pkt_pop(pipe, NULL);
+		if (!pkt)
+			break;
+
+		/*
+		 * if all packet are gone, usbhsh_endpoint_disable()
+		 * will be called.
+		 * then, attached device/endpoint/pipe will be detached
+		 */
+		usbhsh_queue_done(priv, pkt);
+	}
+}
+
+static void usbhsh_queue_force_pop_all(struct usbhs_priv *priv)
+{
+	struct usbhs_pipe *pos;
+	int i;
+
+	usbhs_for_each_pipe_with_dcp(pos, priv, i)
+		usbhsh_queue_force_pop(priv, pos);
+}
+
 /*
  *		DCP setup stage
  */
 static int usbhsh_is_request_address(struct urb *urb)
 {
-	struct usb_ctrlrequest *cmd;
+	struct usb_ctrlrequest *req;
 
-	cmd = (struct usb_ctrlrequest *)urb->setup_packet;
+	req = (struct usb_ctrlrequest *)urb->setup_packet;
 
-	if ((DeviceOutRequest    == cmd->bRequestType << 8) &&
-	    (USB_REQ_SET_ADDRESS == cmd->bRequest))
+	if ((DeviceOutRequest    == req->bRequestType << 8) &&
+	    (USB_REQ_SET_ADDRESS == req->bRequest))
 		return 1;
 	else
 		return 0;
@@ -570,11 +768,15 @@
 	/*
 	 * renesas_usbhs can not use original usb address.
 	 * see HARDWARE LIMITATION.
-	 * modify usb address here.
+	 * modify usb address here to use attached device.
+	 * see usbhsh_device_attach()
 	 */
 	if (usbhsh_is_request_address(urb)) {
-		/* FIXME */
-		req.wValue = 1;
+		struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
+		struct usbhsh_device *udev = usbhsh_usbv_to_udev(usbv);
+
+		/* udev is a attached device */
+		req.wValue = usbhsh_device_number(hpriv, udev);
 		dev_dbg(dev, "create new address - %d\n", req.wValue);
 	}
 
@@ -595,82 +797,80 @@
 static void usbhsh_data_stage_packet_done(struct usbhs_priv *priv,
 					  struct usbhs_pkt *pkt)
 {
-	struct usbhsh_request *ureq = usbhsh_pkt_to_req(pkt);
+	struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt);
 	struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);
-	struct urb *urb = ureq->urb;
 
 	/* this ureq was connected to urb when usbhsh_urb_enqueue()  */
 
-	usbhsh_req_free(hpriv, ureq);
-	usbhsh_urb_to_ureq(urb) = NULL;
+	usbhsh_ureq_free(hpriv, ureq);
 }
 
-static void usbhsh_data_stage_packet_push(struct usbhsh_hpriv *hpriv,
-					  struct urb *urb,
-					  struct usbhs_pipe *pipe)
+static int usbhsh_data_stage_packet_push(struct usbhsh_hpriv *hpriv,
+					 struct urb *urb,
+					 struct usbhs_pipe *pipe,
+					 gfp_t mem_flags)
+
 {
 	struct usbhsh_request *ureq;
-	struct usbhs_pkt *pkt;
 
-	/*
-	 * FIXME
-	 *
-	 * data stage uses ureq which is connected to urb
-	 * see usbhsh_urb_enqueue() :: alloc new request.
-	 * it will be freed in usbhsh_data_stage_packet_done()
-	 */
-	ureq	= usbhsh_urb_to_ureq(urb);
-	pkt	= &ureq->pkt;
+	/* this ureq will be freed on usbhsh_data_stage_packet_done() */
+	ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags);
+	if (unlikely(!ureq))
+		return -ENOMEM;
 
 	if (usb_pipein(urb->pipe))
 		pipe->handler = &usbhs_dcp_data_stage_in_handler;
 	else
 		pipe->handler = &usbhs_dcp_data_stage_out_handler;
 
-	usbhs_pkt_push(pipe, pkt,
+	usbhs_pkt_push(pipe, &ureq->pkt,
 		       usbhsh_data_stage_packet_done,
 		       urb->transfer_buffer,
 		       urb->transfer_buffer_length,
-		       (urb->transfer_flags & URB_ZERO_PACKET));
+		       (urb->transfer_flags & URB_ZERO_PACKET),
+		       -1);
+
+	return 0;
 }
 
 /*
  *		DCP status stage
  */
-static void usbhsh_status_stage_packet_push(struct usbhsh_hpriv *hpriv,
+static int usbhsh_status_stage_packet_push(struct usbhsh_hpriv *hpriv,
 					    struct urb *urb,
-					    struct usbhs_pipe *pipe)
+					    struct usbhs_pipe *pipe,
+					    gfp_t mem_flags)
 {
 	struct usbhsh_request *ureq;
-	struct usbhs_pkt *pkt;
 
-	/*
-	 * FIXME
-	 *
-	 * status stage uses allocated ureq.
-	 * it will be freed on usbhsh_queue_done()
-	 */
-	ureq	= usbhsh_req_alloc(hpriv, urb, GFP_KERNEL);
-	pkt	= &ureq->pkt;
+	/* This ureq will be freed on usbhsh_queue_done() */
+	ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags);
+	if (unlikely(!ureq))
+		return -ENOMEM;
 
 	if (usb_pipein(urb->pipe))
 		pipe->handler = &usbhs_dcp_status_stage_in_handler;
 	else
 		pipe->handler = &usbhs_dcp_status_stage_out_handler;
 
-	usbhs_pkt_push(pipe, pkt,
+	usbhs_pkt_push(pipe, &ureq->pkt,
 		       usbhsh_queue_done,
 		       NULL,
 		       urb->transfer_buffer_length,
-		       0);
+		       0, -1);
+
+	return 0;
 }
 
 static int usbhsh_dcp_queue_push(struct usb_hcd *hcd,
-				 struct usbhsh_hpriv *hpriv,
-				 struct usbhs_pipe *pipe,
-				 struct urb *urb)
+				 struct urb *urb,
+				 gfp_t mflags)
 {
+	struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd);
+	struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep);
+	struct usbhs_pipe *pipe = usbhsh_uep_to_pipe(uep);
 	struct device *dev = usbhsh_hcd_to_dev(hcd);
+	int ret;
 
 	dev_dbg(dev, "%s\n", __func__);
 
@@ -686,13 +886,22 @@
 	 *
 	 * It is pushed only when urb has buffer.
 	 */
-	if (urb->transfer_buffer_length)
-		usbhsh_data_stage_packet_push(hpriv, urb, pipe);
+	if (urb->transfer_buffer_length) {
+		ret = usbhsh_data_stage_packet_push(hpriv, urb, pipe, mflags);
+		if (ret < 0) {
+			dev_err(dev, "data stage failed\n");
+			return ret;
+		}
+	}
 
 	/*
 	 * status stage
 	 */
-	usbhsh_status_stage_packet_push(hpriv, urb, pipe);
+	ret = usbhsh_status_stage_packet_push(hpriv, urb, pipe, mflags);
+	if (ret < 0) {
+		dev_err(dev, "status stage failed\n");
+		return ret;
+	}
 
 	/*
 	 * start pushed packets
@@ -729,71 +938,82 @@
 	struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd);
 	struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
 	struct device *dev = usbhs_priv_to_dev(priv);
-	struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
 	struct usb_host_endpoint *ep = urb->ep;
-	struct usbhsh_request *ureq;
-	struct usbhsh_device *udev, *new_udev = NULL;
-	struct usbhs_pipe *pipe;
-	struct usbhsh_ep *uep;
+	struct usbhsh_device *new_udev = NULL;
 	int is_dir_in = usb_pipein(urb->pipe);
-
+	int i;
 	int ret;
 
 	dev_dbg(dev, "%s (%s)\n", __func__, is_dir_in ? "in" : "out");
 
-	ret = usb_hcd_link_urb_to_ep(hcd, urb);
-	if (ret)
+	if (!usbhsh_is_running(hpriv)) {
+		ret = -EIO;
+		dev_err(dev, "host is not running\n");
 		goto usbhsh_urb_enqueue_error_not_linked;
+	}
+
+	ret = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (ret) {
+		dev_err(dev, "urb link failed\n");
+		goto usbhsh_urb_enqueue_error_not_linked;
+	}
 
 	/*
-	 * get udev
+	 * attach udev if needed
+	 * see [image of mod_host]
 	 */
-	udev = usbhsh_usbv_to_udev(usbv);
-	if (!udev) {
-		new_udev = usbhsh_device_alloc(hpriv, urb);
-		if (!new_udev)
+	if (!usbhsh_device_get(hpriv, urb)) {
+		new_udev = usbhsh_device_attach(hpriv, urb);
+		if (!new_udev) {
+			ret = -EIO;
+			dev_err(dev, "device attach failed\n");
 			goto usbhsh_urb_enqueue_error_not_linked;
-
-		udev = new_udev;
+		}
 	}
 
 	/*
-	 * get uep
+	 * attach endpoint if needed
+	 * see [image of mod_host]
 	 */
-	uep = usbhsh_ep_to_uep(ep);
-	if (!uep) {
-		uep = usbhsh_endpoint_alloc(hpriv, udev, ep,
-					    is_dir_in, mem_flags);
-		if (!uep)
+	if (!usbhsh_ep_to_uep(ep)) {
+		ret = usbhsh_endpoint_attach(hpriv, urb, mem_flags);
+		if (ret < 0) {
+			dev_err(dev, "endpoint attach failed\n");
 			goto usbhsh_urb_enqueue_error_free_device;
+		}
 	}
-	pipe = usbhsh_uep_to_pipe(uep);
 
 	/*
-	 * alloc new request
+	 * attach pipe to endpoint
+	 * see [image of mod_host]
 	 */
-	ureq = usbhsh_req_alloc(hpriv, urb, mem_flags);
-	if (unlikely(!ureq)) {
-		ret = -ENOMEM;
+	for (i = 0; i < 1024; i++) {
+		ret = usbhsh_pipe_attach(hpriv, urb);
+		if (ret < 0)
+			msleep(100);
+		else
+			break;
+	}
+	if (ret < 0) {
+		dev_err(dev, "pipe attach failed\n");
 		goto usbhsh_urb_enqueue_error_free_endpoint;
 	}
-	usbhsh_urb_to_ureq(urb) = ureq;
 
 	/*
 	 * push packet
 	 */
 	if (usb_pipecontrol(urb->pipe))
-		usbhsh_dcp_queue_push(hcd, hpriv, pipe, urb);
+		ret = usbhsh_dcp_queue_push(hcd, urb, mem_flags);
 	else
-		usbhsh_queue_push(hcd, pipe, urb);
+		ret = usbhsh_queue_push(hcd, urb, mem_flags);
 
-	return 0;
+	return ret;
 
 usbhsh_urb_enqueue_error_free_endpoint:
-	usbhsh_endpoint_free(hpriv, ep);
+	usbhsh_endpoint_detach(hpriv, ep);
 usbhsh_urb_enqueue_error_free_device:
 	if (new_udev)
-		usbhsh_device_free(hpriv, new_udev);
+		usbhsh_device_detach(hpriv, new_udev);
 usbhsh_urb_enqueue_error_not_linked:
 
 	dev_dbg(dev, "%s error\n", __func__);
@@ -807,8 +1027,11 @@
 	struct usbhsh_request *ureq = usbhsh_urb_to_ureq(urb);
 
 	if (ureq) {
-		usbhsh_req_free(hpriv, ureq);
-		usbhsh_urb_to_ureq(urb) = NULL;
+		struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+		struct usbhs_pkt *pkt = &ureq->pkt;
+
+		usbhs_pkt_pop(pkt->pipe, pkt);
+		usbhsh_queue_done(priv, pkt);
 	}
 
 	return 0;
@@ -823,7 +1046,7 @@
 
 	/*
 	 * this function might be called manytimes by same hcd/ep
-	 * in-endpoitn == out-endpoint if ep == dcp.
+	 * in-endpoint == out-endpoint if ep == dcp.
 	 */
 	if (!uep)
 		return;
@@ -831,15 +1054,14 @@
 	udev	= usbhsh_uep_to_udev(uep);
 	hpriv	= usbhsh_hcd_to_hpriv(hcd);
 
-	usbhsh_endpoint_free(hpriv, ep);
-	ep->hcpriv = NULL;
+	usbhsh_endpoint_detach(hpriv, ep);
 
 	/*
 	 * if there is no endpoint,
 	 * free device
 	 */
 	if (!usbhsh_device_has_endpoint(udev))
-		usbhsh_device_free(hpriv, udev);
+		usbhsh_device_detach(hpriv, udev);
 }
 
 static int usbhsh_hub_status_data(struct usb_hcd *hcd, char *buf)
@@ -919,6 +1141,8 @@
 				       USB_PORT_STAT_HIGH_SPEED |
 				       USB_PORT_STAT_LOW_SPEED);
 
+		usbhsh_queue_force_pop_all(priv);
+
 		usbhs_bus_send_reset(priv);
 		msleep(20);
 		usbhs_bus_send_sof_enable(priv);
@@ -1082,6 +1306,20 @@
 	usbhsh_port_stat_set(hpriv, USB_PORT_STAT_CONNECTION);
 	usbhsh_port_stat_set(hpriv, USB_PORT_STAT_C_CONNECTION << 16);
 
+	/*
+	 * attch interrupt might happen infinitely on some device
+	 * (on self power USB hub ?)
+	 * disable it here.
+	 *
+	 * usbhsh_is_running() becomes effective
+	 * according to this process.
+	 * see
+	 *	usbhsh_is_running()
+	 *	usbhsh_urb_enqueue()
+	 */
+	hpriv->mod.irq_attch = NULL;
+	usbhs_irq_callback_update(priv, &hpriv->mod);
+
 	return 0;
 }
 
@@ -1096,6 +1334,24 @@
 	usbhsh_port_stat_clear(hpriv, USB_PORT_STAT_CONNECTION);
 	usbhsh_port_stat_set(hpriv, USB_PORT_STAT_C_CONNECTION << 16);
 
+	/*
+	 * enable attch interrupt again
+	 *
+	 * usbhsh_is_running() becomes invalid
+	 * according to this process.
+	 * see
+	 *	usbhsh_is_running()
+	 *	usbhsh_urb_enqueue()
+	 */
+	hpriv->mod.irq_attch = usbhsh_irq_attch;
+	usbhs_irq_callback_update(priv, &hpriv->mod);
+
+	/*
+	 * usbhsh_queue_force_pop_all() should be called
+	 * after usbhsh_is_running() becomes invalid.
+	 */
+	usbhsh_queue_force_pop_all(priv);
+
 	return 0;
 }
 
@@ -1131,7 +1387,6 @@
 static void usbhsh_pipe_init_for_host(struct usbhs_priv *priv)
 {
 	struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);
-	struct usbhsh_pipe_info *pipe_info = hpriv->pipe_info;
 	struct usbhs_pipe *pipe;
 	u32 *pipe_type = usbhs_get_dparam(priv, pipe_type);
 	int pipe_size = usbhs_get_dparam(priv, pipe_size);
@@ -1140,7 +1395,6 @@
 	/* init all pipe */
 	old_type = USB_ENDPOINT_XFER_CONTROL;
 	for (i = 0; i < pipe_size; i++) {
-		pipe_info[i].usr_cnt	= 0;
 
 		/*
 		 * data "output" will be finished as soon as possible,
@@ -1174,7 +1428,7 @@
 						 dir_in);
 		}
 
-		pipe->mod_private = pipe_info + i;
+		pipe->mod_private = NULL;
 	}
 }
 
@@ -1205,9 +1459,7 @@
 	 * - host
 	 * - usb module
 	 */
-	usbhs_sys_hispeed_ctrl(priv, 1);
 	usbhs_sys_host_ctrl(priv, 1);
-	usbhs_sys_usb_ctrl(priv, 1);
 
 	/*
 	 * enable irq callback
@@ -1242,9 +1494,7 @@
 	usb_remove_hcd(hcd);
 
 	/* disable sys */
-	usbhs_sys_hispeed_ctrl(priv, 0);
 	usbhs_sys_host_ctrl(priv, 0);
-	usbhs_sys_usb_ctrl(priv, 0);
 
 	dev_dbg(dev, "quit host\n");
 
@@ -1255,10 +1505,8 @@
 {
 	struct usbhsh_hpriv *hpriv;
 	struct usb_hcd *hcd;
-	struct usbhsh_pipe_info *pipe_info;
 	struct usbhsh_device *udev;
 	struct device *dev = usbhs_priv_to_dev(priv);
-	int pipe_size = usbhs_get_dparam(priv, pipe_size);
 	int i;
 
 	/* initialize hcd */
@@ -1269,12 +1517,6 @@
 	}
 	hcd->has_tt = 1; /* for low/full speed */
 
-	pipe_info = kzalloc(sizeof(*pipe_info) * pipe_size, GFP_KERNEL);
-	if (!pipe_info) {
-		dev_err(dev, "Could not allocate pipe_info\n");
-		goto usbhs_mod_host_probe_err;
-	}
-
 	/*
 	 * CAUTION
 	 *
@@ -1294,9 +1536,6 @@
 	hpriv->mod.name		= "host";
 	hpriv->mod.start	= usbhsh_start;
 	hpriv->mod.stop		= usbhsh_stop;
-	hpriv->pipe_info	= pipe_info;
-	hpriv->pipe_size	= pipe_size;
-	usbhsh_req_list_init(hpriv);
 	usbhsh_port_stat_init(hpriv);
 
 	/* init all device */
@@ -1308,11 +1547,6 @@
 	dev_info(dev, "host probed\n");
 
 	return 0;
-
-usbhs_mod_host_probe_err:
-	usb_put_hcd(hcd);
-
-	return -ENOMEM;
 }
 
 int usbhs_mod_host_remove(struct usbhs_priv *priv)
@@ -1320,8 +1554,6 @@
 	struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);
 	struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
 
-	usbhsh_req_list_quit(hpriv);
-
 	usb_put_hcd(hcd);
 
 	return 0;
diff --git a/drivers/usb/renesas_usbhs/pipe.c b/drivers/usb/renesas_usbhs/pipe.c
index c74389c..feb06d6 100644
--- a/drivers/usb/renesas_usbhs/pipe.c
+++ b/drivers/usb/renesas_usbhs/pipe.c
@@ -257,6 +257,13 @@
 	}
 }
 
+int usbhs_pipe_is_stall(struct usbhs_pipe *pipe)
+{
+	u16 pid = usbhsp_pipectrl_get(pipe) & PID_MASK;
+
+	return (int)(pid == PID_STALL10 || pid == PID_STALL11);
+}
+
 /*
  *		pipe setup
  */
@@ -323,8 +330,7 @@
 	if (dir_in)
 		usbhsp_flags_set(pipe, IS_DIR_HOST);
 
-	if ((is_host  && !dir_in) ||
-	    (!is_host && dir_in))
+	if (!!is_host ^ !!dir_in)
 		dir |= DIR_OUT;
 
 	if (!dir)
@@ -471,10 +477,27 @@
 	return usbhsp_flags_has(pipe, IS_DIR_HOST);
 }
 
-void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int data)
+void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int sequence)
 {
 	u16 mask = (SQCLR | SQSET);
-	u16 val = (data) ? SQSET : SQCLR;
+	u16 val;
+
+	/*
+	 * sequence
+	 *  0  : data0
+	 *  1  : data1
+	 *  -1 : no change
+	 */
+	switch (sequence) {
+	case 0:
+		val = SQCLR;
+		break;
+	case 1:
+		val = SQSET;
+		break;
+	default:
+		return;
+	}
 
 	usbhsp_pipectrl_set(pipe, mask, val);
 }
diff --git a/drivers/usb/renesas_usbhs/pipe.h b/drivers/usb/renesas_usbhs/pipe.h
index 6334fc6..fa18b7d 100644
--- a/drivers/usb/renesas_usbhs/pipe.h
+++ b/drivers/usb/renesas_usbhs/pipe.h
@@ -87,6 +87,7 @@
 void usbhs_pipe_enable(struct usbhs_pipe *pipe);
 void usbhs_pipe_disable(struct usbhs_pipe *pipe);
 void usbhs_pipe_stall(struct usbhs_pipe *pipe);
+int usbhs_pipe_is_stall(struct usbhs_pipe *pipe);
 void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo);
 void usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel,
 			      u16 epnum, u16 maxp);
diff --git a/drivers/usb/serial/ChangeLog.history b/drivers/usb/serial/ChangeLog.history
deleted file mode 100644
index f13fd48..0000000
--- a/drivers/usb/serial/ChangeLog.history
+++ /dev/null
@@ -1,730 +0,0 @@
-This is the contents of some of the drivers/usb/serial/ files that had  old
-changelog comments.  They were quite old, and out of date, and we don't keep
-them anymore, so I've put them here, away from the source files, in case
-people still care to see them.
-
-- Greg Kroah-Hartman <greg@kroah.com> October 20, 2005
-
------------------------------------------------------------------------
-usb-serial.h Change Log comments:
-
- (03/26/2002) gkh
-	removed the port->tty check from port_paranoia_check() due to serial
-	consoles not having a tty device assigned to them.
-
- (12/03/2001) gkh
-	removed active from the port structure.
-	added documentation to the usb_serial_device_type structure
-
- (10/10/2001) gkh
-	added vendor and product to serial structure.  Needed to determine device
-	owner when the device is disconnected.
-
- (05/30/2001) gkh
-	added sem to port structure and removed port_lock
-
- (10/05/2000) gkh
-	Added interrupt_in_endpointAddress and bulk_in_endpointAddress to help
-	fix bug with urb->dev not being set properly, now that the usb core
-	needs it.
-
- (09/11/2000) gkh
-	Added usb_serial_debug_data function to help get rid of #DEBUG in the
-	drivers.
-
- (08/28/2000) gkh
-	Added port_lock to port structure.
-
- (08/08/2000) gkh
-	Added open_count to port structure.
-
- (07/23/2000) gkh
-	Added bulk_out_endpointAddress to port structure.
-
- (07/19/2000) gkh, pberger, and borchers
-	Modifications to allow usb-serial drivers to be modules.
-
------------------------------------------------------------------------
-usb-serial.c Change Log comments:
-
- (12/10/2002) gkh
-	Split the ports off into their own struct device, and added a
-	usb-serial bus driver.
-
- (11/19/2002) gkh
-	removed a few #ifdefs for the generic code and cleaned up the failure
-	logic in initialization.
-
- (10/02/2002) gkh
-	moved the console code to console.c and out of this file.
-
- (06/05/2002) gkh
-	moved location of startup() call in serial_probe() until after all
-	of the port information and endpoints are initialized.  This makes
-	things easier for some drivers.
-
- (04/10/2002) gkh
-	added serial_read_proc function which creates a
-	/proc/tty/driver/usb-serial file.
-
- (03/27/2002) gkh
-	Got USB serial console code working properly and merged into the main
-	version of the tree.  Thanks to Randy Dunlap for the initial version
-	of this code, and for pushing me to finish it up.
-	The USB serial console works with any usb serial driver device.
-
- (03/21/2002) gkh
-	Moved all manipulation of port->open_count into the core.  Now the
-	individual driver's open and close functions are called only when the
-	first open() and last close() is called.  Making the drivers a bit
-	smaller and simpler.
-	Fixed a bug if a driver didn't have the owner field set.
-
- (02/26/2002) gkh
-	Moved all locking into the main serial_* functions, instead of having
-	the individual drivers have to grab the port semaphore.  This should
-	reduce races.
-	Reworked the MOD_INC logic a bit to always increment and decrement, even
-	if the generic driver is being used.
-
- (10/10/2001) gkh
-	usb_serial_disconnect() now sets the serial->dev pointer is to NULL to
-	help prevent child drivers from accessing the device since it is now
-	gone.
-
- (09/13/2001) gkh
-	Moved generic driver initialize after we have registered with the USB
-	core.  Thanks to Randy Dunlap for pointing this problem out.
-
- (07/03/2001) gkh
-	Fixed module paramater size.  Thanks to John Brockmeyer for the pointer.
-	Fixed vendor and product getting defined through the MODULE_PARM macro
-	if the Generic driver wasn't compiled in.
-	Fixed problem with generic_shutdown() not being called for drivers that
-	don't have a shutdown() function.
-
- (06/06/2001) gkh
-	added evil hack that is needed for the prolific pl2303 device due to the
-	crazy way its endpoints are set up.
-
- (05/30/2001) gkh
-	switched from using spinlock to a semaphore, which fixes lots of problems.
-
- (04/08/2001) gb
-	Identify version on module load.
-
- 2001_02_05 gkh
-	Fixed buffer overflows bug with the generic serial driver.  Thanks to
-	Todd Squires <squirest@ct0.com> for fixing this.
-
- (01/10/2001) gkh
-	Fixed bug where the generic serial adaptor grabbed _any_ device that was
-	offered to it.
-
- (12/12/2000) gkh
-	Removed MOD_INC and MOD_DEC from poll and disconnect functions, and
-	moved them to the serial_open and serial_close functions.
-	Also fixed bug with there not being a MOD_DEC for the generic driver
-	(thanks to Gary Brubaker for finding this.)
-
- (11/29/2000) gkh
-	Small NULL pointer initialization cleanup which saves a bit of disk image
-
- (11/01/2000) Adam J. Richter
-	instead of using idVendor/idProduct pairs, usb serial drivers
-	now identify their hardware interest with usb_device_id tables,
-	which they usually have anyhow for use with MODULE_DEVICE_TABLE.
-
- (10/05/2000) gkh
-	Fixed bug with urb->dev not being set properly, now that the usb
-	core needs it.
-
- (09/11/2000) gkh
-	Removed DEBUG #ifdefs with call to usb_serial_debug_data
-
- (08/28/2000) gkh
-	Added port_lock to port structure.
-	Added locks for SMP safeness to generic driver
-	Fixed the ability to open a generic device's port more than once.
-
- (07/23/2000) gkh
-	Added bulk_out_endpointAddress to port structure.
-
- (07/19/2000) gkh, pberger, and borchers
-	Modifications to allow usb-serial drivers to be modules.
-
- (07/03/2000) gkh
-	Added more debugging to serial_ioctl call
-
- (06/25/2000) gkh
-	Changed generic_write_bulk_callback to not call wake_up_interruptible
-	directly, but to have port_softint do it at a safer time.
-
- (06/23/2000) gkh
-	Cleaned up debugging statements in a quest to find UHCI timeout bug.
-
- (05/22/2000) gkh
-	Changed the makefile, enabling the big CONFIG_USB_SERIAL_SOMTHING to be
-	removed from the individual device source files.
-
- (05/03/2000) gkh
-	Added the Digi Acceleport driver from Al Borchers and Peter Berger.
-
- (05/02/2000) gkh
-	Changed devfs and tty register code to work properly now. This was based on
-	the ACM driver changes by Vojtech Pavlik.
-
- (04/27/2000) Ryan VanderBijl
- 	Put calls to *_paranoia_checks into one function.
-
- (04/23/2000) gkh
-	Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports.
-	Moved when the startup code printed out the devices that are supported.
-
- (04/19/2000) gkh
-	Added driver for ZyXEL omni.net lcd plus ISDN TA
-	Made startup info message specify which drivers were compiled in.
-
- (04/03/2000) gkh
-	Changed the probe process to remove the module unload races.
-	Changed where the tty layer gets initialized to have devfs work nicer.
-	Added initial devfs support.
-
- (03/26/2000) gkh
-	Split driver up into device specific pieces.
-
- (03/19/2000) gkh
-	Fixed oops that could happen when device was removed while a program
-	was talking to the device.
-	Removed the static urbs and now all urbs are created and destroyed
-	dynamically.
-	Reworked the internal interface. Now everything is based on the
-	usb_serial_port structure instead of the larger usb_serial structure.
-	This fixes the bug that a multiport device could not have more than
-	one port open at one time.
-
- (03/17/2000) gkh
-	Added config option for debugging messages.
-	Added patch for keyspan pda from Brian Warner.
-
- (03/06/2000) gkh
-	Added the keyspan pda code from Brian Warner <warner@lothar.com>
-	Moved a bunch of the port specific stuff into its own structure. This
-	is in anticipation of the true multiport devices (there's a bug if you
-	try to access more than one port of any multiport device right now)
-
- (02/21/2000) gkh
-	Made it so that any serial devices only have to specify which functions
-	they want to overload from the generic function calls (great,
-	inheritance in C, in a driver, just what I wanted...)
-	Added support for set_termios and ioctl function calls. No drivers take
-	advantage of this yet.
-	Removed the #ifdef MODULE, now there is no module specific code.
-	Cleaned up a few comments in usb-serial.h that were wrong (thanks again
-	to Miles Lott).
-	Small fix to get_free_serial.
-
- (02/14/2000) gkh
-	Removed the Belkin and Peracom functionality from the driver due to
-	the lack of support from the vendor, and me not wanting people to
-	accidenatly buy the device, expecting it to work with Linux.
-	Added read_bulk_callback and write_bulk_callback to the type structure
-	for the needs of the FTDI and WhiteHEAT driver.
-	Changed all reverences to FTDI to FTDI_SIO at the request of Bill
-	Ryder.
-	Changed the output urb size back to the max endpoint size to make
-	the ftdi_sio driver have it easier, and due to the fact that it didn't
-	really increase the speed any.
-
- (02/11/2000) gkh
-	Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a
-	patch from Miles Lott (milos@insync.net).
-	Fixed bug with not restoring the minor range that a device grabs, if
-	the startup function fails (thanks Miles for finding this).
-
- (02/05/2000) gkh
-	Added initial framework for the Keyspan PDA serial converter so that
-	Brian Warner has a place to put his code.
-	Made the ezusb specific functions generic enough that different
-	devices can use them (whiteheat and keyspan_pda both need them).
-	Split out a whole bunch of structure and other stuff to a separate
-	usb-serial.h file.
-	Made the Visor connection messages a little more understandable, now
-	that Miles Lott (milos@insync.net) has gotten the Generic channel to
-	work. Also made them always show up in the log file.
-
- (01/25/2000) gkh
-	Added initial framework for FTDI serial converter so that Bill Ryder
-	has a place to put his code.
-	Added the vendor specific info from Handspring. Now we can print out
-	informational debug messages as well as understand what is happening.
-
- (01/23/2000) gkh
-	Fixed problem of crash when trying to open a port that didn't have a
-	device assigned to it. Made the minor node finding a little smarter,
-	now it looks to find a continuous space for the new device.
-
- (01/21/2000) gkh
-	Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net)
-	Fixed get_serial_by_minor which was all messed up for multi port
-	devices. Fixed multi port problem for generic devices. Now the number
-	of ports is determined by the number of bulk out endpoints for the
-	generic device.
-
- (01/19/2000) gkh
-	Removed lots of cruft that was around from the old (pre urb) driver
-	interface.
-	Made the serial_table dynamic. This should save lots of memory when
-	the number of minor nodes goes up to 256.
-	Added initial support for devices that have more than one port.
-	Added more debugging comments for the Visor, and added a needed
-	set_configuration call.
-
- (01/17/2000) gkh
-	Fixed the WhiteHEAT firmware (my processing tool had a bug)
-	and added new debug loader firmware for it.
-	Removed the put_char function as it isn't really needed.
-	Added visor startup commands as found by the Win98 dump.
-
- (01/13/2000) gkh
-	Fixed the vendor id for the generic driver to the one I meant it to be.
-
- (01/12/2000) gkh
-	Forget the version numbering...that's pretty useless...
-	Made the driver able to be compiled so that the user can select which
-	converter they want to use. This allows people who only want the Visor
-	support to not pay the memory size price of the WhiteHEAT.
-	Fixed bug where the generic driver (idVendor=0000 and idProduct=0000)
-	grabbed the root hub. Not good.
-
- version 0.4.0 (01/10/2000) gkh
-	Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT
-	device. Added startup function to allow firmware to be downloaded to
-	a device if it needs to be.
-	Added firmware download logic to the WhiteHEAT device.
-	Started to add #defines to split up the different drivers for potential
-	configuration option.
-
- version 0.3.1 (12/30/99) gkh
-      Fixed problems with urb for bulk out.
-      Added initial support for multiple sets of endpoints. This enables
-      the Handspring Visor to be attached successfully. Only the first
-      bulk in / bulk out endpoint pair is being used right now.
-
- version 0.3.0 (12/27/99) gkh
-	Added initial support for the Handspring Visor based on a patch from
-	Miles Lott (milos@sneety.insync.net)
-	Cleaned up the code a bunch and converted over to using urbs only.
-
- version 0.2.3 (12/21/99) gkh
-	Added initial support for the Connect Tech WhiteHEAT converter.
-	Incremented the number of ports in expectation of getting the
-	WhiteHEAT to work properly (4 ports per connection).
-	Added notification on insertion and removal of what port the
-	device is/was connected to (and what kind of device it was).
-
- version 0.2.2 (12/16/99) gkh
-	Changed major number to the new allocated number. We're legal now!
-
- version 0.2.1 (12/14/99) gkh
-	Fixed bug that happens when device node is opened when there isn't a
-	device attached to it. Thanks to marek@webdesign.no for noticing this.
-
- version 0.2.0 (11/10/99) gkh
-	Split up internals to make it easier to add different types of serial
-	converters to the code.
-	Added a "generic" driver that gets it's vendor and product id
-	from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net)
-	for the idea and sample code (from the usb scanner driver.)
-	Cleared up any licensing questions by releasing it under the GNU GPL.
-
- version 0.1.2 (10/25/99) gkh
- 	Fixed bug in detecting device.
-
- version 0.1.1 (10/05/99) gkh
- 	Changed the major number to not conflict with anything else.
-
- version 0.1 (09/28/99) gkh
- 	Can recognize the two different devices and start up a read from
-	device when asked to. Writes also work. No control signals yet, this
-	all is vendor specific data (i.e. no spec), also no control for
-	different baud rates or other bit settings.
-	Currently we are using the same devid as the acm driver. This needs
-	to change.
-
------------------------------------------------------------------------
-visor.c Change Log comments:
-
- (06/03/2003) Judd Montgomery <judd at jpilot.org>
-     Added support for module parameter options for untested/unknown
-     devices.
-
- (03/09/2003) gkh
-	Added support for the Sony Clie NZ90V device.  Thanks to Martin Brachtl
-	<brachtl@redgrep.cz> for the information.
-
- (03/05/2003) gkh
-	Think Treo support is now working.
-
- (04/03/2002) gkh
-	Added support for the Sony OS 4.1 devices.  Thanks to Hiroyuki ARAKI
-	<hiro@zob.ne.jp> for the information.
-
- (03/27/2002) gkh
-	Removed assumptions that port->tty was always valid (is not true
-	for usb serial console devices.)
-
- (03/23/2002) gkh
-	Added support for the Palm i705 device, thanks to Thomas Riemer
-	<tom@netmech.com> for the information.
-
- (03/21/2002) gkh
-	Added support for the Palm m130 device, thanks to Udo Eisenbarth
-	<udo.eisenbarth@web.de> for the information.
-
- (02/27/2002) gkh
-	Reworked the urb handling logic.  We have no more pool, but dynamically
-	allocate the urb and the transfer buffer on the fly.  In testing this
-	does not incure any measurable overhead.  This also relies on the fact
-	that we have proper reference counting logic for urbs.
-
- (02/21/2002) SilaS
-  Added initial support for the Palm m515 devices.
-
- (02/14/2002) gkh
-	Added support for the Clie S-360 device.
-
- (12/18/2001) gkh
-	Added better Clie support for 3.5 devices.  Thanks to Geoffrey Levand
-	for the patch.
-
- (11/11/2001) gkh
-	Added support for the m125 devices, and added check to prevent oopses
-	for Clié devices that lie about the number of ports they have.
-
- (08/30/2001) gkh
-	Added support for the Clie devices, both the 3.5 and 4.0 os versions.
-	Many thanks to Daniel Burke, and Bryan Payne for helping with this.
-
- (08/23/2001) gkh
-	fixed a few potential bugs pointed out by Oliver Neukum.
-
- (05/30/2001) gkh
-	switched from using spinlock to a semaphore, which fixes lots of problems.
-
- (05/28/2000) gkh
-	Added initial support for the Palm m500 and Palm m505 devices.
-
- (04/08/2001) gb
-	Identify version on module load.
-
- (01/21/2000) gkh
-	Added write_room and chars_in_buffer, as they were previously using the
-	generic driver versions which is all wrong now that we are using an urb
-	pool.  Thanks to Wolfgang Grandegger for pointing this out to me.
-	Removed count assignment in the write function, which was not needed anymore
-	either.  Thanks to Al Borchers for pointing this out.
-
- (12/12/2000) gkh
-	Moved MOD_DEC to end of visor_close to be nicer, as the final write
-	message can sleep.
-
- (11/12/2000) gkh
-	Fixed bug with data being dropped on the floor by forcing tty->low_latency
-	to be on.  Hopefully this fixes the OHCI issue!
-
- (11/01/2000) Adam J. Richter
-	usb_device_id table support
-
- (10/05/2000) gkh
-	Fixed bug with urb->dev not being set properly, now that the usb
-	core needs it.
-
- (09/11/2000) gkh
-	Got rid of always calling kmalloc for every urb we wrote out to the
-	device.
-	Added visor_read_callback so we can keep track of bytes in and out for
-	those people who like to know the speed of their device.
-	Removed DEBUG #ifdefs with call to usb_serial_debug_data
-
- (09/06/2000) gkh
-	Fixed oops in visor_exit.  Need to uncomment usb_unlink_urb call _after_
-	the host controller drivers set urb->dev = NULL when the urb is finished.
-
- (08/28/2000) gkh
-	Added locks for SMP safeness.
-
- (08/08/2000) gkh
-	Fixed endian problem in visor_startup.
-	Fixed MOD_INC and MOD_DEC logic and the ability to open a port more
-	than once.
-
- (07/23/2000) gkh
-	Added pool of write urbs to speed up transfers to the visor.
-
- (07/19/2000) gkh
-	Added module_init and module_exit functions to handle the fact that this
-	driver is a loadable module now.
-
- (07/03/2000) gkh
-	Added visor_set_ioctl and visor_set_termios functions (they don't do much
-	of anything, but are good for debugging.)
-
- (06/25/2000) gkh
-	Fixed bug in visor_unthrottle that should help with the disconnect in PPP
-	bug that people have been reporting.
-
- (06/23/2000) gkh
-	Cleaned up debugging statements in a quest to find UHCI timeout bug.
-
- (04/27/2000) Ryan VanderBijl
- 	Fixed memory leak in visor_close
-
- (03/26/2000) gkh
-	Split driver up into device specific pieces.
-
------------------------------------------------------------------------
-pl2303.c Change Log comments:
-
- 2002_Mar_26 gkh
-	allowed driver to work properly if there is no tty assigned to a port
-	(this happens for serial console devices.)
-
- 2001_Oct_06 gkh
-	Added RTS and DTR line control.  Thanks to joe@bndlg.de for parts of it.
-
- 2001_Sep_19 gkh
-	Added break support.
-
- 2001_Aug_30 gkh
-	fixed oops in write_bulk_callback.
-
- 2001_Aug_28 gkh
-	reworked buffer logic to be like other usb-serial drivers.  Hopefully
-	removing some reported problems.
-
- 2001_Jun_06 gkh
-	finished porting to 2.4 format.
-
-
------------------------------------------------------------------------
-io_edgeport.c Change Log comments:
-
- 2003_04_03 al borchers
-  - fixed a bug (that shows up with dosemu) where the tty struct is
-    used in a callback after it has been freed
-
- 2.3 2002_03_08 greg kroah-hartman
-	- fixed bug when multiple devices were attached at the same time.
-
- 2.2 2001_11_14 greg kroah-hartman
-	- fixed bug in edge_close that kept the port from being used more
-	  than once.
-	- fixed memory leak on device removal.
-	- fixed potential double free of memory when command urb submitting
-	  failed.
-	- other small cleanups when the device is removed
-
- 2.1 2001_07_09 greg kroah-hartman
-	- added support for TIOCMBIS and TIOCMBIC.
-
-     (04/08/2001) gb
-	- Identify version on module load.
-
- 2.0 2001_03_05 greg kroah-hartman
-	- reworked entire driver to fit properly in with the other usb-serial
-	  drivers.  Occasional oopses still happen, but it's a good start.
-
- 1.2.3 (02/23/2001) greg kroah-hartman
-	- changed device table to work properly for 2.4.x final format.
-	- fixed problem with dropping data at high data rates.
-
- 1.2.2 (11/27/2000) greg kroah-hartman
-	- cleaned up more NTisms.
-	- Added device table for 2.4.0-test11
-
- 1.2.1 (11/08/2000) greg kroah-hartman
-	- Started to clean up NTisms.
-	- Fixed problem with dev field of urb for kernels >= 2.4.0-test9
-
- 1.2 (10/17/2000) David Iacovelli
- 	Remove all EPIC code and GPL source
-  Fix RELEVANT_IFLAG macro to include flow control
-  changes port configuration changes.
-  Fix redefinition of SERIAL_MAGIC
-  Change all timeout values to 5 seconds
-  Tried to fix the UHCI multiple urb submission, but failed miserably.
-  it seems to work fine with OHCI.
-  ( Greg take a look at the #if 0 at end of WriteCmdUsb() we must
-    find a way to work arount this UHCI bug )
-
- 1.1 (10/11/2000) David Iacovelli
-  Fix XON/XOFF flow control to support both IXON and IXOFF
-
- 0.9.27 (06/30/2000) David Iacovelli
-  Added transmit queue and now allocate urb for command writes.
-
- 0.9.26 (06/29/2000) David Iacovelli
-  Add support for 80251 based edgeport
-
- 0.9.25 (06/27/2000) David Iacovelli
-  Do not close the port if it has multiple opens.
-
- 0.9.24 (05/26/2000) David Iacovelli
-  Add IOCTLs to support RXTX and JAVA POS
-  and first cut at running BlackBox Demo
-
- 0.9.23 (05/24/2000) David Iacovelli
-  Add IOCTLs to support RXTX and JAVA POS
-
- 0.9.22 (05/23/2000) David Iacovelli
-  fixed bug in enumeration.  If epconfig turns on mapping by
-  path after a device is already plugged in, we now update
-  the mapping correctly
-
- 0.9.21 (05/16/2000) David Iacovelli
-  Added BlockUntilChaseResp() to also wait for txcredits
-  Updated the way we allocate and handle write URBs
-	Add debug code to dump buffers
-
- 0.9.20 (05/01/2000) David Iacovelli
-	change driver to use usb/tts/
-
- 0.9.19 (05/01/2000) David Iacovelli
-  Update code to compile if DEBUG is off
-
- 0.9.18 (04/28/2000) David Iacovelli
-  cleanup and test tty_register with devfs
-
- 0.9.17 (04/27/2000) greg kroah-hartman
- 	changed tty_register around to be like the way it
- 	was before, but now it works properly with devfs.
-
- 0.9.16 (04/26/2000) david iacovelli
-  Fixed bug in GetProductInfo()
-
- 0.9.15 (04/25/2000) david iacovelli
-	Updated enumeration
-
- 0.9.14 (04/24/2000) david iacovelli
-  Removed all config/status IOCTLS and
-  converted to using /proc/edgeport
-  still playing with devfs
-
- 0.9.13 (04/24/2000) david iacovelli
-  Removed configuration based on ttyUSB0
-  Added support for configuration using /prod/edgeport
-  first attempt at using devfs (not working yet!)
-  Added IOCTL to GetProductInfo()
-  Added support for custom baud rates
-	Add support for random port numbers
-
- 0.9.12 (04/18/2000) david iacovelli
-	added additional configuration IOCTLs
-  use ttyUSB0 for configuration
-
- 0.9.11 (04/17/2000) greg kroah-hartman
-	fixed module initialization race conditions.
-	made all urbs dynamically allocated.
-	made driver devfs compatible. now it only registers the tty device
-	when the device is actually plugged in.
-
- 0.9.10 (04/13/2000) greg kroah-hartman
-	added proc interface framework.
-
- 0.9.9 (04/13/2000) david iacovelli
-	added enumeration code and ioctls to configure the device
-
- 0.9.8 (04/12/2000) david iacovelli
-  Change interrupt read start when device is plugged in
-  and stop when device is removed
-	process interrupt reads when all ports are closed
-  (keep value of rxBytesAvail consistent with the edgeport)
-  set the USB_BULK_QUEUE flag so that we can shove a bunch
-  of urbs at once down the pipe
-
- 0.9.7 (04/10/2000) david iacovelli
- 	start to add enumeration code.
-  generate serial number for epic devices
-  add support for kdb
-
- 0.9.6 (03/30/2000) david iacovelli
-  add IOCTL to get string, manufacture, and boot descriptors
-
- 0.9.5 (03/14/2000) greg kroah-hartman
-	more error checking added to SerialOpen to try to fix UHCI open problem
-
- 0.9.4 (03/09/2000) greg kroah-hartman
-	added more error checking to handle oops when data is hanging
-	around and tty is abruptly closed.
-
- 0.9.3 (03/09/2000) david iacovelli
-	Add epic support for xon/xoff chars
-	play with performance
-
- 0.9.2 (03/08/2000) greg kroah-hartman
-	changed most "info" calls to "dbg"
-	implemented flow control properly in the termios call
-
- 0.9.1 (03/08/2000) david iacovelli
-	added EPIC support
-	enabled bootloader update
-
- 0.9 (03/08/2000) greg kroah-hartman
-	Release to IO networks.
-	Integrated changes that David made
-  made getting urbs for writing SMP safe
-
- 0.8 (03/07/2000) greg kroah-hartman
-	Release to IO networks.
-	Fixed problems that were seen in code by David.
-  Now both Edgeport/4 and Edgeport/2 works properly.
-  Changed most of the functions to use port instead of serial.
-
- 0.7 (02/27/2000) greg kroah-hartman
-	Milestone 3 release.
-	Release to IO Networks
-	ioctl for waiting on line change implemented.
-	ioctl for getting statistics implemented.
-	multiport support working.
-	lsr and msr registers are now handled properly.
-	change break now hooked up and working.
-	support for all known Edgeport devices.
-
- 0.6 (02/22/2000) greg kroah-hartman
-	Release to IO networks.
-	CHASE is implemented correctly when port is closed.
-	SerialOpen now blocks correctly until port is fully opened.
-
- 0.5 (02/20/2000) greg kroah-hartman
-	Release to IO networks.
-	Known problems:
-		modem status register changes are not sent on to the user
-		CHASE is not implemented when the port is closed.
-
- 0.4 (02/16/2000) greg kroah-hartman
-	Second cut at the CeBit demo.
-	Doesn't leak memory on every write to the port
-	Still small leaks on startup.
-	Added support for Edgeport/2 and Edgeport/8
-
- 0.3 (02/15/2000) greg kroah-hartman
-	CeBit demo release.
-	Force the line settings to 4800, 8, 1, e for the demo.
-	Warning! This version leaks memory like crazy!
-
- 0.2 (01/30/2000) greg kroah-hartman
-	Milestone 1 release.
-	Device is found by USB subsystem, enumerated, firmware is downloaded
-	and the descriptors are printed to the debug log, config is set, and
-	green light starts to blink. Open port works, and data can be sent
-	and received at the default settings of the UART. Loopback connector
-	and debug log confirms this.
-
- 0.1 (01/23/2000) greg kroah-hartman
-	Initial release to help IO Networks try to set up their test system.
-	Edgeport4 is recognized, firmware is downloaded, config is set so
-	device blinks green light every 3 sec. Port is bound, but opening,
-	closing, and sending data do not work properly.
-
-
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index d6921fa..f9f29b2 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -20,50 +20,7 @@
  * TODO:
  * -- Add true modem contol line query capability.  Currently we track the
  *    states reported by the interrupt and the states we request.
- * -- Add error reporting back to application for UART error conditions.
- *    Just point me at how to implement this and I'll do it. I've put the
- *    framework in, but haven't analyzed the "tty_flip" interface yet.
  * -- Add support for flush commands
- * -- Add everything that is missing :)
- *
- * 27-Nov-2001 gkh
- * 	compressed all the differnent device entries into 1.
- *
- * 30-May-2001 gkh
- *	switched from using spinlock to a semaphore, which fixes lots of
- *	problems.
- *
- * 08-Apr-2001 gb
- *	- Identify version on module load.
- *
- * 12-Mar-2001 gkh
- *	- Added support for the GoHubs GO-COM232 device which is the same as the
- *	  Peracom device.
- *
- * 06-Nov-2000 gkh
- *	- Added support for the old Belkin and Peracom devices.
- *	- Made the port able to be opened multiple times.
- *	- Added some defaults incase the line settings are things these devices
- *	  can't support.
- *
- * 18-Oct-2000 William Greathouse
- *    Released into the wild (linux-usb-devel)
- *
- * 17-Oct-2000 William Greathouse
- *    Add code to recognize firmware version and set hardware flow control
- *    appropriately.  Belkin states that firmware prior to 3.05 does not
- *    operate correctly in hardware handshake mode.  I have verified this
- *    on firmware 2.05 -- for both RTS and DTR input flow control, the control
- *    line is not reset.  The test performed by the Belkin Win* driver is
- *    to enable hardware flow control for firmware 2.06 or greater and
- *    for 1.00 or prior.  I am only enabling for 2.06 or greater.
- *
- * 12-Oct-2000 William Greathouse
- *    First cut at supporting Belkin USB Serial Adapter F5U103
- *    I did not have a copy of the original work to support this
- *    adapter, so pardon any stupid mistakes.  All of the information
- *    I am using to write this driver was acquired by using a modified
- *    UsbSnoop on Windows2000 and from examining the other USB drivers.
  */
 
 #include <linux/kernel.h>
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index 6ae1c06..0e77511 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -335,13 +335,12 @@
 		goto out;
 
 	dbg("%s - submitting interrupt urb", __func__);
-	port->interrupt_in_urb->dev = serial->dev;
 	r = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 	if (r) {
 		dev_err(&port->dev, "%s - failed submitting interrupt urb,"
 			" error %d\n", __func__, r);
 		ch341_close(port);
-		return -EPROTO;
+		goto out;
 	}
 
 	r = usb_serial_generic_open(tty, port);
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index fd67cc5..adfe660 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -92,6 +92,7 @@
 	{ USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */
 	{ USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */
 	{ USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */
+	{ USB_DEVICE(0x10C4, 0x81A9) }, /* Multiplex RC Interface */
 	{ USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */
 	{ USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */
 	{ USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
@@ -280,7 +281,10 @@
 		dbg("%s - Unable to send config request, "
 				"request=0x%x size=%d result=%d\n",
 				__func__, request, size, result);
-		return -EPROTO;
+		if (result > 0)
+			result = -EPROTO;
+
+		return result;
 	}
 
 	return 0;
@@ -331,7 +335,10 @@
 		dbg("%s - Unable to send request, "
 				"request=0x%x size=%d result=%d\n",
 				__func__, request, size, result);
-		return -EPROTO;
+		if (result > 0)
+			result = -EPROTO;
+
+		return result;
 	}
 
 	return 0;
@@ -395,10 +402,11 @@
 
 	dbg("%s - port %d", __func__, port->number);
 
-	if (cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_ENABLE)) {
-		dev_err(&port->dev, "%s - Unable to enable UART\n",
-				__func__);
-		return -EPROTO;
+	result = cp210x_set_config_single(port, CP210X_IFC_ENABLE,
+								UART_ENABLE);
+	if (result) {
+		dev_err(&port->dev, "%s - Unable to enable UART\n", __func__);
+		return result;
 	}
 
 	result = usb_serial_generic_open(tty, port);
@@ -520,18 +528,13 @@
 		cflag |= PARENB;
 		break;
 	case BITS_PARITY_MARK:
-		dbg("%s - parity = MARK (not supported, disabling parity)",
-				__func__);
-		cflag &= ~PARENB;
-		bits &= ~BITS_PARITY_MASK;
-		cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
+		dbg("%s - parity = MARK", __func__);
+		cflag |= (PARENB|PARODD|CMSPAR);
 		break;
 	case BITS_PARITY_SPACE:
-		dbg("%s - parity = SPACE (not supported, disabling parity)",
-				__func__);
-		cflag &= ~PARENB;
-		bits &= ~BITS_PARITY_MASK;
-		cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
+		dbg("%s - parity = SPACE", __func__);
+		cflag &= ~PARODD;
+		cflag |= (PARENB|CMSPAR);
 		break;
 	default:
 		dbg("%s - Unknown parity mode, disabling parity", __func__);
@@ -588,7 +591,6 @@
 	if (!tty)
 		return;
 
-	tty->termios->c_cflag &= ~CMSPAR;
 	cflag = tty->termios->c_cflag;
 	old_cflag = old_termios->c_cflag;
 	baud = cp210x_quantise_baudrate(tty_get_baud_rate(tty));
@@ -643,16 +645,27 @@
 					"not supported by device\n");
 	}
 
-	if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))) {
+	if ((cflag     & (PARENB|PARODD|CMSPAR)) !=
+	    (old_cflag & (PARENB|PARODD|CMSPAR))) {
 		cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
 		bits &= ~BITS_PARITY_MASK;
 		if (cflag & PARENB) {
-			if (cflag & PARODD) {
-				bits |= BITS_PARITY_ODD;
-				dbg("%s - parity = ODD", __func__);
+			if (cflag & CMSPAR) {
+			    if (cflag & PARODD) {
+				    bits |= BITS_PARITY_MARK;
+				    dbg("%s - parity = MARK", __func__);
+			    } else {
+				    bits |= BITS_PARITY_SPACE;
+				    dbg("%s - parity = SPACE", __func__);
+			    }
 			} else {
-				bits |= BITS_PARITY_EVEN;
-				dbg("%s - parity = EVEN", __func__);
+			    if (cflag & PARODD) {
+				    bits |= BITS_PARITY_ODD;
+				    dbg("%s - parity = ODD", __func__);
+			    } else {
+				    bits |= BITS_PARITY_EVEN;
+				    dbg("%s - parity = EVEN", __func__);
+			    }
 			}
 		}
 		if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index f744ab7..98bf833 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -138,7 +138,6 @@
 
 	for (i = 0; i < serial->num_ports; ++i) {
 		int result;
-		serial->port[i]->interrupt_in_urb->dev = serial->dev;
 		result = usb_submit_urb(serial->port[i]->interrupt_in_urb,
 					GFP_KERNEL);
 		if (result)
@@ -208,7 +207,6 @@
 static int cyberjack_write(struct tty_struct *tty,
 	struct usb_serial_port *port, const unsigned char *buf, int count)
 {
-	struct usb_serial *serial = port->serial;
 	struct cyberjack_private *priv = usb_get_serial_port_data(port);
 	unsigned long flags;
 	int result;
@@ -221,22 +219,18 @@
 		return 0;
 	}
 
-	spin_lock_bh(&port->lock);
-	if (port->write_urb_busy) {
-		spin_unlock_bh(&port->lock);
+	if (!test_and_clear_bit(0, &port->write_urbs_free)) {
 		dbg("%s - already writing", __func__);
 		return 0;
 	}
-	port->write_urb_busy = 1;
-	spin_unlock_bh(&port->lock);
 
 	spin_lock_irqsave(&priv->lock, flags);
 
 	if (count+priv->wrfilled > sizeof(priv->wrbuf)) {
 		/* To much data for buffer. Reset buffer. */
 		priv->wrfilled = 0;
-		port->write_urb_busy = 0;
 		spin_unlock_irqrestore(&priv->lock, flags);
+		set_bit(0, &port->write_urbs_free);
 		return 0;
 	}
 
@@ -265,13 +259,7 @@
 		priv->wrsent = length;
 
 		/* set up our urb */
-		usb_fill_bulk_urb(port->write_urb, serial->dev,
-			      usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
-			      port->write_urb->transfer_buffer, length,
-			      ((serial->type->write_bulk_callback) ?
-			       serial->type->write_bulk_callback :
-			       cyberjack_write_bulk_callback),
-			      port);
+		port->write_urb->transfer_buffer_length = length;
 
 		/* send the data out the bulk port */
 		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
@@ -283,7 +271,7 @@
 			priv->wrfilled = 0;
 			priv->wrsent = 0;
 			spin_unlock_irqrestore(&priv->lock, flags);
-			port->write_urb_busy = 0;
+			set_bit(0, &port->write_urbs_free);
 			return 0;
 		}
 
@@ -351,7 +339,6 @@
 		spin_unlock(&priv->lock);
 
 		if (!old_rdtodo) {
-			port->read_urb->dev = port->serial->dev;
 			result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
 			if (result)
 				dev_err(&port->dev, "%s - failed resubmitting "
@@ -362,7 +349,6 @@
 	}
 
 resubmit:
-	port->interrupt_in_urb->dev = port->serial->dev;
 	result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
 	if (result)
 		dev_err(&port->dev, "usb_submit_urb(read int) failed\n");
@@ -415,7 +401,6 @@
 
 	/* Continue to read if we have still urbs to do. */
 	if (todo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/) {
-		port->read_urb->dev = port->serial->dev;
 		result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
 		if (result)
 			dev_err(&port->dev, "%s - failed resubmitting read "
@@ -432,7 +417,7 @@
 
 	dbg("%s - port %d", __func__, port->number);
 
-	port->write_urb_busy = 0;
+	set_bit(0, &port->write_urbs_free);
 	if (status) {
 		dbg("%s - nonzero write bulk status received: %d",
 		    __func__, status);
@@ -455,13 +440,7 @@
 		priv->wrsent += length;
 
 		/* set up our urb */
-		usb_fill_bulk_urb(port->write_urb, port->serial->dev,
-			      usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress),
-			      port->write_urb->transfer_buffer, length,
-			      ((port->serial->type->write_bulk_callback) ?
-			       port->serial->type->write_bulk_callback :
-			       cyberjack_write_bulk_callback),
-			      port);
+		port->write_urb->transfer_buffer_length = length;
 
 		/* send the data out the bulk port */
 		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index d9906eb..07680d6 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -16,32 +16,6 @@
  *
  * See http://geocities.com/i0xox0i for information on this driver and the
  * earthmate usb device.
- *
- *  Lonnie Mendez <dignome@gmail.com>
- *  4-29-2005
- *	Fixed problem where setting or retreiving the serial config would fail
- *	with EPIPE.  Removed CRTS toggling so the driver behaves more like
- *	other usbserial adapters.  Issued new interval of 1ms instead of the
- *	default 10ms.  As a result, transfer speed has been substantially
- *	increased from avg. 850bps to avg. 3300bps.  initial termios has also
- *	been modified.  Cleaned up code and formatting issues so it is more
- *	readable.  Replaced the C++ style comments.
- *
- *  Lonnie Mendez <dignome@gmail.com>
- *  12-15-2004
- *	Incorporated write buffering from pl2303 driver.  Fixed bug with line
- *	handling so both lines are raised in cypress_open. (was dropping rts)
- *      Various code cleanups made as well along with other misc bug fixes.
- *
- *  Lonnie Mendez <dignome@gmail.com>
- *  04-10-2004
- *	Driver modified to support dynamic line settings.  Various improvements
- *      and features.
- *
- *  Neil Whelchel
- *  10-2003
- *	Driver first released.
- *
  */
 
 /* Thanks to Neil Whelchel for writing the first cypress m8 implementation
@@ -1162,8 +1136,6 @@
 		return;
 
 	if (actually_throttled) {
-		port->interrupt_in_urb->dev = port->serial->dev;
-
 		result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 		if (result) {
 			dev_err(&port->dev, "%s - failed submitting read urb, "
@@ -1352,7 +1324,6 @@
 		dbg("%s - nonzero write bulk status received: %d",
 			__func__, status);
 		port->interrupt_out_urb->transfer_buffer_length = 1;
-		port->interrupt_out_urb->dev = port->serial->dev;
 		result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
 		if (!result)
 			return;
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index e92cbefc..6d26a77 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -13,222 +13,6 @@
 *
 *  Peter Berger (pberger@brimson.com)
 *  Al Borchers (borchers@steinerpoint.com)
-* 
-* (12/03/2001) gkh
-*	switched to using port->port.count instead of private version.
-*	Removed port->active
-*
-* (04/08/2001) gb
-*	Identify version on module load.
-*
-* (11/01/2000) Adam J. Richter
-*	usb_device_id table support
-* 
-* (11/01/2000) pberger and borchers
-*    -- Turned off the USB_DISABLE_SPD flag for write bulk urbs--it caused
-*       USB 4 ports to hang on startup.
-*    -- Serialized access to write urbs by adding the dp_write_urb_in_use
-*       flag; otherwise, the driver caused SMP system hangs.  Watching the
-*       urb status is not sufficient.
-*
-* (10/05/2000) gkh
-*    -- Fixed bug with urb->dev not being set properly, now that the usb
-*	core needs it.
-* 
-*  (8/8/2000) pberger and borchers
-*    -- Fixed close so that 
-*       - it can timeout while waiting for transmit idle, if needed;
-*       - it ignores interrupts when flushing the port, turning
-*         of modem signalling, and so on;
-*       - it waits for the flush to really complete before returning.
-*    -- Read_bulk_callback and write_bulk_callback check for a closed
-*       port before using the tty struct or writing to the port.
-*    -- The two changes above fix the oops caused by interrupted closes.
-*    -- Added interruptible args to write_oob_command and set_modem_signals
-*       and added a timeout arg to transmit_idle; needed for fixes to
-*       close.
-*    -- Added code for rx_throttle and rx_unthrottle so that input flow
-*       control works.
-*    -- Added code to set overrun, parity, framing, and break errors
-*       (untested).
-*    -- Set USB_DISABLE_SPD flag for write bulk urbs, so no 0 length
-*       bulk writes are done.  These hung the Digi USB device.  The
-*       0 length bulk writes were a new feature of usb-uhci added in
-*       the 2.4.0-test6 kernels.
-*    -- Fixed mod inc race in open; do mod inc before sleeping to wait
-*       for a close to finish.
-*
-*  (7/31/2000) pberger
-*    -- Fixed bugs with hardware handshaking:
-*       - Added code to set/clear tty->hw_stopped in digi_read_oob_callback()
-*         and digi_set_termios()
-*    -- Added code in digi_set_termios() to
-*       - add conditional in code handling transition from B0 to only
-*         set RTS if RTS/CTS flow control is either not in use or if
-*         the port is not currently throttled.
-*       - handle turning off CRTSCTS.
-*
-*  (7/30/2000) borchers
-*    -- Added support for more than one Digi USB device by moving
-*       globals to a private structure in the pointed to from the
-*       usb_serial structure.
-*    -- Moved the modem change and transmit idle wait queues into
-*       the port private structure, so each port has its own queue
-*       rather than sharing global queues.
-*    -- Added support for break signals.
-*
-*  (7/25/2000) pberger
-*    -- Added USB-2 support.  Note: the USB-2 supports 3 devices: two
-*       serial and a parallel port.  The parallel port is implemented
-*       as a serial-to-parallel converter.  That is, the driver actually
-*       presents all three USB-2 interfaces as serial ports, but the third
-*       one physically connects to a parallel device.  Thus, for example,
-*       one could plug a parallel printer into the USB-2's third port,
-*       but from the kernel's (and userland's) point of view what's
-*       actually out there is a serial device.
-*
-*  (7/15/2000) borchers
-*    -- Fixed race in open when a close is in progress.
-*    -- Keep count of opens and dec the module use count for each
-*       outstanding open when shutdown is called (on disconnect).
-*    -- Fixed sanity checks in read_bulk_callback and write_bulk_callback
-*       so pointers are checked before use.
-*    -- Split read bulk callback into in band and out of band
-*       callbacks, and no longer restart read chains if there is
-*       a status error or a sanity error.  This fixed the seg
-*       faults and other errors we used to get on disconnect.
-*    -- Port->active is once again a flag as usb-serial intended it
-*       to be, not a count.  Since it was only a char it would
-*       have been limited to 256 simultaneous opens.  Now the open
-*       count is kept in the port private structure in dp_open_count.
-*    -- Added code for modularization of the digi_acceleport driver.
-*
-*  (6/27/2000) pberger and borchers
-*    -- Zeroed out sync field in the wakeup_task before first use;
-*       otherwise the uninitialized value might prevent the task from
-*       being scheduled.
-*    -- Initialized ret value to 0 in write_bulk_callback, otherwise
-*       the uninitialized value could cause a spurious debugging message.
-*
-*  (6/22/2000) pberger and borchers
-*    -- Made cond_wait_... inline--apparently on SPARC the flags arg
-*       to spin_lock_irqsave cannot be passed to another function
-*       to call spin_unlock_irqrestore.  Thanks to Pauline Middelink.
-*    -- In digi_set_modem_signals the inner nested spin locks use just
-*       spin_lock() rather than spin_lock_irqsave().  The old code
-*       mistakenly left interrupts off.  Thanks to Pauline Middelink.
-*    -- copy_from_user (which can sleep) is no longer called while a
-*       spinlock is held.  We copy to a local buffer before getting
-*       the spinlock--don't like the extra copy but the code is simpler.
-*    -- Printk and dbg are no longer called while a spin lock is held.
-*
-*  (6/4/2000) pberger and borchers
-*    -- Replaced separate calls to spin_unlock_irqrestore and
-*       interruptible_sleep_on_timeout with a new function
-*       cond_wait_interruptible_timeout_irqrestore.  This eliminates
-*       the race condition where the wake up could happen after
-*       the unlock and before the sleep.
-*    -- Close now waits for output to drain.
-*    -- Open waits until any close in progress is finished.
-*    -- All out of band responses are now processed, not just the
-*       first in a USB packet.
-*    -- Fixed a bug that prevented the driver from working when the
-*       first Digi port was not the first USB serial port--the driver
-*       was mistakenly using the external USB serial port number to
-*       try to index into its internal ports.
-*    -- Fixed an SMP bug -- write_bulk_callback is called directly from
-*       an interrupt, so spin_lock_irqsave/spin_unlock_irqrestore are
-*       needed for locks outside write_bulk_callback that are also
-*       acquired by write_bulk_callback to prevent deadlocks.
-*    -- Fixed support for select() by making digi_chars_in_buffer()
-*       return 256 when -EINPROGRESS is set, as the line discipline
-*       code in n_tty.c expects.
-*    -- Fixed an include file ordering problem that prevented debugging
-*       messages from working.
-*    -- Fixed an intermittent timeout problem that caused writes to
-*       sometimes get stuck on some machines on some kernels.  It turns
-*       out in these circumstances write_chan() (in n_tty.c) was
-*       asleep waiting for our wakeup call.  Even though we call
-*       wake_up_interruptible() in digi_write_bulk_callback(), there is
-*       a race condition that could cause the wakeup to fail: if our
-*       wake_up_interruptible() call occurs between the time that our
-*       driver write routine finishes and write_chan() sets current->state
-*       to TASK_INTERRUPTIBLE, the effect of our wakeup setting the state
-*       to TASK_RUNNING will be lost and write_chan's subsequent call to
-*       schedule() will never return (unless it catches a signal).
-*       This race condition occurs because write_bulk_callback() (and thus
-*       the wakeup) are called asynchronously from an interrupt, rather than
-*       from the scheduler.  We can avoid the race by calling the wakeup
-*       from the scheduler queue and that's our fix:  Now, at the end of
-*       write_bulk_callback() we queue up a wakeup call on the scheduler
-*       task queue.  We still also invoke the wakeup directly since that
-*       squeezes a bit more performance out of the driver, and any lost
-*       race conditions will get cleaned up at the next scheduler run.
-*
-*       NOTE:  The problem also goes away if you comment out
-*       the two code lines in write_chan() where current->state
-*       is set to TASK_RUNNING just before calling driver.write() and to
-*       TASK_INTERRUPTIBLE immediately afterwards.  This is why the
-*       problem did not show up with the 2.2 kernels -- they do not
-*       include that code.
-*
-*  (5/16/2000) pberger and borchers
-*    -- Added timeouts to sleeps, to defend against lost wake ups.
-*    -- Handle transition to/from B0 baud rate in digi_set_termios.
-*
-*  (5/13/2000) pberger and borchers
-*    -- All commands now sent on out of band port, using
-*       digi_write_oob_command.
-*    -- Get modem control signals whenever they change, support TIOCMGET/
-*       SET/BIS/BIC ioctls.
-*    -- digi_set_termios now supports parity, word size, stop bits, and
-*       receive enable.
-*    -- Cleaned up open and close, use digi_set_termios and
-*       digi_write_oob_command to set port parameters.
-*    -- Added digi_startup_device to start read chains on all ports.
-*    -- Write buffer is only used when count==1, to be sure put_char can
-*       write a char (unless the buffer is full).
-*
-*  (5/10/2000) pberger and borchers
-*    -- Added MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT calls on open/close.
-*    -- Fixed problem where the first incoming character is lost on
-*       port opens after the first close on that port.  Now we keep
-*       the read_urb chain open until shutdown.
-*    -- Added more port conditioning calls in digi_open and digi_close.
-*    -- Convert port->active to a use count so that we can deal with multiple
-*       opens and closes properly.
-*    -- Fixed some problems with the locking code.
-*
-*  (5/3/2000) pberger and borchers
-*    -- First alpha version of the driver--many known limitations and bugs.
-*
-*
-*  Locking and SMP
-*
-*  - Each port, including the out-of-band port, has a lock used to
-*    serialize all access to the port's private structure.
-*  - The port lock is also used to serialize all writes and access to
-*    the port's URB.
-*  - The port lock is also used for the port write_wait condition
-*    variable.  Holding the port lock will prevent a wake up on the
-*    port's write_wait; this can be used with cond_wait_... to be sure
-*    the wake up is not lost in a race when dropping the lock and
-*    sleeping waiting for the wakeup.
-*  - digi_write() does not sleep, since it is sometimes called on
-*    interrupt time.
-*  - digi_write_bulk_callback() and digi_read_bulk_callback() are
-*    called directly from interrupts.  Hence spin_lock_irqsave()
-*    and spin_unlock_irqrestore() are used in the rest of the code
-*    for any locks they acquire.
-*  - digi_write_bulk_callback() gets the port lock before waking up
-*    processes sleeping on the port write_wait.  It also schedules
-*    wake ups so they happen from the scheduler, because the tty
-*    system can miss wake ups from interrupts.
-*  - All sleeps use a timeout of DIGI_RETRY_TIMEOUT before looping to
-*    recheck the condition they are sleeping on.  This is defensive,
-*    in case a wake up is lost.
-*  - Following Documentation/DocBook/kernel-locking.tmpl no spin locks
-*    are held when calling copy_to/from_user or printk.
 */
 
 #include <linux/kernel.h>
@@ -654,7 +438,6 @@
 			len &= ~3;
 		memcpy(oob_port->write_urb->transfer_buffer, buf, len);
 		oob_port->write_urb->transfer_buffer_length = len;
-		oob_port->write_urb->dev = port->serial->dev;
 		ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC);
 		if (ret == 0) {
 			oob_priv->dp_write_urb_in_use = 1;
@@ -732,7 +515,6 @@
 			memcpy(data, buf, len);
 			port->write_urb->transfer_buffer_length = len;
 		}
-		port->write_urb->dev = port->serial->dev;
 
 		ret = usb_submit_urb(port->write_urb, GFP_ATOMIC);
 		if (ret == 0) {
@@ -803,7 +585,6 @@
 	data[7] = 0;
 
 	oob_port->write_urb->transfer_buffer_length = 8;
-	oob_port->write_urb->dev = port->serial->dev;
 
 	ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC);
 	if (ret == 0) {
@@ -899,10 +680,8 @@
 	spin_lock_irqsave(&priv->dp_port_lock, flags);
 
 	/* restart read chain */
-	if (priv->dp_throttle_restart) {
-		port->read_urb->dev = port->serial->dev;
+	if (priv->dp_throttle_restart)
 		ret = usb_submit_urb(port->read_urb, GFP_ATOMIC);
-	}
 
 	/* turn throttle off */
 	priv->dp_throttled = 0;
@@ -1195,7 +974,6 @@
 	}
 
 	port->write_urb->transfer_buffer_length = data_len+2;
-	port->write_urb->dev = port->serial->dev;
 
 	*data++ = DIGI_CMD_SEND_DATA;
 	*data++ = data_len;
@@ -1271,7 +1049,6 @@
 			= (unsigned char)priv->dp_out_buf_len;
 		port->write_urb->transfer_buffer_length =
 						priv->dp_out_buf_len + 2;
-		port->write_urb->dev = serial->dev;
 		memcpy(port->write_urb->transfer_buffer + 2, priv->dp_out_buf,
 			priv->dp_out_buf_len);
 		ret = usb_submit_urb(port->write_urb, GFP_ATOMIC);
@@ -1473,7 +1250,6 @@
 	/* set USB_DISABLE_SPD flag for write bulk urbs */
 	for (i = 0; i < serial->type->num_ports + 1; i++) {
 		port = serial->port[i];
-		port->write_urb->dev = port->serial->dev;
 		ret = usb_submit_urb(port->read_urb, GFP_KERNEL);
 		if (ret != 0) {
 			dev_err(&port->dev,
@@ -1616,7 +1392,6 @@
 	}
 
 	/* continue read */
-	urb->dev = port->serial->dev;
 	ret = usb_submit_urb(urb, GFP_ATOMIC);
 	if (ret != 0 && ret != -EPERM) {
 		dev_err(&port->dev,
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index ff3db5d..c290df9 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -2105,6 +2105,9 @@
 
 	cflag = termios->c_cflag;
 
+	if (old_termios == 0)
+		goto no_skip;
+
 	if (old_termios->c_cflag == termios->c_cflag
 	    && old_termios->c_ispeed == termios->c_ispeed
 	    && old_termios->c_ospeed == termios->c_ospeed)
@@ -2118,6 +2121,7 @@
 	    (termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB)))
 		goto no_data_parity_stop_changes;
 
+no_skip:
 	/* Set number of data bits, parity, stop bits */
 
 	urb_value = 0;
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 1a49ca9..bf12565 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -901,7 +901,6 @@
 		usb_kill_urb(port->interrupt_in_urb);
 
 		dbg("%s - adding interrupt input", __func__);
-		port->interrupt_in_urb->dev = serial->dev;
 		status = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 		if (status)
 			dev_err(&serial->dev->dev,
@@ -1277,7 +1276,6 @@
 	unsigned long flags;
 	int retval;
 	struct usb_serial_port *port = urb->context;
-	struct usb_serial *serial = port->serial;
 	struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
 	unsigned char *data = urb->transfer_buffer;
 	int status = urb->status;
@@ -1311,12 +1309,6 @@
 		if (0 == (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) {
 
 			/* bulk data available */
-			usb_fill_bulk_urb(port->read_urb, serial->dev,
-					usb_rcvbulkpipe(serial->dev,
-						port->bulk_in_endpointAddress),
-					port->read_urb->transfer_buffer,
-					port->read_urb->transfer_buffer_length,
-					garmin_read_bulk_callback, port);
 			retval = usb_submit_urb(port->read_urb, GFP_ATOMIC);
 			if (retval) {
 				dev_err(&port->dev,
@@ -1353,7 +1345,6 @@
 
 	garmin_read_process(garmin_data_p, data, urb->actual_length, 0);
 
-	port->interrupt_in_urb->dev = port->serial->dev;
 	retval = usb_submit_urb(urb, GFP_ATOMIC);
 	if (retval)
 		dev_err(&urb->dev->dev,
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index e4db5ad..f740357 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -1,7 +1,7 @@
 /*
  * USB Serial Converter Generic functions
  *
- * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com)
+ * Copyright (C) 2010 - 2011 Johan Hovold (jhovold@gmail.com)
  * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
  *
  *	This program is free software; you can redistribute it and/or
@@ -132,7 +132,7 @@
 
 	/* if we have a bulk endpoint, start reading from it */
 	if (port->bulk_in_size)
-		result = usb_serial_generic_submit_read_urb(port, GFP_KERNEL);
+		result = usb_serial_generic_submit_read_urbs(port, GFP_KERNEL);
 
 	return result;
 }
@@ -157,8 +157,10 @@
 			kfifo_reset_out(&port->write_fifo);
 			spin_unlock_irqrestore(&port->lock, flags);
 		}
-		if (port->bulk_in_size)
-			usb_kill_urb(port->read_urb);
+		if (port->bulk_in_size) {
+			for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
+				usb_kill_urb(port->read_urbs[i]);
+		}
 	}
 }
 
@@ -308,19 +310,52 @@
 	return chars;
 }
 
-int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
+static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
+						int index, gfp_t mem_flags)
+{
+	int res;
+
+	if (!test_and_clear_bit(index, &port->read_urbs_free))
+		return 0;
+
+	dbg("%s - port %d, urb %d\n", __func__, port->number, index);
+
+	res = usb_submit_urb(port->read_urbs[index], mem_flags);
+	if (res) {
+		if (res != -EPERM) {
+			dev_err(&port->dev,
+					"%s - usb_submit_urb failed: %d\n",
+					__func__, res);
+		}
+		set_bit(index, &port->read_urbs_free);
+		return res;
+	}
+
+	return 0;
+}
+
+int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port,
 					gfp_t mem_flags)
 {
-	int result;
+	int res;
+	int i;
 
-	result = usb_submit_urb(port->read_urb, mem_flags);
-	if (result && result != -EPERM) {
-		dev_err(&port->dev, "%s - error submitting urb: %d\n",
-							__func__, result);
+	dbg("%s - port %d", __func__, port->number);
+
+	for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
+		res = usb_serial_generic_submit_read_urb(port, i, mem_flags);
+		if (res)
+			goto err;
 	}
-	return result;
+
+	return 0;
+err:
+	for (; i >= 0; --i)
+		usb_kill_urb(port->read_urbs[i]);
+
+	return res;
 }
-EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urb);
+EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urbs);
 
 void usb_serial_generic_process_read_urb(struct urb *urb)
 {
@@ -356,14 +391,19 @@
 {
 	struct usb_serial_port *port = urb->context;
 	unsigned char *data = urb->transfer_buffer;
-	int status = urb->status;
 	unsigned long flags;
+	int i;
 
-	dbg("%s - port %d", __func__, port->number);
+	for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
+		if (urb == port->read_urbs[i])
+			break;
+	}
+	set_bit(i, &port->read_urbs_free);
 
-	if (unlikely(status != 0)) {
-		dbg("%s - nonzero read bulk status received: %d",
-		    __func__, status);
+	dbg("%s - port %d, urb %d, len %d\n", __func__, port->number, i,
+							urb->actual_length);
+	if (urb->status) {
+		dbg("%s - non-zero urb status: %d\n", __func__, urb->status);
 		return;
 	}
 
@@ -376,7 +416,7 @@
 	port->throttled = port->throttle_req;
 	if (!port->throttled) {
 		spin_unlock_irqrestore(&port->lock, flags);
-		usb_serial_generic_submit_read_urb(port, GFP_ATOMIC);
+		usb_serial_generic_submit_read_urb(port, i, GFP_ATOMIC);
 	} else
 		spin_unlock_irqrestore(&port->lock, flags);
 }
@@ -443,7 +483,7 @@
 	spin_unlock_irq(&port->lock);
 
 	if (was_throttled)
-		usb_serial_generic_submit_read_urb(port, GFP_KERNEL);
+		usb_serial_generic_submit_read_urbs(port, GFP_KERNEL);
 }
 EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle);
 
@@ -509,8 +549,9 @@
 		if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
 			continue;
 
-		if (port->read_urb) {
-			r = usb_submit_urb(port->read_urb, GFP_NOIO);
+		if (port->bulk_in_size) {
+			r = usb_serial_generic_submit_read_urbs(port,
+								GFP_NOIO);
 			if (r < 0)
 				c++;
 		}
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 2ee8075..abd2ee2 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -610,7 +610,6 @@
 
 					/* we have pending bytes on the
 					   bulk in pipe, send a request */
-					edge_serial->read_urb->dev = edge_serial->serial->dev;
 					result = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
 					if (result) {
 						dev_err(&edge_serial->serial->dev->dev, "%s - usb_submit_urb(read bulk) failed with result = %d\n", __func__, result);
@@ -711,7 +710,6 @@
 	/* check to see if there's any more data for us to read */
 	if (edge_serial->rxBytesAvail > 0) {
 		dbg("%s - posting a read", __func__);
-		edge_serial->read_urb->dev = edge_serial->serial->dev;
 		retval = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
 		if (retval) {
 			dev_err(&urb->dev->dev,
@@ -1330,7 +1328,6 @@
 	edge_port->txCredits -= count;
 	edge_port->icount.tx += count;
 
-	urb->dev = edge_serial->serial->dev;
 	status = usb_submit_urb(urb, GFP_ATOMIC);
 	if (status) {
 		/* something went wrong */
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 0aac00a..e44d375 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -15,13 +15,6 @@
  * For questions or problems with this driver, contact Inside Out
  * Networks technical support, or Peter Berger <pberger@brimson.com>,
  * or Al Borchers <alborchers@steinerpoint.com>.
- *
- * Version history:
- *
- *	July 11, 2002 	Removed 4 port device structure since all TI UMP
- *			chips have only 2 ports
- *			David Iacovelli (davidi@ionetworks.com)
- *
  */
 
 #include <linux/kernel.h>
@@ -1777,12 +1770,11 @@
 exit:
 	/* continue read unless stopped */
 	spin_lock(&edge_port->ep_lock);
-	if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING) {
-		urb->dev = edge_port->port->serial->dev;
+	if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING)
 		retval = usb_submit_urb(urb, GFP_ATOMIC);
-	} else if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPING) {
+	else if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPING)
 		edge_port->ep_read_urb_state = EDGE_READ_URB_STOPPED;
-	}
+
 	spin_unlock(&edge_port->ep_lock);
 	if (retval)
 		dev_err(&urb->dev->dev,
@@ -1959,9 +1951,7 @@
 			status = -EINVAL;
 			goto release_es_lock;
 		}
-		urb->complete = edge_interrupt_callback;
 		urb->context = edge_serial;
-		urb->dev = dev;
 		status = usb_submit_urb(urb, GFP_KERNEL);
 		if (status) {
 			dev_err(&port->dev,
@@ -1987,9 +1977,7 @@
 		goto unlink_int_urb;
 	}
 	edge_port->ep_read_urb_state = EDGE_READ_URB_RUNNING;
-	urb->complete = edge_bulk_in_callback;
 	urb->context = edge_port;
-	urb->dev = dev;
 	status = usb_submit_urb(urb, GFP_KERNEL);
 	if (status) {
 		dev_err(&port->dev,
@@ -2118,12 +2106,7 @@
 				port->write_urb->transfer_buffer);
 
 	/* set up our urb */
-	usb_fill_bulk_urb(port->write_urb, port->serial->dev,
-			   usb_sndbulkpipe(port->serial->dev,
-					    port->bulk_out_endpointAddress),
-			   port->write_urb->transfer_buffer, count,
-			   edge_bulk_out_callback,
-			   port);
+	port->write_urb->transfer_buffer_length = count;
 
 	/* send the data out the bulk port */
 	result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
@@ -2267,9 +2250,6 @@
 
 	if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPED) {
 		urb = edge_port->port->read_urb;
-		urb->complete = edge_bulk_in_callback;
-		urb->context = edge_port;
-		urb->dev = edge_port->port->serial->dev;
 		status = usb_submit_urb(urb, GFP_ATOMIC);
 	}
 	edge_port->ep_read_urb_state = EDGE_READ_URB_RUNNING;
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 4735931..36f5cbe 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -8,40 +8,6 @@
  *	it under the terms of the GNU General Public License as published by
  *	the Free Software Foundation; either version 2 of the License, or
  *	(at your option) any later version.
- *
- * (12/12/2002) ganesh
- * 	Added support for practically all devices supported by ActiveSync
- * 	on Windows. Thanks to Wes Cilldhaire <billybobjoehenrybob@hotmail.com>.
- *
- * (26/11/2002) ganesh
- * 	Added insmod options to specify product and vendor id.
- * 	Use modprobe ipaq vendor=0xfoo product=0xbar
- *
- * (26/7/2002) ganesh
- * 	Fixed up broken error handling in ipaq_open. Retry the "kickstart"
- * 	packet much harder - this drastically reduces connection failures.
- *
- * (30/4/2002) ganesh
- * 	Added support for the Casio EM500. Completely untested. Thanks
- * 	to info from Nathan <wfilardo@fuse.net>
- *
- * (19/3/2002) ganesh
- *	Don't submit urbs while holding spinlocks. Not strictly necessary
- *	in 2.5.x.
- *
- * (8/3/2002) ganesh
- * 	The ipaq sometimes emits a '\0' before the CLIENT string. At this
- * 	point of time, the ppp ldisc is not yet attached to the tty, so
- * 	n_tty echoes "^ " to the ipaq, which messes up the chat. In 2.5.6-pre2
- * 	this causes a panic because echo_char() tries to sleep in interrupt
- * 	context.
- * 	The fix is to tell the upper layers that this is a raw device so that
- * 	echoing is suppressed. Thanks to Lyle Lindholm for a detailed bug
- * 	report.
- *
- * (25/2/2002) ganesh
- * 	Added support for the HP Jornada 548 and 568. Completely untested.
- * 	Thanks to info from Heath Robinson and Arieh Davidoff.
  */
 
 #include <linux/kernel.h>
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index ccbce40..0c537da 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -22,38 +22,6 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this
  * driver
- *
- * 2008_Jun_02  Felipe Balbi <me@felipebalbi.com>
- *	Introduced common header to be used also in USB Gadget Framework.
- *	Still needs some other style fixes.
- *
- * 2007_Jun_21  Alan Cox <alan@lxorguk.ukuu.org.uk>
- *	Minimal cleanups for some of the driver problens and tty layer abuse.
- *	Still needs fixing to allow multiple dongles.
- *
- * 2002_Mar_07	greg kh
- *	moved some needed structures and #define values from the
- *	net/irda/irda-usb.h file into our file, as we don't want to depend on
- *	that codebase compiling correctly :)
- *
- * 2002_Jan_14  gb
- *	Added module parameter to force specific number of XBOFs.
- *	Added ir_xbof_change().
- *	Reorganized read_bulk_callback error handling.
- *	Switched from FILL_BULK_URB() to usb_fill_bulk_urb().
- *
- * 2001_Nov_08  greg kh
- *	Changed the irda_usb_find_class_desc() function based on comments and
- *	code from Martin Diehl.
- *
- * 2001_Nov_01	greg kh
- *	Added support for more IrDA USB devices.
- *	Added support for zero packet.  Added buffer override paramater, so
- *	users can transfer larger packets at once if they wish.  Both patches
- *	came from Dag Brattli <dag@obexcode.com>.
- *
- * 2001_Oct_07	greg kh
- *	initial version released.
  */
 
 #include <linux/kernel.h>
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index 6aca631..64d0ffd 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -1168,15 +1168,14 @@
 			  port->write_urb->transfer_buffer, 1,
 			  read_rxcmd_callback, port);
 	result = usb_submit_urb(port->write_urb, GFP_KERNEL);
-
 	if (result) {
 		dev_err(&port->dev, "%s - failed submitting read urb,"
 			" error %d\n", __func__, result);
 		iuu_close(port);
-		return -EPROTO;
 	} else {
 		dbg("%s - rxcmd OK", __func__);
 	}
+
 	return result;
 }
 
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index a442352..bc8dc20 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -25,73 +25,6 @@
 
   Tip 'o the hat to IBM (and previously Linuxcare :) for supporting
   staff in their work on open source projects.
-
-  Change History
-
-    2003sep04	LPM (Keyspan) add support for new single port product USA19HS.
-				Improve setup message handling for all devices.
-
-    Wed Feb 19 22:00:00 PST 2003 (Jeffrey S. Laing <keyspan@jsl.com>)
-      Merged the current (1/31/03) Keyspan code with the current (2.4.21-pre4)
-      Linux source tree.  The Linux tree lacked support for the 49WLC and
-      others.  The Keyspan patches didn't work with the current kernel.
-
-    2003jan30	LPM	add support for the 49WLC and MPR
-
-    Wed Apr 25 12:00:00 PST 2002 (Keyspan)
-      Started with Hugh Blemings' code dated Jan 17, 2002.  All adapters
-      now supported (including QI and QW).  Modified port open, port
-      close, and send setup() logic to fix various data and endpoint
-      synchronization bugs and device LED status bugs.  Changed keyspan_
-      write_room() to accurately return transmit buffer availability.
-      Changed forwardingLength from 1 to 16 for all adapters.
-
-    Fri Oct 12 16:45:00 EST 2001
-      Preliminary USA-19QI and USA-28 support (both test OK for me, YMMV)
-
-    Wed Apr 25 12:00:00 PST 2002 (Keyspan)
-      Started with Hugh Blemings' code dated Jan 17, 2002.  All adapters
-      now supported (including QI and QW).  Modified port open, port
-      close, and send setup() logic to fix various data and endpoint
-      synchronization bugs and device LED status bugs.  Changed keyspan_
-      write_room() to accurately return transmit buffer availability.
-      Changed forwardingLength from 1 to 16 for all adapters.
-
-    Fri Oct 12 16:45:00 EST 2001
-      Preliminary USA-19QI and USA-28 support (both test OK for me, YMMV)
-
-    Mon Oct  8 14:29:00 EST 2001 hugh
-      Fixed bug that prevented mulitport devices operating correctly
-      if they weren't the first unit attached.
-
-    Sat Oct  6 12:31:21 EST 2001 hugh
-      Added support for USA-28XA and -28XB, misc cleanups, break support
-      for usa26 based models thanks to David Gibson.
-
-    Thu May 31 11:56:42 PDT 2001 gkh
-      switched from using spinlock to a semaphore
-
-    (04/08/2001) gb
-	Identify version on module load.
-
-    (11/01/2000) Adam J. Richter
-	usb_device_id table support.
-
-    Tue Oct 10 23:15:33 EST 2000 Hugh
-      Merged Paul's changes with my USA-49W mods.  Work in progress
-      still...
-
-    Wed Jul 19 14:00:42 EST 2000 gkh
-      Added module_init and module_exit functions to handle the fact that
-      this driver is a loadable module now.
-
-    Tue Jul 18 16:14:52 EST 2000 Hugh
-      Basic character input/output for USA-19 now mostly works,
-      fixed at 9600 baud for the moment.
-
-    Sat Jul  8 11:11:48 EST 2000 Hugh
-      First public release - nothing works except the firmware upload.
-      Tested on PPC and x86 architectures, seems to behave...
 */
 
 
@@ -397,7 +330,6 @@
 		/* send the data out the bulk port */
 		this_urb->transfer_buffer_length = todo + dataOffset;
 
-		this_urb->dev = port->serial->dev;
 		err = usb_submit_urb(this_urb, GFP_ATOMIC);
 		if (err != 0)
 			dbg("usb_submit_urb(write bulk) failed (%d)", err);
@@ -463,7 +395,6 @@
 	tty_kref_put(tty);
 
 	/* Resubmit urb so we continue receiving */
-	urb->dev = port->serial->dev;
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err != 0)
 		dbg("%s - resubmit read urb failed. (%d)", __func__, err);
@@ -559,7 +490,6 @@
 	}
 
 	/* Resubmit urb so we continue receiving */
-	urb->dev = serial->dev;
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err != 0)
 		dbg("%s - resubmit read urb failed. (%d)", __func__, err);
@@ -609,7 +539,6 @@
 		tty_kref_put(tty);
 
 		/* Resubmit urb so we continue receiving */
-		urb->dev = port->serial->dev;
 		err = usb_submit_urb(urb, GFP_ATOMIC);
 		if (err != 0)
 			dbg("%s - resubmit read urb failed. (%d)",
@@ -694,7 +623,6 @@
 	}
 
 		/* Resubmit urb so we continue receiving */
-	urb->dev = serial->dev;
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err != 0)
 		dbg("%s - resubmit read urb failed. (%d)", __func__, err);
@@ -789,8 +717,6 @@
 	}
 
 	/* Resubmit urb so we continue receiving */
-	urb->dev = serial->dev;
-
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err != 0)
 		dbg("%s - resubmit read urb failed. (%d)", __func__, err);
@@ -848,7 +774,6 @@
 	tty_kref_put(tty);
 
 	/* Resubmit urb so we continue receiving */
-	urb->dev = port->serial->dev;
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err != 0)
 		dbg("%s - resubmit read urb failed. (%d)", __func__, err);
@@ -919,8 +844,6 @@
 	}
 
 	/* Resubmit urb so we continue receiving */
-	urb->dev = serial->dev;
-
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err != 0)
 		dbg("%s - resubmit read urb failed. (%d)", __func__, err);
@@ -996,7 +919,6 @@
 	}
 
 	/* Resubmit urb so we continue receiving */
-	urb->dev = port->serial->dev;
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err != 0)
 		dbg("%s - resubmit read urb failed. (%d)", __func__, err);
@@ -1047,7 +969,6 @@
 	}
 
 	/* Resubmit urb so we continue receiving */
-	urb->dev = serial->dev;
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err != 0)
 		dbg("%s - resubmit read urb failed. (%d)", __func__, err);
@@ -1123,7 +1044,6 @@
 	}
 
 	/* Resubmit urb so we continue receiving */
-	urb->dev = serial->dev;
 	err = usb_submit_urb(urb, GFP_ATOMIC);
 	if (err != 0)
 		dbg("%s - resubmit read urb failed. (%d)", __func__, err);
@@ -1223,7 +1143,6 @@
 		urb = p_priv->in_urbs[i];
 		if (urb == NULL)
 			continue;
-		urb->dev = serial->dev;
 
 		/* make sure endpoint data toggle is synchronized
 		   with the device */
@@ -1239,7 +1158,6 @@
 		urb = p_priv->out_urbs[i];
 		if (urb == NULL)
 			continue;
-		urb->dev = serial->dev;
 		/* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
 						usb_pipeout(urb->pipe), 0); */
 	}
@@ -1956,7 +1874,6 @@
 	/* send the data out the device on control endpoint */
 	this_urb->transfer_buffer_length = sizeof(msg);
 
-	this_urb->dev = serial->dev;
 	err = usb_submit_urb(this_urb, GFP_ATOMIC);
 	if (err != 0)
 		dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err);
@@ -2084,7 +2001,6 @@
 	/* send the data out the device on control endpoint */
 	this_urb->transfer_buffer_length = sizeof(msg);
 
-	this_urb->dev = serial->dev;
 	err = usb_submit_urb(this_urb, GFP_ATOMIC);
 	if (err != 0)
 		dbg("%s - usb_submit_urb(setup) failed", __func__);
@@ -2271,8 +2187,6 @@
 
 		/* send the data out the device on control endpoint */
 		this_urb->transfer_buffer_length = sizeof(msg);
-
-		this_urb->dev = serial->dev;
 	}
 	err = usb_submit_urb(this_urb, GFP_ATOMIC);
 	if (err != 0)
@@ -2415,7 +2329,6 @@
 	/* send the data out the device on control endpoint */
 	this_urb->transfer_buffer_length = sizeof(msg);
 
-	this_urb->dev = serial->dev;
 	err = usb_submit_urb(this_urb, GFP_ATOMIC);
 	if (err != 0)
 		dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err);
@@ -2561,7 +2474,6 @@
 
 	/* send the data out the device on control endpoint */
 	this_urb->transfer_buffer_length = sizeof(msg);
-	this_urb->dev = serial->dev;
 
 	err = usb_submit_urb(this_urb, GFP_ATOMIC);
 	if (err != 0)
@@ -2650,14 +2562,12 @@
 	keyspan_setup_urbs(serial);
 
 	if (s_priv->instat_urb != NULL) {
-		s_priv->instat_urb->dev = serial->dev;
 		err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
 		if (err != 0)
 			dbg("%s - submit instat urb failed %d", __func__,
 				err);
 	}
 	if (s_priv->indat_urb != NULL) {
-		s_priv->indat_urb->dev = serial->dev;
 		err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
 		if (err != 0)
 			dbg("%s - submit indat urb failed %d", __func__,
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index d5c0c6a..a406156 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -12,59 +12,6 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this
  * driver
- *
- * (09/07/2001) gkh
- *	cleaned up the Xircom support.  Added ids for Entregra device which is
- *	the same as the Xircom device.  Enabled the code to be compiled for
- *	either Xircom or Keyspan devices.
- *
- * (08/11/2001) Cristian M. Craciunescu
- *	support for Xircom PGSDB9
- *
- * (05/31/2001) gkh
- *	switched from using spinlock to a semaphore, which fixes lots of
- *	problems.
- *
- * (04/08/2001) gb
- *	Identify version on module load.
- *
- * (11/01/2000) Adam J. Richter
- *	usb_device_id table support
- *
- * (10/05/2000) gkh
- *	Fixed bug with urb->dev not being set properly, now that the usb
- *	core needs it.
- *
- * (08/28/2000) gkh
- *	Added locks for SMP safeness.
- *	Fixed MOD_INC and MOD_DEC logic and the ability to open a port more
- *	than once.
- *
- * (07/20/2000) borchers
- *	- keyspan_pda_write no longer sleeps if it is called on interrupt time;
- *	  PPP and the line discipline with stty echo on can call write on
- *	  interrupt time and this would cause an oops if write slept
- *	- if keyspan_pda_write is in an interrupt, it will not call
- *	  usb_control_msg (which sleeps) to query the room in the device
- *	  buffer, it simply uses the current room value it has
- *	- if the urb is busy or if it is throttled keyspan_pda_write just
- *	  returns 0, rather than sleeping to wait for this to change; the
- *	  write_chan code in n_tty.c will sleep if needed before calling
- *	  keyspan_pda_write again
- *	- if the device needs to be unthrottled, write now queues up the
- *	  call to usb_control_msg (which sleeps) to unthrottle the device
- *	- the wakeups from keyspan_pda_write_bulk_callback are queued rather
- *	  than done directly from the callback to avoid the race in write_chan
- *	- keyspan_pda_chars_in_buffer also indicates its buffer is full if the
- *	  urb status is -EINPROGRESS, meaning it cannot write at the moment
- *
- * (07/19/2000) gkh
- *	Added module_init and module_exit functions to handle the fact that this
- *	driver is a loadable module now.
- *
- * (03/26/2000) gkh
- *	Split driver up into device specific pieces.
- *
  */
 
 
@@ -290,7 +237,6 @@
 	struct usb_serial_port *port = tty->driver_data;
 	/* just restart the receive interrupt URB */
 	dbg("keyspan_pda_rx_unthrottle port %d", port->number);
-	port->interrupt_in_urb->dev = port->serial->dev;
 	if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL))
 		dbg(" usb_submit_urb(read urb) failed");
 }
@@ -532,11 +478,11 @@
 	   the device is full (wait until it says there is room)
 	*/
 	spin_lock_bh(&port->lock);
-	if (port->write_urb_busy || priv->tx_throttled) {
+	if (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled) {
 		spin_unlock_bh(&port->lock);
 		return 0;
 	}
-	port->write_urb_busy = 1;
+	clear_bit(0, &port->write_urbs_free);
 	spin_unlock_bh(&port->lock);
 
 	/* At this point the URB is in our control, nobody else can submit it
@@ -598,7 +544,6 @@
 
 		priv->tx_room -= count;
 
-		port->write_urb->dev = port->serial->dev;
 		rc = usb_submit_urb(port->write_urb, GFP_ATOMIC);
 		if (rc) {
 			dbg(" usb_submit_urb(write bulk) failed");
@@ -618,7 +563,7 @@
 	rc = count;
 exit:
 	if (rc < 0)
-		port->write_urb_busy = 0;
+		set_bit(0, &port->write_urbs_free);
 	return rc;
 }
 
@@ -628,7 +573,7 @@
 	struct usb_serial_port *port = urb->context;
 	struct keyspan_pda_private *priv;
 
-	port->write_urb_busy = 0;
+	set_bit(0, &port->write_urbs_free);
 	priv = usb_get_serial_port_data(port);
 
 	/* queue up a wakeup at scheduler time */
@@ -661,7 +606,7 @@
 	   n_tty.c:normal_poll() ) that we're not writeable. */
 
 	spin_lock_irqsave(&port->lock, flags);
-	if (port->write_urb_busy || priv->tx_throttled)
+	if (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled)
 		ret = 256;
 	spin_unlock_irqrestore(&port->lock, flags);
 	return ret;
@@ -717,7 +662,6 @@
 	priv->tx_throttled = *room ? 0 : 1;
 
 	/*Start reading from the device*/
-	port->interrupt_in_urb->dev = serial->dev;
 	rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 	if (rc) {
 		dbg("%s - usb_submit_urb(read int) failed", __func__);
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index ddd1463..5d3beee 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -20,18 +20,6 @@
  *
  * Supported readers: USB TWIN, KAAN Standard Plus and SecOVID Reader Plus
  * (Adapter K), B1 Professional and KAAN Professional (Adapter B)
- *
- * (21/05/2004) tw
- *      Fix bug with P'n'P readers
- *
- * (28/05/2003) tw
- *      Add support for KAAN SIM
- *
- * (12/09/2002) tw
- *      Adapted to 2.5.
- *
- * (11/08/2002) tw
- *      Initial version.
  */
 
 
@@ -231,9 +219,6 @@
 	dbg("%s - port %d", __func__, port->number);
 	priv = usb_get_serial_port_data(port);
 
-	/* someone sets the dev to 0 if the close method has been called */
-	port->interrupt_in_urb->dev = port->serial->dev;
-
 	/* allocate memory for transfer buffer */
 	transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
 	if (!transfer_buffer)
@@ -393,8 +378,6 @@
 		tty_flip_buffer_push(tty);
 	}
 	tty_kref_put(tty);
-	/* someone sets the dev to 0 if the close method has been called */
-	port->interrupt_in_urb->dev = port->serial->dev;
 
 	result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
 	dbg("%s - port %d Send read URB returns: %i",
@@ -475,17 +458,9 @@
 		priv->filled = 0;
 		priv->cur_pos = 0;
 
-		/* someone sets the dev to 0 if the close method
-		   has been called */
-		port->interrupt_in_urb->dev = port->serial->dev;
-
 		/* start reading (except TWIN and KAAN SIM) */
 		if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID ||
 			priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) {
-			/* someone sets the dev to 0 if the close method has
-			   been called */
-			port->interrupt_in_urb->dev = port->serial->dev;
-
 			result = usb_submit_urb(port->interrupt_in_urb,
 								GFP_NOIO);
 			dbg("%s - port %d Send read URB returns: %i",
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index ba0d287..a975bb8 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -19,50 +19,6 @@
  *   DTR/RTS signal handling may be incomplete or incorrect. I have mainly
  *   implemented what I have seen with SniffUSB or found in belkin_sa.c.
  *   For further TODOs check also belkin_sa.c.
- *
- * TEST STATUS:
- *   Basic tests have been performed with minicom/zmodem transfers and
- *   modem dialing under Linux 2.4.0-test10 (for me it works fine).
- *
- * 04-Nov-2003 Bill Marr <marr at flex dot com>
- *   - Mimic Windows driver by sending 2 USB 'device request' messages
- *     following normal 'baud rate change' message.  This allows data to be
- *     transmitted to RS-232 devices which don't assert the 'CTS' signal.
- *
- * 10-Nov-2001 Wolfgang Grandegger
- *   - Fixed an endianess problem with the baudrate selection for PowerPC.
- *
- * 06-Dec-2001 Martin Hamilton <martinh@gnu.org>
- *   - Added support for the Belkin F5U109 DB9 adaptor
- *
- * 30-May-2001 Greg Kroah-Hartman
- *   - switched from using spinlock to a semaphore, which fixes lots of
- *     problems.
- *
- * 04-May-2001 Stelian Pop
- *   - Set the maximum bulk output size for Sitecom U232-P25 model to 16 bytes
- *     instead of the device reported 32 (using 32 bytes causes many data
- *     loss, Windows driver uses 16 too).
- *
- * 02-May-2001 Stelian Pop
- *   - Fixed the baud calculation for Sitecom U232-P25 model
- *
- * 08-Apr-2001 gb
- *   - Identify version on module load.
- *
- * 06-Jan-2001 Cornel Ciocirlan
- *   - Added support for Sitecom U232-P25 model (Product Id 0x0230)
- *   - Added support for D-Link DU-H3SP USB BAY (Product Id 0x0200)
- *
- * 29-Nov-2000 Greg Kroah-Hartman
- *   - Added device id table to fit with 2.4.0-test11 structure.
- *   - took out DEAL_WITH_TWO_INT_IN_ENDPOINTS #define as it's not needed
- *     (lots of things will change if/when the usb-serial core changes to
- *     handle these issues.
- *
- * 27-Nov-2000 Wolfgang Grandegge
- *   A version for kernel 2.4.0-test10 released to the Linux community
- *   (via linux-usb-devel).
  */
 
 #include <linux/kernel.h>
@@ -526,7 +482,6 @@
 	mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	port->read_urb->dev = port->serial->dev;
 	retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
 	if (retval) {
 		dev_err(&port->dev,
@@ -535,7 +490,6 @@
 		goto error;
 	}
 
-	port->interrupt_in_urb->dev = port->serial->dev;
 	retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 	if (retval) {
 		usb_kill_urb(port->read_urb);
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 3524a10..19d112f 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -939,14 +939,7 @@
 	}
 	tty_kref_put(tty);
 
-	if (!port->read_urb) {
-		dbg("URB KILLED !!!");
-		return;
-	}
-
 	if (port->read_urb->status != -EINPROGRESS) {
-		port->read_urb->dev = port->serial->dev;
-
 		retval = usb_submit_urb(port->read_urb, GFP_ATOMIC);
 		if (retval)
 			dbg("usb_submit_urb(read bulk) failed, retval = %d",
@@ -1014,7 +1007,6 @@
 static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
 	struct usb_serial *serial;
-	struct usb_serial_port *port0;
 	struct urb *urb;
 	struct moschip_port *mos7720_port;
 	int response;
@@ -1029,8 +1021,6 @@
 	if (mos7720_port == NULL)
 		return -ENODEV;
 
-	port0 = serial->port[0];
-
 	usb_clear_halt(serial->dev, port->write_urb->pipe);
 	usb_clear_halt(serial->dev, port->read_urb->pipe);
 
@@ -1735,8 +1725,6 @@
 	write_mos_reg(serial, port_number, IER, 0x0c);
 
 	if (port->read_urb->status != -EINPROGRESS) {
-		port->read_urb->dev = serial->dev;
-
 		status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
 		if (status)
 			dbg("usb_submit_urb(read bulk) failed, status = %d",
@@ -1786,13 +1774,7 @@
 	/* change the port settings to the new ones specified */
 	change_port_settings(tty, mos7720_port, old_termios);
 
-	if (!port->read_urb) {
-		dbg("%s", "URB KILLED !!!!!");
-		return;
-	}
-
 	if (port->read_urb->status != -EINPROGRESS) {
-		port->read_urb->dev = serial->dev;
 		status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
 		if (status)
 			dbg("usb_submit_urb(read bulk) failed, status = %d",
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index c72abd5..55cfd62 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -792,8 +792,6 @@
 	}
 
 
-	mos7840_port->read_urb->dev = serial->dev;
-
 	mos7840_port->read_urb_busy = true;
 	retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
 
@@ -2058,7 +2056,6 @@
 	mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
 
 	if (mos7840_port->read_urb_busy == false) {
-		mos7840_port->read_urb->dev = serial->dev;
 		mos7840_port->read_urb_busy = true;
 		status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
 		if (status) {
@@ -2130,7 +2127,6 @@
 	}
 
 	if (mos7840_port->read_urb_busy == false) {
-		mos7840_port->read_urb->dev = serial->dev;
 		mos7840_port->read_urb_busy = true;
 		status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
 		if (status) {
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 60f38d5..45a8c55 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -9,31 +9,6 @@
  * driver
  *
  * Please report both successes and troubles to the author at omninet@kroah.com
- *
- * (05/30/2001) gkh
- *	switched from using spinlock to a semaphore, which fixes lots of
- *	problems.
- *
- * (04/08/2001) gb
- *	Identify version on module load.
- *
- * (11/01/2000) Adam J. Richter
- *	usb_device_id table support
- *
- * (10/05/2000) gkh
- *	Fixed bug with urb->dev not being set properly, now that the usb
- *	core needs it.
- *
- * (08/28/2000) gkh
- *	Added locks for SMP safeness.
- *	Fixed MOD_INC and MOD_DEC logic and the ability to open a port more
- *	than once.
- *	Fixed potential race in omninet_write_bulk_callback
- *
- * (07/19/2000) gkh
- *	Added module_init and module_exit functions to handle the fact that this
- *	driver is a loadable module now.
- *
  */
 
 #include <linux/kernel.h>
@@ -44,7 +19,6 @@
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
-#include <linux/spinlock.h>
 #include <linux/uaccess.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
@@ -174,12 +148,6 @@
 	tty_port_tty_set(&wport->port, tty);
 
 	/* Start reading from the device */
-	usb_fill_bulk_urb(port->read_urb, serial->dev,
-			usb_rcvbulkpipe(serial->dev,
-				port->bulk_in_endpointAddress),
-			port->read_urb->transfer_buffer,
-			port->read_urb->transfer_buffer_length,
-			omninet_read_bulk_callback, port);
 	result = usb_submit_urb(port->read_urb, GFP_KERNEL);
 	if (result)
 		dev_err(&port->dev,
@@ -236,11 +204,6 @@
 	}
 
 	/* Continue trying to always read  */
-	usb_fill_bulk_urb(urb, port->serial->dev,
-			usb_rcvbulkpipe(port->serial->dev,
-					port->bulk_in_endpointAddress),
-			urb->transfer_buffer, urb->transfer_buffer_length,
-			omninet_read_bulk_callback, port);
 	result = usb_submit_urb(urb, GFP_ATOMIC);
 	if (result)
 		dev_err(&port->dev,
@@ -267,14 +230,10 @@
 		return 0;
 	}
 
-	spin_lock_bh(&wport->lock);
-	if (wport->write_urb_busy) {
-		spin_unlock_bh(&wport->lock);
+	if (!test_and_clear_bit(0, &port->write_urbs_free)) {
 		dbg("%s - already writing", __func__);
 		return 0;
 	}
-	wport->write_urb_busy = 1;
-	spin_unlock_bh(&wport->lock);
 
 	count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
 
@@ -292,10 +251,9 @@
 	/* send the data out the bulk port, always 64 bytes */
 	wport->write_urb->transfer_buffer_length = 64;
 
-	wport->write_urb->dev = serial->dev;
 	result = usb_submit_urb(wport->write_urb, GFP_ATOMIC);
 	if (result) {
-		wport->write_urb_busy = 0;
+		set_bit(0, &wport->write_urbs_free);
 		dev_err(&port->dev,
 			"%s - failed submitting write urb, error %d\n",
 			__func__, result);
@@ -314,8 +272,7 @@
 
 	int room = 0; /* Default: no room */
 
-	/* FIXME: no consistent locking for write_urb_busy */
-	if (wport->write_urb_busy)
+	if (test_bit(0, &wport->write_urbs_free))
 		room = wport->bulk_out_size - OMNINET_HEADERLEN;
 
 	dbg("%s - returns %d", __func__, room);
@@ -332,7 +289,7 @@
 
 	dbg("%s - port %0x", __func__, port->number);
 
-	port->write_urb_busy = 0;
+	set_bit(0, &port->write_urbs_free);
 	if (status) {
 		dbg("%s - nonzero write bulk status received: %d",
 		    __func__, status);
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
index c248a91..691f57a 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -384,7 +384,6 @@
 	priv->actually_throttled = false;
 	spin_unlock_irqrestore(&priv->lock, flags);
 
-	priv->bulk_read_urb->dev = port->serial->dev;
 	if (was_throttled) {
 		result = usb_submit_urb(priv->bulk_read_urb, GFP_ATOMIC);
 		if (result)
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 6dd6453..c96b6b6 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -476,6 +476,10 @@
 #define VIETTEL_VENDOR_ID			0x2262
 #define VIETTEL_PRODUCT_VT1000			0x0002
 
+/* ZD Incorporated */
+#define ZD_VENDOR_ID				0x0685
+#define ZD_PRODUCT_7000				0x7000
+
 /* some devices interfaces need special handling due to a number of reasons */
 enum option_blacklist_reason {
 		OPTION_BLACKLIST_NONE = 0,
@@ -1178,6 +1182,7 @@
 	{ USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU528) },
 	{ USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU526) },
 	{ USB_DEVICE_AND_INTERFACE_INFO(VIETTEL_VENDOR_ID, VIETTEL_PRODUCT_VT1000, 0xff, 0xff, 0xff) },
+	{ USB_DEVICE_AND_INTERFACE_INFO(ZD_VENDOR_ID, ZD_PRODUCT_7000, 0xff, 0xff, 0xff) },
 	{ } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index 4c29e6c..2161d1c 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -264,7 +264,6 @@
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	dbg("%s(): submitting interrupt urb", __func__);
-	port->interrupt_in_urb->dev = port->serial->dev;
 	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 	if (result != 0) {
 		dev_err(&port->dev, "%s(): usb_submit_urb() failed"
@@ -321,7 +320,6 @@
 		priv->flags.write_urb_in_use = 0;
 
 		dbg("%s(): submitting interrupt urb", __func__);
-		port->interrupt_in_urb->dev = port->serial->dev;
 		result = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
 		if (result != 0) {
 			dev_err(&port->dev, "%s(): usb_submit_urb() failed"
@@ -334,7 +332,6 @@
 					port->write_urb->transfer_buffer,
 					count, &port->lock);
 	port->write_urb->transfer_buffer_length = count;
-	port->write_urb->dev = port->serial->dev;
 	result = usb_submit_urb(port->write_urb, GFP_NOIO);
 	if (result != 0) {
 		dev_err(&port->dev, "%s(): usb_submit_urb() failed"
@@ -583,13 +580,12 @@
 	kfree(buf);
 
 	dbg("%s(): submitting interrupt urb", __func__);
-	port->interrupt_in_urb->dev = serial->dev;
 	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 	if (result != 0) {
 		dev_err(&port->dev, "%s(): usb_submit_urb() failed"
 			       " with error %d\n", __func__, result);
 		oti6858_close(port);
-		return -EPROTO;
+		return result;
 	}
 
 	/* setup termios */
@@ -837,7 +833,6 @@
 	if (can_recv) {
 		int result;
 
-		port->read_urb->dev = port->serial->dev;
 		result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
 		if (result != 0) {
 			priv->flags.read_urb_in_use = 0;
@@ -866,7 +861,6 @@
 		int result;
 
 /*		dbg("%s(): submitting interrupt urb", __func__); */
-		urb->dev = port->serial->dev;
 		result = usb_submit_urb(urb, GFP_ATOMIC);
 		if (result != 0) {
 			dev_err(&urb->dev->dev,
@@ -894,18 +888,6 @@
 	spin_unlock_irqrestore(&priv->lock, flags);
 
 	if (status != 0) {
-		/*
-		if (status == -EPROTO) {
-			* PL2303 mysteriously fails with -EPROTO reschedule
-			   the read *
-			dbg("%s - caught -EPROTO, resubmitting the urb",
-								__func__);
-			result = usb_submit_urb(urb, GFP_ATOMIC);
-			if (result)
-				dev_err(&urb->dev->dev, "%s - failed resubmitting read urb, error %d\n", __func__, result);
-			return;
-		}
-		*/
 		dbg("%s(): unable to handle the error, exiting", __func__);
 		return;
 	}
@@ -918,7 +900,6 @@
 	tty_kref_put(tty);
 
 	/* schedule the interrupt urb */
-	port->interrupt_in_urb->dev = port->serial->dev;
 	result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
 	if (result != 0 && result != -EPERM) {
 		dev_err(&port->dev, "%s(): usb_submit_urb() failed,"
@@ -955,7 +936,6 @@
 		dbg("%s(): overflow in write", __func__);
 
 		port->write_urb->transfer_buffer_length = 1;
-		port->write_urb->dev = port->serial->dev;
 		result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
 		if (result) {
 			dev_err(&port->dev, "%s(): usb_submit_urb() failed,"
@@ -968,7 +948,6 @@
 	priv->flags.write_urb_in_use = 0;
 
 	/* schedule the interrupt urb if we are still open */
-	port->interrupt_in_urb->dev = port->serial->dev;
 	dbg("%s(): submitting interrupt urb", __func__);
 	result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
 	if (result != 0) {
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index fc2d66f..3292956 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -502,21 +502,20 @@
 	if (tty)
 		pl2303_set_termios(tty, port, &tmp_termios);
 
-	dbg("%s - submitting read urb", __func__);
-	result = usb_serial_generic_submit_read_urb(port, GFP_KERNEL);
-	if (result) {
-		pl2303_close(port);
-		return -EPROTO;
-	}
-
 	dbg("%s - submitting interrupt urb", __func__);
 	result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
 	if (result) {
 		dev_err(&port->dev, "%s - failed submitting interrupt urb,"
 			" error %d\n", __func__, result);
-		pl2303_close(port);
-		return -EPROTO;
+		return result;
 	}
+
+	result = usb_serial_generic_open(tty, port);
+	if (result) {
+		usb_kill_urb(port->interrupt_in_urb);
+		return result;
+	}
+
 	port->port.drain_delay = 256;
 	return 0;
 }
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index b18179b..f248542 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -681,7 +681,6 @@
 	/* Resubmit urb so we continue receiving IRQ data */
 	if (status != -ESHUTDOWN && status != -ENOENT) {
 		usb_mark_last_busy(serial->dev);
-		urb->dev = serial->dev;
 		err = usb_submit_urb(urb, GFP_ATOMIC);
 		if (err && err != -EPERM)
 			dev_err(&port->dev, "%s: resubmit intr urb "
diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c
index 7096f79..c70cc01 100644
--- a/drivers/usb/serial/symbolserial.c
+++ b/drivers/usb/serial/symbolserial.c
@@ -182,7 +182,6 @@
 	priv->actually_throttled = false;
 	spin_unlock_irq(&priv->lock);
 
-	priv->int_urb->dev = port->serial->dev;
 	if (was_throttled) {
 		result = usb_submit_urb(priv->int_urb, GFP_KERNEL);
 		if (result)
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index ea84456..4af21f4 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -535,9 +535,7 @@
 			status = -EINVAL;
 			goto release_lock;
 		}
-		urb->complete = ti_interrupt_callback;
 		urb->context = tdev;
-		urb->dev = dev;
 		status = usb_submit_urb(urb, GFP_KERNEL);
 		if (status) {
 			dev_err(&port->dev,
@@ -619,9 +617,7 @@
 		goto unlink_int_urb;
 	}
 	tport->tp_read_urb_state = TI_READ_URB_RUNNING;
-	urb->complete = ti_bulk_in_callback;
 	urb->context = tport;
-	urb->dev = dev;
 	status = usb_submit_urb(urb, GFP_KERNEL);
 	if (status) {
 		dev_err(&port->dev, "%s - submit read urb failed, %d\n",
@@ -1236,12 +1232,11 @@
 exit:
 	/* continue to read unless stopping */
 	spin_lock(&tport->tp_lock);
-	if (tport->tp_read_urb_state == TI_READ_URB_RUNNING) {
-		urb->dev = port->serial->dev;
+	if (tport->tp_read_urb_state == TI_READ_URB_RUNNING)
 		retval = usb_submit_urb(urb, GFP_ATOMIC);
-	} else if (tport->tp_read_urb_state == TI_READ_URB_STOPPING) {
+	else if (tport->tp_read_urb_state == TI_READ_URB_STOPPING)
 		tport->tp_read_urb_state = TI_READ_URB_STOPPED;
-	}
+
 	spin_unlock(&tport->tp_lock);
 	if (retval)
 		dev_err(dev, "%s - resubmit read urb failed, %d\n",
@@ -1574,9 +1569,7 @@
 		tport->tp_read_urb_state = TI_READ_URB_RUNNING;
 		urb = tport->tp_port->read_urb;
 		spin_unlock_irqrestore(&tport->tp_lock, flags);
-		urb->complete = ti_bulk_in_callback;
 		urb->context = tport;
-		urb->dev = tport->tp_port->serial->dev;
 		status = usb_submit_urb(urb, GFP_KERNEL);
 	} else  {
 		tport->tp_read_urb_state = TI_READ_URB_RUNNING;
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index cc274fd..ce6c1a6 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -50,7 +50,7 @@
 	.disconnect =	usb_serial_disconnect,
 	.suspend =	usb_serial_suspend,
 	.resume =	usb_serial_resume,
-	.no_dynamic_id = 	1,
+	.no_dynamic_id =	1,
 	.supports_autosuspend =	1,
 };
 
@@ -260,6 +260,10 @@
 	else
 		retval = port->serial->type->open(tty, port);
 	mutex_unlock(&serial->disc_mutex);
+
+	if (retval < 0)
+		retval = usb_translate_errors(retval);
+
 	return retval;
 }
 
@@ -360,7 +364,8 @@
 
 	/* pass on to the driver specific version of this function */
 	retval = port->serial->type->write(tty, port, buf, count);
-
+	if (retval < 0)
+		retval = usb_translate_errors(retval);
 exit:
 	return retval;
 }
@@ -562,8 +567,8 @@
 {
 	int i;
 
-	usb_kill_urb(port->read_urb);
-	usb_kill_urb(port->write_urb);
+	for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
+		usb_kill_urb(port->read_urbs[i]);
 	for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
 		usb_kill_urb(port->write_urbs[i]);
 	/*
@@ -595,17 +600,17 @@
 	kill_traffic(port);
 	cancel_work_sync(&port->work);
 
-	usb_free_urb(port->read_urb);
-	usb_free_urb(port->write_urb);
 	usb_free_urb(port->interrupt_in_urb);
 	usb_free_urb(port->interrupt_out_urb);
+	for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
+		usb_free_urb(port->read_urbs[i]);
+		kfree(port->bulk_in_buffers[i]);
+	}
 	for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) {
 		usb_free_urb(port->write_urbs[i]);
 		kfree(port->bulk_out_buffers[i]);
 	}
 	kfifo_free(&port->write_fifo);
-	kfree(port->bulk_in_buffer);
-	kfree(port->bulk_out_buffer);
 	kfree(port->interrupt_in_buffer);
 	kfree(port->interrupt_out_buffer);
 	kfree(port);
@@ -686,16 +691,18 @@
 {
 	struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
 	struct usb_serial_driver *drv = p->serial->type;
+
 	if (drv->carrier_raised)
 		return drv->carrier_raised(p);
 	/* No carrier control - don't block */
-	return 1;	
+	return 1;
 }
 
 static void serial_dtr_rts(struct tty_port *port, int on)
 {
 	struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
 	struct usb_serial_driver *drv = p->serial->type;
+
 	if (drv->dtr_rts)
 		drv->dtr_rts(p, on);
 }
@@ -724,6 +731,7 @@
 	unsigned int minor;
 	int buffer_size;
 	int i;
+	int j;
 	int num_interrupt_in = 0;
 	int num_interrupt_out = 0;
 	int num_bulk_in = 0;
@@ -906,38 +914,41 @@
 	for (i = 0; i < num_bulk_in; ++i) {
 		endpoint = bulk_in_endpoint[i];
 		port = serial->port[i];
-		port->read_urb = usb_alloc_urb(0, GFP_KERNEL);
-		if (!port->read_urb) {
-			dev_err(&interface->dev, "No free urbs available\n");
-			goto probe_error;
-		}
 		buffer_size = max_t(int, serial->type->bulk_in_size,
 				usb_endpoint_maxp(endpoint));
 		port->bulk_in_size = buffer_size;
 		port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
-		port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
-		if (!port->bulk_in_buffer) {
-			dev_err(&interface->dev,
+
+		for (j = 0; j < ARRAY_SIZE(port->read_urbs); ++j) {
+			set_bit(j, &port->read_urbs_free);
+			port->read_urbs[j] = usb_alloc_urb(0, GFP_KERNEL);
+			if (!port->read_urbs[j]) {
+				dev_err(&interface->dev,
+						"No free urbs available\n");
+				goto probe_error;
+			}
+			port->bulk_in_buffers[j] = kmalloc(buffer_size,
+								GFP_KERNEL);
+			if (!port->bulk_in_buffers[j]) {
+				dev_err(&interface->dev,
 					"Couldn't allocate bulk_in_buffer\n");
-			goto probe_error;
-		}
-		usb_fill_bulk_urb(port->read_urb, dev,
-				usb_rcvbulkpipe(dev,
+				goto probe_error;
+			}
+			usb_fill_bulk_urb(port->read_urbs[j], dev,
+					usb_rcvbulkpipe(dev,
 						endpoint->bEndpointAddress),
-				port->bulk_in_buffer, buffer_size,
-				serial->type->read_bulk_callback, port);
+					port->bulk_in_buffers[j], buffer_size,
+					serial->type->read_bulk_callback,
+					port);
+		}
+
+		port->read_urb = port->read_urbs[0];
+		port->bulk_in_buffer = port->bulk_in_buffers[0];
 	}
 
 	for (i = 0; i < num_bulk_out; ++i) {
-		int j;
-
 		endpoint = bulk_out_endpoint[i];
 		port = serial->port[i];
-		port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
-		if (!port->write_urb) {
-			dev_err(&interface->dev, "No free urbs available\n");
-			goto probe_error;
-		}
 		if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL))
 			goto probe_error;
 		buffer_size = serial->type->bulk_out_size;
@@ -945,17 +956,7 @@
 			buffer_size = usb_endpoint_maxp(endpoint);
 		port->bulk_out_size = buffer_size;
 		port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
-		port->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
-		if (!port->bulk_out_buffer) {
-			dev_err(&interface->dev,
-					"Couldn't allocate bulk_out_buffer\n");
-			goto probe_error;
-		}
-		usb_fill_bulk_urb(port->write_urb, dev,
-				usb_sndbulkpipe(dev,
-					endpoint->bEndpointAddress),
-				port->bulk_out_buffer, buffer_size,
-				serial->type->write_bulk_callback, port);
+
 		for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) {
 			set_bit(j, &port->write_urbs_free);
 			port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL);
@@ -978,6 +979,9 @@
 					serial->type->write_bulk_callback,
 					port);
 		}
+
+		port->write_urb = port->write_urbs[0];
+		port->bulk_out_buffer = port->bulk_out_buffers[0];
 	}
 
 	if (serial->type->read_int_callback) {
@@ -1196,7 +1200,7 @@
 	.open =			serial_open,
 	.close =		serial_close,
 	.write =		serial_write,
-	.hangup = 		serial_hangup,
+	.hangup =		serial_hangup,
 	.write_room =		serial_write_room,
 	.ioctl =		serial_ioctl,
 	.set_termios =		serial_set_termios,
@@ -1206,9 +1210,9 @@
 	.chars_in_buffer =	serial_chars_in_buffer,
 	.tiocmget =		serial_tiocmget,
 	.tiocmset =		serial_tiocmset,
-	.get_icount = 		serial_get_icount,
-	.cleanup = 		serial_cleanup,
-	.install = 		serial_install,
+	.get_icount =		serial_get_icount,
+	.cleanup =		serial_cleanup,
+	.install =		serial_install,
 	.proc_fops =		&serial_proc_fops,
 };
 
@@ -1237,7 +1241,7 @@
 
 	usb_serial_tty_driver->owner = THIS_MODULE;
 	usb_serial_tty_driver->driver_name = "usbserial";
-	usb_serial_tty_driver->name = 	"ttyUSB";
+	usb_serial_tty_driver->name = "ttyUSB";
 	usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
 	usb_serial_tty_driver->minor_start = 0;
 	usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
@@ -1336,7 +1340,6 @@
 
 int usb_serial_register(struct usb_serial_driver *driver)
 {
-	/* must be called with BKL held */
 	int retval;
 
 	if (usb_disabled())
@@ -1374,7 +1377,6 @@
 
 void usb_serial_deregister(struct usb_serial_driver *device)
 {
-	/* must be called with BKL held */
 	printk(KERN_INFO "USB Serial deregistering driver %s\n",
 	       device->description);
 	mutex_lock(&table_lock);
diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c
index 95a8214..9b632e7 100644
--- a/drivers/usb/serial/usb_debug.c
+++ b/drivers/usb/serial/usb_debug.c
@@ -40,7 +40,7 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
-	.no_dynamic_id = 	1,
+	.no_dynamic_id =	1,
 };
 
 /* This HW really does not support a serial break, so one will be
@@ -54,19 +54,18 @@
 	usb_serial_generic_write(tty, port, USB_DEBUG_BRK, USB_DEBUG_BRK_SIZE);
 }
 
-static void usb_debug_read_bulk_callback(struct urb *urb)
+static void usb_debug_process_read_urb(struct urb *urb)
 {
 	struct usb_serial_port *port = urb->context;
 
 	if (urb->actual_length == USB_DEBUG_BRK_SIZE &&
-	    memcmp(urb->transfer_buffer, USB_DEBUG_BRK,
-		   USB_DEBUG_BRK_SIZE) == 0) {
+		memcmp(urb->transfer_buffer, USB_DEBUG_BRK,
+						USB_DEBUG_BRK_SIZE) == 0) {
 		usb_serial_handle_break(port);
-		usb_serial_generic_submit_read_urb(port, GFP_ATOMIC);
 		return;
 	}
 
-	usb_serial_generic_read_bulk_callback(urb);
+	usb_serial_generic_process_read_urb(urb);
 }
 
 static struct usb_serial_driver debug_device = {
@@ -79,7 +78,7 @@
 	.num_ports =		1,
 	.bulk_out_size =	USB_DEBUG_MAX_PACKET_SIZE,
 	.break_ctl =		usb_debug_break_ctl,
-	.read_bulk_callback =	usb_debug_read_bulk_callback,
+	.process_read_urb =	usb_debug_process_read_urb,
 };
 
 static int __init debug_init(void)
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 5b073bc..11af903 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -14,57 +14,6 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this
  * driver
- *
- * (10/09/2002) Stuart MacDonald (stuartm@connecttech.com)
- *	Upgrade to full working driver
- *
- * (05/30/2001) gkh
- *	switched from using spinlock to a semaphore, which fixes lots of
- *	problems.
- *
- * (04/08/2001) gb
- *	Identify version on module load.
- *
- * 2001_Mar_19 gkh
- *	Fixed MOD_INC and MOD_DEC logic, the ability to open a port more
- *	than once, and the got the proper usb_device_id table entries so
- *	the driver works again.
- *
- * (11/01/2000) Adam J. Richter
- *	usb_device_id table support
- *
- * (10/05/2000) gkh
- *	Fixed bug with urb->dev not being set properly, now that the usb
- *	core needs it.
- *
- * (10/03/2000) smd
- *	firmware is improved to guard against crap sent to device
- *	firmware now replies CMD_FAILURE on bad things
- *	read_callback fix you provided for private info struct
- *	command_finished now indicates success or fail
- *	setup_port struct now packed to avoid gcc padding
- *	firmware uses 1 based port numbering, driver now handles that
- *
- * (09/11/2000) gkh
- *	Removed DEBUG #ifdefs with call to usb_serial_debug_data
- *
- * (07/19/2000) gkh
- *	Added module_init and module_exit functions to handle the fact that this
- *	driver is a loadable module now.
- *	Fixed bug with port->minor that was found by Al Borchers
- *
- * (07/04/2000) gkh
- *	Added support for port settings. Baud rate can now be changed. Line
- *	signals are not transferred to and from the tty layer yet, but things
- *	seem to be working well now.
- *
- * (05/04/2000) gkh
- *	First cut at open and close commands. Data can flow through the ports at
- *	default speeds now.
- *
- * (03/26/2000) gkh
- *	Split driver up into device specific pieces.
- *
  */
 
 #include <linux/kernel.h>
@@ -753,7 +702,6 @@
 static int whiteheat_write(struct tty_struct *tty,
 	struct usb_serial_port *port, const unsigned char *buf, int count)
 {
-	struct usb_serial *serial = port->serial;
 	struct whiteheat_private *info = usb_get_serial_port_data(port);
 	struct whiteheat_urb_wrap *wrap;
 	struct urb *urb;
@@ -789,7 +737,6 @@
 		usb_serial_debug_data(debug, &port->dev,
 				__func__, bytes, urb->transfer_buffer);
 
-		urb->dev = serial->dev;
 		urb->transfer_buffer_length = bytes;
 		result = usb_submit_urb(urb, GFP_ATOMIC);
 		if (result) {
@@ -1035,7 +982,6 @@
 		dbg("%s - bad reply from firmware", __func__);
 
 	/* Continue trying to always read */
-	command_port->read_urb->dev = command_port->serial->dev;
 	result = usb_submit_urb(command_port->read_urb, GFP_ATOMIC);
 	if (result)
 		dbg("%s - failed resubmitting read urb, error %d",
@@ -1141,7 +1087,6 @@
 	transfer_buffer[0] = command;
 	memcpy(&transfer_buffer[1], data, datasize);
 	command_port->write_urb->transfer_buffer_length = datasize + 1;
-	command_port->write_urb->dev = port->serial->dev;
 	retval = usb_submit_urb(command_port->write_urb, GFP_NOIO);
 	if (retval) {
 		dbg("%s - submit urb failed", __func__);
@@ -1362,7 +1307,6 @@
 		/* Work around HCD bugs */
 		usb_clear_halt(serial->dev, command_port->read_urb->pipe);
 
-		command_port->read_urb->dev = serial->dev;
 		retval = usb_submit_urb(command_port->read_urb, GFP_KERNEL);
 		if (retval) {
 			dev_err(&serial->dev->dev,
@@ -1410,7 +1354,6 @@
 		list_del(tmp);
 		wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
 		urb = wrap->urb;
-		urb->dev = port->serial->dev;
 		spin_unlock_irqrestore(&info->lock, flags);
 		retval = usb_submit_urb(urb, GFP_KERNEL);
 		if (retval) {
@@ -1490,7 +1433,6 @@
 			sent += tty_insert_flip_string(tty,
 				urb->transfer_buffer, urb->actual_length);
 
-		urb->dev = port->serial->dev;
 		result = usb_submit_urb(urb, GFP_ATOMIC);
 		if (result) {
 			dev_err(&port->dev,
diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c
index 3ca87a8..51af2fe 100644
--- a/drivers/usb/storage/alauda.c
+++ b/drivers/usb/storage/alauda.c
@@ -139,7 +139,7 @@
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id alauda_usb_ids[] = {
+static struct usb_device_id alauda_usb_ids[] = {
 #	include "unusual_alauda.h"
 	{ }		/* Terminating entry */
 };
diff --git a/drivers/usb/storage/cypress_atacb.c b/drivers/usb/storage/cypress_atacb.c
index c7909df..387cbd47 100644
--- a/drivers/usb/storage/cypress_atacb.c
+++ b/drivers/usb/storage/cypress_atacb.c
@@ -43,7 +43,7 @@
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id cypress_usb_ids[] = {
+static struct usb_device_id cypress_usb_ids[] = {
 #	include "unusual_cypress.h"
 	{ }		/* Terminating entry */
 };
diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c
index a99be85..15d41f2 100644
--- a/drivers/usb/storage/datafab.c
+++ b/drivers/usb/storage/datafab.c
@@ -88,7 +88,7 @@
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id datafab_usb_ids[] = {
+static struct usb_device_id datafab_usb_ids[] = {
 #	include "unusual_datafab.h"
 	{ }		/* Terminating entry */
 };
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
index b0a1687..a6ade40 100644
--- a/drivers/usb/storage/ene_ub6250.c
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -42,7 +42,7 @@
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
 	.driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id ene_ub6250_usb_ids[] = {
+static struct usb_device_id ene_ub6250_usb_ids[] = {
 #	include "unusual_ene_ub6250.h"
 	{ }		/* Terminating entry */
 };
@@ -607,8 +607,8 @@
 
 static int sd_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb)
 {
-	u32   bl_num;
-	u16    bl_len;
+	u32	bl_num;
+	u32	bl_len;
 	unsigned int offset = 0;
 	unsigned char    buf[8];
 	struct scatterlist *sg = NULL;
@@ -622,7 +622,7 @@
 		else
 			bl_num = (info->HC_C_SIZE + 1) * 1024 - 1;
 	} else {
-		bl_len = 1<<(info->SD_READ_BL_LEN);
+		bl_len = 1 << (info->SD_READ_BL_LEN);
 		bl_num = info->SD_Block_Mult * (info->SD_C_SIZE + 1)
 				* (1 << (info->SD_C_SIZE_MULT + 2)) - 1;
 	}
@@ -777,7 +777,7 @@
 	return 0;
 }
 
-int ms_lib_alloc_logicalmap(struct us_data *us)
+static int ms_lib_alloc_logicalmap(struct us_data *us)
 {
 	u32  i;
 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
@@ -2248,7 +2248,7 @@
 /*
  * ms_scsi_irp()
  */
-int ms_scsi_irp(struct us_data *us, struct scsi_cmnd *srb)
+static int ms_scsi_irp(struct us_data *us, struct scsi_cmnd *srb)
 {
 	int result;
 	struct ene_ub6250_info *info = (struct ene_ub6250_info *)us->extra;
diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
index 03d4a87..fa16157 100644
--- a/drivers/usb/storage/freecom.c
+++ b/drivers/usb/storage/freecom.c
@@ -119,7 +119,7 @@
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id freecom_usb_ids[] = {
+static struct usb_device_id freecom_usb_ids[] = {
 #	include "unusual_freecom.h"
 	{ }		/* Terminating entry */
 };
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
index 93d359f..bd55027 100644
--- a/drivers/usb/storage/isd200.c
+++ b/drivers/usb/storage/isd200.c
@@ -76,7 +76,7 @@
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id isd200_usb_ids[] = {
+static struct usb_device_id isd200_usb_ids[] = {
 #	include "unusual_isd200.h"
 	{ }		/* Terminating entry */
 };
diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c
index 54b7165..a19211b 100644
--- a/drivers/usb/storage/jumpshot.c
+++ b/drivers/usb/storage/jumpshot.c
@@ -71,7 +71,7 @@
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id jumpshot_usb_ids[] = {
+static struct usb_device_id jumpshot_usb_ids[] = {
 #	include "unusual_jumpshot.h"
 	{ }		/* Terminating entry */
 };
diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c
index 35181e2..e720f8e 100644
--- a/drivers/usb/storage/karma.c
+++ b/drivers/usb/storage/karma.c
@@ -59,7 +59,7 @@
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id karma_usb_ids[] = {
+static struct usb_device_id karma_usb_ids[] = {
 #	include "unusual_karma.h"
 	{ }		/* Terminating entry */
 };
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index 721c8c5..d75155c 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -69,7 +69,7 @@
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id onetouch_usb_ids[] = {
+static struct usb_device_id onetouch_usb_ids[] = {
 #	include "unusual_onetouch.h"
 	{ }		/* Terminating entry */
 };
diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c
index c41cd30..1f62723 100644
--- a/drivers/usb/storage/realtek_cr.c
+++ b/drivers/usb/storage/realtek_cr.c
@@ -398,10 +398,9 @@
 	u8 cmnd[12] = { 0 };
 	u8 *buf;
 
-	buf = kmalloc(len, GFP_NOIO);
+	buf = kmemdup(data, len, GFP_NOIO);
 	if (buf == NULL)
 		return USB_STOR_TRANSPORT_ERROR;
-	memcpy(buf, data, len);
 
 	US_DEBUGP("%s, addr = 0x%x, len = %d\n", __func__, addr, len);
 
@@ -507,15 +506,14 @@
 static int __do_config_autodelink(struct us_data *us, u8 *data, u16 len)
 {
 	int retval;
-	u16 addr = 0xFE47;
 	u8 cmnd[12] = {0};
 
-	US_DEBUGP("%s, addr = 0x%x, len = %d\n", __FUNCTION__, addr, len);
+	US_DEBUGP("%s, addr = 0xfe47, len = %d\n", __FUNCTION__, len);
 
 	cmnd[0] = 0xF0;
 	cmnd[1] = 0x0E;
-	cmnd[2] = (u8)(addr >> 8);
-	cmnd[3] = (u8)addr;
+	cmnd[2] = 0xfe;
+	cmnd[3] = 0x47;
 	cmnd[4] = (u8)(len >> 8);
 	cmnd[5] = (u8)len;
 
@@ -818,7 +816,7 @@
 	return 1;
 }
 
-void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
+static void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
 {
 	struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra);
 	static int card_first_show = 1;
@@ -977,7 +975,7 @@
 }
 
 #ifdef CONFIG_PM
-int realtek_cr_suspend(struct usb_interface *iface, pm_message_t message)
+static int realtek_cr_suspend(struct usb_interface *iface, pm_message_t message)
 {
 	struct us_data *us = usb_get_intfdata(iface);
 
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
index 83ee49e..425df7d 100644
--- a/drivers/usb/storage/sddr09.c
+++ b/drivers/usb/storage/sddr09.c
@@ -71,7 +71,7 @@
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id sddr09_usb_ids[] = {
+static struct usb_device_id sddr09_usb_ids[] = {
 #	include "unusual_sddr09.h"
 	{ }		/* Terminating entry */
 };
diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c
index 8983ec2..e4ca5fc 100644
--- a/drivers/usb/storage/sddr55.c
+++ b/drivers/usb/storage/sddr55.c
@@ -48,7 +48,7 @@
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id sddr55_usb_ids[] = {
+static struct usb_device_id sddr55_usb_ids[] = {
 #	include "unusual_sddr55.h"
 	{ }		/* Terminating entry */
 };
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
index a4c0275..1369d25 100644
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -170,7 +170,7 @@
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id usbat_usb_ids[] = {
+static struct usb_device_id usbat_usb_ids[] = {
 #	include "unusual_usbat.h"
 	{ }		/* Terminating entry */
 };
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index aa84b3d..3dd7da9 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -1074,6 +1074,7 @@
 	.id_table =	usb_storage_usb_ids,
 	.supports_autosuspend = 1,
 	.soft_unbind =	1,
+	.no_dynamic_id = 1,
 };
 
 static int __init usb_stor_init(void)
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 5c6c1bd..8efeae2 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -27,6 +27,8 @@
 #define USB_SKEL_VENDOR_ID	0xfff0
 #define USB_SKEL_PRODUCT_ID	0xfff0
 
+static DEFINE_MUTEX(skel_mutex);
+
 /* table of devices that work with this driver */
 static const struct usb_device_id skel_table[] = {
 	{ USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
@@ -60,7 +62,6 @@
 	__u8			bulk_in_endpointAddr;	/* the address of the bulk in endpoint */
 	__u8			bulk_out_endpointAddr;	/* the address of the bulk out endpoint */
 	int			errors;			/* the last request tanked */
-	int			open_count;		/* count the number of openers */
 	bool			ongoing_read;		/* a read is going on */
 	bool			processed_urb;		/* indicates we haven't processed the urb */
 	spinlock_t		err_lock;		/* lock for errors */
@@ -100,39 +101,37 @@
 		goto exit;
 	}
 
+	mutex_lock(&skel_mutex);
 	dev = usb_get_intfdata(interface);
 	if (!dev) {
+		mutex_unlock(&skel_mutex);
 		retval = -ENODEV;
 		goto exit;
 	}
 
 	/* increment our usage count for the device */
 	kref_get(&dev->kref);
+	mutex_unlock(&skel_mutex);
 
 	/* lock the device to allow correctly handling errors
 	 * in resumption */
 	mutex_lock(&dev->io_mutex);
+	if (!dev->interface) {
+		retval = -ENODEV;
+		goto out_err;
+	}
 
-	if (!dev->open_count++) {
-		retval = usb_autopm_get_interface(interface);
-			if (retval) {
-				dev->open_count--;
-				mutex_unlock(&dev->io_mutex);
-				kref_put(&dev->kref, skel_delete);
-				goto exit;
-			}
-	} /* else { //uncomment this block if you want exclusive open
-		retval = -EBUSY;
-		dev->open_count--;
-		mutex_unlock(&dev->io_mutex);
-		kref_put(&dev->kref, skel_delete);
-		goto exit;
-	} */
-	/* prevent the device from being autosuspended */
+	retval = usb_autopm_get_interface(interface);
+	if (retval)
+		goto out_err;
 
 	/* save our object in the file's private structure */
 	file->private_data = dev;
+
+out_err:
 	mutex_unlock(&dev->io_mutex);
+	if (retval)
+		kref_put(&dev->kref, skel_delete);
 
 exit:
 	return retval;
@@ -148,7 +147,7 @@
 
 	/* allow the device to be autosuspended */
 	mutex_lock(&dev->io_mutex);
-	if (!--dev->open_count && dev->interface)
+	if (dev->interface)
 		usb_autopm_put_interface(dev->interface);
 	mutex_unlock(&dev->io_mutex);
 
@@ -612,7 +611,6 @@
 	int minor = interface->minor;
 
 	dev = usb_get_intfdata(interface);
-	usb_set_intfdata(interface, NULL);
 
 	/* give back our minor */
 	usb_deregister_dev(interface, &skel_class);
@@ -624,8 +622,12 @@
 
 	usb_kill_anchored_urbs(&dev->submitted);
 
+	mutex_lock(&skel_mutex);
+	usb_set_intfdata(interface, NULL);
+
 	/* decrement our usage count */
 	kref_put(&dev->kref, skel_delete);
+	mutex_unlock(&skel_mutex);
 
 	dev_info(&interface->dev, "USB Skeleton #%d now disconnected", minor);
 }
diff --git a/drivers/usb/wusbcore/Kconfig b/drivers/usb/wusbcore/Kconfig
index eb09a0a..0ead882 100644
--- a/drivers/usb/wusbcore/Kconfig
+++ b/drivers/usb/wusbcore/Kconfig
@@ -5,6 +5,7 @@
 	tristate "Enable Wireless USB extensions (EXPERIMENTAL)"
 	depends on EXPERIMENTAL
 	depends on USB
+	depends on PCI
         select UWB
         select CRYPTO
         select CRYPTO_BLKCIPHER
diff --git a/drivers/usb/wusbcore/security.c b/drivers/usb/wusbcore/security.c
index 371f617..fa810a8 100644
--- a/drivers/usb/wusbcore/security.c
+++ b/drivers/usb/wusbcore/security.c
@@ -354,7 +354,7 @@
 	struct wusb_keydvt_in keydvt_in;
 	struct wusb_keydvt_out keydvt_out;
 
-	hs = kzalloc(3*sizeof(hs[0]), GFP_KERNEL);
+	hs = kcalloc(3, sizeof(hs[0]), GFP_KERNEL);
 	if (hs == NULL) {
 		dev_err(dev, "can't allocate handshake data\n");
 		goto error_kzalloc;
diff --git a/drivers/uwb/est.c b/drivers/uwb/est.c
index de81ebf..86ed7e6 100644
--- a/drivers/uwb/est.c
+++ b/drivers/uwb/est.c
@@ -184,7 +184,7 @@
 
 	uwb_est_size = 2;
 	uwb_est_used = 0;
-	uwb_est = kzalloc(uwb_est_size * sizeof(uwb_est[0]), GFP_KERNEL);
+	uwb_est = kcalloc(uwb_est_size, sizeof(uwb_est[0]), GFP_KERNEL);
 	if (uwb_est == NULL)
 		return -ENOMEM;
 
diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c
index 3a444b4..a81eb23 100644
--- a/fs/fat/namei_vfat.c
+++ b/fs/fat/namei_vfat.c
@@ -512,7 +512,8 @@
 	int charlen;
 
 	if (utf8) {
-		*outlen = utf8s_to_utf16s(name, len, (wchar_t *)outname);
+		*outlen = utf8s_to_utf16s(name, len, UTF16_HOST_ENDIAN,
+				(wchar_t *) outname, FAT_LFN_LEN + 2);
 		if (*outlen < 0)
 			return *outlen;
 		else if (*outlen > FAT_LFN_LEN)
diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c
index 44a88a9..fea6bd5 100644
--- a/fs/nls/nls_base.c
+++ b/fs/nls/nls_base.c
@@ -52,7 +52,7 @@
 #define SURROGATE_LOW	0x00000400
 #define SURROGATE_BITS	0x000003ff
 
-int utf8_to_utf32(const u8 *s, int len, unicode_t *pu)
+int utf8_to_utf32(const u8 *s, int inlen, unicode_t *pu)
 {
 	unsigned long l;
 	int c0, c, nc;
@@ -71,7 +71,7 @@
 			*pu = (unicode_t) l;
 			return nc;
 		}
-		if (len <= nc)
+		if (inlen <= nc)
 			return -1;
 		s++;
 		c = (*s ^ 0x80) & 0xFF;
@@ -83,7 +83,7 @@
 }
 EXPORT_SYMBOL(utf8_to_utf32);
 
-int utf32_to_utf8(unicode_t u, u8 *s, int maxlen)
+int utf32_to_utf8(unicode_t u, u8 *s, int maxout)
 {
 	unsigned long l;
 	int c, nc;
@@ -97,7 +97,7 @@
 		return -1;
 
 	nc = 0;
-	for (t = utf8_table; t->cmask && maxlen; t++, maxlen--) {
+	for (t = utf8_table; t->cmask && maxout; t++, maxout--) {
 		nc++;
 		if (l <= t->lmask) {
 			c = t->shift;
@@ -114,34 +114,57 @@
 }
 EXPORT_SYMBOL(utf32_to_utf8);
 
-int utf8s_to_utf16s(const u8 *s, int len, wchar_t *pwcs)
+static inline void put_utf16(wchar_t *s, unsigned c, enum utf16_endian endian)
+{
+	switch (endian) {
+	default:
+		*s = (wchar_t) c;
+		break;
+	case UTF16_LITTLE_ENDIAN:
+		*s = __cpu_to_le16(c);
+		break;
+	case UTF16_BIG_ENDIAN:
+		*s = __cpu_to_be16(c);
+		break;
+	}
+}
+
+int utf8s_to_utf16s(const u8 *s, int inlen, enum utf16_endian endian,
+		wchar_t *pwcs, int maxout)
 {
 	u16 *op;
 	int size;
 	unicode_t u;
 
 	op = pwcs;
-	while (*s && len > 0) {
+	while (inlen > 0 && maxout > 0 && *s) {
 		if (*s & 0x80) {
-			size = utf8_to_utf32(s, len, &u);
+			size = utf8_to_utf32(s, inlen, &u);
 			if (size < 0)
 				return -EINVAL;
+			s += size;
+			inlen -= size;
 
 			if (u >= PLANE_SIZE) {
+				if (maxout < 2)
+					break;
 				u -= PLANE_SIZE;
-				*op++ = (wchar_t) (SURROGATE_PAIR |
-						((u >> 10) & SURROGATE_BITS));
-				*op++ = (wchar_t) (SURROGATE_PAIR |
+				put_utf16(op++, SURROGATE_PAIR |
+						((u >> 10) & SURROGATE_BITS),
+						endian);
+				put_utf16(op++, SURROGATE_PAIR |
 						SURROGATE_LOW |
-						(u & SURROGATE_BITS));
+						(u & SURROGATE_BITS),
+						endian);
+				maxout -= 2;
 			} else {
-				*op++ = (wchar_t) u;
+				put_utf16(op++, u, endian);
+				maxout--;
 			}
-			s += size;
-			len -= size;
 		} else {
-			*op++ = *s++;
-			len--;
+			put_utf16(op++, *s++, endian);
+			inlen--;
+			maxout--;
 		}
 	}
 	return op - pwcs;
@@ -160,27 +183,27 @@
 	}
 }
 
-int utf16s_to_utf8s(const wchar_t *pwcs, int len, enum utf16_endian endian,
-		u8 *s, int maxlen)
+int utf16s_to_utf8s(const wchar_t *pwcs, int inlen, enum utf16_endian endian,
+		u8 *s, int maxout)
 {
 	u8 *op;
 	int size;
 	unsigned long u, v;
 
 	op = s;
-	while (len > 0 && maxlen > 0) {
+	while (inlen > 0 && maxout > 0) {
 		u = get_utf16(*pwcs, endian);
 		if (!u)
 			break;
 		pwcs++;
-		len--;
+		inlen--;
 		if (u > 0x7f) {
 			if ((u & SURROGATE_MASK) == SURROGATE_PAIR) {
 				if (u & SURROGATE_LOW) {
 					/* Ignore character and move on */
 					continue;
 				}
-				if (len <= 0)
+				if (inlen <= 0)
 					break;
 				v = get_utf16(*pwcs, endian);
 				if ((v & SURROGATE_MASK) != SURROGATE_PAIR ||
@@ -191,18 +214,18 @@
 				u = PLANE_SIZE + ((u & SURROGATE_BITS) << 10)
 						+ (v & SURROGATE_BITS);
 				pwcs++;
-				len--;
+				inlen--;
 			}
-			size = utf32_to_utf8(u, op, maxlen);
+			size = utf32_to_utf8(u, op, maxout);
 			if (size == -1) {
 				/* Ignore character and move on */
 			} else {
 				op += size;
-				maxlen -= size;
+				maxout -= size;
 			}
 		} else {
 			*op++ = (u8) u;
-			maxlen--;
+			maxout--;
 		}
 	}
 	return op - s;
diff --git a/include/linux/nls.h b/include/linux/nls.h
index d47beef..5dc635f 100644
--- a/include/linux/nls.h
+++ b/include/linux/nls.h
@@ -43,7 +43,7 @@
 	UTF16_BIG_ENDIAN
 };
 
-/* nls.c */
+/* nls_base.c */
 extern int register_nls(struct nls_table *);
 extern int unregister_nls(struct nls_table *);
 extern struct nls_table *load_nls(char *);
@@ -52,7 +52,8 @@
 
 extern int utf8_to_utf32(const u8 *s, int len, unicode_t *pu);
 extern int utf32_to_utf8(unicode_t u, u8 *s, int maxlen);
-extern int utf8s_to_utf16s(const u8 *s, int len, wchar_t *pwcs);
+extern int utf8s_to_utf16s(const u8 *s, int len,
+		enum utf16_endian endian, wchar_t *pwcs, int maxlen);
 extern int utf16s_to_utf8s(const wchar_t *pwcs, int len,
 		enum utf16_endian endian, u8 *s, int maxlen);
 
diff --git a/include/linux/platform_data/mv_usb.h b/include/linux/platform_data/mv_usb.h
index e9d9149..d94804a 100644
--- a/include/linux/platform_data/mv_usb.h
+++ b/include/linux/platform_data/mv_usb.h
@@ -42,9 +42,23 @@
 	/* only valid for HCD. OTG or Host only*/
 	unsigned int		mode;
 
-	int     (*phy_init)(unsigned int regbase);
-	void    (*phy_deinit)(unsigned int regbase);
+	/* This flag is used for that needs id pin checked by otg */
+	unsigned int    disable_otg_clock_gating:1;
+	/* Force a_bus_req to be asserted */
+	 unsigned int    otg_force_a_bus_req:1;
+
+	int	(*phy_init)(void __iomem *regbase);
+	void	(*phy_deinit)(void __iomem *regbase);
 	int	(*set_vbus)(unsigned int vbus);
+	int     (*private_init)(void __iomem *opregs, void __iomem *phyregs);
 };
 
+#ifndef CONFIG_HAVE_CLK
+/* Dummy stub for clk framework */
+#define clk_get(dev, id)       NULL
+#define clk_put(clock)         do {} while (0)
+#define clk_enable(clock)      do {} while (0)
+#define clk_disable(clock)     do {} while (0)
+#endif
+
 #endif
diff --git a/include/linux/platform_data/s3c-hsudc.h b/include/linux/platform_data/s3c-hsudc.h
new file mode 100644
index 0000000..6fa1093
--- /dev/null
+++ b/include/linux/platform_data/s3c-hsudc.h
@@ -0,0 +1,34 @@
+/*
+ * S3C24XX USB 2.0 High-speed USB controller gadget driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *		http://www.samsung.com/
+ *
+ * The S3C24XX USB 2.0 high-speed USB controller supports upto 9 endpoints.
+ * Each endpoint can be configured as either in or out endpoint. Endpoints
+ * can be configured for Bulk or Interrupt transfer mode.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __LINUX_USB_S3C_HSUDC_H
+#define __LINUX_USB_S3C_HSUDC_H
+
+/**
+ * s3c24xx_hsudc_platdata - Platform data for USB High-Speed gadget controller.
+ * @epnum: Number of endpoints to be instantiated by the controller driver.
+ * @gpio_init: Platform specific USB related GPIO initialization.
+ * @gpio_uninit: Platform specific USB releted GPIO uninitialzation.
+ *
+ * Representation of platform data for the S3C24XX USB 2.0 High Speed gadget
+ * controllers.
+ */
+struct s3c24xx_hsudc_platdata {
+	unsigned int	epnum;
+	void		(*gpio_init)(void);
+	void		(*gpio_uninit)(void);
+};
+
+#endif	/* __LINUX_USB_S3C_HSUDC_H */
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 7f8d4d6..27a4e16 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -1233,6 +1233,7 @@
 	void *transfer_buffer;		/* (in) associated data buffer */
 	dma_addr_t transfer_dma;	/* (in) dma addr for transfer_buffer */
 	struct scatterlist *sg;		/* (in) scatter gather buffer list */
+	int num_mapped_sgs;		/* (internal) mapped sg entries */
 	int num_sgs;			/* (in) number of entries in the sg list */
 	u32 transfer_buffer_length;	/* (in) data buffer length */
 	u32 actual_length;		/* (return) actual transfer length */
@@ -1610,6 +1611,19 @@
 
 /* ----------------------------------------------------------------------- */
 
+/* translate USB error codes to codes user space understands */
+static inline int usb_translate_errors(int error_code)
+{
+	switch (error_code) {
+	case 0:
+	case -ENOMEM:
+	case -ENODEV:
+		return error_code;
+	default:
+		return -EIO;
+	}
+}
+
 /* Events from the usb core */
 #define USB_DEVICE_ADD		0x0001
 #define USB_DEVICE_REMOVE	0x0002
diff --git a/include/linux/usb/ch11.h b/include/linux/usb/ch11.h
index 4ebaf08..31fdb4c 100644
--- a/include/linux/usb/ch11.h
+++ b/include/linux/usb/ch11.h
@@ -26,7 +26,6 @@
 #define HUB_RESET_TT		9
 #define HUB_GET_TT_STATE	10
 #define HUB_STOP_TT		11
-#define HUB_SET_DEPTH		12
 
 /*
  * Hub class additional requests defined by USB 3.0 spec
@@ -165,11 +164,20 @@
  * wHubCharacteristics (masks)
  * See USB 2.0 spec Table 11-13, offset 3
  */
-#define HUB_CHAR_LPSM		0x0003 /* D1 .. D0 */
-#define HUB_CHAR_COMPOUND	0x0004 /* D2       */
-#define HUB_CHAR_OCPM		0x0018 /* D4 .. D3 */
-#define HUB_CHAR_TTTT           0x0060 /* D6 .. D5 */
-#define HUB_CHAR_PORTIND        0x0080 /* D7       */
+#define HUB_CHAR_LPSM		0x0003 /* Logical Power Switching Mode mask */
+#define HUB_CHAR_COMMON_LPSM	0x0000 /* All ports power control at once */
+#define HUB_CHAR_INDV_PORT_LPSM	0x0001 /* per-port power control */
+#define HUB_CHAR_NO_LPSM	0x0002 /* no power switching */
+
+#define HUB_CHAR_COMPOUND	0x0004 /* hub is part of a compound device */
+
+#define HUB_CHAR_OCPM		0x0018 /* Over-Current Protection Mode mask */
+#define HUB_CHAR_COMMON_OCPM	0x0000 /* All ports Over-Current reporting */
+#define HUB_CHAR_INDV_PORT_OCPM	0x0008 /* per-port Over-current reporting */
+#define HUB_CHAR_NO_OCPM	0x0010 /* No Over-current Protection support */
+
+#define HUB_CHAR_TTTT		0x0060 /* TT Think Time mask */
+#define HUB_CHAR_PORTIND	0x0080 /* per-port indicators (LEDs) */
 
 struct usb_hub_status {
 	__le16 wHubStatus;
@@ -198,6 +206,17 @@
 #define USB_DT_HUB_NONVAR_SIZE		7
 #define USB_DT_SS_HUB_SIZE              12
 
+/*
+ * Hub Device descriptor
+ * USB Hub class device protocols
+ */
+
+#define USB_HUB_PR_FS		0 /* Full speed hub */
+#define USB_HUB_PR_HS_NO_TT	0 /* Hi-speed hub without TT */
+#define USB_HUB_PR_HS_SINGLE_TT	1 /* Hi-speed hub with single TT */
+#define USB_HUB_PR_HS_MULTI_TT	2 /* Hi-speed hub with multiple TT */
+#define USB_HUB_PR_SS		3 /* Super speed hub */
+
 struct usb_hub_descriptor {
 	__u8  bDescLength;
 	__u8  bDescriptorType;
diff --git a/include/linux/usb/ch9.h b/include/linux/usb/ch9.h
index d5da6c6..61b2905 100644
--- a/include/linux/usb/ch9.h
+++ b/include/linux/usb/ch9.h
@@ -605,8 +605,26 @@
 } __attribute__ ((packed));
 
 #define USB_DT_SS_EP_COMP_SIZE		6
+
 /* Bits 4:0 of bmAttributes if this is a bulk endpoint */
-#define USB_SS_MAX_STREAMS(p)		(1 << ((p) & 0x1f))
+static inline int
+usb_ss_max_streams(const struct usb_ss_ep_comp_descriptor *comp)
+{
+	int		max_streams;
+
+	if (!comp)
+		return 0;
+
+	max_streams = comp->bmAttributes & 0x1f;
+
+	if (!max_streams)
+		return 0;
+
+	max_streams = 1 << max_streams;
+
+	return max_streams;
+}
+
 /* Bits 1:0 of bmAttributes if this is an isoc endpoint */
 #define USB_SS_MULT(p)			(1 + ((p) & 0x3))
 
diff --git a/include/linux/usb/gadget.h b/include/linux/usb/gadget.h
index 1d3a675..da653b5 100644
--- a/include/linux/usb/gadget.h
+++ b/include/linux/usb/gadget.h
@@ -20,6 +20,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/slab.h>
+#include <linux/scatterlist.h>
 #include <linux/types.h>
 #include <linux/usb/ch9.h>
 
@@ -32,6 +33,9 @@
  * @dma: DMA address corresponding to 'buf'.  If you don't set this
  *	field, and the usb controller needs one, it is responsible
  *	for mapping and unmapping the buffer.
+ * @sg: a scatterlist for SG-capable controllers.
+ * @num_sgs: number of SG entries
+ * @num_mapped_sgs: number of SG entries mapped to DMA (internal)
  * @length: Length of that data
  * @stream_id: The stream id, when USB3.0 bulk streams are being used
  * @no_interrupt: If true, hints that no completion irq is needed.
@@ -88,6 +92,10 @@
 	unsigned		length;
 	dma_addr_t		dma;
 
+	struct scatterlist	*sg;
+	unsigned		num_sgs;
+	unsigned		num_mapped_sgs;
+
 	unsigned		stream_id:16;
 	unsigned		no_interrupt:1;
 	unsigned		zero:1;
@@ -164,7 +172,7 @@
 	unsigned		maxpacket:16;
 	unsigned		max_streams:16;
 	unsigned		mult:2;
-	unsigned		maxburst:4;
+	unsigned		maxburst:5;
 	u8			address;
 	const struct usb_endpoint_descriptor	*desc;
 	const struct usb_ss_ep_comp_descriptor	*comp_desc;
@@ -477,8 +485,9 @@
  *	driver setup() requests
  * @ep_list: List of other endpoints supported by the device.
  * @speed: Speed of current connection to USB host.
- * @is_dualspeed: True if the controller supports both high and full speed
- *	operation.  If it does, the gadget driver must also support both.
+ * @max_speed: Maximal speed the UDC can handle.  UDC must support this
+ *      and all slower speeds.
+ * @sg_supported: true if we can handle scatter-gather
  * @is_otg: True if the USB device port uses a Mini-AB jack, so that the
  *	gadget driver must provide a USB OTG descriptor.
  * @is_a_peripheral: False unless is_otg, the "A" end of a USB cable
@@ -518,7 +527,8 @@
 	struct usb_ep			*ep0;
 	struct list_head		ep_list;	/* of usb_ep */
 	enum usb_device_speed		speed;
-	unsigned			is_dualspeed:1;
+	enum usb_device_speed		max_speed;
+	unsigned			sg_supported:1;
 	unsigned			is_otg:1;
 	unsigned			is_a_peripheral:1;
 	unsigned			b_hnp_enable:1;
@@ -549,7 +559,7 @@
 static inline int gadget_is_dualspeed(struct usb_gadget *g)
 {
 #ifdef CONFIG_USB_GADGET_DUALSPEED
-	/* runtime test would check "g->is_dualspeed" ... that might be
+	/* runtime test would check "g->max_speed" ... that might be
 	 * useful to work around hardware bugs, but is mostly pointless
 	 */
 	return 1;
@@ -567,7 +577,7 @@
 {
 #ifdef CONFIG_USB_GADGET_SUPERSPEED
 	/*
-	 * runtime test would check "g->is_superspeed" ... that might be
+	 * runtime test would check "g->max_speed" ... that might be
 	 * useful to work around hardware bugs, but is mostly pointless
 	 */
 	return 1;
@@ -760,7 +770,7 @@
 /**
  * struct usb_gadget_driver - driver for usb 'slave' devices
  * @function: String describing the gadget's function
- * @speed: Highest speed the driver handles.
+ * @max_speed: Highest speed the driver handles.
  * @setup: Invoked for ep0 control requests that aren't handled by
  *	the hardware level driver. Most calls must be handled by
  *	the gadget driver, including descriptor and configuration
@@ -824,7 +834,7 @@
  */
 struct usb_gadget_driver {
 	char			*function;
-	enum usb_device_speed	speed;
+	enum usb_device_speed	max_speed;
 	void			(*unbind)(struct usb_gadget *);
 	int			(*setup)(struct usb_gadget *,
 					const struct usb_ctrlrequest *);
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index 03354d5..b2f62f3 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -99,7 +99,6 @@
 	 */
 	unsigned long		flags;
 #define HCD_FLAG_HW_ACCESSIBLE		0	/* at full power */
-#define HCD_FLAG_SAW_IRQ		1
 #define HCD_FLAG_POLL_RH		2	/* poll for rh status? */
 #define HCD_FLAG_POLL_PENDING		3	/* status has changed? */
 #define HCD_FLAG_WAKEUP_PENDING		4	/* root hub is resuming? */
@@ -110,7 +109,6 @@
 	 * be slightly faster than test_bit().
 	 */
 #define HCD_HW_ACCESSIBLE(hcd)	((hcd)->flags & (1U << HCD_FLAG_HW_ACCESSIBLE))
-#define HCD_SAW_IRQ(hcd)	((hcd)->flags & (1U << HCD_FLAG_SAW_IRQ))
 #define HCD_POLL_RH(hcd)	((hcd)->flags & (1U << HCD_FLAG_POLL_RH))
 #define HCD_POLL_PENDING(hcd)	((hcd)->flags & (1U << HCD_FLAG_POLL_PENDING))
 #define HCD_WAKEUP_PENDING(hcd)	((hcd)->flags & (1U << HCD_FLAG_WAKEUP_PENDING))
diff --git a/include/linux/usb/renesas_usbhs.h b/include/linux/usb/renesas_usbhs.h
index e5a40c3..0d3f988 100644
--- a/include/linux/usb/renesas_usbhs.h
+++ b/include/linux/usb/renesas_usbhs.h
@@ -67,6 +67,14 @@
 	/*
 	 * option:
 	 *
+	 * for board specific clock control
+	 */
+	void (*power_ctrl)(struct platform_device *pdev,
+			   void __iomem *base, int enable);
+
+	/*
+	 * option:
+	 *
 	 * Phy reset for platform
 	 */
 	void (*phy_reset)(struct platform_device *pdev);
@@ -118,7 +126,7 @@
 	 *
 	 * delay time from notify_hotplug callback
 	 */
-	int detection_delay;
+	int detection_delay; /* msec */
 
 	/*
 	 * option:
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index b29f70b..4267a9c 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -58,11 +58,13 @@
  * @read_urb: pointer to the bulk in struct urb for this port.
  * @bulk_in_endpointAddress: endpoint address for the bulk in pipe for this
  *	port.
+ * @bulk_in_buffers: pointers to the bulk in buffers for this port
+ * @read_urbs: pointers to the bulk in urbs for this port
+ * @read_urbs_free: status bitmap the for bulk in urbs
  * @bulk_out_buffer: pointer to the bulk out buffer for this port.
  * @bulk_out_size: the size of the bulk_out_buffer, in bytes.
  * @write_urb: pointer to the bulk out struct urb for this port.
  * @write_fifo: kfifo used to buffer outgoing data
- * @write_urb_busy: port`s writing status
  * @bulk_out_buffers: pointers to the bulk out buffers for this port
  * @write_urbs: pointers to the bulk out urbs for this port
  * @write_urbs_free: status bitmap the for bulk out urbs
@@ -99,11 +101,14 @@
 	struct urb		*read_urb;
 	__u8			bulk_in_endpointAddress;
 
+	unsigned char		*bulk_in_buffers[2];
+	struct urb		*read_urbs[2];
+	unsigned long		read_urbs_free;
+
 	unsigned char		*bulk_out_buffer;
 	int			bulk_out_size;
 	struct urb		*write_urb;
 	struct kfifo		write_fifo;
-	int			write_urb_busy;
 
 	unsigned char		*bulk_out_buffers[2];
 	struct urb		*write_urbs[2];
@@ -340,7 +345,7 @@
 extern void usb_serial_generic_release(struct usb_serial *serial);
 extern int usb_serial_generic_register(int debug);
 extern void usb_serial_generic_deregister(void);
-extern int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
+extern int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port,
 						 gfp_t mem_flags);
 extern void usb_serial_generic_process_read_urb(struct urb *urb);
 extern int usb_serial_generic_prepare_write_buffer(struct usb_serial_port *port,