Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6: (70 commits)
  USB: remove duplicate device id from zc0301
  USB: remove duplicate device id from usb_storage
  USB: remove duplicate device id from keyspan
  USB: remove duplicate device id from ftdi_sio
  USB: remove duplicate device id from visor
  USB: a bit more coding style cleanup
  usbcore: trivial whitespace fixes
  usb-storage: use first bulk endpoints, not last
  EHCI: fix interrupt-driven remote wakeup
  USB: switch ehci-hcd to new polling scheme
  USB: autosuspend for usb printer driver
  USB Input: Added kernel module to support all GTCO CalComp USB InterWrite School products
  USB: Sierra Wireless auto set D0
  USB: usb ethernet gadget recognizes HUSB2DEV
  USB: list atmel husb2_udc gadget controller
  USB: gadgetfs AIO tweaks
  USB: gadgetfs behaves better on userspace init bug
  USB: gadgetfs race fix
  USB: gadgetfs simplifications
  USB: gadgetfs cleanups
  ...
diff --git a/Documentation/usb/proc_usb_info.txt b/Documentation/usb/proc_usb_info.txt
index 22c5331..077e903 100644
--- a/Documentation/usb/proc_usb_info.txt
+++ b/Documentation/usb/proc_usb_info.txt
@@ -213,15 +213,16 @@
 
 Interface descriptor info (can be multiple per Config):
 
-I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
-|   |      |      |       |             |      |       |__Driver name
-|   |      |      |       |             |      |          or "(none)"
-|   |      |      |       |             |      |__InterfaceProtocol
-|   |      |      |       |             |__InterfaceSubClass
-|   |      |      |       |__InterfaceClass
-|   |      |      |__NumberOfEndpoints
-|   |      |__AlternateSettingNumber
-|   |__InterfaceNumber
+I:* If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
+| | |      |      |       |             |      |       |__Driver name
+| | |      |      |       |             |      |          or "(none)"
+| | |      |      |       |             |      |__InterfaceProtocol
+| | |      |      |       |             |__InterfaceSubClass
+| | |      |      |       |__InterfaceClass
+| | |      |      |__NumberOfEndpoints
+| | |      |__AlternateSettingNumber
+| | |__InterfaceNumber
+| |__ "*" indicates the active altsetting (others are " ")
 |__Interface info tag
 
     A given interface may have one or more "alternate" settings.
@@ -277,7 +278,7 @@
 on how to do this.)
 
 The Interface lines can be used to determine what driver is
-being used for each device.
+being used for each device, and which altsetting it activated.
 
 The Configuration lines could be used to list maximum power
 (in milliamps) that a system's USB devices are using.
diff --git a/Documentation/usb/usbmon.txt b/Documentation/usb/usbmon.txt
index e65ec82..0f6808a 100644
--- a/Documentation/usb/usbmon.txt
+++ b/Documentation/usb/usbmon.txt
@@ -77,7 +77,7 @@
 
 The '1t' type data consists of a stream of events, such as URB submission,
 URB callback, submission error. Every event is a text line, which consists
-of whitespace separated words. The number of position of words may depend
+of whitespace separated words. The number or position of words may depend
 on the event type, but there is a set of words, common for all types.
 
 Here is the list of words, from left to right:
@@ -170,4 +170,152 @@
 
 * Raw binary format and API
 
-TBD
+The overall architecture of the API is about the same as the one above,
+only the events are delivered in binary format. Each event is sent in
+the following structure (its name is made up, so that we can refer to it):
+
+struct usbmon_packet {
+	u64 id;			/*  0: URB ID - from submission to callback */
+	unsigned char type;	/*  8: Same as text; extensible. */
+	unsigned char xfer_type; /*    ISO (0), Intr, Control, Bulk (3) */
+	unsigned char epnum;	/*     Endpoint number and transfer direction */
+	unsigned char devnum;	/*     Device address */
+	u16 busnum;		/* 12: Bus number */
+	char flag_setup;	/* 14: Same as text */
+	char flag_data;		/* 15: Same as text; Binary zero is OK. */
+	s64 ts_sec;		/* 16: gettimeofday */
+	s32 ts_usec;		/* 24: gettimeofday */
+	int status;		/* 28: */
+	unsigned int length;	/* 32: Length of data (submitted or actual) */
+	unsigned int len_cap;	/* 36: Delivered length */
+	unsigned char setup[8];	/* 40: Only for Control 'S' */
+};				/* 48 bytes total */
+
+These events can be received from a character device by reading with read(2),
+with an ioctl(2), or by accessing the buffer with mmap.
+
+The character device is usually called /dev/usbmonN, where N is the USB bus
+number. Number zero (/dev/usbmon0) is special and means "all buses".
+However, this feature is not implemented yet. Note that specific naming
+policy is set by your Linux distribution.
+
+If you create /dev/usbmon0 by hand, make sure that it is owned by root
+and has mode 0600. Otherwise, unpriviledged users will be able to snoop
+keyboard traffic.
+
+The following ioctl calls are available, with MON_IOC_MAGIC 0x92:
+
+ MON_IOCQ_URB_LEN, defined as _IO(MON_IOC_MAGIC, 1)
+
+This call returns the length of data in the next event. Note that majority of
+events contain no data, so if this call returns zero, it does not mean that
+no events are available.
+
+ MON_IOCG_STATS, defined as _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)
+
+The argument is a pointer to the following structure:
+
+struct mon_bin_stats {
+	u32 queued;
+	u32 dropped;
+};
+
+The member "queued" refers to the number of events currently queued in the
+buffer (and not to the number of events processed since the last reset).
+
+The member "dropped" is the number of events lost since the last call
+to MON_IOCG_STATS.
+
+ MON_IOCT_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 4)
+
+This call sets the buffer size. The argument is the size in bytes.
+The size may be rounded down to the next chunk (or page). If the requested
+size is out of [unspecified] bounds for this kernel, the call fails with
+-EINVAL.
+
+ MON_IOCQ_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 5)
+
+This call returns the current size of the buffer in bytes.
+
+ MON_IOCX_GET, defined as _IOW(MON_IOC_MAGIC, 6, struct mon_get_arg)
+
+This call waits for events to arrive if none were in the kernel buffer,
+then returns the first event. Its argument is a pointer to the following
+structure:
+
+struct mon_get_arg {
+	struct usbmon_packet *hdr;
+	void *data;
+	size_t alloc;		/* Length of data (can be zero) */
+};
+
+Before the call, hdr, data, and alloc should be filled. Upon return, the area
+pointed by hdr contains the next event structure, and the data buffer contains
+the data, if any. The event is removed from the kernel buffer.
+
+ MON_IOCX_MFETCH, defined as _IOWR(MON_IOC_MAGIC, 7, struct mon_mfetch_arg)
+
+This ioctl is primarily used when the application accesses the buffer
+with mmap(2). Its argument is a pointer to the following structure:
+
+struct mon_mfetch_arg {
+	uint32_t *offvec;	/* Vector of events fetched */
+	uint32_t nfetch;	/* Number of events to fetch (out: fetched) */
+	uint32_t nflush;	/* Number of events to flush */
+};
+
+The ioctl operates in 3 stages.
+
+First, it removes and discards up to nflush events from the kernel buffer.
+The actual number of events discarded is returned in nflush.
+
+Second, it waits for an event to be present in the buffer, unless the pseudo-
+device is open with O_NONBLOCK.
+
+Third, it extracts up to nfetch offsets into the mmap buffer, and stores
+them into the offvec. The actual number of event offsets is stored into
+the nfetch.
+
+ MON_IOCH_MFLUSH, defined as _IO(MON_IOC_MAGIC, 8)
+
+This call removes a number of events from the kernel buffer. Its argument
+is the number of events to remove. If the buffer contains fewer events
+than requested, all events present are removed, and no error is reported.
+This works when no events are available too.
+
+ FIONBIO
+
+The ioctl FIONBIO may be implemented in the future, if there's a need.
+
+In addition to ioctl(2) and read(2), the special file of binary API can
+be polled with select(2) and poll(2). But lseek(2) does not work.
+
+* Memory-mapped access of the kernel buffer for the binary API
+
+The basic idea is simple:
+
+To prepare, map the buffer by getting the current size, then using mmap(2).
+Then, execute a loop similar to the one written in pseudo-code below:
+
+   struct mon_mfetch_arg fetch;
+   struct usbmon_packet *hdr;
+   int nflush = 0;
+   for (;;) {
+      fetch.offvec = vec; // Has N 32-bit words
+      fetch.nfetch = N;   // Or less than N
+      fetch.nflush = nflush;
+      ioctl(fd, MON_IOCX_MFETCH, &fetch);   // Process errors, too
+      nflush = fetch.nfetch;       // This many packets to flush when done
+      for (i = 0; i < nflush; i++) {
+         hdr = (struct ubsmon_packet *) &mmap_area[vec[i]];
+         if (hdr->type == '@')     // Filler packet
+            continue;
+         caddr_t data = &mmap_area[vec[i]] + 64;
+         process_packet(hdr, data);
+      }
+   }
+
+Thus, the main idea is to execute only one ioctl per N events.
+
+Although the buffer is circular, the returned headers and data do not cross
+the end of the buffer, so the above pseudo-code does not need any gathering.
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index d6abe49..c1e01b2 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -529,6 +529,11 @@
 	bool "Sony PS3 (incomplete)"
 	depends on PPC_MULTIPLATFORM && PPC64
 	select PPC_CELL
+	select USB_ARCH_HAS_OHCI
+	select USB_OHCI_LITTLE_ENDIAN
+	select USB_OHCI_BIG_ENDIAN_MMIO
+	select USB_ARCH_HAS_EHCI
+	select USB_EHCI_BIG_ENDIAN_MMIO
 	help
 	  This option enables support for the Sony PS3 game console
 	  and other platforms using the PS3 hypervisor.
diff --git a/drivers/i2c/chips/isp1301_omap.c b/drivers/i2c/chips/isp1301_omap.c
index ccdf3e9..9fafadb 100644
--- a/drivers/i2c/chips/isp1301_omap.c
+++ b/drivers/i2c/chips/isp1301_omap.c
@@ -27,7 +27,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb.h>
 #include <linux/usb/otg.h>
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
index 4363a91..3daf049 100644
--- a/drivers/media/video/zc0301/zc0301_sensor.h
+++ b/drivers/media/video/zc0301/zc0301_sensor.h
@@ -75,7 +75,6 @@
 	{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
 	{ ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */           \
 	{ ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */           \
-	{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
 	{ ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), },                         \
 	{ ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */    \
 	{ ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */           \
diff --git a/drivers/usb/atm/speedtch.c b/drivers/usb/atm/speedtch.c
index 8ed6c75..638b800 100644
--- a/drivers/usb/atm/speedtch.c
+++ b/drivers/usb/atm/speedtch.c
@@ -36,7 +36,7 @@
 #include <linux/stat.h>
 #include <linux/timer.h>
 #include <linux/types.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/workqueue.h>
 
 #include "usbatm.h"
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index 6377db1..63e50a1 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -398,6 +398,9 @@
 	retval = 0;
 #endif
 
+	retval = usb_autopm_get_interface(intf);
+	if (retval < 0)
+		goto out;
 	usblp->used = 1;
 	file->private_data = usblp;
 
@@ -442,6 +445,7 @@
 	usblp->used = 0;
 	if (usblp->present) {
 		usblp_unlink_urbs(usblp);
+		usb_autopm_put_interface(usblp->intf);
 	} else 		/* finish cleanup from disconnect */
 		usblp_cleanup (usblp);
 	mutex_unlock (&usblp_mutex);
@@ -1203,14 +1207,9 @@
 {
 	struct usblp *usblp = usb_get_intfdata (intf);
 
-	/* this races against normal access and open */
-	mutex_lock (&usblp_mutex);
-	mutex_lock (&usblp->mut);
 	/* we take no more IO */
 	usblp->sleeping = 1;
 	usblp_unlink_urbs(usblp);
-	mutex_unlock (&usblp->mut);
-	mutex_unlock (&usblp_mutex);
 
 	return 0;
 }
@@ -1220,15 +1219,9 @@
 	struct usblp *usblp = usb_get_intfdata (intf);
 	int r;
 
-	mutex_lock (&usblp_mutex);
-	mutex_lock (&usblp->mut);
-
 	usblp->sleeping = 0;
 	r = handle_bidir (usblp);
 
-	mutex_unlock (&usblp->mut);
-	mutex_unlock (&usblp_mutex);
-
 	return r;
 }
 
@@ -1251,6 +1244,7 @@
 	.suspend =	usblp_suspend,
 	.resume =	usblp_resume,
 	.id_table =	usblp_ids,
+	.supports_autosuspend =	1,
 };
 
 static int __init usblp_init(void)
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index 3e66b2a..2fc0f88 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -33,19 +33,6 @@
 
 	  Most users want to say Y here.
 
-config USB_BANDWIDTH
-	bool "Enforce USB bandwidth allocation (EXPERIMENTAL)"
-	depends on USB && EXPERIMENTAL
-	help
-	  If you say Y here, the USB subsystem enforces USB bandwidth
-	  allocation and will prevent some device opens from succeeding
-	  if they would cause USB bandwidth usage to go above 90% of
-	  the bus bandwidth.
-
-	  If you say N here, these conditions will cause warning messages
-	  about USB bandwidth usage to be logged and some devices or
-	  drivers may not work correctly.
-
 config USB_DYNAMIC_MINORS
 	bool "Dynamic USB minor allocation (EXPERIMENTAL)"
 	depends on USB && EXPERIMENTAL
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index c3915dc..ead2475 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -49,9 +49,9 @@
  *
  * Call hcd_buffer_destroy() to clean up after using those pools.
  */
-int hcd_buffer_create (struct usb_hcd *hcd)
+int hcd_buffer_create(struct usb_hcd *hcd)
 {
-	char		name [16];
+	char		name[16];
 	int 		i, size;
 
 	if (!hcd->self.controller->dma_mask)
@@ -60,11 +60,11 @@
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) { 
 		if (!(size = pool_max [i]))
 			continue;
-		snprintf (name, sizeof name, "buffer-%d", size);
-		hcd->pool [i] = dma_pool_create (name, hcd->self.controller,
+		snprintf(name, sizeof name, "buffer-%d", size);
+		hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
 				size, size, 0);
 		if (!hcd->pool [i]) {
-			hcd_buffer_destroy (hcd);
+			hcd_buffer_destroy(hcd);
 			return -ENOMEM;
 		}
 	}
@@ -79,14 +79,14 @@
  *
  * This frees the buffer pools created by hcd_buffer_create().
  */
-void hcd_buffer_destroy (struct usb_hcd *hcd)
+void hcd_buffer_destroy(struct usb_hcd *hcd)
 {
 	int		i;
 
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) { 
-		struct dma_pool		*pool = hcd->pool [i];
+		struct dma_pool		*pool = hcd->pool[i];
 		if (pool) {
-			dma_pool_destroy (pool);
+			dma_pool_destroy(pool);
 			hcd->pool[i] = NULL;
 		}
 	}
@@ -97,8 +97,8 @@
  * better sharing and to leverage mm/slab.c intelligence.
  */
 
-void *hcd_buffer_alloc (
-	struct usb_bus 		*bus,
+void *hcd_buffer_alloc(
+	struct usb_bus 	*bus,
 	size_t			size,
 	gfp_t			mem_flags,
 	dma_addr_t		*dma
@@ -110,18 +110,18 @@
 	/* some USB hosts just use PIO */
 	if (!bus->controller->dma_mask) {
 		*dma = ~(dma_addr_t) 0;
-		return kmalloc (size, mem_flags);
+		return kmalloc(size, mem_flags);
 	}
 
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
 		if (size <= pool_max [i])
-			return dma_pool_alloc (hcd->pool [i], mem_flags, dma);
+			return dma_pool_alloc(hcd->pool [i], mem_flags, dma);
 	}
-	return dma_alloc_coherent (hcd->self.controller, size, dma, 0);
+	return dma_alloc_coherent(hcd->self.controller, size, dma, 0);
 }
 
-void hcd_buffer_free (
-	struct usb_bus 		*bus,
+void hcd_buffer_free(
+	struct usb_bus 	*bus,
 	size_t			size,
 	void 			*addr,
 	dma_addr_t		dma
@@ -134,15 +134,15 @@
 		return;
 
 	if (!bus->controller->dma_mask) {
-		kfree (addr);
+		kfree(addr);
 		return;
 	}
 
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
 		if (size <= pool_max [i]) {
-			dma_pool_free (hcd->pool [i], addr, dma);
+			dma_pool_free(hcd->pool [i], addr, dma);
 			return;
 		}
 	}
-	dma_free_coherent (hcd->self.controller, size, addr, dma);
+	dma_free_coherent(hcd->self.controller, size, addr, dma);
 }
diff --git a/drivers/usb/core/devices.c b/drivers/usb/core/devices.c
index ea398e5..a47c30b 100644
--- a/drivers/usb/core/devices.c
+++ b/drivers/usb/core/devices.c
@@ -104,7 +104,7 @@
   
 static const char *format_iface =
 /* I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
-  "I:  If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
+  "I:%c If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
 
 static const char *format_endpt =
 /* E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
@@ -164,10 +164,10 @@
 	for (ix = 0; clas_info[ix].class != -1; ix++)
 		if (clas_info[ix].class == class)
 			break;
-	return (clas_info[ix].class_name);
+	return clas_info[ix].class_name;
 }
 
-static char *usb_dump_endpoint_descriptor (
+static char *usb_dump_endpoint_descriptor(
 	int speed,
 	char *start,
 	char *end,
@@ -212,9 +212,9 @@
 		break;
 	case USB_ENDPOINT_XFER_INT:
 		type = "Int.";
-		if (speed == USB_SPEED_HIGH) {
+		if (speed == USB_SPEED_HIGH)
 			interval = 1 << (desc->bInterval - 1);
-		} else
+		else
 			interval = desc->bInterval;
 		break;
 	default:	/* "can't happen" */
@@ -242,15 +242,19 @@
 {
 	const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc;
 	const char *driver_name = "";
+	int active = 0;
 
 	if (start > end)
 		return start;
 	down_read(&usb_bus_type.subsys.rwsem);
-	if (iface)
+	if (iface) {
 		driver_name = (iface->dev.driver
 				? iface->dev.driver->name
 				: "(none)");
+		active = (desc == &iface->cur_altsetting->desc);
+	}
 	start += sprintf(start, format_iface,
+			 active ? '*' : ' ',	/* mark active altsetting */
 			 desc->bInterfaceNumber,
 			 desc->bAlternateSetting,
 			 desc->bNumEndpoints,
@@ -343,7 +347,7 @@
 
 	if (start > end)
 		return start;
-	start += sprintf (start, format_device1,
+	start += sprintf(start, format_device1,
 			  bcdUSB >> 8, bcdUSB & 0xff,
 			  desc->bDeviceClass,
 			  class_decode (desc->bDeviceClass),
@@ -363,7 +367,7 @@
 /*
  * Dump the different strings that this device holds.
  */
-static char *usb_dump_device_strings (char *start, char *end, struct usb_device *dev)
+static char *usb_dump_device_strings(char *start, char *end, struct usb_device *dev)
 {
 	if (start > end)
 		return start;
@@ -395,7 +399,7 @@
 	if (start > end)
 		return start;
 	
-	start = usb_dump_device_strings (start, end, dev);
+	start = usb_dump_device_strings(start, end, dev);
 
 	for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
 		if (start > end)
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 4b3a6ab..2087766 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -522,19 +522,19 @@
 
 static struct usb_device *usbdev_lookup_minor(int minor)
 {
-	struct class_device *class_dev;
-	struct usb_device *dev = NULL;
+	struct device *device;
+	struct usb_device *udev = NULL;
 
 	down(&usb_device_class->sem);
-	list_for_each_entry(class_dev, &usb_device_class->children, node) {
-		if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
-			dev = class_dev->class_data;
+	list_for_each_entry(device, &usb_device_class->devices, node) {
+		if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
+			udev = device->platform_data;
 			break;
 		}
 	}
 	up(&usb_device_class->sem);
 
-	return dev;
+	return udev;
 };
 
 /*
@@ -570,6 +570,7 @@
 	ps->dev = dev;
 	ps->file = file;
 	spin_lock_init(&ps->lock);
+	INIT_LIST_HEAD(&ps->list);
 	INIT_LIST_HEAD(&ps->async_pending);
 	INIT_LIST_HEAD(&ps->async_completed);
 	init_waitqueue_head(&ps->wait);
@@ -1596,19 +1597,19 @@
 {
 	int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
 
-	dev->class_dev = class_device_create(usb_device_class, NULL,
-				MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
+	dev->usbfs_dev = device_create(usb_device_class, &dev->dev,
+				MKDEV(USB_DEVICE_MAJOR, minor),
 				"usbdev%d.%d", dev->bus->busnum, dev->devnum);
-	if (IS_ERR(dev->class_dev))
-		return PTR_ERR(dev->class_dev);
+	if (IS_ERR(dev->usbfs_dev))
+		return PTR_ERR(dev->usbfs_dev);
 
-	dev->class_dev->class_data = dev;
+	dev->usbfs_dev->platform_data = dev;
 	return 0;
 }
 
 static void usbdev_remove(struct usb_device *dev)
 {
-	class_device_unregister(dev->class_dev);
+	device_unregister(dev->usbfs_dev);
 }
 
 static int usbdev_notify(struct notifier_block *self, unsigned long action,
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index d505926..600d1bc 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -28,24 +28,16 @@
 #include "hcd.h"
 #include "usb.h"
 
-static int usb_match_one_id(struct usb_interface *interface,
-			    const struct usb_device_id *id);
-
-struct usb_dynid {
-	struct list_head node;
-	struct usb_device_id id;
-};
-
 #ifdef CONFIG_HOTPLUG
 
 /*
  * Adds a new dynamic USBdevice ID to this driver,
  * and cause the driver to probe for all devices again.
  */
-static ssize_t store_new_id(struct device_driver *driver,
-			    const char *buf, size_t count)
+ssize_t usb_store_new_id(struct usb_dynids *dynids,
+			 struct device_driver *driver,
+			 const char *buf, size_t count)
 {
-	struct usb_driver *usb_drv = to_usb_driver(driver);
 	struct usb_dynid *dynid;
 	u32 idVendor = 0;
 	u32 idProduct = 0;
@@ -65,9 +57,9 @@
 	dynid->id.idProduct = idProduct;
 	dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
 
-	spin_lock(&usb_drv->dynids.lock);
-	list_add_tail(&usb_drv->dynids.list, &dynid->node);
-	spin_unlock(&usb_drv->dynids.lock);
+	spin_lock(&dynids->lock);
+	list_add_tail(&dynids->list, &dynid->node);
+	spin_unlock(&dynids->lock);
 
 	if (get_driver(driver)) {
 		retval = driver_attach(driver);
@@ -78,6 +70,15 @@
 		return retval;
 	return count;
 }
+EXPORT_SYMBOL_GPL(usb_store_new_id);
+
+static ssize_t store_new_id(struct device_driver *driver,
+			    const char *buf, size_t count)
+{
+	struct usb_driver *usb_drv = to_usb_driver(driver);
+
+	return usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+}
 static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
 
 static int usb_create_newid_file(struct usb_driver *usb_drv)
@@ -365,8 +366,8 @@
 EXPORT_SYMBOL(usb_driver_release_interface);
 
 /* returns 0 if no match, 1 if match */
-static int usb_match_one_id(struct usb_interface *interface,
-			    const struct usb_device_id *id)
+int usb_match_one_id(struct usb_interface *interface,
+		     const struct usb_device_id *id)
 {
 	struct usb_host_interface *intf;
 	struct usb_device *dev;
@@ -432,6 +433,8 @@
 
 	return 1;
 }
+EXPORT_SYMBOL_GPL(usb_match_one_id);
+
 /**
  * usb_match_id - find first usb_device_id matching device or interface
  * @interface: the interface of interest
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index f794f07..01c857a 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -194,14 +194,13 @@
 		++temp;
 	else
 		temp = name;
-	intf->class_dev = class_device_create(usb_class->class, NULL,
-					      MKDEV(USB_MAJOR, minor),
-					      &intf->dev, "%s", temp);
-	if (IS_ERR(intf->class_dev)) {
+	intf->usb_dev = device_create(usb_class->class, &intf->dev,
+				      MKDEV(USB_MAJOR, minor), "%s", temp);
+	if (IS_ERR(intf->usb_dev)) {
 		spin_lock (&minor_lock);
 		usb_minors[intf->minor] = NULL;
 		spin_unlock (&minor_lock);
-		retval = PTR_ERR(intf->class_dev);
+		retval = PTR_ERR(intf->usb_dev);
 	}
 exit:
 	return retval;
@@ -242,8 +241,8 @@
 	spin_unlock (&minor_lock);
 
 	snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
-	class_device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
-	intf->class_dev = NULL;
+	device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
+	intf->usb_dev = NULL;
 	intf->minor = -1;
 	destroy_usb_class();
 }
diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c
index ebb20ff..b531a4f 100644
--- a/drivers/usb/core/generic.c
+++ b/drivers/usb/core/generic.c
@@ -25,6 +25,20 @@
 	return (n == 1 ? "" : "s");
 }
 
+static int is_rndis(struct usb_interface_descriptor *desc)
+{
+	return desc->bInterfaceClass == USB_CLASS_COMM
+		&& desc->bInterfaceSubClass == 2
+		&& desc->bInterfaceProtocol == 0xff;
+}
+
+static int is_activesync(struct usb_interface_descriptor *desc)
+{
+	return desc->bInterfaceClass == USB_CLASS_MISC
+		&& desc->bInterfaceSubClass == 1
+		&& desc->bInterfaceProtocol == 1;
+}
+
 static int choose_configuration(struct usb_device *udev)
 {
 	int i;
@@ -87,14 +101,12 @@
 			continue;
 		}
 
-		/* If the first config's first interface is COMM/2/0xff
-		 * (MSFT RNDIS), rule it out unless Linux has host-side
-		 * RNDIS support. */
-		if (i == 0 && desc
-				&& desc->bInterfaceClass == USB_CLASS_COMM
-				&& desc->bInterfaceSubClass == 2
-				&& desc->bInterfaceProtocol == 0xff) {
-#ifndef CONFIG_USB_NET_RNDIS_HOST
+		/* When the first config's first interface is one of Microsoft's
+		 * pet nonstandard Ethernet-over-USB protocols, ignore it unless
+		 * this kernel has enabled the necessary host side driver.
+		 */
+		if (i == 0 && desc && (is_rndis(desc) || is_activesync(desc))) {
+#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
 			continue;
 #else
 			best = c;
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 10064af..b26c19e 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -45,8 +45,6 @@
 #include "hub.h"
 
 
-// #define USB_BANDWIDTH_MESSAGES
-
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -891,136 +889,6 @@
 }
 EXPORT_SYMBOL (usb_calc_bus_time);
 
-/*
- * usb_check_bandwidth():
- *
- * old_alloc is from host_controller->bandwidth_allocated in microseconds;
- * bustime is from calc_bus_time(), but converted to microseconds.
- *
- * returns <bustime in us> if successful,
- * or -ENOSPC if bandwidth request fails.
- *
- * FIXME:
- * This initial implementation does not use Endpoint.bInterval
- * in managing bandwidth allocation.
- * It probably needs to be expanded to use Endpoint.bInterval.
- * This can be done as a later enhancement (correction).
- *
- * This will also probably require some kind of
- * frame allocation tracking...meaning, for example,
- * that if multiple drivers request interrupts every 10 USB frames,
- * they don't all have to be allocated at
- * frame numbers N, N+10, N+20, etc.  Some of them could be at
- * N+11, N+21, N+31, etc., and others at
- * N+12, N+22, N+32, etc.
- *
- * Similarly for isochronous transfers...
- *
- * Individual HCDs can schedule more directly ... this logic
- * is not correct for high speed transfers.
- */
-int usb_check_bandwidth (struct usb_device *dev, struct urb *urb)
-{
-	unsigned int	pipe = urb->pipe;
-	long		bustime;
-	int		is_in = usb_pipein (pipe);
-	int		is_iso = usb_pipeisoc (pipe);
-	int		old_alloc = dev->bus->bandwidth_allocated;
-	int		new_alloc;
-
-
-	bustime = NS_TO_US (usb_calc_bus_time (dev->speed, is_in, is_iso,
-			usb_maxpacket (dev, pipe, !is_in)));
-	if (is_iso)
-		bustime /= urb->number_of_packets;
-
-	new_alloc = old_alloc + (int) bustime;
-	if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) {
-#ifdef	DEBUG
-		char	*mode = 
-#ifdef CONFIG_USB_BANDWIDTH
-			"";
-#else
-			"would have ";
-#endif
-		dev_dbg (&dev->dev, "usb_check_bandwidth %sFAILED: %d + %ld = %d usec\n",
-			mode, old_alloc, bustime, new_alloc);
-#endif
-#ifdef CONFIG_USB_BANDWIDTH
-		bustime = -ENOSPC;	/* report error */
-#endif
-	}
-
-	return bustime;
-}
-EXPORT_SYMBOL (usb_check_bandwidth);
-
-
-/**
- * usb_claim_bandwidth - records bandwidth for a periodic transfer
- * @dev: source/target of request
- * @urb: request (urb->dev == dev)
- * @bustime: bandwidth consumed, in (average) microseconds per frame
- * @isoc: true iff the request is isochronous
- *
- * Bus bandwidth reservations are recorded purely for diagnostic purposes.
- * HCDs are expected not to overcommit periodic bandwidth, and to record such
- * reservations whenever endpoints are added to the periodic schedule.
- *
- * FIXME averaging per-frame is suboptimal.  Better to sum over the HCD's
- * entire periodic schedule ... 32 frames for OHCI, 1024 for UHCI, settable
- * for EHCI (256/512/1024 frames, default 1024) and have the bus expose how
- * large its periodic schedule is.
- */
-void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc)
-{
-	dev->bus->bandwidth_allocated += bustime;
-	if (isoc)
-		dev->bus->bandwidth_isoc_reqs++;
-	else
-		dev->bus->bandwidth_int_reqs++;
-	urb->bandwidth = bustime;
-
-#ifdef USB_BANDWIDTH_MESSAGES
-	dev_dbg (&dev->dev, "bandwidth alloc increased by %d (%s) to %d for %d requesters\n",
-		bustime,
-		isoc ? "ISOC" : "INTR",
-		dev->bus->bandwidth_allocated,
-		dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
-#endif
-}
-EXPORT_SYMBOL (usb_claim_bandwidth);
-
-
-/**
- * usb_release_bandwidth - reverses effect of usb_claim_bandwidth()
- * @dev: source/target of request
- * @urb: request (urb->dev == dev)
- * @isoc: true iff the request is isochronous
- *
- * This records that previously allocated bandwidth has been released.
- * Bandwidth is released when endpoints are removed from the host controller's
- * periodic schedule.
- */
-void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc)
-{
-	dev->bus->bandwidth_allocated -= urb->bandwidth;
-	if (isoc)
-		dev->bus->bandwidth_isoc_reqs--;
-	else
-		dev->bus->bandwidth_int_reqs--;
-
-#ifdef USB_BANDWIDTH_MESSAGES
-	dev_dbg (&dev->dev, "bandwidth alloc reduced by %d (%s) to %d for %d requesters\n",
-		urb->bandwidth,
-		isoc ? "ISOC" : "INTR",
-		dev->bus->bandwidth_allocated,
-		dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
-#endif
-	urb->bandwidth = 0;
-}
-EXPORT_SYMBOL (usb_release_bandwidth);
-
 
 /*-------------------------------------------------------------------------*/
 
@@ -1034,11 +902,6 @@
 {
 	unsigned long		flags;
 
-	/* Release any periodic transfer bandwidth */
-	if (urb->bandwidth)
-		usb_release_bandwidth (urb->dev, urb,
-			usb_pipeisoc (urb->pipe));
-
 	/* clear all state linking urb to this dev (and hcd) */
 
 	spin_lock_irqsave (&hcd_data_lock, flags);
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 8f8df0d..2a269ca 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -308,10 +308,6 @@
 #define NS_TO_US(ns)	((ns + 500L) / 1000L)
 			/* convert & round nanoseconds to microseconds */
 
-extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb,
-		int bustime, int isoc);
-extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb,
-		int isoc);
 
 /*
  * Full/low speed bandwidth allocation constants/support.
@@ -324,8 +320,6 @@
 #define FRAME_TIME_MAX_BITS_ALLOC	(90L * FRAME_TIME_BITS / 100L)
 #define FRAME_TIME_MAX_USECS_ALLOC	(90L * FRAME_TIME_USECS / 100L)
 
-extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
-
 /*
  * Ceiling [nano/micro]seconds (typical) for that many bytes at high speed
  * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 1988224..590ec82 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -87,9 +87,6 @@
 
 static struct task_struct *khubd_task;
 
-/* multithreaded probe logic */
-static int multithread_probe = 0;
-
 /* cycle leds on hubs that aren't blinking for attention */
 static int blinkenlights = 0;
 module_param (blinkenlights, bool, S_IRUGO);
@@ -1256,9 +1253,28 @@
 static int __usb_port_suspend(struct usb_device *, int port1);
 #endif
 
-static int __usb_new_device(void *void_data)
+/**
+ * usb_new_device - perform initial device setup (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is called with devices which have been enumerated, but not yet
+ * configured.  The device descriptor is available, but not descriptors
+ * for any device configuration.  The caller must have locked either
+ * the parent hub (if udev is a normal device) or else the
+ * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
+ * udev has already been installed, but udev is not yet visible through
+ * sysfs or other filesystem code.
+ *
+ * It will return if the device is configured properly or not.  Zero if
+ * the interface was registered with the driver core; else a negative
+ * errno value.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only the hub driver or root-hub registrar should ever call this.
+ */
+int usb_new_device(struct usb_device *udev)
 {
-	struct usb_device *udev = void_data;
 	int err;
 
 	/* Lock ourself into memory in order to keep a probe sequence
@@ -1375,44 +1391,6 @@
 	goto exit;
 }
 
-/**
- * usb_new_device - perform initial device setup (usbcore-internal)
- * @udev: newly addressed device (in ADDRESS state)
- *
- * This is called with devices which have been enumerated, but not yet
- * configured.  The device descriptor is available, but not descriptors
- * for any device configuration.  The caller must have locked either
- * the parent hub (if udev is a normal device) or else the
- * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
- * udev has already been installed, but udev is not yet visible through
- * sysfs or other filesystem code.
- *
- * The return value for this function depends on if the
- * multithread_probe variable is set or not.  If it's set, it will
- * return a if the probe thread was successfully created or not.  If the
- * variable is not set, it will return if the device is configured
- * properly or not.  interfaces, in sysfs); else a negative errno value.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Only the hub driver or root-hub registrar should ever call this.
- */
-int usb_new_device(struct usb_device *udev)
-{
-	struct task_struct *probe_task;
-	int ret = 0;
-
-	if (multithread_probe) {
-		probe_task = kthread_run(__usb_new_device, udev,
-					 "usb-probe-%s", udev->devnum);
-		if (IS_ERR(probe_task))
-			ret = PTR_ERR(probe_task);
-	} else
-		ret = __usb_new_device(udev);
-
-	return ret;
-}
-
 static int hub_port_status(struct usb_hub *hub, int port1,
 			       u16 *status, u16 *change)
 {
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index 149aa8b..8aca357 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1545,11 +1545,7 @@
 	INIT_WORK(&req->work, driver_set_config_work);
 
 	usb_get_dev(udev);
-	if (!schedule_work(&req->work)) {
-		usb_put_dev(udev);
-		kfree(req);
-		return -EINVAL;
-	}
+	schedule_work(&req->work);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(usb_driver_set_configuration);
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 55d8f57..4eaa0ee 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -16,16 +16,16 @@
 
 /* Active configuration fields */
 #define usb_actconfig_show(field, multiplier, format_string)		\
-static ssize_t  show_##field (struct device *dev,			\
+static ssize_t  show_##field(struct device *dev,			\
 		struct device_attribute *attr, char *buf)		\
 {									\
 	struct usb_device *udev;					\
 	struct usb_host_config *actconfig;				\
 									\
-	udev = to_usb_device (dev);					\
+	udev = to_usb_device(dev);					\
 	actconfig = udev->actconfig;					\
 	if (actconfig)							\
-		return sprintf (buf, format_string,			\
+		return sprintf(buf, format_string,			\
 				actconfig->desc.field * multiplier);	\
 	else								\
 		return 0;						\
@@ -35,9 +35,9 @@
 usb_actconfig_show(field, multiplier, format_string)			\
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
 
-usb_actconfig_attr (bNumInterfaces, 1, "%2d\n")
-usb_actconfig_attr (bmAttributes, 1, "%2x\n")
-usb_actconfig_attr (bMaxPower, 2, "%3dmA\n")
+usb_actconfig_attr(bNumInterfaces, 1, "%2d\n")
+usb_actconfig_attr(bmAttributes, 1, "%2x\n")
+usb_actconfig_attr(bMaxPower, 2, "%3dmA\n")
 
 static ssize_t show_configuration_string(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -45,7 +45,7 @@
 	struct usb_device *udev;
 	struct usb_host_config *actconfig;
 
-	udev = to_usb_device (dev);
+	udev = to_usb_device(dev);
 	actconfig = udev->actconfig;
 	if ((!actconfig) || (!actconfig->string))
 		return 0;
@@ -57,16 +57,16 @@
 usb_actconfig_show(bConfigurationValue, 1, "%u\n");
 
 static ssize_t
-set_bConfigurationValue (struct device *dev, struct device_attribute *attr,
+set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
 		const char *buf, size_t count)
 {
-	struct usb_device	*udev = to_usb_device (dev);
+	struct usb_device	*udev = to_usb_device(dev);
 	int			config, value;
 
-	if (sscanf (buf, "%u", &config) != 1 || config > 255)
+	if (sscanf(buf, "%u", &config) != 1 || config > 255)
 		return -EINVAL;
 	usb_lock_device(udev);
-	value = usb_set_configuration (udev, config);
+	value = usb_set_configuration(udev, config);
 	usb_unlock_device(udev);
 	return (value < 0) ? value : count;
 }
@@ -81,7 +81,7 @@
 {									\
 	struct usb_device *udev;					\
 									\
-	udev = to_usb_device (dev);					\
+	udev = to_usb_device(dev);					\
 	return sprintf(buf, "%s\n", udev->name);			\
 }									\
 static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
@@ -91,12 +91,12 @@
 usb_string_attr(serial);
 
 static ssize_t
-show_speed (struct device *dev, struct device_attribute *attr, char *buf)
+show_speed(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct usb_device *udev;
 	char *speed;
 
-	udev = to_usb_device (dev);
+	udev = to_usb_device(dev);
 
 	switch (udev->speed) {
 	case USB_SPEED_LOW:
@@ -112,22 +112,22 @@
 	default:
 		speed = "unknown";
 	}
-	return sprintf (buf, "%s\n", speed);
+	return sprintf(buf, "%s\n", speed);
 }
 static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL);
 
 static ssize_t
-show_devnum (struct device *dev, struct device_attribute *attr, char *buf)
+show_devnum(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct usb_device *udev;
 
-	udev = to_usb_device (dev);
-	return sprintf (buf, "%d\n", udev->devnum);
+	udev = to_usb_device(dev);
+	return sprintf(buf, "%d\n", udev->devnum);
 }
 static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL);
 
 static ssize_t
-show_version (struct device *dev, struct device_attribute *attr, char *buf)
+show_version(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct usb_device *udev;
 	u16 bcdUSB;
@@ -139,25 +139,25 @@
 static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
 
 static ssize_t
-show_maxchild (struct device *dev, struct device_attribute *attr, char *buf)
+show_maxchild(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct usb_device *udev;
 
-	udev = to_usb_device (dev);
-	return sprintf (buf, "%d\n", udev->maxchild);
+	udev = to_usb_device(dev);
+	return sprintf(buf, "%d\n", udev->maxchild);
 }
 static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL);
 
 /* Descriptor fields */
 #define usb_descriptor_attr_le16(field, format_string)			\
 static ssize_t								\
-show_##field (struct device *dev, struct device_attribute *attr,	\
+show_##field(struct device *dev, struct device_attribute *attr,	\
 		char *buf)						\
 {									\
 	struct usb_device *udev;					\
 									\
-	udev = to_usb_device (dev);					\
-	return sprintf (buf, format_string, 				\
+	udev = to_usb_device(dev);					\
+	return sprintf(buf, format_string, 				\
 			le16_to_cpu(udev->descriptor.field));		\
 }									\
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
@@ -168,21 +168,21 @@
 
 #define usb_descriptor_attr(field, format_string)			\
 static ssize_t								\
-show_##field (struct device *dev, struct device_attribute *attr,	\
+show_##field(struct device *dev, struct device_attribute *attr,	\
 		char *buf)						\
 {									\
 	struct usb_device *udev;					\
 									\
-	udev = to_usb_device (dev);					\
-	return sprintf (buf, format_string, udev->descriptor.field);	\
+	udev = to_usb_device(dev);					\
+	return sprintf(buf, format_string, udev->descriptor.field);	\
 }									\
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
 
-usb_descriptor_attr (bDeviceClass, "%02x\n")
-usb_descriptor_attr (bDeviceSubClass, "%02x\n")
-usb_descriptor_attr (bDeviceProtocol, "%02x\n")
-usb_descriptor_attr (bNumConfigurations, "%d\n")
-usb_descriptor_attr (bMaxPacketSize0, "%d\n")
+usb_descriptor_attr(bDeviceClass, "%02x\n")
+usb_descriptor_attr(bDeviceSubClass, "%02x\n")
+usb_descriptor_attr(bDeviceProtocol, "%02x\n")
+usb_descriptor_attr(bNumConfigurations, "%d\n")
+usb_descriptor_attr(bMaxPacketSize0, "%d\n")
 
 static struct attribute *dev_attrs[] = {
 	/* current configuration's attributes */
@@ -220,17 +220,17 @@
 		return retval;
 
 	if (udev->manufacturer) {
-		retval = device_create_file (dev, &dev_attr_manufacturer);
+		retval = device_create_file(dev, &dev_attr_manufacturer);
 		if (retval)
 			goto error;
 	}
 	if (udev->product) {
-		retval = device_create_file (dev, &dev_attr_product);
+		retval = device_create_file(dev, &dev_attr_product);
 		if (retval)
 			goto error;
 	}
 	if (udev->serial) {
-		retval = device_create_file (dev, &dev_attr_serial);
+		retval = device_create_file(dev, &dev_attr_serial);
 		if (retval)
 			goto error;
 	}
@@ -246,7 +246,7 @@
 	return retval;
 }
 
-void usb_remove_sysfs_dev_files (struct usb_device *udev)
+void usb_remove_sysfs_dev_files(struct usb_device *udev)
 {
 	struct device *dev = &udev->dev;
 
@@ -264,22 +264,22 @@
 /* Interface fields */
 #define usb_intf_attr(field, format_string)				\
 static ssize_t								\
-show_##field (struct device *dev, struct device_attribute *attr,	\
+show_##field(struct device *dev, struct device_attribute *attr,	\
 		char *buf)						\
 {									\
-	struct usb_interface *intf = to_usb_interface (dev);		\
+	struct usb_interface *intf = to_usb_interface(dev);		\
 									\
-	return sprintf (buf, format_string,				\
+	return sprintf(buf, format_string,				\
 			intf->cur_altsetting->desc.field); 		\
 }									\
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
 
-usb_intf_attr (bInterfaceNumber, "%02x\n")
-usb_intf_attr (bAlternateSetting, "%2d\n")
-usb_intf_attr (bNumEndpoints, "%02x\n")
-usb_intf_attr (bInterfaceClass, "%02x\n")
-usb_intf_attr (bInterfaceSubClass, "%02x\n")
-usb_intf_attr (bInterfaceProtocol, "%02x\n")
+usb_intf_attr(bInterfaceNumber, "%02x\n")
+usb_intf_attr(bAlternateSetting, "%2d\n")
+usb_intf_attr(bNumEndpoints, "%02x\n")
+usb_intf_attr(bInterfaceClass, "%02x\n")
+usb_intf_attr(bInterfaceSubClass, "%02x\n")
+usb_intf_attr(bInterfaceProtocol, "%02x\n")
 
 static ssize_t show_interface_string(struct device *dev,
 		struct device_attribute *attr, char *buf)
@@ -288,8 +288,8 @@
 	struct usb_device *udev;
 	int len;
 
-	intf = to_usb_interface (dev);
-	udev = interface_to_usbdev (intf);
+	intf = to_usb_interface(dev);
+	udev = interface_to_usbdev(intf);
 	len = snprintf(buf, 256, "%s", intf->cur_altsetting->string);
 	if (len < 0)
 		return 0;
@@ -384,7 +384,7 @@
 	return retval;
 }
 
-void usb_remove_sysfs_intf_files (struct usb_interface *intf)
+void usb_remove_sysfs_intf_files(struct usb_interface *intf)
 {
 	usb_remove_intf_ep_files(intf);
 	sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 9801d08..94ea972 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -235,16 +235,15 @@
 
 	urb->status = -EINPROGRESS;
 	urb->actual_length = 0;
-	urb->bandwidth = 0;
 
 	/* Lots of sanity checks, so HCDs can rely on clean data
 	 * and don't need to duplicate tests
 	 */
 	pipe = urb->pipe;
-	temp = usb_pipetype (pipe);
-	is_out = usb_pipeout (pipe);
+	temp = usb_pipetype(pipe);
+	is_out = usb_pipeout(pipe);
 
-	if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED)
+	if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
 		return -ENODEV;
 
 	/* FIXME there should be a sharable lock protecting us against
@@ -253,11 +252,11 @@
 	 * checks get made.)
 	 */
 
-	max = usb_maxpacket (dev, pipe, is_out);
+	max = usb_maxpacket(dev, pipe, is_out);
 	if (max <= 0) {
 		dev_dbg(&dev->dev,
 			"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
-			usb_pipeendpoint (pipe), is_out ? "out" : "in",
+			usb_pipeendpoint(pipe), is_out ? "out" : "in",
 			__FUNCTION__, max);
 		return -EMSGSIZE;
 	}
@@ -279,11 +278,11 @@
 		if (urb->number_of_packets <= 0)		    
 			return -EINVAL;
 		for (n = 0; n < urb->number_of_packets; n++) {
-			len = urb->iso_frame_desc [n].length;
+			len = urb->iso_frame_desc[n].length;
 			if (len < 0 || len > max) 
 				return -EMSGSIZE;
-			urb->iso_frame_desc [n].status = -EXDEV;
-			urb->iso_frame_desc [n].actual_length = 0;
+			urb->iso_frame_desc[n].status = -EXDEV;
+			urb->iso_frame_desc[n].actual_length = 0;
 		}
 	}
 
@@ -322,7 +321,7 @@
 
 	/* fail if submitter gave bogus flags */
 	if (urb->transfer_flags != orig_flags) {
-		err ("BOGUS urb flags, %x --> %x",
+		err("BOGUS urb flags, %x --> %x",
 			orig_flags, urb->transfer_flags);
 		return -EINVAL;
 	}
@@ -373,7 +372,7 @@
 		urb->interval = temp;
 	}
 
-	return usb_hcd_submit_urb (urb, mem_flags);
+	return usb_hcd_submit_urb(urb, mem_flags);
 }
 
 /*-------------------------------------------------------------------*/
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 02426d0..3db721c 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -233,7 +233,7 @@
  * @parent: hub to which device is connected; null to allocate a root hub
  * @bus: bus used to access the device
  * @port1: one-based index of port; ignored for root hubs
- * Context: !in_interrupt ()
+ * Context: !in_interrupt()
  *
  * Only hub drivers (including virtual root hub drivers for host
  * controllers) should ever call this.
@@ -277,22 +277,22 @@
 	 * as stable:  bus->busnum changes easily from modprobe order,
 	 * cardbus or pci hotplugging, and so on.
 	 */
-	if (unlikely (!parent)) {
-		dev->devpath [0] = '0';
+	if (unlikely(!parent)) {
+		dev->devpath[0] = '0';
 
 		dev->dev.parent = bus->controller;
-		sprintf (&dev->dev.bus_id[0], "usb%d", bus->busnum);
+		sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
 	} else {
 		/* match any labeling on the hubs; it's one-based */
-		if (parent->devpath [0] == '0')
-			snprintf (dev->devpath, sizeof dev->devpath,
+		if (parent->devpath[0] == '0')
+			snprintf(dev->devpath, sizeof dev->devpath,
 				"%d", port1);
 		else
-			snprintf (dev->devpath, sizeof dev->devpath,
+			snprintf(dev->devpath, sizeof dev->devpath,
 				"%s.%d", parent->devpath, port1);
 
 		dev->dev.parent = &parent->dev;
-		sprintf (&dev->dev.bus_id[0], "%d-%s",
+		sprintf(&dev->dev.bus_id[0], "%d-%s",
 			bus->busnum, dev->devpath);
 
 		/* hub driver sets up TT records */
@@ -463,7 +463,7 @@
 	/* see if this device matches */
 	if ((vendor_id == le16_to_cpu(dev->descriptor.idVendor)) &&
 	    (product_id == le16_to_cpu(dev->descriptor.idProduct))) {
-		dev_dbg (&dev->dev, "matched this device!\n");
+		dev_dbg(&dev->dev, "matched this device!\n");
 		ret_dev = usb_get_dev(dev);
 		goto exit;
 	}
@@ -535,7 +535,7 @@
  */
 int usb_get_current_frame_number(struct usb_device *dev)
 {
-	return usb_hcd_get_frame_number (dev);
+	return usb_hcd_get_frame_number(dev);
 }
 
 /*-------------------------------------------------------------------*/
@@ -593,7 +593,7 @@
  *
  * When the buffer is no longer used, free it with usb_buffer_free().
  */
-void *usb_buffer_alloc (
+void *usb_buffer_alloc(
 	struct usb_device *dev,
 	size_t size,
 	gfp_t mem_flags,
@@ -602,7 +602,7 @@
 {
 	if (!dev || !dev->bus)
 		return NULL;
-	return hcd_buffer_alloc (dev->bus, size, mem_flags, dma);
+	return hcd_buffer_alloc(dev->bus, size, mem_flags, dma);
 }
 
 /**
@@ -616,7 +616,7 @@
  * been allocated using usb_buffer_alloc(), and the parameters must match
  * those provided in that allocation request. 
  */
-void usb_buffer_free (
+void usb_buffer_free(
 	struct usb_device *dev,
 	size_t size,
 	void *addr,
@@ -627,7 +627,7 @@
 		return;
 	if (!addr)
 		return;
-	hcd_buffer_free (dev->bus, size, addr, dma);
+	hcd_buffer_free(dev->bus, size, addr, dma);
 }
 
 /**
@@ -647,7 +647,7 @@
  * Reverse the effect of this call with usb_buffer_unmap().
  */
 #if 0
-struct urb *usb_buffer_map (struct urb *urb)
+struct urb *usb_buffer_map(struct urb *urb)
 {
 	struct usb_bus		*bus;
 	struct device		*controller;
@@ -659,14 +659,14 @@
 		return NULL;
 
 	if (controller->dma_mask) {
-		urb->transfer_dma = dma_map_single (controller,
+		urb->transfer_dma = dma_map_single(controller,
 			urb->transfer_buffer, urb->transfer_buffer_length,
-			usb_pipein (urb->pipe)
+			usb_pipein(urb->pipe)
 				? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-		if (usb_pipecontrol (urb->pipe))
-			urb->setup_dma = dma_map_single (controller,
+		if (usb_pipecontrol(urb->pipe))
+			urb->setup_dma = dma_map_single(controller,
 					urb->setup_packet,
-					sizeof (struct usb_ctrlrequest),
+					sizeof(struct usb_ctrlrequest),
 					DMA_TO_DEVICE);
 	// FIXME generic api broken like pci, can't report errors
 	// if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
@@ -689,7 +689,7 @@
  * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s)
  * @urb: urb whose transfer_buffer/setup_packet will be synchronized
  */
-void usb_buffer_dmasync (struct urb *urb)
+void usb_buffer_dmasync(struct urb *urb)
 {
 	struct usb_bus		*bus;
 	struct device		*controller;
@@ -702,14 +702,14 @@
 		return;
 
 	if (controller->dma_mask) {
-		dma_sync_single (controller,
+		dma_sync_single(controller,
 			urb->transfer_dma, urb->transfer_buffer_length,
-			usb_pipein (urb->pipe)
+			usb_pipein(urb->pipe)
 				? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-		if (usb_pipecontrol (urb->pipe))
-			dma_sync_single (controller,
+		if (usb_pipecontrol(urb->pipe))
+			dma_sync_single(controller,
 					urb->setup_dma,
-					sizeof (struct usb_ctrlrequest),
+					sizeof(struct usb_ctrlrequest),
 					DMA_TO_DEVICE);
 	}
 }
@@ -722,7 +722,7 @@
  * Reverses the effect of usb_buffer_map().
  */
 #if 0
-void usb_buffer_unmap (struct urb *urb)
+void usb_buffer_unmap(struct urb *urb)
 {
 	struct usb_bus		*bus;
 	struct device		*controller;
@@ -735,14 +735,14 @@
 		return;
 
 	if (controller->dma_mask) {
-		dma_unmap_single (controller,
+		dma_unmap_single(controller,
 			urb->transfer_dma, urb->transfer_buffer_length,
-			usb_pipein (urb->pipe)
+			usb_pipein(urb->pipe)
 				? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-		if (usb_pipecontrol (urb->pipe))
-			dma_unmap_single (controller,
+		if (usb_pipecontrol(urb->pipe))
+			dma_unmap_single(controller,
 					urb->setup_dma,
-					sizeof (struct usb_ctrlrequest),
+					sizeof(struct usb_ctrlrequest),
 					DMA_TO_DEVICE);
 	}
 	urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP
@@ -783,15 +783,15 @@
 	struct device		*controller;
 
 	if (!dev
-			|| usb_pipecontrol (pipe)
+			|| usb_pipecontrol(pipe)
 			|| !(bus = dev->bus)
 			|| !(controller = bus->controller)
 			|| !controller->dma_mask)
 		return -1;
 
 	// FIXME generic api broken like pci, can't report errors
-	return dma_map_sg (controller, sg, nents,
-			usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+	return dma_map_sg(controller, sg, nents,
+			usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /* XXX DISABLED, no users currently.  If you wish to re-enable this
@@ -823,8 +823,8 @@
 			|| !controller->dma_mask)
 		return;
 
-	dma_sync_sg (controller, sg, n_hw_ents,
-			usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+	dma_sync_sg(controller, sg, n_hw_ents,
+			usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 #endif
 
@@ -849,8 +849,8 @@
 			|| !controller->dma_mask)
 		return;
 
-	dma_unmap_sg (controller, sg, n_hw_ents,
-			usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+	dma_unmap_sg(controller, sg, n_hw_ents,
+			usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /* format to disable USB on kernel command line is: nousb */
@@ -871,7 +871,7 @@
 {
 	int retval;
 	if (nousb) {
-		pr_info ("%s: USB support disabled\n", usbcore_name);
+		pr_info("%s: USB support disabled\n", usbcore_name);
 		return 0;
 	}
 
@@ -971,19 +971,19 @@
 EXPORT_SYMBOL(usb_find_device);
 EXPORT_SYMBOL(usb_get_current_frame_number);
 
-EXPORT_SYMBOL (usb_buffer_alloc);
-EXPORT_SYMBOL (usb_buffer_free);
+EXPORT_SYMBOL(usb_buffer_alloc);
+EXPORT_SYMBOL(usb_buffer_free);
 
 #if 0
-EXPORT_SYMBOL (usb_buffer_map);
-EXPORT_SYMBOL (usb_buffer_dmasync);
-EXPORT_SYMBOL (usb_buffer_unmap);
+EXPORT_SYMBOL(usb_buffer_map);
+EXPORT_SYMBOL(usb_buffer_dmasync);
+EXPORT_SYMBOL(usb_buffer_unmap);
 #endif
 
-EXPORT_SYMBOL (usb_buffer_map_sg);
+EXPORT_SYMBOL(usb_buffer_map_sg);
 #if 0
-EXPORT_SYMBOL (usb_buffer_dmasync_sg);
+EXPORT_SYMBOL(usb_buffer_dmasync_sg);
 #endif
-EXPORT_SYMBOL (usb_buffer_unmap_sg);
+EXPORT_SYMBOL(usb_buffer_unmap_sg);
 
 MODULE_LICENSE("GPL");
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 812c733..f390501 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -39,7 +39,7 @@
 #include <linux/interrupt.h>
 #include <linux/proc_fs.h>
 #include <linux/clk.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include <asm/byteorder.h>
@@ -1807,16 +1807,13 @@
 			|| !wake
 			|| at91_suspend_entering_slow_clock()) {
 		pullup(udc, 0);
-		disable_irq_wake(udc->udp_irq);
+		wake = 0;
 	} else
 		enable_irq_wake(udc->udp_irq);
 
-	if (udc->board.vbus_pin > 0) {
-		if (wake)
-			enable_irq_wake(udc->board.vbus_pin);
-		else
-			disable_irq_wake(udc->board.vbus_pin);
-	}
+	udc->active_suspend = wake;
+	if (udc->board.vbus_pin > 0 && wake)
+		enable_irq_wake(udc->board.vbus_pin);
 	return 0;
 }
 
@@ -1824,8 +1821,14 @@
 {
 	struct at91_udc *udc = platform_get_drvdata(pdev);
 
+	if (udc->board.vbus_pin > 0 && udc->active_suspend)
+		disable_irq_wake(udc->board.vbus_pin);
+
 	/* maybe reconnect to host; if so, clocks on */
-	pullup(udc, 1);
+	if (udc->active_suspend)
+		disable_irq_wake(udc->udp_irq);
+	else
+		pullup(udc, 1);
 	return 0;
 }
 #else
diff --git a/drivers/usb/gadget/at91_udc.h b/drivers/usb/gadget/at91_udc.h
index 677089b..7e34e2f 100644
--- a/drivers/usb/gadget/at91_udc.h
+++ b/drivers/usb/gadget/at91_udc.h
@@ -136,6 +136,7 @@
 	unsigned			wait_for_addr_ack:1;
 	unsigned			wait_for_config_ack:1;
 	unsigned			selfpowered:1;
+	unsigned			active_suspend:1;
 	u8				addr;
 	struct at91_udc_data		board;
 	struct clk			*iclk, *fclk;
diff --git a/drivers/usb/gadget/config.c b/drivers/usb/gadget/config.c
index 83b4866..d18901b 100644
--- a/drivers/usb/gadget/config.c
+++ b/drivers/usb/gadget/config.c
@@ -24,7 +24,7 @@
 #include <linux/string.h>
 #include <linux/device.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index 53d5845..f28af06 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -27,7 +27,7 @@
 #include <linux/ctype.h>
 #include <linux/string.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include "gadget_chips.h"
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index d15bf22..22e3c94 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -47,7 +47,7 @@
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
 #include <linux/usb_gadget.h>
 
@@ -72,9 +72,18 @@
  *
  * There's some hardware that can't talk CDC.  We make that hardware
  * implement a "minimalist" vendor-agnostic CDC core:  same framing, but
- * link-level setup only requires activating the configuration.
- * Linux supports it, but other host operating systems may not.
- * (This is a subset of CDC Ethernet.)
+ * link-level setup only requires activating the configuration.  Only the
+ * endpoint descriptors, and product/vendor IDs, are relevant; no control
+ * operations are available.  Linux supports it, but other host operating
+ * systems may not.  (This is a subset of CDC Ethernet.)
+ *
+ * It turns out that if you add a few descriptors to that "CDC Subset",
+ * (Windows) host side drivers from MCCI can treat it as one submode of
+ * a proprietary scheme called "SAFE" ... without needing to know about
+ * specific product/vendor IDs.  So we do that, making it easier to use
+ * those MS-Windows drivers.  Those added descriptors make it resemble a
+ * CDC MDLM device, but they don't change device behavior at all.  (See
+ * MCCI Engineering report 950198 "SAFE Networking Functions".)
  *
  * A third option is also in use.  Rather than CDC Ethernet, or something
  * simpler, Microsoft pushes their own approach: RNDIS.  The published
@@ -254,6 +263,10 @@
 #define DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_S3C2410
+#define DEV_CONFIG_CDC
+#endif
+
 #ifdef CONFIG_USB_GADGET_AT91
 #define DEV_CONFIG_CDC
 #endif
@@ -266,6 +279,10 @@
 #define DEV_CONFIG_CDC
 #endif
 
+#ifdef CONFIG_USB_GADGET_HUSB2DEV
+#define DEV_CONFIG_CDC
+#endif
+
 
 /* For CDC-incapable hardware, choose the simple cdc subset.
  * Anything that talks bulk (without notable bugs) can do this.
@@ -283,9 +300,6 @@
 #define	DEV_CONFIG_SUBSET
 #endif
 
-#ifdef CONFIG_USB_GADGET_S3C2410
-#define DEV_CONFIG_CDC
-#endif
 
 /*-------------------------------------------------------------------------*/
 
@@ -487,8 +501,17 @@
  * endpoint.  Both have a "data" interface and two bulk endpoints.
  * There are also differences in how control requests are handled.
  *
- * RNDIS shares a lot with CDC-Ethernet, since it's a variant of
- * the CDC-ACM (modem) spec.
+ * RNDIS shares a lot with CDC-Ethernet, since it's a variant of the
+ * CDC-ACM (modem) spec.  Unfortunately MSFT's RNDIS driver is buggy; it
+ * may hang or oops.  Since bugfixes (or accurate specs, letting Linux
+ * work around those bugs) are unlikely to ever come from MSFT, you may
+ * wish to avoid using RNDIS.
+ *
+ * MCCI offers an alternative to RNDIS if you need to connect to Windows
+ * but have hardware that can't support CDC Ethernet.   We add descriptors
+ * to present the CDC Subset as a (nonconformant) CDC MDLM variant called
+ * "SAFE".  That borrows from both CDC Ethernet and CDC MDLM.  You can
+ * get those drivers from MCCI, or bundled with various products.
  */
 
 #ifdef	DEV_CONFIG_CDC
@@ -522,8 +545,6 @@
 };
 #endif
 
-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
-
 static const struct usb_cdc_header_desc header_desc = {
 	.bLength =		sizeof header_desc,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
@@ -532,6 +553,8 @@
 	.bcdCDC =		__constant_cpu_to_le16 (0x0110),
 };
 
+#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+
 static const struct usb_cdc_union_desc union_desc = {
 	.bLength =		sizeof union_desc,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
@@ -564,7 +587,40 @@
 
 #endif
 
-#ifdef	DEV_CONFIG_CDC
+#ifndef DEV_CONFIG_CDC
+
+/* "SAFE" loosely follows CDC WMC MDLM, violating the spec in various
+ * ways:  data endpoints live in the control interface, there's no data
+ * interface, and it's not used to talk to a cell phone radio.
+ */
+
+static const struct usb_cdc_mdlm_desc mdlm_desc = {
+	.bLength =		sizeof mdlm_desc,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_MDLM_TYPE,
+
+	.bcdVersion =		__constant_cpu_to_le16(0x0100),
+	.bGUID = {
+		0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,
+		0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,
+	},
+};
+
+/* since "usb_cdc_mdlm_detail_desc" is a variable length structure, we
+ * can't really use its struct.  All we do here is say that we're using
+ * the submode of "SAFE" which directly matches the CDC Subset.
+ */
+static const u8 mdlm_detail_desc[] = {
+	6,
+	USB_DT_CS_INTERFACE,
+	USB_CDC_MDLM_DETAIL_TYPE,
+
+	0,	/* "SAFE" */
+	0,	/* network control capabilities (none) */
+	0,	/* network data capabilities ("raw" encapsulation) */
+};
+
+#endif
 
 static const struct usb_cdc_ether_desc ether_desc = {
 	.bLength =		sizeof ether_desc,
@@ -579,7 +635,6 @@
 	.bNumberPowerFilters =	0,
 };
 
-#endif
 
 #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
 
@@ -672,6 +727,9 @@
 /*
  * "Simple" CDC-subset option is a simple vendor-neutral model that most
  * full speed controllers can handle:  one interface, two bulk endpoints.
+ *
+ * To assist host side drivers, we fancy it up a bit, and add descriptors
+ * so some host side drivers will understand it as a "SAFE" variant.
  */
 
 static const struct usb_interface_descriptor
@@ -682,8 +740,8 @@
 	.bInterfaceNumber =	0,
 	.bAlternateSetting =	0,
 	.bNumEndpoints =	2,
-	.bInterfaceClass =	USB_CLASS_VENDOR_SPEC,
-	.bInterfaceSubClass =	0,
+	.bInterfaceClass =      USB_CLASS_COMM,
+	.bInterfaceSubClass =	USB_CDC_SUBCLASS_MDLM,
 	.bInterfaceProtocol =	0,
 	.iInterface =		STRING_DATA,
 };
@@ -731,10 +789,15 @@
 static inline void __init fs_subset_descriptors(void)
 {
 #ifdef DEV_CONFIG_SUBSET
+	/* behavior is "CDC Subset"; extra descriptors say "SAFE" */
 	fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
-	fs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
-	fs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
-	fs_eth_function[4] = NULL;
+	fs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+	fs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+	fs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+	fs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+	fs_eth_function[6] = (struct usb_descriptor_header *) &fs_source_desc;
+	fs_eth_function[7] = (struct usb_descriptor_header *) &fs_sink_desc;
+	fs_eth_function[8] = NULL;
 #else
 	fs_eth_function[1] = NULL;
 #endif
@@ -828,10 +891,15 @@
 static inline void __init hs_subset_descriptors(void)
 {
 #ifdef DEV_CONFIG_SUBSET
+	/* behavior is "CDC Subset"; extra descriptors say "SAFE" */
 	hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
-	hs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
-	hs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
-	hs_eth_function[4] = NULL;
+	hs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+	hs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+	hs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+	hs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+	hs_eth_function[6] = (struct usb_descriptor_header *) &hs_source_desc;
+	hs_eth_function[7] = (struct usb_descriptor_header *) &hs_sink_desc;
+	hs_eth_function[8] = NULL;
 #else
 	hs_eth_function[1] = NULL;
 #endif
@@ -878,10 +946,8 @@
 static char				product_desc [40] = DRIVER_DESC;
 static char				serial_number [20];
 
-#ifdef	DEV_CONFIG_CDC
 /* address that the host will use ... usually assigned at random */
 static char				ethaddr [2 * ETH_ALEN + 1];
-#endif
 
 /* static strings, in UTF-8 */
 static struct usb_string		strings [] = {
@@ -889,9 +955,9 @@
 	{ STRING_PRODUCT,	product_desc, },
 	{ STRING_SERIALNUMBER,	serial_number, },
 	{ STRING_DATA,		"Ethernet Data", },
+	{ STRING_ETHADDR,	ethaddr, },
 #ifdef	DEV_CONFIG_CDC
 	{ STRING_CDC,		"CDC Ethernet", },
-	{ STRING_ETHADDR,	ethaddr, },
 	{ STRING_CONTROL,	"CDC Communications Control", },
 #endif
 #ifdef	DEV_CONFIG_SUBSET
@@ -986,10 +1052,10 @@
 	}
 #endif
 
-	dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
+	dev->in = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
 	dev->in_ep->driver_data = dev;
 
-	dev->out = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
+	dev->out = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
 	dev->out_ep->driver_data = dev;
 
 	/* With CDC,  the host isn't allowed to use these two data
@@ -2278,10 +2344,10 @@
 			"RNDIS/%s", driver_desc);
 
 	/* CDC subset ... recognized by Linux since 2.4.10, but Windows
-	 * drivers aren't widely available.
+	 * drivers aren't widely available.  (That may be improved by
+	 * supporting one submode of the "SAFE" variant of MDLM.)
 	 */
 	} else if (!cdc) {
-		device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
 		device_desc.idVendor =
 			__constant_cpu_to_le16(SIMPLE_VENDOR_NUM);
 		device_desc.idProduct =
@@ -2352,6 +2418,10 @@
 	if (!cdc) {
 		eth_config.bNumInterfaces = 1;
 		eth_config.iConfiguration = STRING_SUBSET;
+
+		/* use functions to set these up, in case we're built to work
+		 * with multiple controllers and must override CDC Ethernet.
+		 */
 		fs_subset_descriptors();
 		hs_subset_descriptors();
 	}
@@ -2415,22 +2485,20 @@
 
 	/* Module params for these addresses should come from ID proms.
 	 * The host side address is used with CDC and RNDIS, and commonly
-	 * ends up in a persistent config database.
+	 * ends up in a persistent config database.  It's not clear if
+	 * host side code for the SAFE thing cares -- its original BLAN
+	 * thing didn't, Sharp never assigned those addresses on Zaurii.
 	 */
 	if (get_ether_addr(dev_addr, net->dev_addr))
 		dev_warn(&gadget->dev,
 			"using random %s ethernet address\n", "self");
-	if (cdc || rndis) {
-		if (get_ether_addr(host_addr, dev->host_mac))
-			dev_warn(&gadget->dev,
-				"using random %s ethernet address\n", "host");
-#ifdef	DEV_CONFIG_CDC
-		snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
-			dev->host_mac [0], dev->host_mac [1],
-			dev->host_mac [2], dev->host_mac [3],
-			dev->host_mac [4], dev->host_mac [5]);
-#endif
-	}
+	if (get_ether_addr(host_addr, dev->host_mac))
+		dev_warn(&gadget->dev,
+			"using random %s ethernet address\n", "host");
+	snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
+		dev->host_mac [0], dev->host_mac [1],
+		dev->host_mac [2], dev->host_mac [3],
+		dev->host_mac [4], dev->host_mac [5]);
 
 	if (rndis) {
 		status = rndis_init();
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 72f2ae9..f04a29a 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -253,7 +253,7 @@
 #include <linux/freezer.h>
 #include <linux/utsname.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include "gadget_chips.h"
@@ -1148,7 +1148,7 @@
 
 static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
 {
-	struct fsg_dev		*fsg = (struct fsg_dev *) ep->driver_data;
+	struct fsg_dev		*fsg = ep->driver_data;
 
 	if (req->actual > 0)
 		dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
@@ -1170,8 +1170,8 @@
 
 static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
 {
-	struct fsg_dev		*fsg = (struct fsg_dev *) ep->driver_data;
-	struct fsg_buffhd	*bh = (struct fsg_buffhd *) req->context;
+	struct fsg_dev		*fsg = ep->driver_data;
+	struct fsg_buffhd	*bh = req->context;
 
 	if (req->status || req->actual != req->length)
 		DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
@@ -1190,8 +1190,8 @@
 
 static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
 {
-	struct fsg_dev		*fsg = (struct fsg_dev *) ep->driver_data;
-	struct fsg_buffhd	*bh = (struct fsg_buffhd *) req->context;
+	struct fsg_dev		*fsg = ep->driver_data;
+	struct fsg_buffhd	*bh = req->context;
 
 	dump_msg(fsg, "bulk-out", req->buf, req->actual);
 	if (req->status || req->actual != bh->bulk_out_intended_length)
@@ -1214,8 +1214,8 @@
 #ifdef CONFIG_USB_FILE_STORAGE_TEST
 static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
 {
-	struct fsg_dev		*fsg = (struct fsg_dev *) ep->driver_data;
-	struct fsg_buffhd	*bh = (struct fsg_buffhd *) req->context;
+	struct fsg_dev		*fsg = ep->driver_data;
+	struct fsg_buffhd	*bh = req->context;
 
 	if (req->status || req->actual != req->length)
 		DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
@@ -2577,7 +2577,7 @@
 	}
 
 	if (transport_is_bbb()) {
-		struct bulk_cs_wrap	*csw = (struct bulk_cs_wrap *) bh->buf;
+		struct bulk_cs_wrap	*csw = bh->buf;
 
 		/* Store and send the Bulk-only CSW */
 		csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG);
@@ -2596,8 +2596,7 @@
 		return 0;
 
 	} else {			// USB_PR_CBI
-		struct interrupt_data	*buf = (struct interrupt_data *)
-						bh->buf;
+		struct interrupt_data	*buf = bh->buf;
 
 		/* Store and send the Interrupt data.  UFI sends the ASC
 		 * and ASCQ bytes.  Everything else sends a Type (which
@@ -2982,7 +2981,7 @@
 static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
 {
 	struct usb_request	*req = bh->outreq;
-	struct bulk_cb_wrap	*cbw = (struct bulk_cb_wrap *) req->buf;
+	struct bulk_cb_wrap	*cbw = req->buf;
 
 	/* Was this a real packet? */
 	if (req->status)
@@ -3428,7 +3427,7 @@
 
 static int fsg_main_thread(void *fsg_)
 {
-	struct fsg_dev		*fsg = (struct fsg_dev *) fsg_;
+	struct fsg_dev		*fsg = fsg_;
 
 	/* Allow the thread to be killed by a signal, but set the signal mask
 	 * to block everything but INT, TERM, KILL, and USR1. */
@@ -3600,7 +3599,7 @@
 static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf)
 {
 	struct lun	*curlun = dev_to_lun(dev);
-	struct fsg_dev	*fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+	struct fsg_dev	*fsg = dev_get_drvdata(dev);
 	char		*p;
 	ssize_t		rc;
 
@@ -3629,7 +3628,7 @@
 {
 	ssize_t		rc = count;
 	struct lun	*curlun = dev_to_lun(dev);
-	struct fsg_dev	*fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+	struct fsg_dev	*fsg = dev_get_drvdata(dev);
 	int		i;
 
 	if (sscanf(buf, "%d", &i) != 1)
@@ -3652,7 +3651,7 @@
 static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
 	struct lun	*curlun = dev_to_lun(dev);
-	struct fsg_dev	*fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+	struct fsg_dev	*fsg = dev_get_drvdata(dev);
 	int		rc = 0;
 
 	if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) {
@@ -3700,7 +3699,7 @@
 
 static void lun_release(struct device *dev)
 {
-	struct fsg_dev	*fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+	struct fsg_dev	*fsg = dev_get_drvdata(dev);
 
 	kref_put(&fsg->ref, fsg_release);
 }
diff --git a/drivers/usb/gadget/gadget_chips.h b/drivers/usb/gadget/gadget_chips.h
index aa80f09..2e3d662 100644
--- a/drivers/usb/gadget/gadget_chips.h
+++ b/drivers/usb/gadget/gadget_chips.h
@@ -75,6 +75,12 @@
 #define	gadget_is_pxa27x(g)	0
 #endif
 
+#ifdef CONFIG_USB_GADGET_HUSB2DEV
+#define gadget_is_husb2dev(g)	!strcmp("husb2_udc", (g)->name)
+#else
+#define gadget_is_husb2dev(g)	0
+#endif
+
 #ifdef CONFIG_USB_GADGET_S3C2410
 #define gadget_is_s3c2410(g)    !strcmp("s3c2410_udc", (g)->name)
 #else
@@ -169,5 +175,7 @@
 		return 0x16;
 	else if (gadget_is_mpc8272(gadget))
 		return 0x17;
+	else if (gadget_is_husb2dev(gadget))
+		return 0x18;
 	return -ENOENT;
 }
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c
index f1a67965..d08a8d0 100644
--- a/drivers/usb/gadget/gmidi.c
+++ b/drivers/usb/gadget/gmidi.c
@@ -35,7 +35,7 @@
 #include <sound/initval.h>
 #include <sound/rawmidi.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb/audio.h>
 #include <linux/usb/midi.h>
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index d0ef1d6..e873cf4 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -39,7 +39,7 @@
 #include <linux/interrupt.h>
 #include <linux/proc_fs.h>
 #include <linux/device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include <asm/byteorder.h>
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index 3fb1044a..34296e7 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -20,7 +20,7 @@
  */
 
 
-// #define	DEBUG 			/* data to help fault diagnosis */
+// #define	DEBUG			/* data to help fault diagnosis */
 // #define	VERBOSE		/* extra debug messages (success too) */
 
 #include <linux/init.h>
@@ -59,11 +59,11 @@
  *   may serve as a source of device events, used to handle all control
  *   requests other than basic enumeration.
  *
- * - Then either immediately, or after a SET_CONFIGURATION control request,
- *   ep_config() is called when each /dev/gadget/ep* file is configured
- *   (by writing endpoint descriptors).  Afterwards these files are used
- *   to write() IN data or to read() OUT data.  To halt the endpoint, a
- *   "wrong direction" request is issued (like reading an IN endpoint).
+ * - Then, after a SET_CONFIGURATION control request, ep_config() is
+ *   called when each /dev/gadget/ep* file is configured (by writing
+ *   endpoint descriptors).  Afterwards these files are used to write()
+ *   IN data or to read() OUT data.  To halt the endpoint, a "wrong
+ *   direction" request is issued (like reading an IN endpoint).
  *
  * Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe
  * not possible on all hardware.  For example, precise fault handling with
@@ -98,16 +98,16 @@
 	 * must always write descriptors to initialize the device, then
 	 * the device becomes UNCONNECTED until enumeration.
 	 */
-	STATE_OPENED,
+	STATE_DEV_OPENED,
 
 	/* From then on, ep0 fd is in either of two basic modes:
 	 * - (UN)CONNECTED: read usb_gadgetfs_event(s) from it
 	 * - SETUP: read/write will transfer control data and succeed;
 	 *   or if "wrong direction", performs protocol stall
 	 */
-	STATE_UNCONNECTED,
-	STATE_CONNECTED,
-	STATE_SETUP,
+	STATE_DEV_UNCONNECTED,
+	STATE_DEV_CONNECTED,
+	STATE_DEV_SETUP,
 
 	/* UNBOUND means the driver closed ep0, so the device won't be
 	 * accessible again (DEV_DISABLED) until all fds are closed.
@@ -121,7 +121,7 @@
 struct dev_data {
 	spinlock_t			lock;
 	atomic_t			count;
-	enum ep0_state			state;
+	enum ep0_state			state;		/* P: lock */
 	struct usb_gadgetfs_event	event [N_EVENT];
 	unsigned			ev_next;
 	struct fasync_struct		*fasync;
@@ -188,7 +188,6 @@
 enum ep_state {
 	STATE_EP_DISABLED = 0,
 	STATE_EP_READY,
-	STATE_EP_DEFER_ENABLE,
 	STATE_EP_ENABLED,
 	STATE_EP_UNBOUND,
 };
@@ -313,18 +312,10 @@
 
 	if ((val = down_interruptible (&epdata->lock)) < 0)
 		return val;
-newstate:
+
 	switch (epdata->state) {
 	case STATE_EP_ENABLED:
 		break;
-	case STATE_EP_DEFER_ENABLE:
-		DBG (epdata->dev, "%s wait for host\n", epdata->name);
-		if ((val = wait_event_interruptible (epdata->wait, 
-				epdata->state != STATE_EP_DEFER_ENABLE
-				|| epdata->dev->state == STATE_DEV_UNBOUND
-				)) < 0)
-			goto fail;
-		goto newstate;
 	// case STATE_EP_DISABLED:		/* "can't happen" */
 	// case STATE_EP_READY:			/* "can't happen" */
 	default:				/* error! */
@@ -333,7 +324,6 @@
 		// FALLTHROUGH
 	case STATE_EP_UNBOUND:			/* clean disconnect */
 		val = -ENODEV;
-fail:
 		up (&epdata->lock);
 	}
 	return val;
@@ -565,29 +555,28 @@
 	ssize_t			len, total;
 	int			i;
 
-  	/* we "retry" to get the right mm context for this: */
+	/* we "retry" to get the right mm context for this: */
 
- 	/* copy stuff into user buffers */
- 	total = priv->actual;
- 	len = 0;
- 	for (i=0; i < priv->nr_segs; i++) {
- 		ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
+	/* copy stuff into user buffers */
+	total = priv->actual;
+	len = 0;
+	for (i=0; i < priv->nr_segs; i++) {
+		ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
 
- 		if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
- 			if (len == 0)
- 				len = -EFAULT;
- 			break;
- 		}
+		if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
+			if (len == 0)
+				len = -EFAULT;
+			break;
+		}
 
- 		total -= this;
- 		len += this;
- 		if (total == 0)
- 			break;
- 	}
-  	kfree(priv->buf);
-  	kfree(priv);
-  	aio_put_req(iocb);
- 	return len;
+		total -= this;
+		len += this;
+		if (total == 0)
+			break;
+	}
+	kfree(priv->buf);
+	kfree(priv);
+	return len;
 }
 
 static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
@@ -600,18 +589,17 @@
 	spin_lock(&epdata->dev->lock);
 	priv->req = NULL;
 	priv->epdata = NULL;
-	if (priv->iv == NULL
-			|| unlikely(req->actual == 0)
-			|| unlikely(kiocbIsCancelled(iocb))) {
+
+	/* if this was a write or a read returning no data then we
+	 * don't need to copy anything to userspace, so we can
+	 * complete the aio request immediately.
+	 */
+	if (priv->iv == NULL || unlikely(req->actual == 0)) {
 		kfree(req->buf);
 		kfree(priv);
 		iocb->private = NULL;
 		/* aio_complete() reports bytes-transferred _and_ faults */
-		if (unlikely(kiocbIsCancelled(iocb)))
-			aio_put_req(iocb);
-		else
-			aio_complete(iocb,
-				req->actual ? req->actual : req->status,
+		aio_complete(iocb, req->actual ? req->actual : req->status,
 				req->status);
 	} else {
 		/* retry() won't report both; so we hide some faults */
@@ -636,7 +624,7 @@
 	size_t		len,
 	struct ep_data	*epdata,
 	const struct iovec *iv,
-	unsigned long 	nr_segs
+	unsigned long	nr_segs
 )
 {
 	struct kiocb_priv	*priv;
@@ -852,9 +840,9 @@
 		break;
 #endif
 	default:
-		DBG (data->dev, "unconnected, %s init deferred\n",
+		DBG(data->dev, "unconnected, %s init abandoned\n",
 				data->name);
-		data->state = STATE_EP_DEFER_ENABLE;
+		value = -EINVAL;
 	}
 	if (value == 0) {
 		fd->f_op = &ep_io_operations;
@@ -943,22 +931,24 @@
 static void ep0_complete (struct usb_ep *ep, struct usb_request *req)
 {
 	struct dev_data		*dev = ep->driver_data;
+	unsigned long		flags;
 	int			free = 1;
 
 	/* for control OUT, data must still get to userspace */
+	spin_lock_irqsave(&dev->lock, flags);
 	if (!dev->setup_in) {
 		dev->setup_out_error = (req->status != 0);
 		if (!dev->setup_out_error)
 			free = 0;
 		dev->setup_out_ready = 1;
 		ep0_readable (dev);
-	} else if (dev->state == STATE_SETUP)
-		dev->state = STATE_CONNECTED;
+	}
 
 	/* clean up as appropriate */
 	if (free && req->buf != &dev->rbuf)
 		clean_req (ep, req);
 	req->complete = epio_complete;
+	spin_unlock_irqrestore(&dev->lock, flags);
 }
 
 static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
@@ -998,13 +988,13 @@
 	}
 
 	/* control DATA stage */
-	if ((state = dev->state) == STATE_SETUP) {
+	if ((state = dev->state) == STATE_DEV_SETUP) {
 
 		if (dev->setup_in) {		/* stall IN */
 			VDEBUG(dev, "ep0in stall\n");
 			(void) usb_ep_set_halt (dev->gadget->ep0);
 			retval = -EL2HLT;
-			dev->state = STATE_CONNECTED;
+			dev->state = STATE_DEV_CONNECTED;
 
 		} else if (len == 0) {		/* ack SET_CONFIGURATION etc */
 			struct usb_ep		*ep = dev->gadget->ep0;
@@ -1012,7 +1002,7 @@
 
 			if ((retval = setup_req (ep, req, 0)) == 0)
 				retval = usb_ep_queue (ep, req, GFP_ATOMIC);
-			dev->state = STATE_CONNECTED;
+			dev->state = STATE_DEV_CONNECTED;
 
 			/* assume that was SET_CONFIGURATION */
 			if (dev->current_config) {
@@ -1040,6 +1030,13 @@
 			spin_lock_irq (&dev->lock);
 			if (retval)
 				goto done;
+
+			if (dev->state != STATE_DEV_SETUP) {
+				retval = -ECANCELED;
+				goto done;
+			}
+			dev->state = STATE_DEV_CONNECTED;
+
 			if (dev->setup_out_error)
 				retval = -EIO;
 			else {
@@ -1066,39 +1063,36 @@
 	/* return queued events right away */
 	if (dev->ev_next != 0) {
 		unsigned		i, n;
-		int			tmp = dev->ev_next;
 
-		len = min (len, tmp * sizeof (struct usb_gadgetfs_event));
 		n = len / sizeof (struct usb_gadgetfs_event);
+		if (dev->ev_next < n)
+			n = dev->ev_next;
 
-		/* ep0 can't deliver events when STATE_SETUP */
+		/* ep0 i/o has special semantics during STATE_DEV_SETUP */
 		for (i = 0; i < n; i++) {
 			if (dev->event [i].type == GADGETFS_SETUP) {
-				len = i + 1;
-				len *= sizeof (struct usb_gadgetfs_event);
-				n = 0;
+				dev->state = STATE_DEV_SETUP;
+				n = i + 1;
 				break;
 			}
 		}
 		spin_unlock_irq (&dev->lock);
+		len = n * sizeof (struct usb_gadgetfs_event);
 		if (copy_to_user (buf, &dev->event, len))
 			retval = -EFAULT;
 		else
 			retval = len;
 		if (len > 0) {
-			len /= sizeof (struct usb_gadgetfs_event);
-
 			/* NOTE this doesn't guard against broken drivers;
 			 * concurrent ep0 readers may lose events.
 			 */
 			spin_lock_irq (&dev->lock);
-			dev->ev_next -= len;
-			if (dev->ev_next != 0)
-				memmove (&dev->event, &dev->event [len],
+			if (dev->ev_next > n) {
+				memmove(&dev->event[0], &dev->event[n],
 					sizeof (struct usb_gadgetfs_event)
-						* (tmp - len));
-			if (n == 0)
-				dev->state = STATE_SETUP;
+						* (dev->ev_next - n));
+			}
+			dev->ev_next -= n;
 			spin_unlock_irq (&dev->lock);
 		}
 		return retval;
@@ -1113,8 +1107,8 @@
 		DBG (dev, "fail %s, state %d\n", __FUNCTION__, state);
 		retval = -ESRCH;
 		break;
-	case STATE_UNCONNECTED:
-	case STATE_CONNECTED:
+	case STATE_DEV_UNCONNECTED:
+	case STATE_DEV_CONNECTED:
 		spin_unlock_irq (&dev->lock);
 		DBG (dev, "%s wait\n", __FUNCTION__);
 
@@ -1141,7 +1135,7 @@
 	switch (type) {
 	/* these events purge the queue */
 	case GADGETFS_DISCONNECT:
-		if (dev->state == STATE_SETUP)
+		if (dev->state == STATE_DEV_SETUP)
 			dev->setup_abort = 1;
 		// FALL THROUGH
 	case GADGETFS_CONNECT:
@@ -1153,7 +1147,7 @@
 		for (i = 0; i != dev->ev_next; i++) {
 			if (dev->event [i].type != type)
 				continue;
-			DBG (dev, "discard old event %d\n", type);
+			DBG(dev, "discard old event[%d] %d\n", i, type);
 			dev->ev_next--;
 			if (i == dev->ev_next)
 				break;
@@ -1166,9 +1160,9 @@
 	default:
 		BUG ();
 	}
+	VDEBUG(dev, "event[%d] = %d\n", dev->ev_next, type);
 	event = &dev->event [dev->ev_next++];
 	BUG_ON (dev->ev_next > N_EVENT);
-	VDEBUG (dev, "ev %d, next %d\n", type, dev->ev_next);
 	memset (event, 0, sizeof *event);
 	event->type = type;
 	return event;
@@ -1188,12 +1182,13 @@
 		retval = -EIDRM;
 
 	/* data and/or status stage for control request */
-	} else if (dev->state == STATE_SETUP) {
+	} else if (dev->state == STATE_DEV_SETUP) {
 
 		/* IN DATA+STATUS caller makes len <= wLength */
 		if (dev->setup_in) {
 			retval = setup_req (dev->gadget->ep0, dev->req, len);
 			if (retval == 0) {
+				dev->state = STATE_DEV_CONNECTED;
 				spin_unlock_irq (&dev->lock);
 				if (copy_from_user (dev->req->buf, buf, len))
 					retval = -EFAULT;
@@ -1219,7 +1214,7 @@
 			VDEBUG(dev, "ep0out stall\n");
 			(void) usb_ep_set_halt (dev->gadget->ep0);
 			retval = -EL2HLT;
-			dev->state = STATE_CONNECTED;
+			dev->state = STATE_DEV_CONNECTED;
 		} else {
 			DBG(dev, "bogus ep0out stall!\n");
 		}
@@ -1261,7 +1256,9 @@
 	put_dev (dev);
 
 	/* other endpoints were all decoupled from this device */
+	spin_lock_irq(&dev->lock);
 	dev->state = STATE_DEV_DISABLED;
+	spin_unlock_irq(&dev->lock);
 	return 0;
 }
 
@@ -1282,7 +1279,7 @@
                goto out;
        }
 
-       if (dev->state == STATE_SETUP) {
+       if (dev->state == STATE_DEV_SETUP) {
                if (dev->setup_in || dev->setup_can_stall)
                        mask = POLLOUT;
        } else {
@@ -1392,52 +1389,29 @@
 
 	spin_lock (&dev->lock);
 	dev->setup_abort = 0;
-	if (dev->state == STATE_UNCONNECTED) {
-		struct usb_ep	*ep;
-		struct ep_data	*data;
-
-		dev->state = STATE_CONNECTED;
-		dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
-
+	if (dev->state == STATE_DEV_UNCONNECTED) {
 #ifdef	CONFIG_USB_GADGET_DUALSPEED
 		if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == 0) {
+			spin_unlock(&dev->lock);
 			ERROR (dev, "no high speed config??\n");
 			return -EINVAL;
 		}
 #endif	/* CONFIG_USB_GADGET_DUALSPEED */
 
+		dev->state = STATE_DEV_CONNECTED;
+		dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
+
 		INFO (dev, "connected\n");
 		event = next_event (dev, GADGETFS_CONNECT);
 		event->u.speed = gadget->speed;
 		ep0_readable (dev);
 
-		list_for_each_entry (ep, &gadget->ep_list, ep_list) {
-			data = ep->driver_data;
-			/* ... down_trylock (&data->lock) ... */
-			if (data->state != STATE_EP_DEFER_ENABLE)
-				continue;
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-			if (gadget->speed == USB_SPEED_HIGH)
-				value = usb_ep_enable (ep, &data->hs_desc);
-			else
-#endif	/* CONFIG_USB_GADGET_DUALSPEED */
-				value = usb_ep_enable (ep, &data->desc);
-			if (value) {
-				ERROR (dev, "deferred %s enable --> %d\n",
-					data->name, value);
-				continue;
-			}
-			data->state = STATE_EP_ENABLED;
-			wake_up (&data->wait);
-			DBG (dev, "woke up %s waiters\n", data->name);
-		}
-
 	/* host may have given up waiting for response.  we can miss control
 	 * requests handled lower down (device/endpoint status and features);
 	 * then ep0_{read,write} will report the wrong status. controller
 	 * driver will have aborted pending i/o.
 	 */
-	} else if (dev->state == STATE_SETUP)
+	} else if (dev->state == STATE_DEV_SETUP)
 		dev->setup_abort = 1;
 
 	req->buf = dev->rbuf;
@@ -1583,7 +1557,7 @@
 	}
 
 	/* proceed with data transfer and status phases? */
-	if (value >= 0 && dev->state != STATE_SETUP) {
+	if (value >= 0 && dev->state != STATE_DEV_SETUP) {
 		req->length = value;
 		req->zero = value < w_length;
 		value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
@@ -1747,7 +1721,9 @@
 		goto enomem;
 
 	INFO (dev, "bound to %s driver\n", gadget->name);
-	dev->state = STATE_UNCONNECTED;
+	spin_lock_irq(&dev->lock);
+	dev->state = STATE_DEV_UNCONNECTED;
+	spin_unlock_irq(&dev->lock);
 	get_dev (dev);
 	return 0;
 
@@ -1762,11 +1738,9 @@
 	struct dev_data		*dev = get_gadget_data (gadget);
 
 	spin_lock (&dev->lock);
-	if (dev->state == STATE_UNCONNECTED) {
-		DBG (dev, "already unconnected\n");
+	if (dev->state == STATE_DEV_UNCONNECTED)
 		goto exit;
-	}
-	dev->state = STATE_UNCONNECTED;
+	dev->state = STATE_DEV_UNCONNECTED;
 
 	INFO (dev, "disconnected\n");
 	next_event (dev, GADGETFS_DISCONNECT);
@@ -1783,9 +1757,9 @@
 	INFO (dev, "suspended from state %d\n", dev->state);
 	spin_lock (&dev->lock);
 	switch (dev->state) {
-	case STATE_SETUP:		// VERY odd... host died??
-	case STATE_CONNECTED:
-	case STATE_UNCONNECTED:
+	case STATE_DEV_SETUP:		// VERY odd... host died??
+	case STATE_DEV_CONNECTED:
+	case STATE_DEV_UNCONNECTED:
 		next_event (dev, GADGETFS_SUSPEND);
 		ep0_readable (dev);
 		/* FALLTHROUGH */
@@ -1808,7 +1782,7 @@
 	.disconnect	= gadgetfs_disconnect,
 	.suspend	= gadgetfs_suspend,
 
-	.driver 	= {
+	.driver	= {
 		.name		= (char *) shortname,
 	},
 };
@@ -1829,7 +1803,7 @@
 	.unbind		= gadgetfs_nop,
 	.setup		= (void *)gadgetfs_nop,
 	.disconnect	= gadgetfs_nop,
-	.driver 	= {
+	.driver	= {
 		.name		= "nop",
 	},
 };
@@ -1849,19 +1823,16 @@
  * . full/low speed config ... all wTotalLength bytes (with interface,
  *	class, altsetting, endpoint, and other descriptors)
  * . high speed config ... all descriptors, for high speed operation;
- * 	this one's optional except for high-speed hardware
+ *	this one's optional except for high-speed hardware
  * . device descriptor
  *
- * Endpoints are not yet enabled. Drivers may want to immediately
- * initialize them, using the /dev/gadget/ep* files that are available
- * as soon as the kernel sees the configuration, or they can wait
- * until device configuration and interface altsetting changes create
+ * Endpoints are not yet enabled. Drivers must wait until device
+ * configuration and interface altsetting changes create
  * the need to configure (or unconfigure) them.
  *
  * After initialization, the device stays active for as long as that
- * $CHIP file is open.  Events may then be read from that descriptor,
- * such as configuration notifications.  More complex drivers will handle
- * some control requests in user space.
+ * $CHIP file is open.  Events must then be read from that descriptor,
+ * such as configuration notifications.
  */
 
 static int is_valid_config (struct usb_config_descriptor *config)
@@ -1884,9 +1855,6 @@
 	u32			tag;
 	char			*kbuf;
 
-	if (dev->state != STATE_OPENED)
-		return -EEXIST;
-
 	if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4))
 		return -EINVAL;
 
@@ -1978,13 +1946,15 @@
 	struct dev_data		*dev = inode->i_private;
 	int			value = -EBUSY;
 
+	spin_lock_irq(&dev->lock);
 	if (dev->state == STATE_DEV_DISABLED) {
 		dev->ev_next = 0;
-		dev->state = STATE_OPENED;
+		dev->state = STATE_DEV_OPENED;
 		fd->private_data = dev;
 		get_dev (dev);
 		value = 0;
 	}
+	spin_unlock_irq(&dev->lock);
 	return value;
 }
 
diff --git a/drivers/usb/gadget/lh7a40x_udc.h b/drivers/usb/gadget/lh7a40x_udc.h
index e3bb785..b3fe197 100644
--- a/drivers/usb/gadget/lh7a40x_udc.h
+++ b/drivers/usb/gadget/lh7a40x_udc.h
@@ -49,7 +49,7 @@
 #include <asm/unaligned.h>
 #include <asm/hardware.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 /*
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index 569eb8c..7617ff7 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -63,7 +63,7 @@
 #include <linux/interrupt.h>
 #include <linux/moduleparam.h>
 #include <linux/device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include <asm/byteorder.h>
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index cdcfd42..1401043 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -38,7 +38,7 @@
 #include <linux/mm.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/dma-mapping.h>
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index b78de96..0d22536 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -56,7 +56,7 @@
 #include <asm/arch/pxa-regs.h>
 #endif
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include <asm/arch/udc.h>
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index f8a3ec6..6c742a9 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -43,7 +43,7 @@
 #include <asm/unaligned.h>
 #include <asm/uaccess.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
 #include <linux/usb_gadget.h>
 
diff --git a/drivers/usb/gadget/usbstring.c b/drivers/usb/gadget/usbstring.c
index b173576..3459ea6 100644
--- a/drivers/usb/gadget/usbstring.c
+++ b/drivers/usb/gadget/usbstring.c
@@ -14,7 +14,7 @@
 #include <linux/device.h>
 #include <linux/init.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include <asm/unaligned.h>
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index 40710ea..ebe04e0 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -84,7 +84,7 @@
 #include <asm/system.h>
 #include <asm/unaligned.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 
 #include "gadget_chips.h"
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index cc60759..6271187 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -67,6 +67,11 @@
 
 	  If unsure, say N.
 
+config USB_EHCI_BIG_ENDIAN_MMIO
+	bool
+	depends on USB_EHCI_HCD
+	default n
+
 config USB_ISP116X_HCD
 	tristate "ISP116X HCD support"
 	depends on USB
@@ -101,21 +106,48 @@
 	bool "OHCI support for on-chip PPC USB controller"
 	depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
 	default y
-	select USB_OHCI_BIG_ENDIAN
+	select USB_OHCI_BIG_ENDIAN_DESC
+	select USB_OHCI_BIG_ENDIAN_MMIO
 	---help---
 	  Enables support for the USB controller on the MPC52xx or
 	  STB03xxx processor chip.  If unsure, say Y.
 
+config USB_OHCI_HCD_PPC_OF
+	bool "OHCI support for PPC USB controller on OF platform bus"
+	depends on USB_OHCI_HCD && PPC_OF
+	default y
+	---help---
+	  Enables support for the USB controller PowerPC present on the
+	  OpenFirmware platform bus.
+
+config USB_OHCI_HCD_PPC_OF_BE
+	bool "Support big endian HC"
+	depends on USB_OHCI_HCD_PPC_OF
+	default y
+	select USB_OHCI_BIG_ENDIAN_DESC
+	select USB_OHCI_BIG_ENDIAN_MMIO
+
+config USB_OHCI_HCD_PPC_OF_LE
+	bool "Support little endian HC"
+	depends on USB_OHCI_HCD_PPC_OF
+	default n
+	select USB_OHCI_LITTLE_ENDIAN
+
 config USB_OHCI_HCD_PCI
 	bool "OHCI support for PCI-bus USB controllers"
-	depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx)
+	depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF)
 	default y
 	select USB_OHCI_LITTLE_ENDIAN
 	---help---
 	  Enables support for PCI-bus plug-in USB controller cards.
 	  If unsure, say Y.
 
-config USB_OHCI_BIG_ENDIAN
+config USB_OHCI_BIG_ENDIAN_DESC
+	bool
+	depends on USB_OHCI_HCD
+	default n
+
+config USB_OHCI_BIG_ENDIAN_MMIO
 	bool
 	depends on USB_OHCI_HCD
 	default n
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index 56349d2..246afea 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -43,7 +43,7 @@
  */
 static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
 {
-	u32	params = readl (&ehci->caps->hcs_params);
+	u32	params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
 	ehci_dbg (ehci,
 		"%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n",
@@ -87,7 +87,7 @@
  * */
 static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
 {
-	u32	params = readl (&ehci->caps->hcc_params);
+	u32	params = ehci_readl(ehci, &ehci->caps->hcc_params);
 
 	if (HCC_ISOC_CACHE (params)) {
 		ehci_dbg (ehci,
@@ -653,7 +653,7 @@
 	}
 
 	/* Capability Registers */
-	i = HC_VERSION(readl (&ehci->caps->hc_capbase));
+	i = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
 	temp = scnprintf (next, size,
 		"bus %s, device %s (driver " DRIVER_VERSION ")\n"
 		"%s\n"
@@ -673,7 +673,7 @@
 		unsigned	count = 256/4;
 
 		pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
-		offset = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
+		offset = HCC_EXT_CAPS (ehci_readl(ehci, &ehci->caps->hcc_params));
 		while (offset && count--) {
 			pci_read_config_dword (pdev, offset, &cap);
 			switch (cap & 0xff) {
@@ -704,50 +704,50 @@
 #endif
 
 	// FIXME interpret both types of params
-	i = readl (&ehci->caps->hcs_params);
+	i = ehci_readl(ehci, &ehci->caps->hcs_params);
 	temp = scnprintf (next, size, "structural params 0x%08x\n", i);
 	size -= temp;
 	next += temp;
 
-	i = readl (&ehci->caps->hcc_params);
+	i = ehci_readl(ehci, &ehci->caps->hcc_params);
 	temp = scnprintf (next, size, "capability params 0x%08x\n", i);
 	size -= temp;
 	next += temp;
 
 	/* Operational Registers */
 	temp = dbg_status_buf (scratch, sizeof scratch, label,
-			readl (&ehci->regs->status));
+			ehci_readl(ehci, &ehci->regs->status));
 	temp = scnprintf (next, size, fmt, temp, scratch);
 	size -= temp;
 	next += temp;
 
 	temp = dbg_command_buf (scratch, sizeof scratch, label,
-			readl (&ehci->regs->command));
+			ehci_readl(ehci, &ehci->regs->command));
 	temp = scnprintf (next, size, fmt, temp, scratch);
 	size -= temp;
 	next += temp;
 
 	temp = dbg_intr_buf (scratch, sizeof scratch, label,
-			readl (&ehci->regs->intr_enable));
+			ehci_readl(ehci, &ehci->regs->intr_enable));
 	temp = scnprintf (next, size, fmt, temp, scratch);
 	size -= temp;
 	next += temp;
 
 	temp = scnprintf (next, size, "uframe %04x\n",
-			readl (&ehci->regs->frame_index));
+			ehci_readl(ehci, &ehci->regs->frame_index));
 	size -= temp;
 	next += temp;
 
 	for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) {
 		temp = dbg_port_buf (scratch, sizeof scratch, label, i,
-				readl (&ehci->regs->port_status [i - 1]));
+				ehci_readl(ehci, &ehci->regs->port_status [i - 1]));
 		temp = scnprintf (next, size, fmt, temp, scratch);
 		size -= temp;
 		next += temp;
 		if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) {
 			temp = scnprintf (next, size,
 					"    debug control %08x\n",
-					readl (&ehci->debug->control));
+					ehci_readl(ehci, &ehci->debug->control));
 			size -= temp;
 			next += temp;
 		}
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index 1a915e9..a524805 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -177,7 +177,7 @@
 	case FSL_USB2_PHY_NONE:
 		break;
 	}
-	writel(portsc, &ehci->regs->port_status[port_offset]);
+	ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
 }
 
 static void mpc83xx_usb_setup(struct usb_hcd *hcd)
@@ -214,7 +214,7 @@
 	}
 
 	/* put controller in host mode. */
-	writel(0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
+	ehci_writel(ehci, 0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
 	out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
 	out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
 	out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
@@ -238,12 +238,12 @@
 	/* EHCI registers start at offset 0x100 */
 	ehci->caps = hcd->regs + 0x100;
 	ehci->regs = hcd->regs + 0x100 +
-	    HC_LENGTH(readl(&ehci->caps->hc_capbase));
+	    HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
 	dbg_hcs_params(ehci, "reset");
 	dbg_hcc_params(ehci, "reset");
 
 	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = readl(&ehci->caps->hcs_params);
+	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
 	retval = ehci_halt(ehci);
 	if (retval)
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 025d333..185721d 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -157,12 +157,13 @@
  * before driver shutdown. But it also seems to be caused by bugs in cardbus
  * bridge shutdown:  shutting down the bridge before the devices using it.
  */
-static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec)
+static int handshake (struct ehci_hcd *ehci, void __iomem *ptr,
+		      u32 mask, u32 done, int usec)
 {
 	u32	result;
 
 	do {
-		result = readl (ptr);
+		result = ehci_readl(ehci, ptr);
 		if (result == ~(u32)0)		/* card removed */
 			return -ENODEV;
 		result &= mask;
@@ -177,18 +178,19 @@
 /* force HC to halt state from unknown (EHCI spec section 2.3) */
 static int ehci_halt (struct ehci_hcd *ehci)
 {
-	u32	temp = readl (&ehci->regs->status);
+	u32	temp = ehci_readl(ehci, &ehci->regs->status);
 
 	/* disable any irqs left enabled by previous code */
-	writel (0, &ehci->regs->intr_enable);
+	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 
 	if ((temp & STS_HALT) != 0)
 		return 0;
 
-	temp = readl (&ehci->regs->command);
+	temp = ehci_readl(ehci, &ehci->regs->command);
 	temp &= ~CMD_RUN;
-	writel (temp, &ehci->regs->command);
-	return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125);
+	ehci_writel(ehci, temp, &ehci->regs->command);
+	return handshake (ehci, &ehci->regs->status,
+			  STS_HALT, STS_HALT, 16 * 125);
 }
 
 /* put TDI/ARC silicon into EHCI mode */
@@ -198,23 +200,24 @@
 	u32		tmp;
 
 	reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68);
-	tmp = readl (reg_ptr);
+	tmp = ehci_readl(ehci, reg_ptr);
 	tmp |= 0x3;
-	writel (tmp, reg_ptr);
+	ehci_writel(ehci, tmp, reg_ptr);
 }
 
 /* reset a non-running (STS_HALT == 1) controller */
 static int ehci_reset (struct ehci_hcd *ehci)
 {
 	int	retval;
-	u32	command = readl (&ehci->regs->command);
+	u32	command = ehci_readl(ehci, &ehci->regs->command);
 
 	command |= CMD_RESET;
 	dbg_cmd (ehci, "reset", command);
-	writel (command, &ehci->regs->command);
+	ehci_writel(ehci, command, &ehci->regs->command);
 	ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 	ehci->next_statechange = jiffies;
-	retval = handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000);
+	retval = handshake (ehci, &ehci->regs->command,
+			    CMD_RESET, 0, 250 * 1000);
 
 	if (retval)
 		return retval;
@@ -236,21 +239,21 @@
 #endif
 
 	/* wait for any schedule enables/disables to take effect */
-	temp = readl (&ehci->regs->command) << 10;
+	temp = ehci_readl(ehci, &ehci->regs->command) << 10;
 	temp &= STS_ASS | STS_PSS;
-	if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+	if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
 				temp, 16 * 125) != 0) {
 		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 		return;
 	}
 
 	/* then disable anything that's still active */
-	temp = readl (&ehci->regs->command);
+	temp = ehci_readl(ehci, &ehci->regs->command);
 	temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
-	writel (temp, &ehci->regs->command);
+	ehci_writel(ehci, temp, &ehci->regs->command);
 
 	/* hardware can take 16 microframes to turn off ... */
-	if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+	if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
 				0, 16 * 125) != 0) {
 		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 		return;
@@ -277,11 +280,11 @@
 
 	/* lost IAA irqs wedge things badly; seen with a vt8235 */
 	if (ehci->reclaim) {
-		u32		status = readl (&ehci->regs->status);
+		u32		status = ehci_readl(ehci, &ehci->regs->status);
 		if (status & STS_IAA) {
 			ehci_vdbg (ehci, "lost IAA\n");
 			COUNT (ehci->stats.lost_iaa);
-			writel (STS_IAA, &ehci->regs->status);
+			ehci_writel(ehci, STS_IAA, &ehci->regs->status);
 			ehci->reclaim_ready = 1;
 		}
 	}
@@ -309,7 +312,7 @@
 	(void) ehci_halt (ehci);
 
 	/* make BIOS/etc use companion controller during reboot */
-	writel (0, &ehci->regs->configured_flag);
+	ehci_writel(ehci, 0, &ehci->regs->configured_flag);
 }
 
 static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
@@ -379,12 +382,13 @@
 		ehci_quiesce (ehci);
 
 	ehci_reset (ehci);
-	writel (0, &ehci->regs->intr_enable);
+	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 	spin_unlock_irq(&ehci->lock);
 
 	/* let companion controllers work when we aren't */
-	writel (0, &ehci->regs->configured_flag);
+	ehci_writel(ehci, 0, &ehci->regs->configured_flag);
 
+	remove_companion_file(ehci);
 	remove_debug_files (ehci);
 
 	/* root hub is shut down separately (first, when possible) */
@@ -402,7 +406,8 @@
 		ehci->stats.complete, ehci->stats.unlink);
 #endif
 
-	dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
+	dbg_status (ehci, "ehci_stop completed",
+		    ehci_readl(ehci, &ehci->regs->status));
 }
 
 /* one-time init, only for memory state */
@@ -428,7 +433,7 @@
 		return retval;
 
 	/* controllers may cache some of the periodic schedule ... */
-	hcc_params = readl(&ehci->caps->hcc_params);
+	hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
 	if (HCC_ISOC_CACHE(hcc_params))		// full frame cache
 		ehci->i_thresh = 8;
 	else					// N microframes cached
@@ -496,13 +501,16 @@
 	u32			temp;
 	u32			hcc_params;
 
+	hcd->uses_new_polling = 1;
+	hcd->poll_rh = 0;
+
 	/* EHCI spec section 4.1 */
 	if ((retval = ehci_reset(ehci)) != 0) {
 		ehci_mem_cleanup(ehci);
 		return retval;
 	}
-	writel(ehci->periodic_dma, &ehci->regs->frame_list);
-	writel((u32)ehci->async->qh_dma, &ehci->regs->async_next);
+	ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+	ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
 
 	/*
 	 * hcc_params controls whether ehci->regs->segment must (!!!)
@@ -516,9 +524,9 @@
 	 * Scsi_Host.highmem_io, and so forth.  It's readonly to all
 	 * host side drivers though.
 	 */
-	hcc_params = readl(&ehci->caps->hcc_params);
+	hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
 	if (HCC_64BIT_ADDR(hcc_params)) {
-		writel(0, &ehci->regs->segment);
+		ehci_writel(ehci, 0, &ehci->regs->segment);
 #if 0
 // this is deeply broken on almost all architectures
 		if (!dma_set_mask(hcd->self.controller, DMA_64BIT_MASK))
@@ -531,7 +539,7 @@
 	// root hub will detect new devices (why?); NEC doesn't
 	ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
 	ehci->command |= CMD_RUN;
-	writel (ehci->command, &ehci->regs->command);
+	ehci_writel(ehci, ehci->command, &ehci->regs->command);
 	dbg_cmd (ehci, "init", ehci->command);
 
 	/*
@@ -541,23 +549,25 @@
 	 * and there's no companion controller unless maybe for USB OTG.)
 	 */
 	hcd->state = HC_STATE_RUNNING;
-	writel (FLAG_CF, &ehci->regs->configured_flag);
-	readl (&ehci->regs->command);	/* unblock posted writes */
+	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
 
-	temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
+	temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
 	ehci_info (ehci,
 		"USB %x.%x started, EHCI %x.%02x, driver %s%s\n",
 		((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
 		temp >> 8, temp & 0xff, DRIVER_VERSION,
 		ignore_oc ? ", overcurrent ignored" : "");
 
-	writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
+	ehci_writel(ehci, INTR_MASK,
+		    &ehci->regs->intr_enable); /* Turn On Interrupts */
 
 	/* GRR this is run-once init(), being done every time the HC starts.
 	 * So long as they're part of class devices, we can't do it init()
 	 * since the class device isn't created that early.
 	 */
 	create_debug_files(ehci);
+	create_companion_file(ehci);
 
 	return 0;
 }
@@ -567,12 +577,12 @@
 static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	u32			status;
+	u32			status, pcd_status = 0;
 	int			bh;
 
 	spin_lock (&ehci->lock);
 
-	status = readl (&ehci->regs->status);
+	status = ehci_readl(ehci, &ehci->regs->status);
 
 	/* e.g. cardbus physical eject */
 	if (status == ~(u32) 0) {
@@ -587,8 +597,8 @@
 	}
 
 	/* clear (just) interrupts */
-	writel (status, &ehci->regs->status);
-	readl (&ehci->regs->command);	/* unblock posted write */
+	ehci_writel(ehci, status, &ehci->regs->status);
+	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted write */
 	bh = 0;
 
 #ifdef	EHCI_VERBOSE_DEBUG
@@ -617,13 +627,15 @@
 	/* remote wakeup [4.3.1] */
 	if (status & STS_PCD) {
 		unsigned	i = HCS_N_PORTS (ehci->hcs_params);
+		pcd_status = status;
 
 		/* resume root hub? */
-		if (!(readl(&ehci->regs->command) & CMD_RUN))
+		if (!(ehci_readl(ehci, &ehci->regs->command) & CMD_RUN))
 			usb_hcd_resume_root_hub(hcd);
 
 		while (i--) {
-			int pstatus = readl (&ehci->regs->port_status [i]);
+			int pstatus = ehci_readl(ehci,
+						 &ehci->regs->port_status [i]);
 
 			if (pstatus & PORT_OWNER)
 				continue;
@@ -643,14 +655,15 @@
 	/* PCI errors [4.15.2.4] */
 	if (unlikely ((status & STS_FATAL) != 0)) {
 		/* bogus "fatal" IRQs appear on some chips... why?  */
-		status = readl (&ehci->regs->status);
-		dbg_cmd (ehci, "fatal", readl (&ehci->regs->command));
+		status = ehci_readl(ehci, &ehci->regs->status);
+		dbg_cmd (ehci, "fatal", ehci_readl(ehci,
+						   &ehci->regs->command));
 		dbg_status (ehci, "fatal", status);
 		if (status & STS_HALT) {
 			ehci_err (ehci, "fatal error\n");
 dead:
 			ehci_reset (ehci);
-			writel (0, &ehci->regs->configured_flag);
+			ehci_writel(ehci, 0, &ehci->regs->configured_flag);
 			/* generic layer kills/unlinks all urbs, then
 			 * uses ehci_stop to clean up the rest
 			 */
@@ -661,6 +674,8 @@
 	if (bh)
 		ehci_work (ehci);
 	spin_unlock (&ehci->lock);
+	if (pcd_status & STS_PCD)
+		usb_hcd_poll_rh_status(hcd);
 	return IRQ_HANDLED;
 }
 
@@ -873,7 +888,8 @@
 static int ehci_get_frame (struct usb_hcd *hcd)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size;
+	return (ehci_readl(ehci, &ehci->regs->frame_index) >> 3) %
+		ehci->periodic_size;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -899,7 +915,13 @@
 #define	PLATFORM_DRIVER		ehci_hcd_au1xxx_driver
 #endif
 
-#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER)
+#ifdef CONFIG_PPC_PS3
+#include "ehci-ps3.c"
+#define	PS3_SYSTEM_BUS_DRIVER	ps3_ehci_sb_driver
+#endif
+
+#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
+    !defined(PS3_SYSTEM_BUS_DRIVER)
 #error "missing bus glue for ehci-hcd"
 #endif
 
@@ -924,6 +946,20 @@
 #ifdef PLATFORM_DRIVER
 		platform_driver_unregister(&PLATFORM_DRIVER);
 #endif
+		return retval;
+	}
+#endif
+
+#ifdef PS3_SYSTEM_BUS_DRIVER
+	retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+	if (retval < 0) {
+#ifdef PLATFORM_DRIVER
+		platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+#ifdef PCI_DRIVER
+		pci_unregister_driver(&PCI_DRIVER);
+#endif
+		return retval;
 	}
 #endif
 
@@ -939,6 +975,9 @@
 #ifdef PCI_DRIVER
 	pci_unregister_driver(&PCI_DRIVER);
 #endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+	ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+#endif
 }
 module_exit(ehci_hcd_cleanup);
 
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index bfe5f30..0d83c6d 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -47,7 +47,7 @@
 		ehci_quiesce (ehci);
 		hcd->state = HC_STATE_QUIESCING;
 	}
-	ehci->command = readl (&ehci->regs->command);
+	ehci->command = ehci_readl(ehci, &ehci->regs->command);
 	if (ehci->reclaim)
 		ehci->reclaim_ready = 1;
 	ehci_work(ehci);
@@ -60,7 +60,7 @@
 	ehci->bus_suspended = 0;
 	while (port--) {
 		u32 __iomem	*reg = &ehci->regs->port_status [port];
-		u32		t1 = readl (reg) & ~PORT_RWC_BITS;
+		u32		t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
 		u32		t2 = t1;
 
 		/* keep track of which ports we suspend */
@@ -79,7 +79,7 @@
 		if (t1 != t2) {
 			ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
 				port + 1, t1, t2);
-			writel (t2, reg);
+			ehci_writel(ehci, t2, reg);
 		}
 	}
 
@@ -92,8 +92,8 @@
 	mask = INTR_MASK;
 	if (!device_may_wakeup(&hcd->self.root_hub->dev))
 		mask &= ~STS_PCD;
-	writel(mask, &ehci->regs->intr_enable);
-	readl(&ehci->regs->intr_enable);
+	ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+	ehci_readl(ehci, &ehci->regs->intr_enable);
 
 	ehci->next_statechange = jiffies + msecs_to_jiffies(10);
 	spin_unlock_irq (&ehci->lock);
@@ -118,26 +118,26 @@
 	 * the last user of the controller, not reset/pm hardware keeping
 	 * state we gave to it.
 	 */
-	temp = readl(&ehci->regs->intr_enable);
+	temp = ehci_readl(ehci, &ehci->regs->intr_enable);
 	ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss");
 
 	/* at least some APM implementations will try to deliver
 	 * IRQs right away, so delay them until we're ready.
 	 */
-	writel(0, &ehci->regs->intr_enable);
+	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 
 	/* re-init operational registers */
-	writel(0, &ehci->regs->segment);
-	writel(ehci->periodic_dma, &ehci->regs->frame_list);
-	writel((u32) ehci->async->qh_dma, &ehci->regs->async_next);
+	ehci_writel(ehci, 0, &ehci->regs->segment);
+	ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+	ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next);
 
 	/* restore CMD_RUN, framelist size, and irq threshold */
-	writel (ehci->command, &ehci->regs->command);
+	ehci_writel(ehci, ehci->command, &ehci->regs->command);
 
 	/* manually resume the ports we suspended during bus_suspend() */
 	i = HCS_N_PORTS (ehci->hcs_params);
 	while (i--) {
-		temp = readl (&ehci->regs->port_status [i]);
+		temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
 		temp &= ~(PORT_RWC_BITS
 			| PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
 		if (test_bit(i, &ehci->bus_suspended) &&
@@ -145,20 +145,20 @@
 			ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
 			temp |= PORT_RESUME;
 		}
-		writel (temp, &ehci->regs->port_status [i]);
+		ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
 	}
 	i = HCS_N_PORTS (ehci->hcs_params);
 	mdelay (20);
 	while (i--) {
-		temp = readl (&ehci->regs->port_status [i]);
+		temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
 		if (test_bit(i, &ehci->bus_suspended) &&
 				(temp & PORT_SUSPEND)) {
 			temp &= ~(PORT_RWC_BITS | PORT_RESUME);
-			writel (temp, &ehci->regs->port_status [i]);
+			ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
 			ehci_vdbg (ehci, "resumed port %d\n", i + 1);
 		}
 	}
-	(void) readl (&ehci->regs->command);
+	(void) ehci_readl(ehci, &ehci->regs->command);
 
 	/* maybe re-activate the schedule(s) */
 	temp = 0;
@@ -168,14 +168,14 @@
 		temp |= CMD_PSE;
 	if (temp) {
 		ehci->command |= temp;
-		writel (ehci->command, &ehci->regs->command);
+		ehci_writel(ehci, ehci->command, &ehci->regs->command);
 	}
 
 	ehci->next_statechange = jiffies + msecs_to_jiffies(5);
 	hcd->state = HC_STATE_RUNNING;
 
 	/* Now we can safely re-enable irqs */
-	writel(INTR_MASK, &ehci->regs->intr_enable);
+	ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
 
 	spin_unlock_irq (&ehci->lock);
 	return 0;
@@ -190,9 +190,107 @@
 
 /*-------------------------------------------------------------------------*/
 
+/* Display the ports dedicated to the companion controller */
+static ssize_t show_companion(struct class_device *class_dev, char *buf)
+{
+	struct ehci_hcd		*ehci;
+	int			nports, index, n;
+	int			count = PAGE_SIZE;
+	char			*ptr = buf;
+
+	ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
+	nports = HCS_N_PORTS(ehci->hcs_params);
+
+	for (index = 0; index < nports; ++index) {
+		if (test_bit(index, &ehci->companion_ports)) {
+			n = scnprintf(ptr, count, "%d\n", index + 1);
+			ptr += n;
+			count -= n;
+		}
+	}
+	return ptr - buf;
+}
+
+/*
+ * Dedicate or undedicate a port to the companion controller.
+ * Syntax is "[-]portnum", where a leading '-' sign means
+ * return control of the port to the EHCI controller.
+ */
+static ssize_t store_companion(struct class_device *class_dev,
+		const char *buf, size_t count)
+{
+	struct ehci_hcd		*ehci;
+	int			portnum, new_owner, try;
+	u32 __iomem		*status_reg;
+	u32			port_status;
+
+	ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
+	new_owner = PORT_OWNER;		/* Owned by companion */
+	if (sscanf(buf, "%d", &portnum) != 1)
+		return -EINVAL;
+	if (portnum < 0) {
+		portnum = - portnum;
+		new_owner = 0;		/* Owned by EHCI */
+	}
+	if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
+		return -ENOENT;
+	status_reg = &ehci->regs->port_status[--portnum];
+	if (new_owner)
+		set_bit(portnum, &ehci->companion_ports);
+	else
+		clear_bit(portnum, &ehci->companion_ports);
+
+	/*
+	 * The controller won't set the OWNER bit if the port is
+	 * enabled, so this loop will sometimes require at least two
+	 * iterations: one to disable the port and one to set OWNER.
+	 */
+
+	for (try = 4; try > 0; --try) {
+		spin_lock_irq(&ehci->lock);
+		port_status = ehci_readl(ehci, status_reg);
+		if ((port_status & PORT_OWNER) == new_owner
+				|| (port_status & (PORT_OWNER | PORT_CONNECT))
+					== 0)
+			try = 0;
+		else {
+			port_status ^= PORT_OWNER;
+			port_status &= ~(PORT_PE | PORT_RWC_BITS);
+			ehci_writel(ehci, port_status, status_reg);
+		}
+		spin_unlock_irq(&ehci->lock);
+		if (try > 1)
+			msleep(5);
+	}
+	return count;
+}
+static CLASS_DEVICE_ATTR(companion, 0644, show_companion, store_companion);
+
+static inline void create_companion_file(struct ehci_hcd *ehci)
+{
+	int	i;
+
+	/* with integrated TT there is no companion! */
+	if (!ehci_is_TDI(ehci))
+		i = class_device_create_file(ehci_to_hcd(ehci)->self.class_dev,
+				&class_device_attr_companion);
+}
+
+static inline void remove_companion_file(struct ehci_hcd *ehci)
+{
+	/* with integrated TT there is no companion! */
+	if (!ehci_is_TDI(ehci))
+		class_device_remove_file(ehci_to_hcd(ehci)->self.class_dev,
+				&class_device_attr_companion);
+}
+
+
+/*-------------------------------------------------------------------------*/
+
 static int check_reset_complete (
 	struct ehci_hcd	*ehci,
 	int		index,
+	u32 __iomem	*status_reg,
 	int		port_status
 ) {
 	if (!(port_status & PORT_CONNECT)) {
@@ -217,7 +315,7 @@
 		// what happens if HCS_N_CC(params) == 0 ?
 		port_status |= PORT_OWNER;
 		port_status &= ~PORT_RWC_BITS;
-		writel (port_status, &ehci->regs->port_status [index]);
+		ehci_writel(ehci, port_status, status_reg);
 
 	} else
 		ehci_dbg (ehci, "port %d high speed\n", index + 1);
@@ -268,22 +366,21 @@
 	/* port N changes (bit N)? */
 	spin_lock_irqsave (&ehci->lock, flags);
 	for (i = 0; i < ports; i++) {
-		temp = readl (&ehci->regs->port_status [i]);
-		if (temp & PORT_OWNER) {
-			/* don't report this in GetPortStatus */
-			if (temp & PORT_CSC) {
-				temp &= ~PORT_RWC_BITS;
-				temp |= PORT_CSC;
-				writel (temp, &ehci->regs->port_status [i]);
-			}
-			continue;
-		}
+		temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
+
+		/*
+		 * Return status information even for ports with OWNER set.
+		 * Otherwise khubd wouldn't see the disconnect event when a
+		 * high-speed device is switched over to the companion
+		 * controller by the user.
+		 */
+
 		if (!(temp & PORT_CONNECT))
 			ehci->reset_done [i] = 0;
 		if ((temp & mask) != 0
 				|| ((temp & PORT_RESUME) != 0
-					&& time_after (jiffies,
-						ehci->reset_done [i]))) {
+					&& time_after_eq(jiffies,
+						ehci->reset_done[i]))) {
 			if (i < 7)
 			    buf [0] |= 1 << (i + 1);
 			else
@@ -345,6 +442,7 @@
 ) {
 	struct ehci_hcd	*ehci = hcd_to_ehci (hcd);
 	int		ports = HCS_N_PORTS (ehci->hcs_params);
+	u32 __iomem	*status_reg = &ehci->regs->port_status[wIndex - 1];
 	u32		temp, status;
 	unsigned long	flags;
 	int		retval = 0;
@@ -373,18 +471,22 @@
 		if (!wIndex || wIndex > ports)
 			goto error;
 		wIndex--;
-		temp = readl (&ehci->regs->port_status [wIndex]);
-		if (temp & PORT_OWNER)
-			break;
+		temp = ehci_readl(ehci, status_reg);
+
+		/*
+		 * Even if OWNER is set, so the port is owned by the
+		 * companion controller, khubd needs to be able to clear
+		 * the port-change status bits (especially
+		 * USB_PORT_FEAT_C_CONNECTION).
+		 */
 
 		switch (wValue) {
 		case USB_PORT_FEAT_ENABLE:
-			writel (temp & ~PORT_PE,
-				&ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, temp & ~PORT_PE, status_reg);
 			break;
 		case USB_PORT_FEAT_C_ENABLE:
-			writel((temp & ~PORT_RWC_BITS) | PORT_PEC,
-				&ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC,
+					status_reg);
 			break;
 		case USB_PORT_FEAT_SUSPEND:
 			if (temp & PORT_RESET)
@@ -396,8 +498,8 @@
 					goto error;
 				/* resume signaling for 20 msec */
 				temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
-				writel (temp | PORT_RESUME,
-					&ehci->regs->port_status [wIndex]);
+				ehci_writel(ehci, temp | PORT_RESUME,
+						status_reg);
 				ehci->reset_done [wIndex] = jiffies
 						+ msecs_to_jiffies (20);
 			}
@@ -407,16 +509,17 @@
 			break;
 		case USB_PORT_FEAT_POWER:
 			if (HCS_PPC (ehci->hcs_params))
-				writel (temp & ~(PORT_RWC_BITS | PORT_POWER),
-					&ehci->regs->port_status [wIndex]);
+				ehci_writel(ehci,
+					  temp & ~(PORT_RWC_BITS | PORT_POWER),
+					  status_reg);
 			break;
 		case USB_PORT_FEAT_C_CONNECTION:
-			writel((temp & ~PORT_RWC_BITS) | PORT_CSC,
-				&ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC,
+					status_reg);
 			break;
 		case USB_PORT_FEAT_C_OVER_CURRENT:
-			writel((temp & ~PORT_RWC_BITS) | PORT_OCC,
-				&ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC,
+					status_reg);
 			break;
 		case USB_PORT_FEAT_C_RESET:
 			/* GetPortStatus clears reset */
@@ -424,7 +527,7 @@
 		default:
 			goto error;
 		}
-		readl (&ehci->regs->command);	/* unblock posted write */
+		ehci_readl(ehci, &ehci->regs->command);	/* unblock posted write */
 		break;
 	case GetHubDescriptor:
 		ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)
@@ -440,7 +543,7 @@
 			goto error;
 		wIndex--;
 		status = 0;
-		temp = readl (&ehci->regs->port_status [wIndex]);
+		temp = ehci_readl(ehci, status_reg);
 
 		// wPortChange bits
 		if (temp & PORT_CSC)
@@ -451,42 +554,55 @@
 			status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
 
 		/* whoever resumes must GetPortStatus to complete it!! */
-		if ((temp & PORT_RESUME)
-				&& time_after (jiffies,
-					ehci->reset_done [wIndex])) {
-			status |= 1 << USB_PORT_FEAT_C_SUSPEND;
-			ehci->reset_done [wIndex] = 0;
+		if (temp & PORT_RESUME) {
 
-			/* stop resume signaling */
-			temp = readl (&ehci->regs->port_status [wIndex]);
-			writel (temp & ~(PORT_RWC_BITS | PORT_RESUME),
-				&ehci->regs->port_status [wIndex]);
-			retval = handshake (
-					&ehci->regs->port_status [wIndex],
-					PORT_RESUME, 0, 2000 /* 2msec */);
-			if (retval != 0) {
-				ehci_err (ehci, "port %d resume error %d\n",
-					wIndex + 1, retval);
-				goto error;
+			/* Remote Wakeup received? */
+			if (!ehci->reset_done[wIndex]) {
+				/* resume signaling for 20 msec */
+				ehci->reset_done[wIndex] = jiffies
+						+ msecs_to_jiffies(20);
+				/* check the port again */
+				mod_timer(&ehci_to_hcd(ehci)->rh_timer,
+						ehci->reset_done[wIndex]);
 			}
-			temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
+
+			/* resume completed? */
+			else if (time_after_eq(jiffies,
+					ehci->reset_done[wIndex])) {
+				status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+				ehci->reset_done[wIndex] = 0;
+
+				/* stop resume signaling */
+				temp = ehci_readl(ehci, status_reg);
+				ehci_writel(ehci,
+					temp & ~(PORT_RWC_BITS | PORT_RESUME),
+					status_reg);
+				retval = handshake(ehci, status_reg,
+					   PORT_RESUME, 0, 2000 /* 2msec */);
+				if (retval != 0) {
+					ehci_err(ehci,
+						"port %d resume error %d\n",
+						wIndex + 1, retval);
+					goto error;
+				}
+				temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
+			}
 		}
 
 		/* whoever resets must GetPortStatus to complete it!! */
 		if ((temp & PORT_RESET)
-				&& time_after (jiffies,
-					ehci->reset_done [wIndex])) {
+				&& time_after_eq(jiffies,
+					ehci->reset_done[wIndex])) {
 			status |= 1 << USB_PORT_FEAT_C_RESET;
 			ehci->reset_done [wIndex] = 0;
 
 			/* force reset to complete */
-			writel (temp & ~(PORT_RWC_BITS | PORT_RESET),
-					&ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET),
+					status_reg);
 			/* REVISIT:  some hardware needs 550+ usec to clear
 			 * this bit; seems too long to spin routinely...
 			 */
-			retval = handshake (
-					&ehci->regs->port_status [wIndex],
+			retval = handshake(ehci, status_reg,
 					PORT_RESET, 0, 750);
 			if (retval != 0) {
 				ehci_err (ehci, "port %d reset error %d\n",
@@ -495,29 +611,42 @@
 			}
 
 			/* see what we found out */
-			temp = check_reset_complete (ehci, wIndex,
-				readl (&ehci->regs->port_status [wIndex]));
+			temp = check_reset_complete (ehci, wIndex, status_reg,
+					ehci_readl(ehci, status_reg));
 		}
 
-		// don't show wPortStatus if it's owned by a companion hc
-		if (!(temp & PORT_OWNER)) {
-			if (temp & PORT_CONNECT) {
-				status |= 1 << USB_PORT_FEAT_CONNECTION;
-				// status may be from integrated TT
-				status |= ehci_port_speed(ehci, temp);
-			}
-			if (temp & PORT_PE)
-				status |= 1 << USB_PORT_FEAT_ENABLE;
-			if (temp & (PORT_SUSPEND|PORT_RESUME))
-				status |= 1 << USB_PORT_FEAT_SUSPEND;
-			if (temp & PORT_OC)
-				status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
-			if (temp & PORT_RESET)
-				status |= 1 << USB_PORT_FEAT_RESET;
-			if (temp & PORT_POWER)
-				status |= 1 << USB_PORT_FEAT_POWER;
+		/* transfer dedicated ports to the companion hc */
+		if ((temp & PORT_CONNECT) &&
+				test_bit(wIndex, &ehci->companion_ports)) {
+			temp &= ~PORT_RWC_BITS;
+			temp |= PORT_OWNER;
+			ehci_writel(ehci, temp, status_reg);
+			ehci_dbg(ehci, "port %d --> companion\n", wIndex + 1);
+			temp = ehci_readl(ehci, status_reg);
 		}
 
+		/*
+		 * Even if OWNER is set, there's no harm letting khubd
+		 * see the wPortStatus values (they should all be 0 except
+		 * for PORT_POWER anyway).
+		 */
+
+		if (temp & PORT_CONNECT) {
+			status |= 1 << USB_PORT_FEAT_CONNECTION;
+			// status may be from integrated TT
+			status |= ehci_port_speed(ehci, temp);
+		}
+		if (temp & PORT_PE)
+			status |= 1 << USB_PORT_FEAT_ENABLE;
+		if (temp & (PORT_SUSPEND|PORT_RESUME))
+			status |= 1 << USB_PORT_FEAT_SUSPEND;
+		if (temp & PORT_OC)
+			status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
+		if (temp & PORT_RESET)
+			status |= 1 << USB_PORT_FEAT_RESET;
+		if (temp & PORT_POWER)
+			status |= 1 << USB_PORT_FEAT_POWER;
+
 #ifndef	EHCI_VERBOSE_DEBUG
 	if (status & ~0xffff)	/* only if wPortChange is interesting */
 #endif
@@ -541,7 +670,7 @@
 		if (!wIndex || wIndex > ports)
 			goto error;
 		wIndex--;
-		temp = readl (&ehci->regs->port_status [wIndex]);
+		temp = ehci_readl(ehci, status_reg);
 		if (temp & PORT_OWNER)
 			break;
 
@@ -555,13 +684,12 @@
 				goto error;
 			if (device_may_wakeup(&hcd->self.root_hub->dev))
 				temp |= PORT_WAKE_BITS;
-			writel (temp | PORT_SUSPEND,
-				&ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
 			break;
 		case USB_PORT_FEAT_POWER:
 			if (HCS_PPC (ehci->hcs_params))
-				writel (temp | PORT_POWER,
-					&ehci->regs->port_status [wIndex]);
+				ehci_writel(ehci, temp | PORT_POWER,
+						status_reg);
 			break;
 		case USB_PORT_FEAT_RESET:
 			if (temp & PORT_RESUME)
@@ -589,7 +717,7 @@
 				ehci->reset_done [wIndex] = jiffies
 						+ msecs_to_jiffies (50);
 			}
-			writel (temp, &ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, temp, status_reg);
 			break;
 
 		/* For downstream facing ports (these):  one hub port is put
@@ -604,13 +732,13 @@
 			ehci_quiesce(ehci);
 			ehci_halt(ehci);
 			temp |= selector << 16;
-			writel (temp, &ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, temp, status_reg);
 			break;
 
 		default:
 			goto error;
 		}
-		readl (&ehci->regs->command);	/* unblock posted writes */
+		ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
 		break;
 
 	default:
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 4bc7970..12edc72 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -38,7 +38,7 @@
 		if ((temp & (3 << 13)) == (1 << 13)) {
 			temp &= 0x1fff;
 			ehci->debug = ehci_to_hcd(ehci)->regs + temp;
-			temp = readl(&ehci->debug->control);
+			temp = ehci_readl(ehci, &ehci->debug->control);
 			ehci_info(ehci, "debug port %d%s\n",
 				HCS_DEBUG_PORT(ehci->hcs_params),
 				(temp & DBGP_ENABLED)
@@ -71,8 +71,24 @@
 	u32			temp;
 	int			retval;
 
+	switch (pdev->vendor) {
+	case PCI_VENDOR_ID_TOSHIBA_2:
+		/* celleb's companion chip */
+		if (pdev->device == 0x01b5) {
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+			ehci->big_endian_mmio = 1;
+#else
+			ehci_warn(ehci,
+				  "unsupported big endian Toshiba quirk\n");
+#endif
+		}
+		break;
+	}
+
 	ehci->caps = hcd->regs;
-	ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+	ehci->regs = hcd->regs +
+		HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+
 	dbg_hcs_params(ehci, "reset");
 	dbg_hcc_params(ehci, "reset");
 
@@ -101,7 +117,7 @@
 	}
 
 	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = readl(&ehci->caps->hcs_params);
+	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
 	retval = ehci_halt(ehci);
 	if (retval)
@@ -235,8 +251,8 @@
 		rc = -EINVAL;
 		goto bail;
 	}
-	writel (0, &ehci->regs->intr_enable);
-	(void)readl(&ehci->regs->intr_enable);
+	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+	(void)ehci_readl(ehci, &ehci->regs->intr_enable);
 
 	/* make sure snapshot being resumed re-enumerates everything */
 	if (message.event == PM_EVENT_PRETHAW) {
@@ -270,13 +286,13 @@
 	/* If CF is still set, we maintained PCI Vaux power.
 	 * Just undo the effect of ehci_pci_suspend().
 	 */
-	if (readl(&ehci->regs->configured_flag) == FLAG_CF) {
+	if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
 		int	mask = INTR_MASK;
 
 		if (!device_may_wakeup(&hcd->self.root_hub->dev))
 			mask &= ~STS_PCD;
-		writel(mask, &ehci->regs->intr_enable);
-		readl(&ehci->regs->intr_enable);
+		ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+		ehci_readl(ehci, &ehci->regs->intr_enable);
 		return 0;
 	}
 
@@ -300,9 +316,9 @@
 	/* here we "know" root ports should always stay powered */
 	ehci_port_power(ehci, 1);
 
-	writel(ehci->command, &ehci->regs->command);
-	writel(FLAG_CF, &ehci->regs->configured_flag);
-	readl(&ehci->regs->command);	/* unblock posted writes */
+	ehci_writel(ehci, ehci->command, &ehci->regs->command);
+	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
 
 	hcd->state = HC_STATE_SUSPENDED;
 	return 0;
diff --git a/drivers/usb/host/ehci-ps3.c b/drivers/usb/host/ehci-ps3.c
new file mode 100644
index 0000000..371f194
--- /dev/null
+++ b/drivers/usb/host/ehci-ps3.c
@@ -0,0 +1,193 @@
+/*
+ *  PS3 EHCI Host Controller driver
+ *
+ *  Copyright (C) 2006 Sony Computer Entertainment Inc.
+ *  Copyright 2006 Sony Corp.
+ *
+ *  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; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <asm/ps3.h>
+
+static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
+{
+	int result;
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+	ehci->big_endian_mmio = 1;
+
+	ehci->caps = hcd->regs;
+	ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
+		&ehci->caps->hc_capbase));
+
+	dbg_hcs_params(ehci, "reset");
+	dbg_hcc_params(ehci, "reset");
+
+	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+	result = ehci_halt(ehci);
+
+	if (result)
+		return result;
+
+	result = ehci_init(hcd);
+
+	if (result)
+		return result;
+
+	ehci_port_power(ehci, 0);
+
+	return result;
+}
+
+static const struct hc_driver ps3_ehci_hc_driver = {
+	.description		= hcd_name,
+	.product_desc		= "PS3 EHCI Host Controller",
+	.hcd_priv_size		= sizeof(struct ehci_hcd),
+	.irq			= ehci_irq,
+	.flags			= HCD_MEMORY | HCD_USB2,
+	.reset			= ps3_ehci_hc_reset,
+	.start			= ehci_run,
+	.stop			= ehci_stop,
+	.shutdown		= ehci_shutdown,
+	.urb_enqueue		= ehci_urb_enqueue,
+	.urb_dequeue		= ehci_urb_dequeue,
+	.endpoint_disable	= ehci_endpoint_disable,
+	.get_frame_number	= ehci_get_frame,
+	.hub_status_data	= ehci_hub_status_data,
+	.hub_control		= ehci_hub_control,
+#if defined(CONFIG_PM)
+	.bus_suspend		= ehci_bus_suspend,
+	.bus_resume		= ehci_bus_resume,
+#endif
+};
+
+#if !defined(DEBUG)
+#undef dev_dbg
+static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+	const struct device *_dev, const char *fmt, ...) {return 0;}
+#endif
+
+
+static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
+{
+	int result;
+	struct usb_hcd *hcd;
+	unsigned int virq;
+	static u64 dummy_mask = DMA_32BIT_MASK;
+
+	if (usb_disabled()) {
+		result = -ENODEV;
+		goto fail_start;
+	}
+
+	result = ps3_mmio_region_create(dev->m_region);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
+			__func__, __LINE__);
+		result = -EPERM;
+		goto fail_mmio;
+	}
+
+	dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
+		__LINE__, dev->m_region->lpar_addr);
+
+	result = ps3_alloc_io_irq(dev->interrupt_id, &virq);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
+			__func__, __LINE__, virq);
+		result = -EPERM;
+		goto fail_irq;
+	}
+
+	dev->core.power.power_state = PMSG_ON;
+	dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
+
+	hcd = usb_create_hcd(&ps3_ehci_hc_driver, &dev->core, dev->core.bus_id);
+
+	if (!hcd) {
+		dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
+			__LINE__);
+		result = -ENOMEM;
+		goto fail_create_hcd;
+	}
+
+	hcd->rsrc_start = dev->m_region->lpar_addr;
+	hcd->rsrc_len = dev->m_region->len;
+	hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
+
+	if (!hcd->regs) {
+		dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
+			__LINE__);
+		result = -EPERM;
+		goto fail_ioremap;
+	}
+
+	dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
+		(unsigned long)hcd->rsrc_start);
+	dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len   %lxh\n", __func__, __LINE__,
+		(unsigned long)hcd->rsrc_len);
+	dev_dbg(&dev->core, "%s:%d: hcd->regs       %lxh\n", __func__, __LINE__,
+		(unsigned long)hcd->regs);
+	dev_dbg(&dev->core, "%s:%d: virq            %lu\n", __func__, __LINE__,
+		(unsigned long)virq);
+
+	ps3_system_bus_set_driver_data(dev, hcd);
+
+	result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
+			__func__, __LINE__, result);
+		goto fail_add_hcd;
+	}
+
+	return result;
+
+fail_add_hcd:
+	iounmap(hcd->regs);
+fail_ioremap:
+	usb_put_hcd(hcd);
+fail_create_hcd:
+	ps3_free_io_irq(virq);
+fail_irq:
+	ps3_free_mmio_region(dev->m_region);
+fail_mmio:
+fail_start:
+	return result;
+}
+
+static int ps3_ehci_sb_remove(struct ps3_system_bus_device *dev)
+{
+	struct usb_hcd *hcd =
+		(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+
+	usb_put_hcd(hcd);
+	ps3_system_bus_set_driver_data(dev, NULL);
+
+	return 0;
+}
+
+MODULE_ALIAS("ps3-ehci");
+
+static struct ps3_system_bus_driver ps3_ehci_sb_driver = {
+	.match_id = PS3_MATCH_ID_EHCI,
+	.core = {
+		.name = "ps3-ehci-driver",
+	},
+	.probe = ps3_ehci_sb_probe,
+	.remove = ps3_ehci_sb_remove,
+};
diff --git a/drivers/usb/host/ehci-q.c b/drivers/usb/host/ehci-q.c
index 62e46dc..e7fbbd0 100644
--- a/drivers/usb/host/ehci-q.c
+++ b/drivers/usb/host/ehci-q.c
@@ -789,13 +789,14 @@
 	head = ehci->async;
 	timer_action_done (ehci, TIMER_ASYNC_OFF);
 	if (!head->qh_next.qh) {
-		u32	cmd = readl (&ehci->regs->command);
+		u32	cmd = ehci_readl(ehci, &ehci->regs->command);
 
 		if (!(cmd & CMD_ASE)) {
 			/* in case a clear of CMD_ASE didn't take yet */
-			(void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
+			(void)handshake(ehci, &ehci->regs->status,
+					STS_ASS, 0, 150);
 			cmd |= CMD_ASE | CMD_RUN;
-			writel (cmd, &ehci->regs->command);
+			ehci_writel(ehci, cmd, &ehci->regs->command);
 			ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
 			/* posted write need not be known to HC yet ... */
 		}
@@ -1007,7 +1008,7 @@
 
 static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
-	int		cmd = readl (&ehci->regs->command);
+	int		cmd = ehci_readl(ehci, &ehci->regs->command);
 	struct ehci_qh	*prev;
 
 #ifdef DEBUG
@@ -1025,7 +1026,8 @@
 		if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
 				&& !ehci->reclaim) {
 			/* ... and CMD_IAAD clear */
-			writel (cmd & ~CMD_ASE, &ehci->regs->command);
+			ehci_writel(ehci, cmd & ~CMD_ASE,
+				    &ehci->regs->command);
 			wmb ();
 			// handshake later, if we need to
 			timer_action_done (ehci, TIMER_ASYNC_OFF);
@@ -1054,8 +1056,8 @@
 
 	ehci->reclaim_ready = 0;
 	cmd |= CMD_IAAD;
-	writel (cmd, &ehci->regs->command);
-	(void) readl (&ehci->regs->command);
+	ehci_writel(ehci, cmd, &ehci->regs->command);
+	(void)ehci_readl(ehci, &ehci->regs->command);
 	timer_action (ehci, TIMER_IAA_WATCHDOG);
 }
 
diff --git a/drivers/usb/host/ehci-sched.c b/drivers/usb/host/ehci-sched.c
index 65c402a..7b5ae71 100644
--- a/drivers/usb/host/ehci-sched.c
+++ b/drivers/usb/host/ehci-sched.c
@@ -433,20 +433,20 @@
 	/* did clearing PSE did take effect yet?
 	 * takes effect only at frame boundaries...
 	 */
-	status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125);
+	status = handshake(ehci, &ehci->regs->status, STS_PSS, 0, 9 * 125);
 	if (status != 0) {
 		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 		return status;
 	}
 
-	cmd = readl (&ehci->regs->command) | CMD_PSE;
-	writel (cmd, &ehci->regs->command);
+	cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
+	ehci_writel(ehci, cmd, &ehci->regs->command);
 	/* posted write ... PSS happens later */
 	ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
 
 	/* make sure ehci_work scans these */
-	ehci->next_uframe = readl (&ehci->regs->frame_index)
-				% (ehci->periodic_size << 3);
+	ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
+		% (ehci->periodic_size << 3);
 	return 0;
 }
 
@@ -458,14 +458,14 @@
 	/* did setting PSE not take effect yet?
 	 * takes effect only at frame boundaries...
 	 */
-	status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
+	status = handshake(ehci, &ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
 	if (status != 0) {
 		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 		return status;
 	}
 
-	cmd = readl (&ehci->regs->command) & ~CMD_PSE;
-	writel (cmd, &ehci->regs->command);
+	cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
+	ehci_writel(ehci, cmd, &ehci->regs->command);
 	/* posted write ... */
 
 	ehci->next_uframe = -1;
@@ -1336,7 +1336,7 @@
 		goto fail;
 	}
 
-	now = readl (&ehci->regs->frame_index) % mod;
+	now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
 
 	/* when's the last uframe this urb could start? */
 	max = now + mod;
@@ -2088,7 +2088,7 @@
 	 */
 	now_uframe = ehci->next_uframe;
 	if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
-		clock = readl (&ehci->regs->frame_index);
+		clock = ehci_readl(ehci, &ehci->regs->frame_index);
 	else
 		clock = now_uframe + mod - 1;
 	clock %= mod;
@@ -2213,7 +2213,7 @@
 			if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
 				break;
 			ehci->next_uframe = now_uframe;
-			now = readl (&ehci->regs->frame_index) % mod;
+			now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
 			if (now_uframe == now)
 				break;
 
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 74dbc6c..ec0da03 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -74,7 +74,11 @@
 
 	/* per root hub port */
 	unsigned long		reset_done [EHCI_MAX_ROOT_PORTS];
-	unsigned long		bus_suspended;
+	/* bit vectors (one bit per port) */
+	unsigned long		bus_suspended;		/* which ports were
+			already suspended at the start of a bus suspend */
+	unsigned long		companion_ports;	/* which ports are
+			dedicated to the companion controller */
 
 	/* per-HC memory pools (could be per-bus, but ...) */
 	struct dma_pool		*qh_pool;	/* qh per active urb */
@@ -92,6 +96,7 @@
 	unsigned		is_tdi_rh_tt:1;	/* TDI roothub with TT */
 	unsigned		no_selective_suspend:1;
 	unsigned		has_fsl_port_bug:1; /* FreeScale */
+	unsigned		big_endian_mmio:1;
 
 	u8			sbrn;		/* packed release number */
 
@@ -651,6 +656,45 @@
 #define	ehci_has_fsl_portno_bug(e)		(0)
 #endif
 
+/*
+ * While most USB host controllers implement their registers in
+ * little-endian format, a minority (celleb companion chip) implement
+ * them in big endian format.
+ *
+ * This attempts to support either format at compile time without a
+ * runtime penalty, or both formats with the additional overhead
+ * of checking a flag bit.
+ */
+
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+#define ehci_big_endian_mmio(e)		((e)->big_endian_mmio)
+#else
+#define ehci_big_endian_mmio(e)		0
+#endif
+
+static inline unsigned int ehci_readl (const struct ehci_hcd *ehci,
+				       __u32 __iomem * regs)
+{
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+	return ehci_big_endian_mmio(ehci) ?
+		readl_be((__force u32 *)regs) :
+		readl((__force u32 *)regs);
+#else
+	return readl((__force u32 *)regs);
+#endif
+}
+
+static inline void ehci_writel (const struct ehci_hcd *ehci,
+				const unsigned int val, __u32 __iomem *regs)
+{
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+	ehci_big_endian_mmio(ehci) ?
+		writel_be(val, (__force u32 *)regs) :
+		writel(val, (__force u32 *)regs);
+#else
+	writel(val, (__force u32 *)regs);
+#endif
+}
 
 /*-------------------------------------------------------------------------*/
 
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index cc40551..9303464 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -170,7 +170,6 @@
 	at91_stop_hc(pdev);
 	iounmap(hcd->regs);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-	disable_irq_wake(hcd->irq);
 
 	clk_put(fclk);
 	clk_put(iclk);
@@ -271,8 +270,6 @@
 
 	if (device_may_wakeup(&pdev->dev))
 		enable_irq_wake(hcd->irq);
-	else
-		disable_irq_wake(hcd->irq);
 
 	/*
 	 * The integrated transceivers seem unable to notice disconnect,
@@ -293,6 +290,11 @@
 
 static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
 {
+	struct usb_hcd	*hcd = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(&pdev->dev))
+		disable_irq_wake(hcd->irq);
+
 	if (!clocked) {
 		clk_enable(iclk);
 		clk_enable(fclk);
@@ -320,18 +322,3 @@
 	},
 };
 
-static int __init ohci_hcd_at91_init (void)
-{
-	if (usb_disabled())
-		return -ENODEV;
-
-	return platform_driver_register(&ohci_hcd_at91_driver);
-}
-
-static void __exit ohci_hcd_at91_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_at91_driver);
-}
-
-module_init (ohci_hcd_at91_init);
-module_exit (ohci_hcd_at91_cleanup);
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index e70b243..663a060 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -345,19 +345,3 @@
 	},
 };
 
-static int __init ohci_hcd_au1xxx_init (void)
-{
-	pr_debug (DRIVER_INFO " (Au1xxx)");
-	pr_debug ("block sizes: ed %d td %d\n",
-		sizeof (struct ed), sizeof (struct td));
-
-	return platform_driver_register(&ohci_hcd_au1xxx_driver);
-}
-
-static void __exit ohci_hcd_au1xxx_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_au1xxx_driver);
-}
-
-module_init (ohci_hcd_au1xxx_init);
-module_exit (ohci_hcd_au1xxx_cleanup);
diff --git a/drivers/usb/host/ohci-ep93xx.c b/drivers/usb/host/ohci-ep93xx.c
index 3348b07..44c60fb 100644
--- a/drivers/usb/host/ohci-ep93xx.c
+++ b/drivers/usb/host/ohci-ep93xx.c
@@ -214,15 +214,3 @@
 	},
 };
 
-static int __init ohci_hcd_ep93xx_init(void)
-{
-	return platform_driver_register(&ohci_hcd_ep93xx_driver);
-}
-
-static void __exit ohci_hcd_ep93xx_cleanup(void)
-{
-	platform_driver_unregister(&ohci_hcd_ep93xx_driver);
-}
-
-module_init(ohci_hcd_ep93xx_init);
-module_exit(ohci_hcd_ep93xx_cleanup);
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index c1c1d87..fa6a7ce 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -855,63 +855,167 @@
 
 #ifdef CONFIG_PCI
 #include "ohci-pci.c"
+#define PCI_DRIVER		ohci_pci_driver
 #endif
 
 #ifdef CONFIG_SA1111
 #include "ohci-sa1111.c"
+#define SA1111_DRIVER		ohci_hcd_sa1111_driver
 #endif
 
 #ifdef CONFIG_ARCH_S3C2410
 #include "ohci-s3c2410.c"
+#define PLATFORM_DRIVER		ohci_hcd_s3c2410_driver
 #endif
 
 #ifdef CONFIG_ARCH_OMAP
 #include "ohci-omap.c"
+#define PLATFORM_DRIVER		ohci_hcd_omap_driver
 #endif
 
 #ifdef CONFIG_ARCH_LH7A404
 #include "ohci-lh7a404.c"
+#define PLATFORM_DRIVER		ohci_hcd_lh7a404_driver
 #endif
 
 #ifdef CONFIG_PXA27x
 #include "ohci-pxa27x.c"
+#define PLATFORM_DRIVER		ohci_hcd_pxa27x_driver
 #endif
 
 #ifdef CONFIG_ARCH_EP93XX
 #include "ohci-ep93xx.c"
+#define PLATFORM_DRIVER		ohci_hcd_ep93xx_driver
 #endif
 
 #ifdef CONFIG_SOC_AU1X00
 #include "ohci-au1xxx.c"
+#define PLATFORM_DRIVER		ohci_hcd_au1xxx_driver
 #endif
 
 #ifdef CONFIG_PNX8550
 #include "ohci-pnx8550.c"
+#define PLATFORM_DRIVER		ohci_hcd_pnx8550_driver
 #endif
 
 #ifdef CONFIG_USB_OHCI_HCD_PPC_SOC
 #include "ohci-ppc-soc.c"
+#define PLATFORM_DRIVER		ohci_hcd_ppc_soc_driver
 #endif
 
 #ifdef CONFIG_ARCH_AT91
 #include "ohci-at91.c"
+#define PLATFORM_DRIVER		ohci_hcd_at91_driver
 #endif
 
 #ifdef CONFIG_ARCH_PNX4008
 #include "ohci-pnx4008.c"
+#define PLATFORM_DRIVER		usb_hcd_pnx4008_driver
 #endif
 
-#if !(defined(CONFIG_PCI) \
-      || defined(CONFIG_SA1111) \
-      || defined(CONFIG_ARCH_S3C2410) \
-      || defined(CONFIG_ARCH_OMAP) \
-      || defined (CONFIG_ARCH_LH7A404) \
-      || defined (CONFIG_PXA27x) \
-      || defined (CONFIG_ARCH_EP93XX) \
-      || defined (CONFIG_SOC_AU1X00) \
-      || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
-      || defined (CONFIG_ARCH_AT91) \
-      || defined (CONFIG_ARCH_PNX4008) \
-	)
+
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF
+#include "ohci-ppc-of.c"
+#define OF_PLATFORM_DRIVER	ohci_hcd_ppc_of_driver
+#endif
+
+#ifdef CONFIG_PPC_PS3
+#include "ohci-ps3.c"
+#define PS3_SYSTEM_BUS_DRIVER	ps3_ohci_sb_driver
+#endif
+
+#if	!defined(PCI_DRIVER) &&		\
+	!defined(PLATFORM_DRIVER) &&	\
+	!defined(OF_PLATFORM_DRIVER) &&	\
+	!defined(SA1111_DRIVER) &&	\
+	!defined(PS3_SYSTEM_BUS_DRIVER)
 #error "missing bus glue for ohci-hcd"
 #endif
+
+static int __init ohci_hcd_mod_init(void)
+{
+	int retval = 0;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	printk (KERN_DEBUG "%s: " DRIVER_INFO "\n", hcd_name);
+	pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
+		sizeof (struct ed), sizeof (struct td));
+
+#ifdef PS3_SYSTEM_BUS_DRIVER
+	retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+	if (retval < 0)
+		goto error_ps3;
+#endif
+
+#ifdef PLATFORM_DRIVER
+	retval = platform_driver_register(&PLATFORM_DRIVER);
+	if (retval < 0)
+		goto error_platform;
+#endif
+
+#ifdef OF_PLATFORM_DRIVER
+	retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
+	if (retval < 0)
+		goto error_of_platform;
+#endif
+
+#ifdef SA1111_DRIVER
+	retval = sa1111_driver_register(&SA1111_DRIVER);
+	if (retval < 0)
+		goto error_sa1111;
+#endif
+
+#ifdef PCI_DRIVER
+	retval = pci_register_driver(&PCI_DRIVER);
+	if (retval < 0)
+		goto error_pci;
+#endif
+
+	return retval;
+
+	/* Error path */
+#ifdef PCI_DRIVER
+ error_pci:
+#endif
+#ifdef SA1111_DRIVER
+	sa1111_driver_unregister(&SA1111_DRIVER);
+ error_sa1111:
+#endif
+#ifdef OF_PLATFORM_DRIVER
+	of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
+ error_of_platform:
+#endif
+#ifdef PLATFORM_DRIVER
+	platform_driver_unregister(&PLATFORM_DRIVER);
+ error_platform:
+#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+	ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+ error_ps3:
+#endif
+	return retval;
+}
+module_init(ohci_hcd_mod_init);
+
+static void __exit ohci_hcd_mod_exit(void)
+{
+#ifdef PCI_DRIVER
+	pci_unregister_driver(&PCI_DRIVER);
+#endif
+#ifdef SA1111_DRIVER
+	sa1111_driver_unregister(&SA1111_DRIVER);
+#endif
+#ifdef OF_PLATFORM_DRIVER
+	of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
+#endif
+#ifdef PLATFORM_DRIVER
+	platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+	ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+#endif
+}
+module_exit(ohci_hcd_mod_exit);
+
diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c
index e9807cf..4a043ab 100644
--- a/drivers/usb/host/ohci-lh7a404.c
+++ b/drivers/usb/host/ohci-lh7a404.c
@@ -251,19 +251,3 @@
 	},
 };
 
-static int __init ohci_hcd_lh7a404_init (void)
-{
-	pr_debug (DRIVER_INFO " (LH7A404)");
-	pr_debug ("block sizes: ed %d td %d\n",
-		sizeof (struct ed), sizeof (struct td));
-
-	return platform_driver_register(&ohci_hcd_lh7a404_driver);
-}
-
-static void __exit ohci_hcd_lh7a404_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_lh7a404_driver);
-}
-
-module_init (ohci_hcd_lh7a404_init);
-module_exit (ohci_hcd_lh7a404_cleanup);
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index 27be1f9..5cfa3d1 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -544,22 +544,3 @@
 	},
 };
 
-static int __init ohci_hcd_omap_init (void)
-{
-	printk (KERN_DEBUG "%s: " DRIVER_INFO " (OMAP)\n", hcd_name);
-	if (usb_disabled())
-		return -ENODEV;
-
-	pr_debug("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
-		sizeof (struct ed), sizeof (struct td));
-
-	return platform_driver_register(&ohci_hcd_omap_driver);
-}
-
-static void __exit ohci_hcd_omap_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_omap_driver);
-}
-
-module_init (ohci_hcd_omap_init);
-module_exit (ohci_hcd_omap_cleanup);
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index 596e0b4..b331ac4 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -20,80 +20,155 @@
 
 /*-------------------------------------------------------------------------*/
 
-static int
-ohci_pci_reset (struct usb_hcd *hcd)
+/* AMD 756, for most chips (early revs), corrupts register
+ * values on read ... so enable the vendor workaround.
+ */
+static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd)
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 
-	ohci_hcd_init (ohci);
-	return ohci_init (ohci);
+	ohci->flags = OHCI_QUIRK_AMD756;
+	ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
+
+	/* also erratum 10 (suspend/resume issues) */
+	device_init_wakeup(&hcd->self.root_hub->dev, 0);
+
+	return 0;
 }
 
-static int __devinit
-ohci_pci_start (struct usb_hcd *hcd)
+/* Apple's OHCI driver has a lot of bizarre workarounds
+ * for this chip.  Evidently control and bulk lists
+ * can get confused.  (B&W G3 models, and ...)
+ */
+static int __devinit ohci_quirk_opti(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+
+	ohci_dbg (ohci, "WARNING: OPTi workarounds unavailable\n");
+
+	return 0;
+}
+
+/* Check for NSC87560. We have to look at the bridge (fn1) to
+ * identify the USB (fn2). This quirk might apply to more or
+ * even all NSC stuff.
+ */
+static int __devinit ohci_quirk_ns(struct usb_hcd *hcd)
+{
+	struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+	struct pci_dev	*b;
+
+	b  = pci_get_slot (pdev->bus, PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
+	if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
+	    && b->vendor == PCI_VENDOR_ID_NS) {
+		struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+
+		ohci->flags |= OHCI_QUIRK_SUPERIO;
+		ohci_dbg (ohci, "Using NSC SuperIO setup\n");
+	}
+	pci_dev_put(b);
+
+	return 0;
+}
+
+/* Check for Compaq's ZFMicro chipset, which needs short
+ * delays before control or bulk queues get re-activated
+ * in finish_unlinks()
+ */
+static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+
+	ohci->flags |= OHCI_QUIRK_ZFMICRO;
+	ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n");
+
+	return 0;
+}
+
+/* Check for Toshiba SCC OHCI which has big endian registers
+ * and little endian in memory data structures
+ */
+static int __devinit ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+
+	/* That chip is only present in the southbridge of some
+	 * cell based platforms which are supposed to select
+	 * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO. We verify here if
+	 * that was the case though.
+	 */
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+	ohci->flags |= OHCI_QUIRK_BE_MMIO;
+	ohci_dbg (ohci, "enabled big endian Toshiba quirk\n");
+	return 0;
+#else
+	ohci_err (ohci, "unsupported big endian Toshiba quirk\n");
+	return -ENXIO;
+#endif
+}
+
+/* List of quirks for OHCI */
+static const struct pci_device_id ohci_pci_quirks[] = {
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x740c),
+		.driver_data = (unsigned long)ohci_quirk_amd756,
+	},
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_OPTI, 0xc861),
+		.driver_data = (unsigned long)ohci_quirk_opti,
+	},
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_ANY_ID),
+		.driver_data = (unsigned long)ohci_quirk_ns,
+	},
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xa0f8),
+		.driver_data = (unsigned long)ohci_quirk_zfmicro,
+	},
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6),
+		.driver_data = (unsigned long)ohci_quirk_toshiba_scc,
+	},
+	/* FIXME for some of the early AMD 760 southbridges, OHCI
+	 * won't work at all.  blacklist them.
+	 */
+
+	{},
+};
+
+static int ohci_pci_reset (struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	int ret = 0;
+
+	if (hcd->self.controller) {
+		struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+		const struct pci_device_id *quirk_id;
+
+		quirk_id = pci_match_id(ohci_pci_quirks, pdev);
+		if (quirk_id != NULL) {
+			int (*quirk)(struct usb_hcd *ohci);
+			quirk = (void *)quirk_id->driver_data;
+			ret = quirk(hcd);
+		}
+	}
+	if (ret == 0) {
+		ohci_hcd_init (ohci);
+		return ohci_init (ohci);
+	}
+	return ret;
+}
+
+
+static int __devinit ohci_pci_start (struct usb_hcd *hcd)
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 	int		ret;
 
-	/* REVISIT this whole block should move to reset(), which handles
-	 * all the other one-time init.
-	 */
+#ifdef CONFIG_PM /* avoid warnings about unused pdev */
 	if (hcd->self.controller) {
 		struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
 
-		/* AMD 756, for most chips (early revs), corrupts register
-		 * values on read ... so enable the vendor workaround.
-		 */
-		if (pdev->vendor == PCI_VENDOR_ID_AMD
-				&& pdev->device == 0x740c) {
-			ohci->flags = OHCI_QUIRK_AMD756;
-			ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
-			/* also erratum 10 (suspend/resume issues) */
-			device_init_wakeup(&hcd->self.root_hub->dev, 0);
-		}
-
-		/* FIXME for some of the early AMD 760 southbridges, OHCI
-		 * won't work at all.  blacklist them.
-		 */
-
-		/* Apple's OHCI driver has a lot of bizarre workarounds
-		 * for this chip.  Evidently control and bulk lists
-		 * can get confused.  (B&W G3 models, and ...)
-		 */
-		else if (pdev->vendor == PCI_VENDOR_ID_OPTI
-				&& pdev->device == 0xc861) {
-			ohci_dbg (ohci,
-				"WARNING: OPTi workarounds unavailable\n");
-		}
-
-		/* Check for NSC87560. We have to look at the bridge (fn1) to
-		 * identify the USB (fn2). This quirk might apply to more or
-		 * even all NSC stuff.
-		 */
-		else if (pdev->vendor == PCI_VENDOR_ID_NS) {
-			struct pci_dev	*b;
-
-			b  = pci_get_slot (pdev->bus,
-					PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
-			if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
-					&& b->vendor == PCI_VENDOR_ID_NS) {
-				ohci->flags |= OHCI_QUIRK_SUPERIO;
-				ohci_dbg (ohci, "Using NSC SuperIO setup\n");
-			}
-			pci_dev_put(b);
-		}
-
-		/* Check for Compaq's ZFMicro chipset, which needs short
-		 * delays before control or bulk queues get re-activated
-		 * in finish_unlinks()
-		 */
-		else if (pdev->vendor == PCI_VENDOR_ID_COMPAQ
-				&& pdev->device  == 0xa0f8) {
-			ohci->flags |= OHCI_QUIRK_ZFMICRO;
-			ohci_dbg (ohci,
-				"enabled Compaq ZFMicro chipset quirk\n");
-		}
-
 		/* RWC may not be set for add-in PCI cards, since boot
 		 * firmware probably ignored them.  This transfers PCI
 		 * PM wakeup capabilities (once the PCI layer is fixed).
@@ -101,16 +176,14 @@
 		if (device_may_wakeup(&pdev->dev))
 			ohci->hc_control |= OHCI_CTRL_RWC;
 	}
+#endif /* CONFIG_PM */
 
-	/* NOTE: there may have already been a first reset, to
-	 * keep bios/smm irqs from making trouble
-	 */
-	if ((ret = ohci_run (ohci)) < 0) {
+	ret = ohci_run (ohci);
+	if (ret < 0) {
 		ohci_err (ohci, "can't start\n");
 		ohci_stop (hcd);
-		return ret;
 	}
-	return 0;
+	return ret;
 }
 
 #ifdef	CONFIG_PM
@@ -238,23 +311,3 @@
 	.shutdown =	usb_hcd_pci_shutdown,
 };
 
-
-static int __init ohci_hcd_pci_init (void)
-{
-	printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name);
-	if (usb_disabled())
-		return -ENODEV;
-
-	pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
-		sizeof (struct ed), sizeof (struct td));
-	return pci_register_driver (&ohci_pci_driver);
-}
-module_init (ohci_hcd_pci_init);
-
-/*-------------------------------------------------------------------------*/
-
-static void __exit ohci_hcd_pci_cleanup (void)
-{
-	pci_unregister_driver (&ohci_pci_driver);
-}
-module_exit (ohci_hcd_pci_cleanup);
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-pnx4008.c
index 3a8cbfb..893b172 100644
--- a/drivers/usb/host/ohci-pnx4008.c
+++ b/drivers/usb/host/ohci-pnx4008.c
@@ -465,15 +465,3 @@
 	.remove = usb_hcd_pnx4008_remove,
 };
 
-static int __init usb_hcd_pnx4008_init(void)
-{
-	return platform_driver_register(&usb_hcd_pnx4008_driver);
-}
-
-static void __exit usb_hcd_pnx4008_cleanup(void)
-{
-	return platform_driver_unregister(&usb_hcd_pnx4008_driver);
-}
-
-module_init(usb_hcd_pnx4008_init);
-module_exit(usb_hcd_pnx4008_cleanup);
diff --git a/drivers/usb/host/ohci-pnx8550.c b/drivers/usb/host/ohci-pnx8550.c
index 6922b91..de45eb0 100644
--- a/drivers/usb/host/ohci-pnx8550.c
+++ b/drivers/usb/host/ohci-pnx8550.c
@@ -240,19 +240,3 @@
 	.remove		= ohci_hcd_pnx8550_drv_remove,
 };
 
-static int __init ohci_hcd_pnx8550_init (void)
-{
-	pr_debug (DRIVER_INFO " (pnx8550)");
-	pr_debug ("block sizes: ed %d td %d\n",
-		sizeof (struct ed), sizeof (struct td));
-
-	return platform_driver_register(&ohci_hcd_pnx8550_driver);
-}
-
-static void __exit ohci_hcd_pnx8550_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_pnx8550_driver);
-}
-
-module_init (ohci_hcd_pnx8550_init);
-module_exit (ohci_hcd_pnx8550_cleanup);
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
new file mode 100644
index 0000000..08e237c
--- /dev/null
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -0,0 +1,232 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ * (C) Copyright 2006 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Bus glue for OHCI HC on the of_platform bus
+ *
+ * Modified for of_platform bus from ohci-sa1111.c
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/signal.h>
+
+#include <asm/of_platform.h>
+#include <asm/prom.h>
+
+
+static int __devinit
+ohci_ppc_of_start(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
+	int		ret;
+
+	if ((ret = ohci_init(ohci)) < 0)
+		return ret;
+
+	if ((ret = ohci_run(ohci)) < 0) {
+		err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
+		ohci_stop(hcd);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct hc_driver ohci_ppc_of_hc_driver = {
+	.description =		hcd_name,
+	.product_desc =		"OF OHCI",
+	.hcd_priv_size =	sizeof(struct ohci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ohci_irq,
+	.flags =		HCD_USB11 | HCD_MEMORY,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.start =		ohci_ppc_of_start,
+	.stop =			ohci_stop,
+	.shutdown = 		ohci_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ohci_urb_enqueue,
+	.urb_dequeue =		ohci_urb_dequeue,
+	.endpoint_disable =	ohci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ohci_hub_status_data,
+	.hub_control =		ohci_hub_control,
+	.hub_irq_enable =	ohci_rhsc_enable,
+#ifdef	CONFIG_PM
+	.bus_suspend =		ohci_bus_suspend,
+	.bus_resume =		ohci_bus_resume,
+#endif
+	.start_port_reset =	ohci_start_port_reset,
+};
+
+
+static int __devinit
+ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+	struct device_node *dn = op->node;
+	struct usb_hcd *hcd;
+	struct ohci_hcd	*ohci;
+	struct resource res;
+	int irq;
+
+	int rv;
+	int is_bigendian;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	is_bigendian =
+		device_is_compatible(dn, "ohci-bigendian") ||
+		device_is_compatible(dn, "ohci-be");
+
+	dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
+
+	rv = of_address_to_resource(dn, 0, &res);
+	if (rv)
+		return rv;
+
+	hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
+	if (!hcd)
+		return -ENOMEM;
+
+	hcd->rsrc_start = res.start;
+	hcd->rsrc_len = res.end - res.start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
+		rv = -EBUSY;
+		goto err_rmr;
+	}
+
+	irq = irq_of_parse_and_map(dn, 0);
+	if (irq == NO_IRQ) {
+		printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+		rv = -EBUSY;
+		goto err_irq;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		printk(KERN_ERR __FILE__ ": ioremap failed\n");
+		rv = -ENOMEM;
+		goto err_ioremap;
+	}
+
+	ohci = hcd_to_ohci(hcd);
+	if (is_bigendian)
+		ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+
+	ohci_hcd_init(ohci);
+
+	rv = usb_add_hcd(hcd, irq, 0);
+	if (rv == 0)
+		return 0;
+
+	iounmap(hcd->regs);
+err_ioremap:
+	irq_dispose_mapping(irq);
+err_irq:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_rmr:
+ 	usb_put_hcd(hcd);
+
+	return rv;
+}
+
+static int ohci_hcd_ppc_of_remove(struct of_device *op)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+	dev_set_drvdata(&op->dev, NULL);
+
+	dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
+
+	usb_remove_hcd(hcd);
+
+	iounmap(hcd->regs);
+	irq_dispose_mapping(hcd->irq);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+	usb_put_hcd(hcd);
+
+	return 0;
+}
+
+static int ohci_hcd_ppc_of_shutdown(struct of_device *op)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+
+        if (hcd->driver->shutdown)
+                hcd->driver->shutdown(hcd);
+
+	return 0;
+}
+
+
+static struct of_device_id ohci_hcd_ppc_of_match[] = {
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
+	{
+		.name = "usb",
+		.compatible = "ohci-bigendian",
+	},
+	{
+		.name = "usb",
+		.compatible = "ohci-be",
+	},
+#endif
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE
+	{
+		.name = "usb",
+		.compatible = "ohci-littledian",
+	},
+	{
+		.name = "usb",
+		.compatible = "ohci-le",
+	},
+#endif
+	{},
+};
+MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
+
+#if	!defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \
+	!defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE)
+#error "No endianess selected for ppc-of-ohci"
+#endif
+
+
+static struct of_platform_driver ohci_hcd_ppc_of_driver = {
+	.name		= "ppc-of-ohci",
+	.match_table	= ohci_hcd_ppc_of_match,
+	.probe		= ohci_hcd_ppc_of_probe,
+	.remove		= ohci_hcd_ppc_of_remove,
+	.shutdown 	= ohci_hcd_ppc_of_shutdown,
+#ifdef CONFIG_PM
+	/*.suspend	= ohci_hcd_ppc_soc_drv_suspend,*/
+	/*.resume	= ohci_hcd_ppc_soc_drv_resume,*/
+#endif
+	.driver		= {
+		.name	= "ppc-of-ohci",
+		.owner	= THIS_MODULE,
+	},
+};
+
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index e1a7eb8..1a2e177 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -72,7 +72,7 @@
 	}
 
 	ohci = hcd_to_ohci(hcd);
-	ohci->flags |= OHCI_BIG_ENDIAN;
+	ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
 	ohci_hcd_init(ohci);
 
 	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
@@ -208,19 +208,3 @@
 	},
 };
 
-static int __init ohci_hcd_ppc_soc_init(void)
-{
-	pr_debug(DRIVER_INFO " (PPC SOC)\n");
-	pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed),
-							sizeof(struct td));
-
-	return platform_driver_register(&ohci_hcd_ppc_soc_driver);
-}
-
-static void __exit ohci_hcd_ppc_soc_cleanup(void)
-{
-	platform_driver_unregister(&ohci_hcd_ppc_soc_driver);
-}
-
-module_init(ohci_hcd_ppc_soc_init);
-module_exit(ohci_hcd_ppc_soc_cleanup);
diff --git a/drivers/usb/host/ohci-ps3.c b/drivers/usb/host/ohci-ps3.c
new file mode 100644
index 0000000..69d948b
--- /dev/null
+++ b/drivers/usb/host/ohci-ps3.c
@@ -0,0 +1,196 @@
+/*
+ *  PS3 OHCI Host Controller driver
+ *
+ *  Copyright (C) 2006 Sony Computer Entertainment Inc.
+ *  Copyright 2006 Sony Corp.
+ *
+ *  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; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <asm/ps3.h>
+
+static int ps3_ohci_hc_reset(struct usb_hcd *hcd)
+{
+	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+	ohci->flags |= OHCI_QUIRK_BE_MMIO;
+	ohci_hcd_init(ohci);
+	return ohci_init(ohci);
+}
+
+static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd)
+{
+	int result;
+	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+	/* Handle root hub init quirk in spider south bridge. */
+	/* Also set PwrOn2PwrGood to 0x7f (254ms). */
+
+	ohci_writel(ohci, 0x7f000000 | RH_A_PSM | RH_A_OCPM,
+		&ohci->regs->roothub.a);
+	ohci_writel(ohci, 0x00060000, &ohci->regs->roothub.b);
+
+	result = ohci_run(ohci);
+
+	if (result < 0) {
+		err("can't start %s", hcd->self.bus_name);
+		ohci_stop(hcd);
+	}
+
+	return result;
+}
+
+static const struct hc_driver ps3_ohci_hc_driver = {
+	.description		= hcd_name,
+	.product_desc		= "PS3 OHCI Host Controller",
+	.hcd_priv_size		= sizeof(struct ohci_hcd),
+	.irq			= ohci_irq,
+	.flags			= HCD_MEMORY | HCD_USB11,
+	.reset			= ps3_ohci_hc_reset,
+	.start			= ps3_ohci_hc_start,
+	.stop			= ohci_stop,
+	.shutdown		= ohci_shutdown,
+	.urb_enqueue		= ohci_urb_enqueue,
+	.urb_dequeue		= ohci_urb_dequeue,
+	.endpoint_disable	= ohci_endpoint_disable,
+	.get_frame_number	= ohci_get_frame,
+	.hub_status_data	= ohci_hub_status_data,
+	.hub_control		= ohci_hub_control,
+	.hub_irq_enable		= ohci_rhsc_enable,
+	.start_port_reset	= ohci_start_port_reset,
+#if defined(CONFIG_PM)
+	.bus_suspend 		= ohci_bus_suspend,
+	.bus_resume 		= ohci_bus_resume,
+#endif
+};
+
+/* redefine dev_dbg to do a syntax check */
+
+#if !defined(DEBUG)
+#undef dev_dbg
+static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+	const struct device *_dev, const char *fmt, ...) {return 0;}
+#endif
+
+static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
+{
+	int result;
+	struct usb_hcd *hcd;
+	unsigned int virq;
+	static u64 dummy_mask = DMA_32BIT_MASK;
+
+	if (usb_disabled()) {
+		result = -ENODEV;
+		goto fail_start;
+	}
+
+	result = ps3_mmio_region_create(dev->m_region);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
+			__func__, __LINE__);
+		result = -EPERM;
+		goto fail_mmio;
+	}
+
+	dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
+		__LINE__, dev->m_region->lpar_addr);
+
+	result = ps3_alloc_io_irq(dev->interrupt_id, &virq);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
+			__func__, __LINE__, virq);
+		result = -EPERM;
+		goto fail_irq;
+	}
+
+	dev->core.power.power_state = PMSG_ON;
+	dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
+
+	hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev->core.bus_id);
+
+	if (!hcd) {
+		dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
+			__LINE__);
+		result = -ENOMEM;
+		goto fail_create_hcd;
+	}
+
+	hcd->rsrc_start = dev->m_region->lpar_addr;
+	hcd->rsrc_len = dev->m_region->len;
+	hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
+
+	if (!hcd->regs) {
+		dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
+			__LINE__);
+		result = -EPERM;
+		goto fail_ioremap;
+	}
+
+	dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
+		(unsigned long)hcd->rsrc_start);
+	dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len   %lxh\n", __func__, __LINE__,
+		(unsigned long)hcd->rsrc_len);
+	dev_dbg(&dev->core, "%s:%d: hcd->regs       %lxh\n", __func__, __LINE__,
+		(unsigned long)hcd->regs);
+	dev_dbg(&dev->core, "%s:%d: virq            %lu\n", __func__, __LINE__,
+		(unsigned long)virq);
+
+	ps3_system_bus_set_driver_data(dev, hcd);
+
+	result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
+			__func__, __LINE__, result);
+		goto fail_add_hcd;
+	}
+
+	return result;
+
+fail_add_hcd:
+	iounmap(hcd->regs);
+fail_ioremap:
+	usb_put_hcd(hcd);
+fail_create_hcd:
+	ps3_free_io_irq(virq);
+fail_irq:
+	ps3_free_mmio_region(dev->m_region);
+fail_mmio:
+fail_start:
+	return result;
+}
+
+static int ps3_ohci_sb_remove (struct ps3_system_bus_device *dev)
+{
+	struct usb_hcd *hcd =
+		(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+
+	usb_put_hcd(hcd);
+	ps3_system_bus_set_driver_data(dev, NULL);
+
+	return 0;
+}
+
+MODULE_ALIAS("ps3-ohci");
+
+static struct ps3_system_bus_driver ps3_ohci_sb_driver = {
+	.match_id = PS3_MATCH_ID_OHCI,
+	.core = {
+		.name = "ps3-ohci-driver",
+	},
+	.probe = ps3_ohci_sb_probe,
+	.remove = ps3_ohci_sb_remove,
+};
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 3bbea84..f1563dc 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -369,19 +369,3 @@
 	},
 };
 
-static int __init ohci_hcd_pxa27x_init (void)
-{
-	pr_debug (DRIVER_INFO " (pxa27x)");
-	pr_debug ("block sizes: ed %d td %d\n",
-		sizeof (struct ed), sizeof (struct td));
-
-	return platform_driver_register(&ohci_hcd_pxa27x_driver);
-}
-
-static void __exit ohci_hcd_pxa27x_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_pxa27x_driver);
-}
-
-module_init (ohci_hcd_pxa27x_init);
-module_exit (ohci_hcd_pxa27x_cleanup);
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index b350d45..6829814 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -501,15 +501,3 @@
 	},
 };
 
-static int __init ohci_hcd_s3c2410_init (void)
-{
-	return platform_driver_register(&ohci_hcd_s3c2410_driver);
-}
-
-static void __exit ohci_hcd_s3c2410_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_s3c2410_driver);
-}
-
-module_init (ohci_hcd_s3c2410_init);
-module_exit (ohci_hcd_s3c2410_cleanup);
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index fe0090e..0f48f2d 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -269,19 +269,3 @@
 	.remove		= ohci_hcd_sa1111_drv_remove,
 };
 
-static int __init ohci_hcd_sa1111_init (void)
-{
-	dbg (DRIVER_INFO " (SA-1111)");
-	dbg ("block sizes: ed %d td %d",
-		sizeof (struct ed), sizeof (struct td));
-
-	return sa1111_driver_register(&ohci_hcd_sa1111_driver);
-}
-
-static void __exit ohci_hcd_sa1111_cleanup (void)
-{
-	sa1111_driver_unregister(&ohci_hcd_sa1111_driver);
-}
-
-module_init (ohci_hcd_sa1111_init);
-module_exit (ohci_hcd_sa1111_cleanup);
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 405257f..0dafcda 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -394,8 +394,9 @@
 #define	OHCI_QUIRK_AMD756	0x01			/* erratum #4 */
 #define	OHCI_QUIRK_SUPERIO	0x02			/* natsemi */
 #define	OHCI_QUIRK_INITRESET	0x04			/* SiS, OPTi, ... */
-#define	OHCI_BIG_ENDIAN		0x08			/* big endian HC */
-#define	OHCI_QUIRK_ZFMICRO	0x10			/* Compaq ZFMicro chipset*/
+#define	OHCI_QUIRK_BE_DESC	0x08			/* BE descriptors */
+#define	OHCI_QUIRK_BE_MMIO	0x10			/* BE registers */
+#define	OHCI_QUIRK_ZFMICRO	0x20			/* Compaq ZFMicro chipset*/
 	// there are also chip quirks/bugs in init logic
 
 };
@@ -439,117 +440,164 @@
  * a minority (notably the IBM STB04XXX and the Motorola MPC5200
  * processors) implement them in big endian format.
  *
+ * In addition some more exotic implementations like the Toshiba
+ * Spider (aka SCC) cell southbridge are "mixed" endian, that is,
+ * they have a different endianness for registers vs. in-memory
+ * descriptors.
+ *
  * This attempts to support either format at compile time without a
  * runtime penalty, or both formats with the additional overhead
  * of checking a flag bit.
+ *
+ * That leads to some tricky Kconfig rules howevber. There are
+ * different defaults based on some arch/ppc platforms, though
+ * the basic rules are:
+ *
+ * Controller type              Kconfig options needed
+ * ---------------              ----------------------
+ * little endian                CONFIG_USB_OHCI_LITTLE_ENDIAN
+ *
+ * fully big endian             CONFIG_USB_OHCI_BIG_ENDIAN_DESC _and_
+ *                              CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ *
+ * mixed endian                 CONFIG_USB_OHCI_LITTLE_ENDIAN _and_
+ *                              CONFIG_USB_OHCI_BIG_ENDIAN_{MMIO,DESC}
+ *
+ * (If you have a mixed endian controller, you -must- also define
+ * CONFIG_USB_OHCI_LITTLE_ENDIAN or things will not work when building
+ * both your mixed endian and a fully big endian controller support in
+ * the same kernel image).
  */
 
-#ifdef CONFIG_USB_OHCI_BIG_ENDIAN
-
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_DESC
 #ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
-#define big_endian(ohci)	(ohci->flags & OHCI_BIG_ENDIAN) /* either */
+#define big_endian_desc(ohci)	(ohci->flags & OHCI_QUIRK_BE_DESC)
 #else
-#define big_endian(ohci)	1		/* only big endian */
+#define big_endian_desc(ohci)	1		/* only big endian */
+#endif
+#else
+#define big_endian_desc(ohci)	0		/* only little endian */
+#endif
+
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
+#define big_endian_mmio(ohci)	(ohci->flags & OHCI_QUIRK_BE_MMIO)
+#else
+#define big_endian_mmio(ohci)	1		/* only big endian */
+#endif
+#else
+#define big_endian_mmio(ohci)	0		/* only little endian */
 #endif
 
 /*
  * Big-endian read/write functions are arch-specific.
  * Other arches can be added if/when they're needed.
+ *
+ * REVISIT: arch/powerpc now has readl/writel_be, so the
+ * definition below can die once the STB04xxx support is
+ * finally ported over.
  */
-#if defined(CONFIG_PPC)
+#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE)
 #define readl_be(addr)		in_be32((__force unsigned *)addr)
 #define writel_be(val, addr)	out_be32((__force unsigned *)addr, val)
 #endif
 
-static inline unsigned int ohci_readl (const struct ohci_hcd *ohci,
-							__hc32 __iomem * regs)
+static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci,
+					__hc32 __iomem * regs)
 {
-	return big_endian(ohci) ? readl_be (regs) : readl ((__force u32 *)regs);
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+	return big_endian_mmio(ohci) ?
+		readl_be ((__force u32 *)regs) :
+		readl ((__force u32 *)regs);
+#else
+	return readl ((__force u32 *)regs);
+#endif
 }
 
-static inline void ohci_writel (const struct ohci_hcd *ohci,
-				const unsigned int val, __hc32 __iomem *regs)
+static inline void _ohci_writel (const struct ohci_hcd *ohci,
+				 const unsigned int val, __hc32 __iomem *regs)
 {
-	big_endian(ohci) ? writel_be (val, regs) :
-			   writel (val, (__force u32 *)regs);
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+	big_endian_mmio(ohci) ?
+		writel_be (val, (__force u32 *)regs) :
+		writel (val, (__force u32 *)regs);
+#else
+		writel (val, (__force u32 *)regs);
+#endif
 }
 
-#else	/* !CONFIG_USB_OHCI_BIG_ENDIAN */
-
-#define big_endian(ohci)	0		/* only little endian */
-
 #ifdef CONFIG_ARCH_LH7A404
-	/* Marc Singer: at the time this code was written, the LH7A404
-	 * had a problem reading the USB host registers.  This
-	 * implementation of the ohci_readl function performs the read
-	 * twice as a work-around.
-	 */
-static inline unsigned int
-ohci_readl (const struct ohci_hcd *ohci, const __hc32 *regs)
-{
-	*(volatile __force unsigned int*) regs;
-	return *(volatile __force unsigned int*) regs;
-}
+/* Marc Singer: at the time this code was written, the LH7A404
+ * had a problem reading the USB host registers.  This
+ * implementation of the ohci_readl function performs the read
+ * twice as a work-around.
+ */
+#define ohci_readl(o,r)		(_ohci_readl(o,r),_ohci_readl(o,r))
+#define ohci_writel(o,v,r)	_ohci_writel(o,v,r)
 #else
-	/* Standard version of ohci_readl uses standard, platform
-	 * specific implementation. */
-static inline unsigned int
-ohci_readl (const struct ohci_hcd *ohci, __hc32 __iomem * regs)
-{
-	return readl(regs);
-}
+#define ohci_readl(o,r)		_ohci_readl(o,r)
+#define ohci_writel(o,v,r)	_ohci_writel(o,v,r)
 #endif
 
-static inline void ohci_writel (const struct ohci_hcd *ohci,
-				const unsigned int val, __hc32 __iomem *regs)
-{
-	writel (val, regs);
-}
-
-#endif	/* !CONFIG_USB_OHCI_BIG_ENDIAN */
 
 /*-------------------------------------------------------------------------*/
 
 /* cpu to ohci */
 static inline __hc16 cpu_to_hc16 (const struct ohci_hcd *ohci, const u16 x)
 {
-	return big_endian(ohci) ? (__force __hc16)cpu_to_be16(x) : (__force __hc16)cpu_to_le16(x);
+	return big_endian_desc(ohci) ?
+		(__force __hc16)cpu_to_be16(x) :
+		(__force __hc16)cpu_to_le16(x);
 }
 
 static inline __hc16 cpu_to_hc16p (const struct ohci_hcd *ohci, const u16 *x)
 {
-	return big_endian(ohci) ? cpu_to_be16p(x) : cpu_to_le16p(x);
+	return big_endian_desc(ohci) ?
+		cpu_to_be16p(x) :
+		cpu_to_le16p(x);
 }
 
 static inline __hc32 cpu_to_hc32 (const struct ohci_hcd *ohci, const u32 x)
 {
-	return big_endian(ohci) ? (__force __hc32)cpu_to_be32(x) : (__force __hc32)cpu_to_le32(x);
+	return big_endian_desc(ohci) ?
+		(__force __hc32)cpu_to_be32(x) :
+		(__force __hc32)cpu_to_le32(x);
 }
 
 static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x)
 {
-	return big_endian(ohci) ? cpu_to_be32p(x) : cpu_to_le32p(x);
+	return big_endian_desc(ohci) ?
+		cpu_to_be32p(x) :
+		cpu_to_le32p(x);
 }
 
 /* ohci to cpu */
 static inline u16 hc16_to_cpu (const struct ohci_hcd *ohci, const __hc16 x)
 {
-	return big_endian(ohci) ? be16_to_cpu((__force __be16)x) : le16_to_cpu((__force __le16)x);
+	return big_endian_desc(ohci) ?
+		be16_to_cpu((__force __be16)x) :
+		le16_to_cpu((__force __le16)x);
 }
 
 static inline u16 hc16_to_cpup (const struct ohci_hcd *ohci, const __hc16 *x)
 {
-	return big_endian(ohci) ? be16_to_cpup((__force __be16 *)x) : le16_to_cpup((__force __le16 *)x);
+	return big_endian_desc(ohci) ?
+		be16_to_cpup((__force __be16 *)x) :
+		le16_to_cpup((__force __le16 *)x);
 }
 
 static inline u32 hc32_to_cpu (const struct ohci_hcd *ohci, const __hc32 x)
 {
-	return big_endian(ohci) ? be32_to_cpu((__force __be32)x) : le32_to_cpu((__force __le32)x);
+	return big_endian_desc(ohci) ?
+		be32_to_cpu((__force __be32)x) :
+		le32_to_cpu((__force __le32)x);
 }
 
 static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
 {
-	return big_endian(ohci) ? be32_to_cpup((__force __be32 *)x) : le32_to_cpup((__force __le32 *)x);
+	return big_endian_desc(ohci) ?
+		be32_to_cpup((__force __be32 *)x) :
+		le32_to_cpup((__force __le32 *)x);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -557,6 +605,9 @@
 /* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
  * hardware handles 16 bit reads.  That creates a different confusion on
  * some big-endian SOC implementations.  Same thing happens with PSW access.
+ *
+ * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over
+ * to arch/powerpc
  */
 
 #ifdef CONFIG_STB03xxx
@@ -568,7 +619,7 @@
 static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
 {
 	u32 tmp;
-	if (big_endian(ohci)) {
+	if (big_endian_desc(ohci)) {
 		tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
 		tmp >>= OHCI_BE_FRAME_NO_SHIFT;
 	} else
@@ -580,7 +631,7 @@
 static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci,
                                  const struct td *td, int index)
 {
-	return (__hc16 *)(big_endian(ohci) ?
+	return (__hc16 *)(big_endian_desc(ohci) ?
 			&td->hwPSW[index ^ 1] : &td->hwPSW[index]);
 }
 
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index e345f15..5d6c06b 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -168,9 +168,13 @@
 			space, "", qh, qtype,
 			le32_to_cpu(qh->link), le32_to_cpu(element));
 	if (qh->type == USB_ENDPOINT_XFER_ISOC)
-		out += sprintf(out, "%*s    period %d frame %x desc [%p]\n",
-				space, "", qh->period, qh->iso_frame,
-				qh->iso_packet_desc);
+		out += sprintf(out, "%*s    period %d phase %d load %d us, "
+				"frame %x desc [%p]\n",
+				space, "", qh->period, qh->phase, qh->load,
+				qh->iso_frame, qh->iso_packet_desc);
+	else if (qh->type == USB_ENDPOINT_XFER_INT)
+		out += sprintf(out, "%*s    period %d phase %d load %d us\n",
+				space, "", qh->period, qh->phase, qh->load);
 
 	if (element & UHCI_PTR_QH)
 		out += sprintf(out, "%*s  Element points to QH (bug?)\n", space, "");
@@ -208,7 +212,7 @@
 					space, "", nurbs);
 	}
 
-	if (qh->udev) {
+	if (qh->dummy_td) {
 		out += sprintf(out, "%*s  Dummy TD\n", space, "");
 		out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0);
 	}
@@ -347,31 +351,80 @@
 	struct uhci_qh *qh;
 	struct uhci_td *td;
 	struct list_head *tmp, *head;
+	int nframes, nerrs;
 
 	out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
 	out += sprintf(out, "HC status\n");
 	out += uhci_show_status(uhci, out, len - (out - buf));
+
+	out += sprintf(out, "Periodic load table\n");
+	for (i = 0; i < MAX_PHASE; ++i) {
+		out += sprintf(out, "\t%d", uhci->load[i]);
+		if (i % 8 == 7)
+			*out++ = '\n';
+	}
+	out += sprintf(out, "Total: %d, #INT: %d, #ISO: %d\n",
+			uhci->total_load,
+			uhci_to_hcd(uhci)->self.bandwidth_int_reqs,
+			uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs);
 	if (debug <= 1)
 		return out - buf;
 
 	out += sprintf(out, "Frame List\n");
+	nframes = 10;
+	nerrs = 0;
 	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
-		td = uhci->frame_cpu[i];
-		if (!td)
-			continue;
+		__le32 link, qh_dma;
 
-		out += sprintf(out, "- Frame %d\n", i); \
-		if (td->dma_handle != (dma_addr_t)uhci->frame[i])
-			out += sprintf(out, "    frame list does not match td->dma_handle!\n");
+		j = 0;
+		td = uhci->frame_cpu[i];
+		link = uhci->frame[i];
+		if (!td)
+			goto check_link;
+
+		if (nframes > 0) {
+			out += sprintf(out, "- Frame %d -> (%08x)\n",
+					i, le32_to_cpu(link));
+			j = 1;
+		}
 
 		head = &td->fl_list;
 		tmp = head;
 		do {
 			td = list_entry(tmp, struct uhci_td, fl_list);
 			tmp = tmp->next;
-			out += uhci_show_td(td, out, len - (out - buf), 4);
+			if (cpu_to_le32(td->dma_handle) != link) {
+				if (nframes > 0)
+					out += sprintf(out, "    link does "
+						"not match list entry!\n");
+				else
+					++nerrs;
+			}
+			if (nframes > 0)
+				out += uhci_show_td(td, out,
+						len - (out - buf), 4);
+			link = td->link;
 		} while (tmp != head);
+
+check_link:
+		qh_dma = uhci_frame_skel_link(uhci, i);
+		if (link != qh_dma) {
+			if (nframes > 0) {
+				if (!j) {
+					out += sprintf(out,
+						"- Frame %d -> (%08x)\n",
+						i, le32_to_cpu(link));
+					j = 1;
+				}
+				out += sprintf(out, "   link does not match "
+					"QH (%08x)!\n", le32_to_cpu(qh_dma));
+			} else
+				++nerrs;
+		}
+		nframes -= j;
 	}
+	if (nerrs > 0)
+		out += sprintf(out, "Skipped %d bad links\n", nerrs);
 
 	out += sprintf(out, "Skeleton QHs\n");
 
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index e0d4c23..49b9d39 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -92,6 +92,34 @@
 static void wakeup_rh(struct uhci_hcd *uhci);
 static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
 
+/*
+ * Calculate the link pointer DMA value for the first Skeleton QH in a frame.
+ */
+static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame)
+{
+	int skelnum;
+
+	/*
+	 * The interrupt queues will be interleaved as evenly as possible.
+	 * There's not much to be done about period-1 interrupts; they have
+	 * to occur in every frame.  But we can schedule period-2 interrupts
+	 * in odd-numbered frames, period-4 interrupts in frames congruent
+	 * to 2 (mod 4), and so on.  This way each frame only has two
+	 * interrupt QHs, which will help spread out bandwidth utilization.
+	 *
+	 * ffs (Find First bit Set) does exactly what we need:
+	 * 1,3,5,...  => ffs = 0 => use skel_int2_qh = skelqh[8],
+	 * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
+	 * ffs >= 7 => not on any high-period queue, so use
+	 *	skel_int1_qh = skelqh[9].
+	 * Add in UHCI_NUMFRAMES to insure at least one bit is set.
+	 */
+	skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES);
+	if (skelnum <= 1)
+		skelnum = 9;
+	return UHCI_PTR_QH | cpu_to_le32(uhci->skelqh[skelnum]->dma_handle);
+}
+
 #include "uhci-debug.c"
 #include "uhci-q.c"
 #include "uhci-hub.c"
@@ -631,32 +659,11 @@
 	/*
 	 * Fill the frame list: make all entries point to the proper
 	 * interrupt queue.
-	 *
-	 * The interrupt queues will be interleaved as evenly as possible.
-	 * There's not much to be done about period-1 interrupts; they have
-	 * to occur in every frame.  But we can schedule period-2 interrupts
-	 * in odd-numbered frames, period-4 interrupts in frames congruent
-	 * to 2 (mod 4), and so on.  This way each frame only has two
-	 * interrupt QHs, which will help spread out bandwidth utilization.
 	 */
 	for (i = 0; i < UHCI_NUMFRAMES; i++) {
-		int irq;
-
-		/*
-		 * ffs (Find First bit Set) does exactly what we need:
-		 * 1,3,5,...  => ffs = 0 => use skel_int2_qh = skelqh[8],
-		 * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
-		 * ffs >= 7 => not on any high-period queue, so use
-		 *	skel_int1_qh = skelqh[9].
-		 * Add UHCI_NUMFRAMES to insure at least one bit is set.
-		 */
-		irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES);
-		if (irq <= 1)
-			irq = 9;
 
 		/* Only place we don't use the frame list routines */
-		uhci->frame[i] = UHCI_PTR_QH |
-				cpu_to_le32(uhci->skelqh[irq]->dma_handle);
+		uhci->frame[i] = uhci_frame_skel_link(uhci, i);
 	}
 
 	/*
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 108e3de..74469b5 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -83,6 +83,7 @@
 #define UHCI_MAX_SOF_NUMBER	2047	/* in an SOF packet */
 #define CAN_SCHEDULE_FRAMES	1000	/* how far in the future frames
 					 * can be scheduled */
+#define MAX_PHASE		32	/* Periodic scheduling length */
 
 /* When no queues need Full-Speed Bandwidth Reclamation,
  * delay this long before turning FSBR off */
@@ -141,6 +142,8 @@
 	unsigned long advance_jiffies;	/* Time of last queue advance */
 	unsigned int unlink_frame;	/* When the QH was unlinked */
 	unsigned int period;		/* For Interrupt and Isochronous QHs */
+	short phase;			/* Between 0 and period-1 */
+	short load;			/* Periodic time requirement, in us */
 	unsigned int iso_frame;		/* Frame # for iso_packet_desc */
 	int iso_status;			/* Status for Isochronous URBs */
 
@@ -153,6 +156,8 @@
 	unsigned int needs_fixup:1;	/* Must fix the TD toggle values */
 	unsigned int is_stopped:1;	/* Queue was stopped by error/unlink */
 	unsigned int wait_expired:1;	/* QH_WAIT_TIMEOUT has expired */
+	unsigned int bandwidth_reserved:1;	/* Periodic bandwidth has
+						 * been allocated */
 } __attribute__((aligned(16)));
 
 /*
@@ -414,6 +419,9 @@
 
 	wait_queue_head_t waitqh;		/* endpoint_disable waiters */
 	int num_waiting;			/* Number of waiters */
+
+	int total_load;				/* Sum of array values */
+	short load[MAX_PHASE];			/* Periodic allocations */
 };
 
 /* Convert between a usb_hcd pointer and the corresponding uhci_hcd */
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 30b8845..2cbb239 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -248,16 +248,26 @@
 	INIT_LIST_HEAD(&qh->node);
 
 	if (udev) {		/* Normal QH */
-		qh->dummy_td = uhci_alloc_td(uhci);
-		if (!qh->dummy_td) {
-			dma_pool_free(uhci->qh_pool, qh, dma_handle);
-			return NULL;
+		qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+		if (qh->type != USB_ENDPOINT_XFER_ISOC) {
+			qh->dummy_td = uhci_alloc_td(uhci);
+			if (!qh->dummy_td) {
+				dma_pool_free(uhci->qh_pool, qh, dma_handle);
+				return NULL;
+			}
 		}
 		qh->state = QH_STATE_IDLE;
 		qh->hep = hep;
 		qh->udev = udev;
 		hep->hcpriv = qh;
-		qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+		if (qh->type == USB_ENDPOINT_XFER_INT ||
+				qh->type == USB_ENDPOINT_XFER_ISOC)
+			qh->load = usb_calc_bus_time(udev->speed,
+					usb_endpoint_dir_in(&hep->desc),
+					qh->type == USB_ENDPOINT_XFER_ISOC,
+					le16_to_cpu(hep->desc.wMaxPacketSize))
+				/ 1000 + 1;
 
 	} else {		/* Skeleton QH */
 		qh->state = QH_STATE_ACTIVE;
@@ -275,7 +285,8 @@
 	list_del(&qh->node);
 	if (qh->udev) {
 		qh->hep->hcpriv = NULL;
-		uhci_free_td(uhci, qh->dummy_td);
+		if (qh->dummy_td)
+			uhci_free_td(uhci, qh->dummy_td);
 	}
 	dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
 }
@@ -327,7 +338,7 @@
 		goto done;
 	qh->element = UHCI_PTR_TERM;
 
-	/* Control pipes have to worry about toggles */
+	/* Control pipes don't have to worry about toggles */
 	if (qh->type == USB_ENDPOINT_XFER_CONTROL)
 		goto done;
 
@@ -493,6 +504,121 @@
 		wake_up_all(&uhci->waitqh);
 }
 
+/*
+ * Find the highest existing bandwidth load for a given phase and period.
+ */
+static int uhci_highest_load(struct uhci_hcd *uhci, int phase, int period)
+{
+	int highest_load = uhci->load[phase];
+
+	for (phase += period; phase < MAX_PHASE; phase += period)
+		highest_load = max_t(int, highest_load, uhci->load[phase]);
+	return highest_load;
+}
+
+/*
+ * Set qh->phase to the optimal phase for a periodic transfer and
+ * check whether the bandwidth requirement is acceptable.
+ */
+static int uhci_check_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+	int minimax_load;
+
+	/* Find the optimal phase (unless it is already set) and get
+	 * its load value. */
+	if (qh->phase >= 0)
+		minimax_load = uhci_highest_load(uhci, qh->phase, qh->period);
+	else {
+		int phase, load;
+		int max_phase = min_t(int, MAX_PHASE, qh->period);
+
+		qh->phase = 0;
+		minimax_load = uhci_highest_load(uhci, qh->phase, qh->period);
+		for (phase = 1; phase < max_phase; ++phase) {
+			load = uhci_highest_load(uhci, phase, qh->period);
+			if (load < minimax_load) {
+				minimax_load = load;
+				qh->phase = phase;
+			}
+		}
+	}
+
+	/* Maximum allowable periodic bandwidth is 90%, or 900 us per frame */
+	if (minimax_load + qh->load > 900) {
+		dev_dbg(uhci_dev(uhci), "bandwidth allocation failed: "
+				"period %d, phase %d, %d + %d us\n",
+				qh->period, qh->phase, minimax_load, qh->load);
+		return -ENOSPC;
+	}
+	return 0;
+}
+
+/*
+ * Reserve a periodic QH's bandwidth in the schedule
+ */
+static void uhci_reserve_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+	int i;
+	int load = qh->load;
+	char *p = "??";
+
+	for (i = qh->phase; i < MAX_PHASE; i += qh->period) {
+		uhci->load[i] += load;
+		uhci->total_load += load;
+	}
+	uhci_to_hcd(uhci)->self.bandwidth_allocated =
+			uhci->total_load / MAX_PHASE;
+	switch (qh->type) {
+	case USB_ENDPOINT_XFER_INT:
+		++uhci_to_hcd(uhci)->self.bandwidth_int_reqs;
+		p = "INT";
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		++uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs;
+		p = "ISO";
+		break;
+	}
+	qh->bandwidth_reserved = 1;
+	dev_dbg(uhci_dev(uhci),
+			"%s dev %d ep%02x-%s, period %d, phase %d, %d us\n",
+			"reserve", qh->udev->devnum,
+			qh->hep->desc.bEndpointAddress, p,
+			qh->period, qh->phase, load);
+}
+
+/*
+ * Release a periodic QH's bandwidth reservation
+ */
+static void uhci_release_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+	int i;
+	int load = qh->load;
+	char *p = "??";
+
+	for (i = qh->phase; i < MAX_PHASE; i += qh->period) {
+		uhci->load[i] -= load;
+		uhci->total_load -= load;
+	}
+	uhci_to_hcd(uhci)->self.bandwidth_allocated =
+			uhci->total_load / MAX_PHASE;
+	switch (qh->type) {
+	case USB_ENDPOINT_XFER_INT:
+		--uhci_to_hcd(uhci)->self.bandwidth_int_reqs;
+		p = "INT";
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		--uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs;
+		p = "ISO";
+		break;
+	}
+	qh->bandwidth_reserved = 0;
+	dev_dbg(uhci_dev(uhci),
+			"%s dev %d ep%02x-%s, period %d, phase %d, %d us\n",
+			"release", qh->udev->devnum,
+			qh->hep->desc.bEndpointAddress, p,
+			qh->period, qh->phase, load);
+}
+
 static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci,
 		struct urb *urb)
 {
@@ -796,7 +922,6 @@
 	wmb();
 	qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
 	qh->dummy_td = td;
-	qh->period = urb->interval;
 
 	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
 			usb_pipeout(urb->pipe), toggle);
@@ -827,28 +952,42 @@
 static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
 		struct uhci_qh *qh)
 {
-	int exponent;
+	int ret;
 
 	/* USB 1.1 interrupt transfers only involve one packet per interval.
 	 * Drivers can submit URBs of any length, but longer ones will need
 	 * multiple intervals to complete.
 	 */
 
-	/* Figure out which power-of-two queue to use */
-	for (exponent = 7; exponent >= 0; --exponent) {
-		if ((1 << exponent) <= urb->interval)
-			break;
-	}
-	if (exponent < 0)
-		return -EINVAL;
-	urb->interval = 1 << exponent;
+	if (!qh->bandwidth_reserved) {
+		int exponent;
 
-	if (qh->period == 0)
+		/* Figure out which power-of-two queue to use */
+		for (exponent = 7; exponent >= 0; --exponent) {
+			if ((1 << exponent) <= urb->interval)
+				break;
+		}
+		if (exponent < 0)
+			return -EINVAL;
+		qh->period = 1 << exponent;
 		qh->skel = uhci->skelqh[UHCI_SKEL_INDEX(exponent)];
-	else if (qh->period != urb->interval)
-		return -EINVAL;		/* Can't change the period */
 
-	return uhci_submit_common(uhci, urb, qh);
+		/* For now, interrupt phase is fixed by the layout
+		 * of the QH lists. */
+		qh->phase = (qh->period / 2) & (MAX_PHASE - 1);
+		ret = uhci_check_bandwidth(uhci, qh);
+		if (ret)
+			return ret;
+	} else if (qh->period > urb->interval)
+		return -EINVAL;		/* Can't decrease the period */
+
+	ret = uhci_submit_common(uhci, urb, qh);
+	if (ret == 0) {
+		urb->interval = qh->period;
+		if (!qh->bandwidth_reserved)
+			uhci_reserve_bandwidth(uhci, qh);
+	}
+	return ret;
 }
 
 /*
@@ -995,15 +1134,32 @@
 		return -EFBIG;
 
 	/* Check the period and figure out the starting frame number */
-	if (qh->period == 0) {
+	if (!qh->bandwidth_reserved) {
+		qh->period = urb->interval;
 		if (urb->transfer_flags & URB_ISO_ASAP) {
+			qh->phase = -1;		/* Find the best phase */
+			i = uhci_check_bandwidth(uhci, qh);
+			if (i)
+				return i;
+
+			/* Allow a little time to allocate the TDs */
 			uhci_get_current_frame_number(uhci);
-			urb->start_frame = uhci->frame_number + 10;
+			frame = uhci->frame_number + 10;
+
+			/* Move forward to the first frame having the
+			 * correct phase */
+			urb->start_frame = frame + ((qh->phase - frame) &
+					(qh->period - 1));
 		} else {
 			i = urb->start_frame - uhci->last_iso_frame;
 			if (i <= 0 || i >= UHCI_NUMFRAMES)
 				return -EINVAL;
+			qh->phase = urb->start_frame & (qh->period - 1);
+			i = uhci_check_bandwidth(uhci, qh);
+			if (i)
+				return i;
 		}
+
 	} else if (qh->period != urb->interval) {
 		return -EINVAL;		/* Can't change the period */
 
@@ -1049,9 +1205,6 @@
 	/* Set the interrupt-on-completion flag on the last packet. */
 	td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
 
-	qh->skel = uhci->skel_iso_qh;
-	qh->period = urb->interval;
-
 	/* Add the TDs to the frame list */
 	frame = urb->start_frame;
 	list_for_each_entry(td, &urbp->td_list, list) {
@@ -1065,6 +1218,9 @@
 		qh->iso_status = 0;
 	}
 
+	qh->skel = uhci->skel_iso_qh;
+	if (!qh->bandwidth_reserved)
+		uhci_reserve_bandwidth(uhci, qh);
 	return 0;
 }
 
@@ -1119,7 +1275,6 @@
 	unsigned long flags;
 	struct urb_priv *urbp;
 	struct uhci_qh *qh;
-	int bustime;
 
 	spin_lock_irqsave(&uhci->lock, flags);
 
@@ -1149,35 +1304,11 @@
 		ret = uhci_submit_bulk(uhci, urb, qh);
 		break;
 	case USB_ENDPOINT_XFER_INT:
-		if (list_empty(&qh->queue)) {
-			bustime = usb_check_bandwidth(urb->dev, urb);
-			if (bustime < 0)
-				ret = bustime;
-			else {
-				ret = uhci_submit_interrupt(uhci, urb, qh);
-				if (ret == 0)
-					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
-			}
-		} else {	/* inherit from parent */
-			struct urb_priv *eurbp;
-
-			eurbp = list_entry(qh->queue.prev, struct urb_priv,
-					node);
-			urb->bandwidth = eurbp->urb->bandwidth;
-			ret = uhci_submit_interrupt(uhci, urb, qh);
-		}
+		ret = uhci_submit_interrupt(uhci, urb, qh);
 		break;
 	case USB_ENDPOINT_XFER_ISOC:
 		urb->error_count = 0;
-		bustime = usb_check_bandwidth(urb->dev, urb);
-		if (bustime < 0) {
-			ret = bustime;
-			break;
-		}
-
 		ret = uhci_submit_isochronous(uhci, urb, qh);
-		if (ret == 0)
-			usb_claim_bandwidth(urb->dev, urb, bustime, 1);
 		break;
 	}
 	if (ret != 0)
@@ -1274,24 +1405,6 @@
 
 	uhci_free_urb_priv(uhci, urbp);
 
-	switch (qh->type) {
-	case USB_ENDPOINT_XFER_ISOC:
-		/* Release bandwidth for Interrupt or Isoc. transfers */
-		if (urb->bandwidth)
-			usb_release_bandwidth(urb->dev, urb, 1);
-		break;
-	case USB_ENDPOINT_XFER_INT:
-		/* Release bandwidth for Interrupt or Isoc. transfers */
-		/* Make sure we don't release if we have a queued URB */
-		if (list_empty(&qh->queue) && urb->bandwidth)
-			usb_release_bandwidth(urb->dev, urb, 0);
-		else
-			/* bandwidth was passed on to queued URB, */
-			/* so don't let usb_unlink_urb() release it */
-			urb->bandwidth = 0;
-		break;
-	}
-
 	spin_unlock(&uhci->lock);
 	usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
 	spin_lock(&uhci->lock);
@@ -1300,9 +1413,8 @@
 	 * reserved bandwidth. */
 	if (list_empty(&qh->queue)) {
 		uhci_unlink_qh(uhci, qh);
-
-		/* Bandwidth stuff not yet implemented */
-		qh->period = 0;
+		if (qh->bandwidth_reserved)
+			uhci_release_bandwidth(uhci, qh);
 	}
 }
 
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index 63a84bb..d308afd 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -565,11 +565,15 @@
 
 		usb_deregister_dev(intf, &mdc800_class);
 
+		/* must be under lock to make sure no URB
+		   is submitted after usb_kill_urb() */
+		mutex_lock(&mdc800->io_lock);
 		mdc800->state=NOT_CONNECTED;
 
 		usb_kill_urb(mdc800->irq_urb);
 		usb_kill_urb(mdc800->write_urb);
 		usb_kill_urb(mdc800->download_urb);
+		mutex_unlock(&mdc800->io_lock);
 
 		mdc800->dev = NULL;
 		usb_set_intfdata(intf, NULL);
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig
index aa6a620..2e71d3c 100644
--- a/drivers/usb/input/Kconfig
+++ b/drivers/usb/input/Kconfig
@@ -352,3 +352,15 @@
 
 	  To compile this driver as a module, choose M here: the
 	  module will be called appletouch.
+
+config USB_GTCO
+        tristate "GTCO CalComp/InterWrite USB Support"
+        depends on USB && INPUT
+        ---help---
+          Say Y here if you want to use the USB version of the GTCO
+          CalComp/InterWrite Tablet.  Make sure to say Y to "Mouse support"
+          (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+          (CONFIG_INPUT_EVDEV) as well.
+
+          To compile this driver as a module, choose M here: the
+          module will be called gtco.
diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile
index a06024e..a9d206c 100644
--- a/drivers/usb/input/Makefile
+++ b/drivers/usb/input/Makefile
@@ -48,6 +48,7 @@
 obj-$(CONFIG_USB_YEALINK)	+= yealink.o
 obj-$(CONFIG_USB_XPAD)		+= xpad.o
 obj-$(CONFIG_USB_APPLETOUCH)	+= appletouch.o
+obj-$(CONFIG_USB_GTCO)         += gtco.o
 
 ifeq ($(CONFIG_USB_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
diff --git a/drivers/usb/input/gtco.c b/drivers/usb/input/gtco.c
new file mode 100644
index 0000000..203cdc1bb
--- /dev/null
+++ b/drivers/usb/input/gtco.c
@@ -0,0 +1,1104 @@
+/*    -*- linux-c -*-
+
+GTCO digitizer USB driver
+
+Use the err(), dbg() and info() macros from usb.h for system logging
+
+TO CHECK:  Is pressure done right on report 5?
+
+Copyright (C) 2006  GTCO CalComp
+
+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; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of GTCO-CalComp not be used in advertising
+or publicity pertaining to distribution of the software without specific,
+written prior permission. GTCO-CalComp makes no representations about the
+suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+
+GTCO-CALCOMP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL GTCO-CALCOMP BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+GTCO CalComp, Inc.
+7125 Riverwood Drive
+Columbia, MD 21046
+
+Jeremy Roberson jroberson@gtcocalcomp.com
+Scott Hill shill@gtcocalcomp.com
+*/
+
+
+
+/*#define DEBUG*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+
+#include <linux/version.h>
+#include <linux/usb/input.h>
+
+/* Version with a Major number of 2 is for kernel inclusion only. */
+#define  GTCO_VERSION   "2.00.0006"
+
+
+/*   MACROS  */
+
+#define VENDOR_ID_GTCO	      0x078C
+#define PID_400               0x400
+#define PID_401               0x401
+#define PID_1000              0x1000
+#define PID_1001              0x1001
+#define PID_1002              0x1002
+
+/* Max size of a single report */
+#define REPORT_MAX_SIZE       10
+
+
+/* Bitmask whether pen is in range */
+#define MASK_INRANGE 0x20
+#define MASK_BUTTON  0x01F
+
+#define  PATHLENGTH     64
+
+/* DATA STRUCTURES */
+
+/* Device table */
+static struct usb_device_id gtco_usbid_table [] = {
+	{ USB_DEVICE(VENDOR_ID_GTCO, PID_400) },
+	{ USB_DEVICE(VENDOR_ID_GTCO, PID_401) },
+	{ USB_DEVICE(VENDOR_ID_GTCO, PID_1000) },
+	{ USB_DEVICE(VENDOR_ID_GTCO, PID_1001) },
+	{ USB_DEVICE(VENDOR_ID_GTCO, PID_1002) },
+	{ }
+};
+MODULE_DEVICE_TABLE (usb, gtco_usbid_table);
+
+
+/* Structure to hold all of our device specific stuff */
+struct gtco {
+
+	struct input_dev  *inputdevice; /* input device struct pointer  */
+	struct usb_device *usbdev; /* the usb device for this device */
+	struct urb        *urbinfo;	 /* urb for incoming reports      */
+	dma_addr_t        buf_dma;  /* dma addr of the data buffer*/
+	unsigned char *   buffer;   /* databuffer for reports */
+
+	char  usbpath[PATHLENGTH];
+	int   openCount;
+
+	/* Information pulled from Report Descriptor */
+	u32  usage;
+	u32  min_X;
+	u32  max_X;
+	u32  min_Y;
+	u32  max_Y;
+	s8   mintilt_X;
+	s8   maxtilt_X;
+	s8   mintilt_Y;
+	s8   maxtilt_Y;
+	u32  maxpressure;
+	u32  minpressure;
+};
+
+
+
+/*   Code for parsing the HID REPORT DESCRIPTOR          */
+
+/* From HID1.11 spec */
+struct hid_descriptor
+{
+	struct usb_descriptor_header header;
+	__le16   bcdHID;
+	u8       bCountryCode;
+	u8       bNumDescriptors;
+	u8       bDescriptorType;
+	__le16   wDescriptorLength;
+} __attribute__ ((packed));
+
+
+#define HID_DESCRIPTOR_SIZE   9
+#define HID_DEVICE_TYPE       33
+#define REPORT_DEVICE_TYPE    34
+
+
+#define PREF_TAG(x)     ((x)>>4)
+#define PREF_TYPE(x)    ((x>>2)&0x03)
+#define PREF_SIZE(x)    ((x)&0x03)
+
+#define TYPE_MAIN       0
+#define TYPE_GLOBAL     1
+#define TYPE_LOCAL      2
+#define TYPE_RESERVED   3
+
+#define TAG_MAIN_INPUT        0x8
+#define TAG_MAIN_OUTPUT       0x9
+#define TAG_MAIN_FEATURE      0xB
+#define TAG_MAIN_COL_START    0xA
+#define TAG_MAIN_COL_END      0xC
+
+#define TAG_GLOB_USAGE        0
+#define TAG_GLOB_LOG_MIN      1
+#define TAG_GLOB_LOG_MAX      2
+#define TAG_GLOB_PHYS_MIN     3
+#define TAG_GLOB_PHYS_MAX     4
+#define TAG_GLOB_UNIT_EXP     5
+#define TAG_GLOB_UNIT         6
+#define TAG_GLOB_REPORT_SZ    7
+#define TAG_GLOB_REPORT_ID    8
+#define TAG_GLOB_REPORT_CNT   9
+#define TAG_GLOB_PUSH         10
+#define TAG_GLOB_POP          11
+
+#define TAG_GLOB_MAX          12
+
+#define DIGITIZER_USAGE_TIP_PRESSURE   0x30
+#define DIGITIZER_USAGE_TILT_X         0x3D
+#define DIGITIZER_USAGE_TILT_Y         0x3E
+
+
+/*
+ *
+ *   This is an abbreviated parser for the HID Report Descriptor.  We
+ *   know what devices we are talking to, so this is by no means meant
+ *   to be generic.  We can make some safe assumptions:
+ *
+ *   - We know there are no LONG tags, all short
+ *   - We know that we have no MAIN Feature and MAIN Output items
+ *   - We know what the IRQ reports are supposed to look like.
+ *
+ *   The main purpose of this is to use the HID report desc to figure
+ *   out the mins and maxs of the fields in the IRQ reports.  The IRQ
+ *   reports for 400/401 change slightly if the max X is bigger than 64K.
+ *
+ */
+static void parse_hid_report_descriptor(struct gtco *device, char * report,
+					int length)
+{
+	int   x,i=0;
+
+	/* Tag primitive vars */
+	__u8   prefix;
+	__u8   size;
+	__u8   tag;
+	__u8   type;
+	__u8   data   = 0;
+	__u16  data16 = 0;
+	__u32  data32 = 0;
+
+
+	/* For parsing logic */
+	int   inputnum = 0;
+	__u32 usage = 0;
+
+	/* Global Values, indexed by TAG */
+	__u32 globalval[TAG_GLOB_MAX];
+	__u32 oldval[TAG_GLOB_MAX];
+
+	/* Debug stuff */
+	char  maintype='x';
+	char  globtype[12];
+	int   indent=0;
+	char  indentstr[10]="";
+
+
+
+	dbg("======>>>>>>PARSE<<<<<<======");
+
+	/* Walk  this report and pull out the info we need */
+	while (i<length){
+		prefix=report[i];
+
+		/* Skip over prefix */
+		i++;
+
+		/* Determine data size and save the data in the proper variable */
+		size = PREF_SIZE(prefix);
+		switch(size){
+		case 1:
+			data = report[i];
+			break;
+		case 2:
+			data16 = le16_to_cpu(get_unaligned((__le16*)(&(report[i]))));
+			break;
+		case 3:
+			size = 4;
+			data32 = le32_to_cpu(get_unaligned((__le32*)(&(report[i]))));
+		}
+
+		/* Skip size of data */
+		i+=size;
+
+		/* What we do depends on the tag type */
+		tag  = PREF_TAG(prefix);
+		type = PREF_TYPE(prefix);
+		switch(type){
+		case TYPE_MAIN:
+			strcpy(globtype,"");
+			switch(tag){
+
+			case TAG_MAIN_INPUT:
+				/*
+				 * The INPUT MAIN tag signifies this is
+				 * information from a report.  We need to
+				 * figure out what it is and store the
+				 * min/max values
+				 */
+
+				maintype='I';
+				if (data==2){
+					strcpy(globtype,"Variable");
+				}
+				if (data==3){
+					strcpy(globtype,"Var|Const");
+				}
+
+				dbg("::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits",
+				    globalval[TAG_GLOB_REPORT_ID],inputnum,
+				    globalval[TAG_GLOB_LOG_MAX],globalval[TAG_GLOB_LOG_MAX],
+				    globalval[TAG_GLOB_LOG_MIN],globalval[TAG_GLOB_LOG_MIN],
+				    (globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]));
+
+
+				/*
+				  We can assume that the first two input items
+				  are always the X and Y coordinates.  After
+				  that, we look for everything else by
+				  local usage value
+				 */
+				switch (inputnum){
+				case 0:  /* X coord */
+					dbg("GER: X Usage: 0x%x",usage);
+					if (device->max_X == 0){
+						device->max_X = globalval[TAG_GLOB_LOG_MAX];
+						device->min_X = globalval[TAG_GLOB_LOG_MIN];
+					}
+
+					break;
+				case 1:  /* Y coord */
+					dbg("GER: Y Usage: 0x%x",usage);
+					if (device->max_Y == 0){
+						device->max_Y = globalval[TAG_GLOB_LOG_MAX];
+						device->min_Y = globalval[TAG_GLOB_LOG_MIN];
+					}
+					break;
+				default:
+					/* Tilt X */
+					if (usage == DIGITIZER_USAGE_TILT_X){
+						if (device->maxtilt_X == 0){
+							device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX];
+							device->mintilt_X = globalval[TAG_GLOB_LOG_MIN];
+						}
+					}
+
+					/* Tilt Y */
+					if (usage == DIGITIZER_USAGE_TILT_Y){
+						if (device->maxtilt_Y == 0){
+							device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX];
+							device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN];
+						}
+					}
+
+
+					/* Pressure */
+					if (usage == DIGITIZER_USAGE_TIP_PRESSURE){
+						if (device->maxpressure == 0){
+							device->maxpressure = globalval[TAG_GLOB_LOG_MAX];
+							device->minpressure = globalval[TAG_GLOB_LOG_MIN];
+						}
+					}
+
+					break;
+				}
+
+				inputnum++;
+
+
+				break;
+			case TAG_MAIN_OUTPUT:
+				maintype='O';
+				break;
+			case TAG_MAIN_FEATURE:
+				maintype='F';
+				break;
+			case TAG_MAIN_COL_START:
+				maintype='S';
+
+				if (data==0){
+					dbg("======>>>>>> Physical");
+					strcpy(globtype,"Physical");
+				}else{
+					dbg("======>>>>>>");
+				}
+
+				/* Indent the debug output */
+				indent++;
+				for (x=0;x<indent;x++){
+					indentstr[x]='-';
+				}
+				indentstr[x]=0;
+
+				/* Save global tags */
+				for (x=0;x<TAG_GLOB_MAX;x++){
+					oldval[x] = globalval[x];
+				}
+
+				break;
+			case TAG_MAIN_COL_END:
+				dbg("<<<<<<======");
+				maintype='E';
+				indent--;
+				for (x=0;x<indent;x++){
+					indentstr[x]='-';
+				}
+				indentstr[x]=0;
+
+				/* Copy global tags back */
+				for (x=0;x<TAG_GLOB_MAX;x++){
+					globalval[x] = oldval[x];
+				}
+
+				break;
+			}
+
+			switch (size){
+			case 1:
+				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+				    indentstr,tag,maintype,size,globtype,data);
+				break;
+			case 2:
+				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+				    indentstr,tag,maintype,size,globtype, data16);
+				break;
+			case 4:
+				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+				    indentstr,tag,maintype,size,globtype,data32);
+				break;
+			}
+			break;
+		case TYPE_GLOBAL:
+			switch(tag){
+			case TAG_GLOB_USAGE:
+				/*
+				 * First time we hit the global usage tag,
+				 * it should tell us the type of device
+				 */
+				if (device->usage == 0){
+					device->usage = data;
+				}
+				strcpy(globtype,"USAGE");
+				break;
+			case TAG_GLOB_LOG_MIN   :
+				strcpy(globtype,"LOG_MIN");
+				break;
+			case TAG_GLOB_LOG_MAX   :
+				strcpy(globtype,"LOG_MAX");
+				break;
+			case TAG_GLOB_PHYS_MIN  :
+				strcpy(globtype,"PHYS_MIN");
+				break;
+			case TAG_GLOB_PHYS_MAX  :
+				strcpy(globtype,"PHYS_MAX");
+				break;
+			case TAG_GLOB_UNIT_EXP  :
+				strcpy(globtype,"EXP");
+				break;
+			case TAG_GLOB_UNIT      :
+				strcpy(globtype,"UNIT");
+				break;
+			case TAG_GLOB_REPORT_SZ :
+				strcpy(globtype,"REPORT_SZ");
+				break;
+			case TAG_GLOB_REPORT_ID :
+				strcpy(globtype,"REPORT_ID");
+				/* New report, restart numbering */
+				inputnum=0;
+				break;
+			case TAG_GLOB_REPORT_CNT:
+				strcpy(globtype,"REPORT_CNT");
+				break;
+			case TAG_GLOB_PUSH :
+				strcpy(globtype,"PUSH");
+				break;
+			case TAG_GLOB_POP:
+				strcpy(globtype,"POP");
+				break;
+			}
+
+
+			/* Check to make sure we have a good tag number
+			   so we don't overflow array */
+			if (tag < TAG_GLOB_MAX){
+				switch (size){
+				case 1:
+					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data);
+					globalval[tag]=data;
+					break;
+				case 2:
+					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data16);
+					globalval[tag]=data16;
+					break;
+				case 4:
+					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data32);
+					globalval[tag]=data32;
+					break;
+				}
+			}else{
+				dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ",
+				    indentstr,tag,size);
+			}
+
+
+			break;
+
+		case TYPE_LOCAL:
+			switch(tag){
+			case TAG_GLOB_USAGE:
+				strcpy(globtype,"USAGE");
+				/* Always 1 byte */
+				usage = data;
+				break;
+			case TAG_GLOB_LOG_MIN   :
+				strcpy(globtype,"MIN");
+				break;
+			case TAG_GLOB_LOG_MAX   :
+				strcpy(globtype,"MAX");
+				break;
+			default:
+				strcpy(globtype,"UNKNOWN");
+			}
+
+			switch (size){
+			case 1:
+				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+				    indentstr,tag,globtype,size,data);
+				break;
+			case 2:
+				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+				    indentstr,tag,globtype,size,data16);
+				break;
+			case 4:
+				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+				    indentstr,tag,globtype,size,data32);
+				break;
+			}
+
+			break;
+		}
+
+	}
+
+}
+
+
+
+/*   INPUT DRIVER Routines                               */
+
+
+/*
+ *    Called when opening the input device.  This will submit the URB to
+ *    the usb system so we start getting reports
+ */
+static int gtco_input_open(struct input_dev *inputdev)
+{
+	struct gtco *device;
+	device = inputdev->private;
+
+	device->urbinfo->dev = device->usbdev;
+	if (usb_submit_urb(device->urbinfo, GFP_KERNEL)) {
+		return -EIO;
+	}
+	return 0;
+}
+
+/**
+    Called when closing the input device.  This will unlink the URB
+*/
+static void gtco_input_close(struct input_dev *inputdev)
+{
+	struct gtco *device = inputdev->private;
+
+	usb_kill_urb(device->urbinfo);
+
+}
+
+
+/*
+ *  Setup input device capabilities.  Tell the input system what this
+ *  device is capable of generating.
+ *
+ *  This information is based on what is read from the HID report and
+ *  placed in the struct gtco structure
+ *
+ */
+static void  gtco_setup_caps(struct input_dev  *inputdev)
+{
+	struct gtco *device = inputdev->private;
+
+
+	/* Which events */
+	inputdev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
+
+
+	/* Misc event menu block */
+	inputdev->mscbit[0] = BIT(MSC_SCAN)|BIT(MSC_SERIAL)|BIT(MSC_RAW) ;
+
+
+	/* Absolute values based on HID report info */
+	input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X,
+			     0, 0);
+	input_set_abs_params(inputdev, ABS_Y, device->min_Y, device->max_Y,
+			     0, 0);
+
+	/* Proximity */
+	input_set_abs_params(inputdev, ABS_DISTANCE, 0, 1, 0, 0);
+
+	/* Tilt & pressure */
+	input_set_abs_params(inputdev, ABS_TILT_X, device->mintilt_X,
+			     device->maxtilt_X, 0, 0);
+	input_set_abs_params(inputdev, ABS_TILT_Y, device->mintilt_Y,
+			     device->maxtilt_Y, 0, 0);
+	input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure,
+			     device->maxpressure, 0, 0);
+
+
+	/* Transducer */
+	input_set_abs_params(inputdev, ABS_MISC, 0,0xFF, 0, 0);
+
+}
+
+
+
+/*   USB Routines  */
+
+
+/*
+ * URB callback routine.  Called when we get IRQ reports from the
+ *  digitizer.
+ *
+ *  This bridges the USB and input device worlds.  It generates events
+ *  on the input device based on the USB reports.
+ */
+static void gtco_urb_callback(struct urb *urbinfo)
+{
+
+
+	struct gtco     *device = urbinfo->context;
+	struct input_dev  *inputdev;
+	int               rc;
+	u32               val = 0;
+	s8                valsigned = 0;
+	char              le_buffer[2];
+
+	inputdev = device->inputdevice;
+
+
+	/* Was callback OK? */
+	if ((urbinfo->status == -ECONNRESET ) ||
+	    (urbinfo->status == -ENOENT ) ||
+	    (urbinfo->status == -ESHUTDOWN )){
+
+		/* Shutdown is occurring. Return and don't queue up any more */
+		return;
+	}
+
+	if (urbinfo->status != 0 ) {
+		/* Some unknown error.  Hopefully temporary.  Just go and */
+		/* requeue an URB */
+		goto resubmit;
+	}
+
+	/*
+	 * Good URB, now process
+	 */
+
+	/* PID dependent when we interpret the report */
+	if ((inputdev->id.product == PID_1000 )||
+	    (inputdev->id.product == PID_1001 )||
+	    (inputdev->id.product == PID_1002 ))
+	{
+
+		/*
+		 * Switch on the report ID
+		 * Conveniently, the reports have more information, the higher
+		 * the report number.  We can just fall through the case
+		 * statements if we start with the highest number report
+		 */
+		switch(device->buffer[0]){
+		case 5:
+			/* Pressure is 9 bits */
+			val =  ((u16)(device->buffer[8]) << 1);
+			val |= (u16)(device->buffer[7] >> 7);
+			input_report_abs(inputdev, ABS_PRESSURE,
+					 device->buffer[8]);
+
+			/* Mask out the Y tilt value used for pressure */
+			device->buffer[7] = (u8)((device->buffer[7]) & 0x7F);
+
+
+			/* Fall thru */
+		case 4:
+			/* Tilt */
+
+			/* Sign extend these 7 bit numbers.  */
+			if (device->buffer[6] & 0x40)
+				device->buffer[6] |= 0x80;
+
+			if (device->buffer[7] & 0x40)
+				device->buffer[7] |= 0x80;
+
+
+			valsigned = (device->buffer[6]);
+			input_report_abs(inputdev, ABS_TILT_X, (s32)valsigned);
+
+			valsigned = (device->buffer[7]);
+			input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned);
+
+			/* Fall thru */
+
+		case 2:
+		case 3:
+			/* Convert buttons, only 5 bits possible */
+			val = (device->buffer[5])&MASK_BUTTON;
+
+			/* We don't apply any meaning to the bitmask,
+			   just report */
+			input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+
+			/*  Fall thru */
+		case 1:
+
+			/* All reports have X and Y coords in the same place */
+			val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[1])));
+			input_report_abs(inputdev, ABS_X, val);
+
+			val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[3])));
+			input_report_abs(inputdev, ABS_Y, val);
+
+
+			/* Ditto for proximity bit */
+			if (device->buffer[5]& MASK_INRANGE){
+				val = 1;
+			}else{
+				val=0;
+			}
+			input_report_abs(inputdev, ABS_DISTANCE, val);
+
+
+			/* Report 1 is an exception to how we handle buttons */
+			/* Buttons are an index, not a bitmask */
+			if (device->buffer[0] == 1){
+
+				/* Convert buttons, 5 bit index */
+				/* Report value of index set as one,
+				   the rest as 0 */
+				val = device->buffer[5]& MASK_BUTTON;
+				dbg("======>>>>>>REPORT 1: val 0x%X(%d)",
+				    val,val);
+
+				/*
+				 * We don't apply any meaning to the button
+				 * index, just report it
+				 */
+				input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+
+
+			}
+
+			break;
+		case 7:
+			/* Menu blocks */
+			input_event(inputdev, EV_MSC, MSC_SCAN,
+				    device->buffer[1]);
+
+
+			break;
+
+		}
+
+
+	}
+	/* Other pid class */
+	if ((inputdev->id.product == PID_400 )||
+	    (inputdev->id.product == PID_401 ))
+	{
+
+		/* Report 2 */
+		if (device->buffer[0] == 2){
+			/* Menu blocks */
+			input_event(inputdev, EV_MSC, MSC_SCAN,
+				    device->buffer[1]);
+		}
+
+		/*  Report 1 */
+		if (device->buffer[0] == 1){
+			char buttonbyte;
+
+
+			/*  IF X max > 64K, we still a bit from the y report */
+			if (device->max_X > 0x10000){
+
+				val = (u16)(((u16)(device->buffer[2]<<8))|((u8)(device->buffer[1])));
+				val |= (u32)(((u8)device->buffer[3]&0x1)<< 16);
+
+				input_report_abs(inputdev, ABS_X, val);
+
+				le_buffer[0]  = (u8)((u8)(device->buffer[3])>>1);
+				le_buffer[0] |= (u8)((device->buffer[3]&0x1)<<7);
+
+				le_buffer[1]  = (u8)(device->buffer[4]>>1);
+				le_buffer[1] |= (u8)((device->buffer[5]&0x1)<<7);
+
+				val = le16_to_cpu(get_unaligned((__le16 *)(le_buffer)));
+
+				input_report_abs(inputdev, ABS_Y, val);
+
+
+				/*
+				 * Shift the button byte right by one to
+				 * make it look like the standard report
+				 */
+				buttonbyte = (device->buffer[5])>>1;
+			}else{
+
+				val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[1]))));
+				input_report_abs(inputdev, ABS_X, val);
+
+				val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[3]))));
+				input_report_abs(inputdev, ABS_Y, val);
+
+				buttonbyte = device->buffer[5];
+
+			}
+
+
+			/* BUTTONS and PROXIMITY */
+			if (buttonbyte& MASK_INRANGE){
+				val = 1;
+			}else{
+				val=0;
+			}
+			input_report_abs(inputdev, ABS_DISTANCE, val);
+
+			/* Convert buttons, only 4 bits possible */
+			val = buttonbyte&0x0F;
+#ifdef USE_BUTTONS
+			for ( i=0;i<5;i++){
+				input_report_key(inputdev, BTN_DIGI+i,val&(1<<i));
+			}
+#else
+			/* We don't apply any meaning to the bitmask, just report */
+			input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+#endif
+			/* TRANSDUCER */
+			input_report_abs(inputdev, ABS_MISC, device->buffer[6]);
+
+		}
+	}
+
+	/* Everybody gets report ID's */
+	input_event(inputdev, EV_MSC, MSC_RAW,  device->buffer[0]);
+
+	/* Sync it up */
+	input_sync(inputdev);
+
+ resubmit:
+	rc = usb_submit_urb(urbinfo, GFP_ATOMIC);
+	if (rc != 0) {
+		err("usb_submit_urb failed rc=0x%x",rc);
+	}
+
+}
+
+/*
+ *  The probe routine.  This is called when the kernel find the matching USB
+ *   vendor/product.  We do the following:
+ *
+ *    - Allocate mem for a local structure to manage the device
+ *    - Request a HID Report Descriptor from the device and parse it to
+ *      find out the device parameters
+ *    - Create an input device and assign it attributes
+ *   - Allocate an URB so the device can talk to us when the input
+ *      queue is open
+ */
+static int gtco_probe(struct usb_interface *usbinterface,
+		      const struct usb_device_id *id)
+{
+
+	struct gtco             *device = NULL;
+	char                    path[PATHLENGTH];
+	struct input_dev        *inputdev;
+	struct hid_descriptor   *hid_desc;
+	char                    *report;
+	int                     result=0, retry;
+	struct usb_endpoint_descriptor *endpoint;
+
+	/* Allocate memory for device structure */
+	device = kzalloc(sizeof(struct gtco), GFP_KERNEL);
+	if (device == NULL) {
+		err("No more memory");
+		return -ENOMEM;
+	}
+
+
+	device->inputdevice = input_allocate_device();
+	if (!device->inputdevice){
+		kfree(device);
+		err("No more memory");
+		return -ENOMEM;
+	}
+
+	/* Get pointer to the input device */
+	inputdev = device->inputdevice;
+
+	/* Save interface information */
+	device->usbdev     = usb_get_dev(interface_to_usbdev(usbinterface));
+
+
+	/* Allocate some data for incoming reports */
+	device->buffer = usb_buffer_alloc(device->usbdev, REPORT_MAX_SIZE,
+					   GFP_KERNEL, &(device->buf_dma));
+	if (!device->buffer){
+		input_free_device(device->inputdevice);
+		kfree(device);
+		err("No more memory");
+		return -ENOMEM;
+	}
+
+	/* Allocate URB for reports */
+	device->urbinfo = usb_alloc_urb(0, GFP_KERNEL);
+	if (!device->urbinfo) {
+		usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+				device->buffer, device->buf_dma);
+		input_free_device(device->inputdevice);
+		kfree(device);
+		err("No more memory");
+		return -ENOMEM;
+	}
+
+
+	/*
+	 * The endpoint is always altsetting 0, we know this since we know
+	 * this device only has one interrupt endpoint
+	 */
+	endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+
+	/* Some debug */
+	dbg("gtco # interfaces: %d",usbinterface->num_altsetting);
+	dbg("num endpoints:     %d",usbinterface->cur_altsetting->desc.bNumEndpoints);
+	dbg("interface class:   %d",usbinterface->cur_altsetting->desc.bInterfaceClass);
+	dbg("endpoint: attribute:0x%x type:0x%x",endpoint->bmAttributes,endpoint->bDescriptorType);
+	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
+		dbg("endpoint: we have interrupt endpoint\n");
+
+	dbg("endpoint extra len:%d ",usbinterface->altsetting[0].extralen);
+
+
+
+	/*
+	 * Find the HID descriptor so we can find out the size of the
+	 * HID report descriptor
+	 */
+	if (usb_get_extra_descriptor(usbinterface->cur_altsetting,
+				     HID_DEVICE_TYPE,&hid_desc) != 0){
+		err("Can't retrieve exta USB descriptor to get hid report descriptor length");
+		usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+				device->buffer, device->buf_dma);
+		input_free_device(device->inputdevice);
+		kfree(device);
+		return -EIO;
+	}
+
+	dbg("Extra descriptor success: type:%d  len:%d",
+	    hid_desc->bDescriptorType,  hid_desc->wDescriptorLength);
+
+	if (!(report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL))) {
+		usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+				device->buffer, device->buf_dma);
+
+		input_free_device(device->inputdevice);
+		kfree(device);
+		err("No more memory");
+		return -ENOMEM;
+	}
+
+	/* Couple of tries to get reply */
+	for (retry=0;retry<3;retry++) {
+		result = usb_control_msg(device->usbdev,
+					 usb_rcvctrlpipe(device->usbdev, 0),
+					 USB_REQ_GET_DESCRIPTOR,
+					 USB_RECIP_INTERFACE | USB_DIR_IN,
+					 (REPORT_DEVICE_TYPE << 8),
+					 0, /* interface */
+					 report,
+					 hid_desc->wDescriptorLength,
+					 5000); /* 5 secs */
+
+		if (result == hid_desc->wDescriptorLength)
+			break;
+	}
+
+	/* If we didn't get the report, fail */
+	dbg("usb_control_msg result: :%d", result);
+	if (result != hid_desc->wDescriptorLength){
+		kfree(report);
+		usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+				device->buffer, device->buf_dma);
+		input_free_device(device->inputdevice);
+		kfree(device);
+		err("Failed to get HID Report Descriptor of size: %d",
+		    hid_desc->wDescriptorLength);
+		return -EIO;
+	}
+
+
+	/* Now we parse the report */
+	parse_hid_report_descriptor(device,report,result);
+
+	/* Now we delete it */
+	kfree(report);
+
+	/* Create a device file node */
+	usb_make_path(device->usbdev, path, PATHLENGTH);
+	sprintf(device->usbpath, "%s/input0", path);
+
+
+	/* Set Input device functions */
+	inputdev->open     = gtco_input_open;
+	inputdev->close    = gtco_input_close;
+
+	/* Set input device information */
+	inputdev->name     = "GTCO_CalComp";
+	inputdev->phys     = device->usbpath;
+	inputdev->private  = device;
+
+
+	/* Now set up all the input device capabilities */
+	gtco_setup_caps(inputdev);
+
+	/* Set input device required ID information */
+	usb_to_input_id(device->usbdev, &device->inputdevice->id);
+	inputdev->cdev.dev = &usbinterface->dev;
+
+	/* Setup the URB, it will be posted later on open of input device */
+	endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+
+	usb_fill_int_urb(device->urbinfo,
+			 device->usbdev,
+			 usb_rcvintpipe(device->usbdev,
+					endpoint->bEndpointAddress),
+			 device->buffer,
+			 REPORT_MAX_SIZE,
+			 gtco_urb_callback,
+			 device,
+			 endpoint->bInterval);
+
+	device->urbinfo->transfer_dma = device->buf_dma;
+	device->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+
+	/* Save device pointer in USB interface device */
+	usb_set_intfdata(usbinterface, device);
+
+	/* All done, now register the input device */
+	input_register_device(inputdev);
+
+	info( "gtco driver created usb:  %s\n",  path);
+	return 0;
+
+}
+
+/*
+ *  This function is a standard USB function called when the USB device
+ *  is disconnected.  We will get rid of the URV, de-register the input
+ *  device, and free up allocated memory
+ */
+static void gtco_disconnect(struct usb_interface *interface)
+{
+
+	/* Grab private device ptr */
+	struct gtco    *device = usb_get_intfdata (interface);
+	struct input_dev *inputdev;
+
+	inputdev = device->inputdevice;
+
+	/* Now reverse all the registration stuff */
+	if (device) {
+		input_unregister_device(inputdev);
+		usb_kill_urb(device->urbinfo);
+		usb_free_urb(device->urbinfo);
+		usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+				device->buffer, device->buf_dma);
+		kfree(device);
+	}
+
+	info("gtco driver disconnected");
+}
+
+
+/*   STANDARD MODULE LOAD ROUTINES  */
+
+static struct usb_driver gtco_driverinfo_table = {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
+	.owner      = THIS_MODULE,
+#endif
+	.name       = "gtco",
+	.id_table   = gtco_usbid_table,
+	.probe      = gtco_probe,
+	.disconnect = gtco_disconnect,
+};
+/*
+ *  Register this module with the USB subsystem
+ */
+static int __init gtco_init(void)
+{
+	int rc;
+	rc = usb_register(&gtco_driverinfo_table);
+	if (rc) {
+		err("usb_register() failed rc=0x%x", rc);
+	}
+	printk("GTCO usb driver version: %s",GTCO_VERSION);
+	return rc;
+}
+
+/*
+ *   Deregister this module with the USB subsystem
+ */
+static void __exit gtco_exit(void)
+{
+	usb_deregister(&gtco_driverinfo_table);
+}
+
+module_init (gtco_init);
+module_exit (gtco_exit);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index e07a304..84983d1 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -768,6 +768,9 @@
 #define USB_VENDOR_ID_PANTHERLORD	0x0810
 #define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK	0x0001
 
+#define USB_VENDOR_ID_SONY			0x054c
+#define USB_DEVICE_ID_SONY_PS3_CONTROLLER	0x0268
+
 /*
  * Alphabetically sorted blacklist by quirk type.
  */
@@ -949,6 +952,8 @@
 
 	{ USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
 
+	{ USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER },
+
 	{ 0, 0 }
 };
 
@@ -1013,6 +1018,32 @@
 	}
 }
 
+/*
+ * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
+ * to "operational".  Without this, the ps3 controller will not report any
+ * events.
+ */
+static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
+{
+	int result;
+	char *buf = kmalloc(18, GFP_KERNEL);
+
+	if (!buf)
+		return;
+
+	result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+				 HID_REQ_GET_REPORT,
+				 USB_DIR_IN | USB_TYPE_CLASS |
+				 USB_RECIP_INTERFACE,
+				 (3 << 8) | 0xf2, ifnum, buf, 17,
+				 USB_CTRL_GET_TIMEOUT);
+
+	if (result < 0)
+		err("%s failed: %d\n", __func__, result);
+
+	kfree(buf);
+}
+
 static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 {
 	struct usb_host_interface *interface = intf->cur_altsetting;
@@ -1303,6 +1334,10 @@
 	if ((hid->claimed & HID_CLAIMED_INPUT))
 		hid_ff_init(hid);
 
+	if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)
+		hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
+			intf->cur_altsetting->desc.bInterfaceNumber);
+
 	printk(KERN_INFO);
 
 	if (hid->claimed & HID_CLAIMED_INPUT)
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index c941853..15c70bd 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -269,7 +269,7 @@
 	/* prevent a race condition with open() */
 	mutex_lock(&disconnect_mutex);
 
-	dev = (struct usb_idmouse *) file->private_data;
+	dev = file->private_data;
 
 	if (dev == NULL) {
 		mutex_unlock(&disconnect_mutex);
@@ -304,17 +304,15 @@
 static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count,
 				loff_t * ppos)
 {
-	struct usb_idmouse *dev;
+	struct usb_idmouse *dev = file->private_data;
 	int result;
 
-	dev = (struct usb_idmouse *) file->private_data;
-
 	/* lock this object */
-	down (&dev->sem);
+	down(&dev->sem);
 
 	/* verify that the device wasn't unplugged */
 	if (!dev->present) {
-		up (&dev->sem);
+		up(&dev->sem);
 		return -ENODEV;
 	}
 
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
index 384fa37..fdf6847 100644
--- a/drivers/usb/misc/rio500.c
+++ b/drivers/usb/misc/rio500.c
@@ -69,7 +69,7 @@
         char *obuf, *ibuf;              /* transfer buffers */
         char bulk_in_ep, bulk_out_ep;   /* Endpoint assignments */
         wait_queue_head_t wait_q;       /* for timeouts */
-	struct semaphore lock;          /* general race avoidance */
+	struct mutex lock;          /* general race avoidance */
 };
 
 static struct rio_usb_data rio_instance;
@@ -78,17 +78,17 @@
 {
 	struct rio_usb_data *rio = &rio_instance;
 
-	down(&(rio->lock));
+	mutex_lock(&(rio->lock));
 
 	if (rio->isopen || !rio->present) {
-		up(&(rio->lock));
+		mutex_unlock(&(rio->lock));
 		return -EBUSY;
 	}
 	rio->isopen = 1;
 
 	init_waitqueue_head(&rio->wait_q);
 
-	up(&(rio->lock));
+	mutex_unlock(&(rio->lock));
 
 	info("Rio opened.");
 
@@ -117,7 +117,7 @@
 	int retries;
 	int retval=0;
 
-	down(&(rio->lock));
+	mutex_lock(&(rio->lock));
         /* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
              rio->present == 0 ||
@@ -257,7 +257,7 @@
 
 
 err_out:
-	up(&(rio->lock));
+	mutex_unlock(&(rio->lock));
 	return retval;
 }
 
@@ -275,14 +275,17 @@
 	int result = 0;
 	int maxretry;
 	int errn = 0;
+	int intr;
 
-	down(&(rio->lock));
+	intr = mutex_lock_interruptible(&(rio->lock));
+	if (intr)
+		return -EINTR;
         /* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
              rio->present == 0 ||
              rio->rio_dev == NULL )
 	{
-		up(&(rio->lock));
+		mutex_unlock(&(rio->lock));
 		return -ENODEV;
 	}
 
@@ -305,7 +308,7 @@
 				goto error;
 			}
 			if (signal_pending(current)) {
-				up(&(rio->lock));
+				mutex_unlock(&(rio->lock));
 				return bytes_written ? bytes_written : -EINTR;
 			}
 
@@ -341,12 +344,12 @@
 		buffer += copy_size;
 	} while (count > 0);
 
-	up(&(rio->lock));
+	mutex_unlock(&(rio->lock));
 
 	return bytes_written ? bytes_written : -EIO;
 
 error:
-	up(&(rio->lock));
+	mutex_unlock(&(rio->lock));
 	return errn;
 }
 
@@ -361,14 +364,17 @@
 	int result;
 	int maxretry = 10;
 	char *ibuf;
+	int intr;
 
-	down(&(rio->lock));
+	intr = mutex_lock_interruptible(&(rio->lock));
+	if (intr)
+		return -EINTR;
 	/* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
              rio->present == 0 ||
              rio->rio_dev == NULL )
 	{
-		up(&(rio->lock));
+		mutex_unlock(&(rio->lock));
 		return -ENODEV;
 	}
 
@@ -379,11 +385,11 @@
 
 	while (count > 0) {
 		if (signal_pending(current)) {
-			up(&(rio->lock));
+			mutex_unlock(&(rio->lock));
 			return read_count ? read_count : -EINTR;
 		}
 		if (!rio->rio_dev) {
-			up(&(rio->lock));
+			mutex_unlock(&(rio->lock));
 			return -ENODEV;
 		}
 		this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
@@ -400,7 +406,7 @@
 			count = this_read = partial;
 		} else if (result == -ETIMEDOUT || result == 15) {	/* FIXME: 15 ??? */
 			if (!maxretry--) {
-				up(&(rio->lock));
+				mutex_unlock(&(rio->lock));
 				err("read_rio: maxretry timeout");
 				return -ETIME;
 			}
@@ -409,18 +415,18 @@
 			finish_wait(&rio->wait_q, &wait);
 			continue;
 		} else if (result != -EREMOTEIO) {
-			up(&(rio->lock));
+			mutex_unlock(&(rio->lock));
 			err("Read Whoops - result:%u partial:%u this_read:%u",
 			     result, partial, this_read);
 			return -EIO;
 		} else {
-			up(&(rio->lock));
+			mutex_unlock(&(rio->lock));
 			return (0);
 		}
 
 		if (this_read) {
 			if (copy_to_user(buffer, ibuf, this_read)) {
-				up(&(rio->lock));
+				mutex_unlock(&(rio->lock));
 				return -EFAULT;
 			}
 			count -= this_read;
@@ -428,7 +434,7 @@
 			buffer += this_read;
 		}
 	}
-	up(&(rio->lock));
+	mutex_unlock(&(rio->lock));
 	return read_count;
 }
 
@@ -480,7 +486,7 @@
 	}
 	dbg("probe_rio: ibuf address:%p", rio->ibuf);
 
-	init_MUTEX(&(rio->lock));
+	mutex_init(&(rio->lock));
 
 	usb_set_intfdata (intf, rio);
 	rio->present = 1;
@@ -496,12 +502,12 @@
 	if (rio) {
 		usb_deregister_dev(intf, &usb_rio_class);
 
-		down(&(rio->lock));
+		mutex_lock(&(rio->lock));
 		if (rio->isopen) {
 			rio->isopen = 0;
 			/* better let it finish - the release will do whats needed */
 			rio->rio_dev = NULL;
-			up(&(rio->lock));
+			mutex_unlock(&(rio->lock));
 			return;
 		}
 		kfree(rio->ibuf);
@@ -510,7 +516,7 @@
 		info("USB Rio disconnected.");
 
 		rio->present = 0;
-		up(&(rio->lock));
+		mutex_unlock(&(rio->lock));
 	}
 }
 
diff --git a/drivers/usb/mon/Makefile b/drivers/usb/mon/Makefile
index 3cf3ea3a..90c5953 100644
--- a/drivers/usb/mon/Makefile
+++ b/drivers/usb/mon/Makefile
@@ -2,7 +2,7 @@
 # Makefile for USB Core files and filesystem
 #
 
-usbmon-objs	:= mon_main.o mon_stat.o mon_text.o mon_dma.o
+usbmon-objs	:= mon_main.o mon_stat.o mon_text.o mon_bin.o mon_dma.o
 
 # This does not use CONFIG_USB_MON because we want this to use a tristate.
 obj-$(CONFIG_USB)	+= usbmon.o
diff --git a/drivers/usb/mon/mon_bin.c b/drivers/usb/mon/mon_bin.c
new file mode 100644
index 0000000..c01dfe6
--- /dev/null
+++ b/drivers/usb/mon/mon_bin.c
@@ -0,0 +1,1172 @@
+/*
+ * The USB Monitor, inspired by Dave Harding's USBMon.
+ *
+ * This is a binary format reader.
+ *
+ * Copyright (C) 2006 Paolo Abeni (paolo.abeni@email.it)
+ * Copyright (C) 2006 Pete Zaitcev (zaitcev@redhat.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/usb.h>
+#include <linux/poll.h>
+#include <linux/compat.h>
+#include <linux/mm.h>
+
+#include <asm/uaccess.h>
+
+#include "usb_mon.h"
+
+/*
+ * Defined by USB 2.0 clause 9.3, table 9.2.
+ */
+#define SETUP_LEN  8
+
+/* ioctl macros */
+#define MON_IOC_MAGIC 0x92
+
+#define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1)
+/* #2 used to be MON_IOCX_URB, removed before it got into Linus tree */
+#define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)
+#define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4)
+#define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5)
+#define MON_IOCX_GET   _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get)
+#define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch)
+#define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8)
+#ifdef CONFIG_COMPAT
+#define MON_IOCX_GET32 _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get32)
+#define MON_IOCX_MFETCH32 _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch32)
+#endif
+
+/*
+ * Some architectures have enormous basic pages (16KB for ia64, 64KB for ppc).
+ * But it's all right. Just use a simple way to make sure the chunk is never
+ * smaller than a page.
+ *
+ * N.B. An application does not know our chunk size.
+ *
+ * Woops, get_zeroed_page() returns a single page. I guess we're stuck with
+ * page-sized chunks for the time being.
+ */
+#define CHUNK_SIZE   PAGE_SIZE
+#define CHUNK_ALIGN(x)   (((x)+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1))
+
+/*
+ * The magic limit was calculated so that it allows the monitoring
+ * application to pick data once in two ticks. This way, another application,
+ * which presumably drives the bus, gets to hog CPU, yet we collect our data.
+ * If HZ is 100, a 480 mbit/s bus drives 614 KB every jiffy. USB has an
+ * enormous overhead built into the bus protocol, so we need about 1000 KB.
+ *
+ * This is still too much for most cases, where we just snoop a few
+ * descriptor fetches for enumeration. So, the default is a "reasonable"
+ * amount for systems with HZ=250 and incomplete bus saturation.
+ *
+ * XXX What about multi-megabyte URBs which take minutes to transfer?
+ */
+#define BUFF_MAX  CHUNK_ALIGN(1200*1024)
+#define BUFF_DFL   CHUNK_ALIGN(300*1024)
+#define BUFF_MIN     CHUNK_ALIGN(8*1024)
+
+/*
+ * The per-event API header (2 per URB).
+ *
+ * This structure is seen in userland as defined by the documentation.
+ */
+struct mon_bin_hdr {
+	u64 id;			/* URB ID - from submission to callback */
+	unsigned char type;	/* Same as in text API; extensible. */
+	unsigned char xfer_type;	/* ISO, Intr, Control, Bulk */
+	unsigned char epnum;	/* Endpoint number and transfer direction */
+	unsigned char devnum;	/* Device address */
+	unsigned short busnum;	/* Bus number */
+	char flag_setup;
+	char flag_data;
+	s64 ts_sec;		/* gettimeofday */
+	s32 ts_usec;		/* gettimeofday */
+	int status;
+	unsigned int len_urb;	/* Length of data (submitted or actual) */
+	unsigned int len_cap;	/* Delivered length */
+	unsigned char setup[SETUP_LEN];	/* Only for Control S-type */
+};
+
+/* per file statistic */
+struct mon_bin_stats {
+	u32 queued;
+	u32 dropped;
+};
+
+struct mon_bin_get {
+	struct mon_bin_hdr __user *hdr;	/* Only 48 bytes, not 64. */
+	void __user *data;
+	size_t alloc;		/* Length of data (can be zero) */
+};
+
+struct mon_bin_mfetch {
+	u32 __user *offvec;	/* Vector of events fetched */
+	u32 nfetch;		/* Number of events to fetch (out: fetched) */
+	u32 nflush;		/* Number of events to flush */
+};
+
+#ifdef CONFIG_COMPAT
+struct mon_bin_get32 {
+	u32 hdr32;
+	u32 data32;
+	u32 alloc32;
+};
+
+struct mon_bin_mfetch32 {
+        u32 offvec32;
+        u32 nfetch32;
+        u32 nflush32;
+};
+#endif
+
+/* Having these two values same prevents wrapping of the mon_bin_hdr */
+#define PKT_ALIGN   64
+#define PKT_SIZE    64
+
+/* max number of USB bus supported */
+#define MON_BIN_MAX_MINOR 128
+
+/*
+ * The buffer: map of used pages.
+ */
+struct mon_pgmap {
+	struct page *pg;
+	unsigned char *ptr;	/* XXX just use page_to_virt everywhere? */
+};
+
+/*
+ * This gets associated with an open file struct.
+ */
+struct mon_reader_bin {
+	/* The buffer: one per open. */
+	spinlock_t b_lock;		/* Protect b_cnt, b_in */
+	unsigned int b_size;		/* Current size of the buffer - bytes */
+	unsigned int b_cnt;		/* Bytes used */
+	unsigned int b_in, b_out;	/* Offsets into buffer - bytes */
+	unsigned int b_read;		/* Amount of read data in curr. pkt. */
+	struct mon_pgmap *b_vec;	/* The map array */
+	wait_queue_head_t b_wait;	/* Wait for data here */
+
+	struct mutex fetch_lock;	/* Protect b_read, b_out */
+	int mmap_active;
+
+	/* A list of these is needed for "bus 0". Some time later. */
+	struct mon_reader r;
+
+	/* Stats */
+	unsigned int cnt_lost;
+};
+
+static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp,
+    unsigned int offset)
+{
+	return (struct mon_bin_hdr *)
+	    (rp->b_vec[offset / CHUNK_SIZE].ptr + offset % CHUNK_SIZE);
+}
+
+#define MON_RING_EMPTY(rp)	((rp)->b_cnt == 0)
+
+static dev_t mon_bin_dev0;
+static struct cdev mon_bin_cdev;
+
+static void mon_buff_area_fill(const struct mon_reader_bin *rp,
+    unsigned int offset, unsigned int size);
+static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp);
+static int mon_alloc_buff(struct mon_pgmap *map, int npages);
+static void mon_free_buff(struct mon_pgmap *map, int npages);
+
+/*
+ * This is a "chunked memcpy". It does not manipulate any counters.
+ * But it returns the new offset for repeated application.
+ */
+unsigned int mon_copy_to_buff(const struct mon_reader_bin *this,
+    unsigned int off, const unsigned char *from, unsigned int length)
+{
+	unsigned int step_len;
+	unsigned char *buf;
+	unsigned int in_page;
+
+	while (length) {
+		/*
+		 * Determine step_len.
+		 */
+		step_len = length;
+		in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1));
+		if (in_page < step_len)
+			step_len = in_page;
+
+		/*
+		 * Copy data and advance pointers.
+		 */
+		buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE;
+		memcpy(buf, from, step_len);
+		if ((off += step_len) >= this->b_size) off = 0;
+		from += step_len;
+		length -= step_len;
+	}
+	return off;
+}
+
+/*
+ * This is a little worse than the above because it's "chunked copy_to_user".
+ * The return value is an error code, not an offset.
+ */
+static int copy_from_buf(const struct mon_reader_bin *this, unsigned int off,
+    char __user *to, int length)
+{
+	unsigned int step_len;
+	unsigned char *buf;
+	unsigned int in_page;
+
+	while (length) {
+		/*
+		 * Determine step_len.
+		 */
+		step_len = length;
+		in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1));
+		if (in_page < step_len)
+			step_len = in_page;
+
+		/*
+		 * Copy data and advance pointers.
+		 */
+		buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE;
+		if (copy_to_user(to, buf, step_len))
+			return -EINVAL;
+		if ((off += step_len) >= this->b_size) off = 0;
+		to += step_len;
+		length -= step_len;
+	}
+	return 0;
+}
+
+/*
+ * Allocate an (aligned) area in the buffer.
+ * This is called under b_lock.
+ * Returns ~0 on failure.
+ */
+static unsigned int mon_buff_area_alloc(struct mon_reader_bin *rp,
+    unsigned int size)
+{
+	unsigned int offset;
+
+	size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+	if (rp->b_cnt + size > rp->b_size)
+		return ~0;
+	offset = rp->b_in;
+	rp->b_cnt += size;
+	if ((rp->b_in += size) >= rp->b_size)
+		rp->b_in -= rp->b_size;
+	return offset;
+}
+
+/*
+ * This is the same thing as mon_buff_area_alloc, only it does not allow
+ * buffers to wrap. This is needed by applications which pass references
+ * into mmap-ed buffers up their stacks (libpcap can do that).
+ *
+ * Currently, we always have the header stuck with the data, although
+ * it is not strictly speaking necessary.
+ *
+ * When a buffer would wrap, we place a filler packet to mark the space.
+ */
+static unsigned int mon_buff_area_alloc_contiguous(struct mon_reader_bin *rp,
+    unsigned int size)
+{
+	unsigned int offset;
+	unsigned int fill_size;
+
+	size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+	if (rp->b_cnt + size > rp->b_size)
+		return ~0;
+	if (rp->b_in + size > rp->b_size) {
+		/*
+		 * This would wrap. Find if we still have space after
+		 * skipping to the end of the buffer. If we do, place
+		 * a filler packet and allocate a new packet.
+		 */
+		fill_size = rp->b_size - rp->b_in;
+		if (rp->b_cnt + size + fill_size > rp->b_size)
+			return ~0;
+		mon_buff_area_fill(rp, rp->b_in, fill_size);
+
+		offset = 0;
+		rp->b_in = size;
+		rp->b_cnt += size + fill_size;
+	} else if (rp->b_in + size == rp->b_size) {
+		offset = rp->b_in;
+		rp->b_in = 0;
+		rp->b_cnt += size;
+	} else {
+		offset = rp->b_in;
+		rp->b_in += size;
+		rp->b_cnt += size;
+	}
+	return offset;
+}
+
+/*
+ * Return a few (kilo-)bytes to the head of the buffer.
+ * This is used if a DMA fetch fails.
+ */
+static void mon_buff_area_shrink(struct mon_reader_bin *rp, unsigned int size)
+{
+
+	size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+	rp->b_cnt -= size;
+	if (rp->b_in < size)
+		rp->b_in += rp->b_size;
+	rp->b_in -= size;
+}
+
+/*
+ * This has to be called under both b_lock and fetch_lock, because
+ * it accesses both b_cnt and b_out.
+ */
+static void mon_buff_area_free(struct mon_reader_bin *rp, unsigned int size)
+{
+
+	size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+	rp->b_cnt -= size;
+	if ((rp->b_out += size) >= rp->b_size)
+		rp->b_out -= rp->b_size;
+}
+
+static void mon_buff_area_fill(const struct mon_reader_bin *rp,
+    unsigned int offset, unsigned int size)
+{
+	struct mon_bin_hdr *ep;
+
+	ep = MON_OFF2HDR(rp, offset);
+	memset(ep, 0, PKT_SIZE);
+	ep->type = '@';
+	ep->len_cap = size - PKT_SIZE;
+}
+
+static inline char mon_bin_get_setup(unsigned char *setupb,
+    const struct urb *urb, char ev_type)
+{
+
+	if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+		return '-';
+
+	if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)
+		return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN);
+	if (urb->setup_packet == NULL)
+		return 'Z';
+
+	memcpy(setupb, urb->setup_packet, SETUP_LEN);
+	return 0;
+}
+
+static char mon_bin_get_data(const struct mon_reader_bin *rp,
+    unsigned int offset, struct urb *urb, unsigned int length)
+{
+
+	if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) {
+		mon_dmapeek_vec(rp, offset, urb->transfer_dma, length);
+		return 0;
+	}
+
+	if (urb->transfer_buffer == NULL)
+		return 'Z';
+
+	mon_copy_to_buff(rp, offset, urb->transfer_buffer, length);
+	return 0;
+}
+
+static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
+    char ev_type)
+{
+	unsigned long flags;
+	struct timeval ts;
+	unsigned int urb_length;
+	unsigned int offset;
+	unsigned int length;
+	struct mon_bin_hdr *ep;
+	char data_tag = 0;
+
+	do_gettimeofday(&ts);
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+
+	/*
+	 * Find the maximum allowable length, then allocate space.
+	 */
+	urb_length = (ev_type == 'S') ?
+	    urb->transfer_buffer_length : urb->actual_length;
+	length = urb_length;
+
+	if (length >= rp->b_size/5)
+		length = rp->b_size/5;
+
+	if (usb_pipein(urb->pipe)) {
+		if (ev_type == 'S') {
+			length = 0;
+			data_tag = '<';
+		}
+	} else {
+		if (ev_type == 'C') {
+			length = 0;
+			data_tag = '>';
+		}
+	}
+
+	if (rp->mmap_active)
+		offset = mon_buff_area_alloc_contiguous(rp, length + PKT_SIZE);
+	else
+		offset = mon_buff_area_alloc(rp, length + PKT_SIZE);
+	if (offset == ~0) {
+		rp->cnt_lost++;
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+		return;
+	}
+
+	ep = MON_OFF2HDR(rp, offset);
+	if ((offset += PKT_SIZE) >= rp->b_size) offset = 0;
+
+	/*
+	 * Fill the allocated area.
+	 */
+	memset(ep, 0, PKT_SIZE);
+	ep->type = ev_type;
+	ep->xfer_type = usb_pipetype(urb->pipe);
+	/* We use the fact that usb_pipein() returns 0x80 */
+	ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
+	ep->devnum = usb_pipedevice(urb->pipe);
+	ep->busnum = rp->r.m_bus->u_bus->busnum;
+	ep->id = (unsigned long) urb;
+	ep->ts_sec = ts.tv_sec;
+	ep->ts_usec = ts.tv_usec;
+	ep->status = urb->status;
+	ep->len_urb = urb_length;
+	ep->len_cap = length;
+
+	ep->flag_setup = mon_bin_get_setup(ep->setup, urb, ev_type);
+	if (length != 0) {
+		ep->flag_data = mon_bin_get_data(rp, offset, urb, length);
+		if (ep->flag_data != 0) {	/* Yes, it's 0x00, not '0' */
+			ep->len_cap = 0;
+			mon_buff_area_shrink(rp, length);
+		}
+	} else {
+		ep->flag_data = data_tag;
+	}
+
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+
+	wake_up(&rp->b_wait);
+}
+
+static void mon_bin_submit(void *data, struct urb *urb)
+{
+	struct mon_reader_bin *rp = data;
+	mon_bin_event(rp, urb, 'S');
+}
+
+static void mon_bin_complete(void *data, struct urb *urb)
+{
+	struct mon_reader_bin *rp = data;
+	mon_bin_event(rp, urb, 'C');
+}
+
+static void mon_bin_error(void *data, struct urb *urb, int error)
+{
+	struct mon_reader_bin *rp = data;
+	unsigned long flags;
+	unsigned int offset;
+	struct mon_bin_hdr *ep;
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+
+	offset = mon_buff_area_alloc(rp, PKT_SIZE);
+	if (offset == ~0) {
+		/* Not incrementing cnt_lost. Just because. */
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+		return;
+	}
+
+	ep = MON_OFF2HDR(rp, offset);
+
+	memset(ep, 0, PKT_SIZE);
+	ep->type = 'E';
+	ep->xfer_type = usb_pipetype(urb->pipe);
+	/* We use the fact that usb_pipein() returns 0x80 */
+	ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
+	ep->devnum = usb_pipedevice(urb->pipe);
+	ep->busnum = rp->r.m_bus->u_bus->busnum;
+	ep->id = (unsigned long) urb;
+	ep->status = error;
+
+	ep->flag_setup = '-';
+	ep->flag_data = 'E';
+
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+
+	wake_up(&rp->b_wait);
+}
+
+static int mon_bin_open(struct inode *inode, struct file *file)
+{
+	struct mon_bus *mbus;
+	struct usb_bus *ubus;
+	struct mon_reader_bin *rp;
+	size_t size;
+	int rc;
+
+	mutex_lock(&mon_lock);
+	if ((mbus = mon_bus_lookup(iminor(inode))) == NULL) {
+		mutex_unlock(&mon_lock);
+		return -ENODEV;
+	}
+	if ((ubus = mbus->u_bus) == NULL) {
+		printk(KERN_ERR TAG ": consistency error on open\n");
+		mutex_unlock(&mon_lock);
+		return -ENODEV;
+	}
+
+	rp = kzalloc(sizeof(struct mon_reader_bin), GFP_KERNEL);
+	if (rp == NULL) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	spin_lock_init(&rp->b_lock);
+	init_waitqueue_head(&rp->b_wait);
+	mutex_init(&rp->fetch_lock);
+
+	rp->b_size = BUFF_DFL;
+
+	size = sizeof(struct mon_pgmap) * (rp->b_size/CHUNK_SIZE);
+	if ((rp->b_vec = kzalloc(size, GFP_KERNEL)) == NULL) {
+		rc = -ENOMEM;
+		goto err_allocvec;
+	}
+
+	if ((rc = mon_alloc_buff(rp->b_vec, rp->b_size/CHUNK_SIZE)) < 0)
+		goto err_allocbuff;
+
+	rp->r.m_bus = mbus;
+	rp->r.r_data = rp;
+	rp->r.rnf_submit = mon_bin_submit;
+	rp->r.rnf_error = mon_bin_error;
+	rp->r.rnf_complete = mon_bin_complete;
+
+	mon_reader_add(mbus, &rp->r);
+
+	file->private_data = rp;
+	mutex_unlock(&mon_lock);
+	return 0;
+
+err_allocbuff:
+	kfree(rp->b_vec);
+err_allocvec:
+	kfree(rp);
+err_alloc:
+	mutex_unlock(&mon_lock);
+	return rc;
+}
+
+/*
+ * Extract an event from buffer and copy it to user space.
+ * Wait if there is no event ready.
+ * Returns zero or error.
+ */
+static int mon_bin_get_event(struct file *file, struct mon_reader_bin *rp,
+    struct mon_bin_hdr __user *hdr, void __user *data, unsigned int nbytes)
+{
+	unsigned long flags;
+	struct mon_bin_hdr *ep;
+	size_t step_len;
+	unsigned int offset;
+	int rc;
+
+	mutex_lock(&rp->fetch_lock);
+
+	if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+		mutex_unlock(&rp->fetch_lock);
+		return rc;
+	}
+
+	ep = MON_OFF2HDR(rp, rp->b_out);
+
+	if (copy_to_user(hdr, ep, sizeof(struct mon_bin_hdr))) {
+		mutex_unlock(&rp->fetch_lock);
+		return -EFAULT;
+	}
+
+	step_len = min(ep->len_cap, nbytes);
+	if ((offset = rp->b_out + PKT_SIZE) >= rp->b_size) offset = 0;
+
+	if (copy_from_buf(rp, offset, data, step_len)) {
+		mutex_unlock(&rp->fetch_lock);
+		return -EFAULT;
+	}
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+	mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+	rp->b_read = 0;
+
+	mutex_unlock(&rp->fetch_lock);
+	return 0;
+}
+
+static int mon_bin_release(struct inode *inode, struct file *file)
+{
+	struct mon_reader_bin *rp = file->private_data;
+	struct mon_bus* mbus = rp->r.m_bus;
+
+	mutex_lock(&mon_lock);
+
+	if (mbus->nreaders <= 0) {
+		printk(KERN_ERR TAG ": consistency error on close\n");
+		mutex_unlock(&mon_lock);
+		return 0;
+	}
+	mon_reader_del(mbus, &rp->r);
+
+	mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE);
+	kfree(rp->b_vec);
+	kfree(rp);
+
+	mutex_unlock(&mon_lock);
+	return 0;
+}
+
+static ssize_t mon_bin_read(struct file *file, char __user *buf,
+    size_t nbytes, loff_t *ppos)
+{
+	struct mon_reader_bin *rp = file->private_data;
+	unsigned long flags;
+	struct mon_bin_hdr *ep;
+	unsigned int offset;
+	size_t step_len;
+	char *ptr;
+	ssize_t done = 0;
+	int rc;
+
+	mutex_lock(&rp->fetch_lock);
+
+	if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+		mutex_unlock(&rp->fetch_lock);
+		return rc;
+	}
+
+	ep = MON_OFF2HDR(rp, rp->b_out);
+
+	if (rp->b_read < sizeof(struct mon_bin_hdr)) {
+		step_len = min(nbytes, sizeof(struct mon_bin_hdr) - rp->b_read);
+		ptr = ((char *)ep) + rp->b_read;
+		if (step_len && copy_to_user(buf, ptr, step_len)) {
+			mutex_unlock(&rp->fetch_lock);
+			return -EFAULT;
+		}
+		nbytes -= step_len;
+		buf += step_len;
+		rp->b_read += step_len;
+		done += step_len;
+	}
+
+	if (rp->b_read >= sizeof(struct mon_bin_hdr)) {
+		step_len = min(nbytes, (size_t)ep->len_cap);
+		offset = rp->b_out + PKT_SIZE;
+		offset += rp->b_read - sizeof(struct mon_bin_hdr);
+		if (offset >= rp->b_size)
+			offset -= rp->b_size;
+		if (copy_from_buf(rp, offset, buf, step_len)) {
+			mutex_unlock(&rp->fetch_lock);
+			return -EFAULT;
+		}
+		nbytes -= step_len;
+		buf += step_len;
+		rp->b_read += step_len;
+		done += step_len;
+	}
+
+	/*
+	 * Check if whole packet was read, and if so, jump to the next one.
+	 */
+	if (rp->b_read >= sizeof(struct mon_bin_hdr) + ep->len_cap) {
+		spin_lock_irqsave(&rp->b_lock, flags);
+		mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+		rp->b_read = 0;
+	}
+
+	mutex_unlock(&rp->fetch_lock);
+	return done;
+}
+
+/*
+ * Remove at most nevents from chunked buffer.
+ * Returns the number of removed events.
+ */
+static int mon_bin_flush(struct mon_reader_bin *rp, unsigned nevents)
+{
+	unsigned long flags;
+	struct mon_bin_hdr *ep;
+	int i;
+
+	mutex_lock(&rp->fetch_lock);
+	spin_lock_irqsave(&rp->b_lock, flags);
+	for (i = 0; i < nevents; ++i) {
+		if (MON_RING_EMPTY(rp))
+			break;
+
+		ep = MON_OFF2HDR(rp, rp->b_out);
+		mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+	}
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+	rp->b_read = 0;
+	mutex_unlock(&rp->fetch_lock);
+	return i;
+}
+
+/*
+ * Fetch at most max event offsets into the buffer and put them into vec.
+ * The events are usually freed later with mon_bin_flush.
+ * Return the effective number of events fetched.
+ */
+static int mon_bin_fetch(struct file *file, struct mon_reader_bin *rp,
+    u32 __user *vec, unsigned int max)
+{
+	unsigned int cur_out;
+	unsigned int bytes, avail;
+	unsigned int size;
+	unsigned int nevents;
+	struct mon_bin_hdr *ep;
+	unsigned long flags;
+	int rc;
+
+	mutex_lock(&rp->fetch_lock);
+
+	if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+		mutex_unlock(&rp->fetch_lock);
+		return rc;
+	}
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+	avail = rp->b_cnt;
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+
+	cur_out = rp->b_out;
+	nevents = 0;
+	bytes = 0;
+	while (bytes < avail) {
+		if (nevents >= max)
+			break;
+
+		ep = MON_OFF2HDR(rp, cur_out);
+		if (put_user(cur_out, &vec[nevents])) {
+			mutex_unlock(&rp->fetch_lock);
+			return -EFAULT;
+		}
+
+		nevents++;
+		size = ep->len_cap + PKT_SIZE;
+		size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+		if ((cur_out += size) >= rp->b_size)
+			cur_out -= rp->b_size;
+		bytes += size;
+	}
+
+	mutex_unlock(&rp->fetch_lock);
+	return nevents;
+}
+
+/*
+ * Count events. This is almost the same as the above mon_bin_fetch,
+ * only we do not store offsets into user vector, and we have no limit.
+ */
+static int mon_bin_queued(struct mon_reader_bin *rp)
+{
+	unsigned int cur_out;
+	unsigned int bytes, avail;
+	unsigned int size;
+	unsigned int nevents;
+	struct mon_bin_hdr *ep;
+	unsigned long flags;
+
+	mutex_lock(&rp->fetch_lock);
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+	avail = rp->b_cnt;
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+
+	cur_out = rp->b_out;
+	nevents = 0;
+	bytes = 0;
+	while (bytes < avail) {
+		ep = MON_OFF2HDR(rp, cur_out);
+
+		nevents++;
+		size = ep->len_cap + PKT_SIZE;
+		size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+		if ((cur_out += size) >= rp->b_size)
+			cur_out -= rp->b_size;
+		bytes += size;
+	}
+
+	mutex_unlock(&rp->fetch_lock);
+	return nevents;
+}
+
+/*
+ */
+static int mon_bin_ioctl(struct inode *inode, struct file *file,
+    unsigned int cmd, unsigned long arg)
+{
+	struct mon_reader_bin *rp = file->private_data;
+	// struct mon_bus* mbus = rp->r.m_bus;
+	int ret = 0;
+	struct mon_bin_hdr *ep;
+	unsigned long flags;
+
+	switch (cmd) {
+
+	case MON_IOCQ_URB_LEN:
+		/*
+		 * N.B. This only returns the size of data, without the header.
+		 */
+		spin_lock_irqsave(&rp->b_lock, flags);
+		if (!MON_RING_EMPTY(rp)) {
+			ep = MON_OFF2HDR(rp, rp->b_out);
+			ret = ep->len_cap;
+		}
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+		break;
+
+	case MON_IOCQ_RING_SIZE:
+		ret = rp->b_size;
+		break;
+
+	case MON_IOCT_RING_SIZE:
+		/*
+		 * Changing the buffer size will flush it's contents; the new
+		 * buffer is allocated before releasing the old one to be sure
+		 * the device will stay functional also in case of memory
+		 * pressure.
+		 */
+		{
+		int size;
+		struct mon_pgmap *vec;
+
+		if (arg < BUFF_MIN || arg > BUFF_MAX)
+			return -EINVAL;
+
+		size = CHUNK_ALIGN(arg);
+		if ((vec = kzalloc(sizeof(struct mon_pgmap) * (size/CHUNK_SIZE),
+		    GFP_KERNEL)) == NULL) {
+			ret = -ENOMEM;
+			break;
+		}
+
+		ret = mon_alloc_buff(vec, size/CHUNK_SIZE);
+		if (ret < 0) {
+			kfree(vec);
+			break;
+		}
+
+		mutex_lock(&rp->fetch_lock);
+		spin_lock_irqsave(&rp->b_lock, flags);
+		mon_free_buff(rp->b_vec, size/CHUNK_SIZE);
+		kfree(rp->b_vec);
+		rp->b_vec  = vec;
+		rp->b_size = size;
+		rp->b_read = rp->b_in = rp->b_out = rp->b_cnt = 0;
+		rp->cnt_lost = 0;
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+		mutex_unlock(&rp->fetch_lock);
+		}
+		break;
+
+	case MON_IOCH_MFLUSH:
+		ret = mon_bin_flush(rp, arg);
+		break;
+
+	case MON_IOCX_GET:
+		{
+		struct mon_bin_get getb;
+
+		if (copy_from_user(&getb, (void __user *)arg,
+					    sizeof(struct mon_bin_get)))
+			return -EFAULT;
+
+		if (getb.alloc > 0x10000000)	/* Want to cast to u32 */
+			return -EINVAL;
+		ret = mon_bin_get_event(file, rp,
+			  getb.hdr, getb.data, (unsigned int)getb.alloc);
+		}
+		break;
+
+#ifdef CONFIG_COMPAT
+	case MON_IOCX_GET32: {
+		struct mon_bin_get32 getb;
+
+		if (copy_from_user(&getb, (void __user *)arg,
+					    sizeof(struct mon_bin_get32)))
+			return -EFAULT;
+
+		ret = mon_bin_get_event(file, rp,
+		    compat_ptr(getb.hdr32), compat_ptr(getb.data32),
+		    getb.alloc32);
+		}
+		break;
+#endif
+
+	case MON_IOCX_MFETCH:
+		{
+		struct mon_bin_mfetch mfetch;
+		struct mon_bin_mfetch __user *uptr;
+
+		uptr = (struct mon_bin_mfetch __user *)arg;
+
+		if (copy_from_user(&mfetch, uptr, sizeof(mfetch)))
+			return -EFAULT;
+
+		if (mfetch.nflush) {
+			ret = mon_bin_flush(rp, mfetch.nflush);
+			if (ret < 0)
+				return ret;
+			if (put_user(ret, &uptr->nflush))
+				return -EFAULT;
+		}
+		ret = mon_bin_fetch(file, rp, mfetch.offvec, mfetch.nfetch);
+		if (ret < 0)
+			return ret;
+		if (put_user(ret, &uptr->nfetch))
+			return -EFAULT;
+		ret = 0;
+		}
+		break;
+
+#ifdef CONFIG_COMPAT
+	case MON_IOCX_MFETCH32:
+		{
+		struct mon_bin_mfetch32 mfetch;
+		struct mon_bin_mfetch32 __user *uptr;
+
+		uptr = (struct mon_bin_mfetch32 __user *) compat_ptr(arg);
+
+		if (copy_from_user(&mfetch, uptr, sizeof(mfetch)))
+			return -EFAULT;
+
+		if (mfetch.nflush32) {
+			ret = mon_bin_flush(rp, mfetch.nflush32);
+			if (ret < 0)
+				return ret;
+			if (put_user(ret, &uptr->nflush32))
+				return -EFAULT;
+		}
+		ret = mon_bin_fetch(file, rp, compat_ptr(mfetch.offvec32),
+		    mfetch.nfetch32);
+		if (ret < 0)
+			return ret;
+		if (put_user(ret, &uptr->nfetch32))
+			return -EFAULT;
+		ret = 0;
+		}
+		break;
+#endif
+
+	case MON_IOCG_STATS: {
+		struct mon_bin_stats __user *sp;
+		unsigned int nevents;
+		unsigned int ndropped;
+
+		spin_lock_irqsave(&rp->b_lock, flags);
+		ndropped = rp->cnt_lost;
+		rp->cnt_lost = 0;
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+		nevents = mon_bin_queued(rp);
+
+		sp = (struct mon_bin_stats __user *)arg;
+		if (put_user(rp->cnt_lost, &sp->dropped))
+			return -EFAULT;
+		if (put_user(nevents, &sp->queued))
+			return -EFAULT;
+
+		}
+		break;
+
+	default:
+		return -ENOTTY;
+	}
+
+	return ret;
+}
+
+static unsigned int
+mon_bin_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct mon_reader_bin *rp = file->private_data;
+	unsigned int mask = 0;
+	unsigned long flags;
+
+	if (file->f_mode & FMODE_READ)
+		poll_wait(file, &rp->b_wait, wait);
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+	if (!MON_RING_EMPTY(rp))
+		mask |= POLLIN | POLLRDNORM;    /* readable */
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+	return mask;
+}
+
+/*
+ * open and close: just keep track of how many times the device is
+ * mapped, to use the proper memory allocation function.
+ */
+static void mon_bin_vma_open(struct vm_area_struct *vma)
+{
+	struct mon_reader_bin *rp = vma->vm_private_data;
+	rp->mmap_active++;
+}
+
+static void mon_bin_vma_close(struct vm_area_struct *vma)
+{
+	struct mon_reader_bin *rp = vma->vm_private_data;
+	rp->mmap_active--;
+}
+
+/*
+ * Map ring pages to user space.
+ */
+struct page *mon_bin_vma_nopage(struct vm_area_struct *vma,
+                                unsigned long address, int *type)
+{
+	struct mon_reader_bin *rp = vma->vm_private_data;
+	unsigned long offset, chunk_idx;
+	struct page *pageptr;
+
+	offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
+	if (offset >= rp->b_size)
+		return NOPAGE_SIGBUS;
+	chunk_idx = offset / CHUNK_SIZE;
+	pageptr = rp->b_vec[chunk_idx].pg;
+	get_page(pageptr);
+	if (type)
+		*type = VM_FAULT_MINOR;
+	return pageptr;
+}
+
+struct vm_operations_struct mon_bin_vm_ops = {
+	.open =     mon_bin_vma_open,
+	.close =    mon_bin_vma_close,
+	.nopage =   mon_bin_vma_nopage,
+};
+
+int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	/* don't do anything here: "nopage" will set up page table entries */
+	vma->vm_ops = &mon_bin_vm_ops;
+	vma->vm_flags |= VM_RESERVED;
+	vma->vm_private_data = filp->private_data;
+	mon_bin_vma_open(vma);
+	return 0;
+}
+
+struct file_operations mon_fops_binary = {
+	.owner =	THIS_MODULE,
+	.open =		mon_bin_open,
+	.llseek =	no_llseek,
+	.read =		mon_bin_read,
+	/* .write =	mon_text_write, */
+	.poll =		mon_bin_poll,
+	.ioctl =	mon_bin_ioctl,
+	.release =	mon_bin_release,
+};
+
+static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp)
+{
+	DECLARE_WAITQUEUE(waita, current);
+	unsigned long flags;
+
+	add_wait_queue(&rp->b_wait, &waita);
+	set_current_state(TASK_INTERRUPTIBLE);
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+	while (MON_RING_EMPTY(rp)) {
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+
+		if (file->f_flags & O_NONBLOCK) {
+			set_current_state(TASK_RUNNING);
+			remove_wait_queue(&rp->b_wait, &waita);
+			return -EWOULDBLOCK; /* Same as EAGAIN in Linux */
+		}
+		schedule();
+		if (signal_pending(current)) {
+			remove_wait_queue(&rp->b_wait, &waita);
+			return -EINTR;
+		}
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		spin_lock_irqsave(&rp->b_lock, flags);
+	}
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&rp->b_wait, &waita);
+	return 0;
+}
+
+static int mon_alloc_buff(struct mon_pgmap *map, int npages)
+{
+	int n;
+	unsigned long vaddr;
+
+	for (n = 0; n < npages; n++) {
+		vaddr = get_zeroed_page(GFP_KERNEL);
+		if (vaddr == 0) {
+			while (n-- != 0)
+				free_page((unsigned long) map[n].ptr);
+			return -ENOMEM;
+		}
+		map[n].ptr = (unsigned char *) vaddr;
+		map[n].pg = virt_to_page(vaddr);
+	}
+	return 0;
+}
+
+static void mon_free_buff(struct mon_pgmap *map, int npages)
+{
+	int n;
+
+	for (n = 0; n < npages; n++)
+		free_page((unsigned long) map[n].ptr);
+}
+
+int __init mon_bin_init(void)
+{
+	int rc;
+
+	rc = alloc_chrdev_region(&mon_bin_dev0, 0, MON_BIN_MAX_MINOR, "usbmon");
+	if (rc < 0)
+		goto err_dev;
+
+	cdev_init(&mon_bin_cdev, &mon_fops_binary);
+	mon_bin_cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&mon_bin_cdev, mon_bin_dev0, MON_BIN_MAX_MINOR);
+	if (rc < 0)
+		goto err_add;
+
+	return 0;
+
+err_add:
+	unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
+err_dev:
+	return rc;
+}
+
+void __exit mon_bin_exit(void)
+{
+	cdev_del(&mon_bin_cdev);
+	unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
+}
diff --git a/drivers/usb/mon/mon_dma.c b/drivers/usb/mon/mon_dma.c
index ddcfc01..140cc80 100644
--- a/drivers/usb/mon/mon_dma.c
+++ b/drivers/usb/mon/mon_dma.c
@@ -48,6 +48,36 @@
 	local_irq_restore(flags);
 	return 0;
 }
+
+void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+    unsigned int offset, dma_addr_t dma_addr, unsigned int length)
+{
+	unsigned long flags;
+	unsigned int step_len;
+	struct page *pg;
+	unsigned char *map;
+	unsigned long page_off, page_len;
+
+	local_irq_save(flags);
+	while (length) {
+		/* compute number of bytes we are going to copy in this page */
+		step_len = length;
+		page_off = dma_addr & (PAGE_SIZE-1);
+		page_len = PAGE_SIZE - page_off;
+		if (page_len < step_len)
+			step_len = page_len;
+
+		/* copy data and advance pointers */
+		pg = phys_to_page(dma_addr);
+		map = kmap_atomic(pg, KM_IRQ0);
+		offset = mon_copy_to_buff(rp, offset, map + page_off, step_len);
+		kunmap_atomic(map, KM_IRQ0);
+		dma_addr += step_len;
+		length -= step_len;
+	}
+	local_irq_restore(flags);
+}
+
 #endif /* __i386__ */
 
 #ifndef MON_HAS_UNMAP
@@ -55,4 +85,11 @@
 {
 	return 'D';
 }
-#endif
+
+void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+    unsigned int offset, dma_addr_t dma_addr, unsigned int length)
+{
+	;
+}
+
+#endif /* MON_HAS_UNMAP */
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index 394bbf2..c9739e7 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -9,7 +9,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/usb.h>
-#include <linux/debugfs.h>
 #include <linux/smp_lock.h>
 #include <linux/notifier.h>
 #include <linux/mutex.h>
@@ -22,11 +21,10 @@
 static void mon_stop(struct mon_bus *mbus);
 static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
 static void mon_bus_drop(struct kref *r);
-static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus);
+static void mon_bus_init(struct usb_bus *ubus);
 
 DEFINE_MUTEX(mon_lock);
 
-static struct dentry *mon_dir;		/* /dbg/usbmon */
 static LIST_HEAD(mon_buses);		/* All buses we know: struct mon_bus */
 
 /*
@@ -200,7 +198,7 @@
  */
 static void mon_bus_add(struct usb_bus *ubus)
 {
-	mon_bus_init(mon_dir, ubus);
+	mon_bus_init(ubus);
 }
 
 /*
@@ -212,8 +210,8 @@
 
 	mutex_lock(&mon_lock);
 	list_del(&mbus->bus_link);
-	debugfs_remove(mbus->dent_t);
-	debugfs_remove(mbus->dent_s);
+	if (mbus->text_inited)
+		mon_text_del(mbus);
 
 	mon_dissolve(mbus, ubus);
 	kref_put(&mbus->ref, mon_bus_drop);
@@ -281,13 +279,9 @@
  *  - refcount USB bus struct
  *  - link
  */
-static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
+static void mon_bus_init(struct usb_bus *ubus)
 {
-	struct dentry *d;
 	struct mon_bus *mbus;
-	enum { NAMESZ = 10 };
-	char name[NAMESZ];
-	int rc;
 
 	if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
 		goto err_alloc;
@@ -303,57 +297,54 @@
 	ubus->mon_bus = mbus;
 	mbus->uses_dma = ubus->uses_dma;
 
-	rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
-	if (rc <= 0 || rc >= NAMESZ)
-		goto err_print_t;
-	d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_text);
-	if (d == NULL)
-		goto err_create_t;
-	mbus->dent_t = d;
-
-	rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
-	if (rc <= 0 || rc >= NAMESZ)
-		goto err_print_s;
-	d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_stat);
-	if (d == NULL)
-		goto err_create_s;
-	mbus->dent_s = d;
+	mbus->text_inited = mon_text_add(mbus, ubus);
+	// mon_bin_add(...)
 
 	mutex_lock(&mon_lock);
 	list_add_tail(&mbus->bus_link, &mon_buses);
 	mutex_unlock(&mon_lock);
 	return;
 
-err_create_s:
-err_print_s:
-	debugfs_remove(mbus->dent_t);
-err_create_t:
-err_print_t:
-	kfree(mbus);
 err_alloc:
 	return;
 }
 
+/*
+ * Search a USB bus by number. Notice that USB bus numbers start from one,
+ * which we may later use to identify "all" with zero.
+ *
+ * This function must be called with mon_lock held.
+ *
+ * This is obviously inefficient and may be revised in the future.
+ */
+struct mon_bus *mon_bus_lookup(unsigned int num)
+{
+	struct list_head *p;
+	struct mon_bus *mbus;
+
+	list_for_each (p, &mon_buses) {
+		mbus = list_entry(p, struct mon_bus, bus_link);
+		if (mbus->u_bus->busnum == num) {
+			return mbus;
+		}
+	}
+	return NULL;
+}
+
 static int __init mon_init(void)
 {
 	struct usb_bus *ubus;
-	struct dentry *mondir;
+	int rc;
 
-	mondir = debugfs_create_dir("usbmon", NULL);
-	if (IS_ERR(mondir)) {
-		printk(KERN_NOTICE TAG ": debugfs is not available\n");
-		return -ENODEV;
-	}
-	if (mondir == NULL) {
-		printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
-		return -ENODEV;
-	}
-	mon_dir = mondir;
+	if ((rc = mon_text_init()) != 0)
+		goto err_text;
+	if ((rc = mon_bin_init()) != 0)
+		goto err_bin;
 
 	if (usb_mon_register(&mon_ops_0) != 0) {
 		printk(KERN_NOTICE TAG ": unable to register with the core\n");
-		debugfs_remove(mondir);
-		return -ENODEV;
+		rc = -ENODEV;
+		goto err_reg;
 	}
 	// MOD_INC_USE_COUNT(which_module?);
 
@@ -361,10 +352,17 @@
 
 	mutex_lock(&usb_bus_list_lock);
 	list_for_each_entry (ubus, &usb_bus_list, bus_list) {
-		mon_bus_init(mondir, ubus);
+		mon_bus_init(ubus);
 	}
 	mutex_unlock(&usb_bus_list_lock);
 	return 0;
+
+err_reg:
+	mon_bin_exit();
+err_bin:
+	mon_text_exit();
+err_text:
+	return rc;
 }
 
 static void __exit mon_exit(void)
@@ -381,8 +379,8 @@
 		mbus = list_entry(p, struct mon_bus, bus_link);
 		list_del(p);
 
-		debugfs_remove(mbus->dent_t);
-		debugfs_remove(mbus->dent_s);
+		if (mbus->text_inited)
+			mon_text_del(mbus);
 
 		/*
 		 * This never happens, because the open/close paths in
@@ -401,7 +399,8 @@
 	}
 	mutex_unlock(&mon_lock);
 
-	debugfs_remove(mon_dir);
+	mon_text_exit();
+	mon_bin_exit();
 }
 
 module_init(mon_init);
diff --git a/drivers/usb/mon/mon_text.c b/drivers/usb/mon/mon_text.c
index 05cf2c9..d38a127 100644
--- a/drivers/usb/mon/mon_text.c
+++ b/drivers/usb/mon/mon_text.c
@@ -9,6 +9,7 @@
 #include <linux/usb.h>
 #include <linux/time.h>
 #include <linux/mutex.h>
+#include <linux/debugfs.h>
 #include <asm/uaccess.h>
 
 #include "usb_mon.h"
@@ -63,6 +64,8 @@
 	char slab_name[SLAB_NAME_SZ];
 };
 
+static struct dentry *mon_dir;		/* Usually /sys/kernel/debug/usbmon */
+
 static void mon_text_ctor(void *, struct kmem_cache *, unsigned long);
 
 /*
@@ -436,7 +439,7 @@
 	return 0;
 }
 
-const struct file_operations mon_fops_text = {
+static const struct file_operations mon_fops_text = {
 	.owner =	THIS_MODULE,
 	.open =		mon_text_open,
 	.llseek =	no_llseek,
@@ -447,6 +450,47 @@
 	.release =	mon_text_release,
 };
 
+int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
+{
+	struct dentry *d;
+	enum { NAMESZ = 10 };
+	char name[NAMESZ];
+	int rc;
+
+	rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
+	if (rc <= 0 || rc >= NAMESZ)
+		goto err_print_t;
+	d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text);
+	if (d == NULL)
+		goto err_create_t;
+	mbus->dent_t = d;
+
+	/* XXX The stats do not belong to here (text API), but oh well... */
+	rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
+	if (rc <= 0 || rc >= NAMESZ)
+		goto err_print_s;
+	d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_stat);
+	if (d == NULL)
+		goto err_create_s;
+	mbus->dent_s = d;
+
+	return 1;
+
+err_create_s:
+err_print_s:
+	debugfs_remove(mbus->dent_t);
+	mbus->dent_t = NULL;
+err_create_t:
+err_print_t:
+	return 0;
+}
+
+void mon_text_del(struct mon_bus *mbus)
+{
+	debugfs_remove(mbus->dent_t);
+	debugfs_remove(mbus->dent_s);
+}
+
 /*
  * Slab interface: constructor.
  */
@@ -459,3 +503,24 @@
 	memset(mem, 0xe5, sizeof(struct mon_event_text));
 }
 
+int __init mon_text_init(void)
+{
+	struct dentry *mondir;
+
+	mondir = debugfs_create_dir("usbmon", NULL);
+	if (IS_ERR(mondir)) {
+		printk(KERN_NOTICE TAG ": debugfs is not available\n");
+		return -ENODEV;
+	}
+	if (mondir == NULL) {
+		printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
+		return -ENODEV;
+	}
+	mon_dir = mondir;
+	return 0;
+}
+
+void __exit mon_text_exit(void)
+{
+	debugfs_remove(mon_dir);
+}
diff --git a/drivers/usb/mon/usb_mon.h b/drivers/usb/mon/usb_mon.h
index ab9d02d..4f949ce 100644
--- a/drivers/usb/mon/usb_mon.h
+++ b/drivers/usb/mon/usb_mon.h
@@ -17,9 +17,11 @@
 struct mon_bus {
 	struct list_head bus_link;
 	spinlock_t lock;
+	struct usb_bus *u_bus;
+
+	int text_inited;
 	struct dentry *dent_s;		/* Debugging file */
 	struct dentry *dent_t;		/* Text interface file */
-	struct usb_bus *u_bus;
 	int uses_dma;
 
 	/* Ref */
@@ -48,13 +50,35 @@
 void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
 void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
 
+struct mon_bus *mon_bus_lookup(unsigned int num);
+
+int /*bool*/ mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus);
+void mon_text_del(struct mon_bus *mbus);
+// void mon_bin_add(struct mon_bus *);
+
+int __init mon_text_init(void);
+void __exit mon_text_exit(void);
+int __init mon_bin_init(void);
+void __exit mon_bin_exit(void);
+
 /*
- */
+ * DMA interface.
+ *
+ * XXX The vectored side needs a serious re-thinking. Abstracting vectors,
+ * like in Paolo's original patch, produces a double pkmap. We need an idea.
+*/
 extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len);
 
+struct mon_reader_bin;
+extern void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+    unsigned int offset, dma_addr_t dma_addr, unsigned int len);
+extern unsigned int mon_copy_to_buff(const struct mon_reader_bin *rp,
+    unsigned int offset, const unsigned char *from, unsigned int len);
+
+/*
+ */
 extern struct mutex mon_lock;
 
-extern const struct file_operations mon_fops_text;
 extern const struct file_operations mon_fops_stat;
 
 #endif /* __USB_MON_H */
diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig
index e081836..a2b94ef5 100644
--- a/drivers/usb/net/Kconfig
+++ b/drivers/usb/net/Kconfig
@@ -222,13 +222,15 @@
 	  adapters marketed under the DeLOCK brand.
 
 config USB_NET_RNDIS_HOST
-	tristate "Host for RNDIS devices (EXPERIMENTAL)"
+	tristate "Host for RNDIS and ActiveSync devices (EXPERIMENTAL)"
 	depends on USB_USBNET && EXPERIMENTAL
 	select USB_NET_CDCETHER
 	help
 	  This option enables hosting "Remote NDIS" USB networking links,
 	  as encouraged by Microsoft (instead of CDC Ethernet!) for use in
-	  various devices that may only support this protocol.
+	  various devices that may only support this protocol.  A variant
+	  of this protocol (with even less public documentation) seems to
+	  be at the root of Microsoft's "ActiveSync" too.
 
 	  Avoid using this protocol unless you have no better options.
 	  The protocol specification is incomplete, and is controlled by
diff --git a/drivers/usb/net/cdc_ether.c b/drivers/usb/net/cdc_ether.c
index 44a9154..e5cdafa 100644
--- a/drivers/usb/net/cdc_ether.c
+++ b/drivers/usb/net/cdc_ether.c
@@ -1,6 +1,7 @@
 /*
  * CDC Ethernet based networking peripherals
  * Copyright (C) 2003-2005 by David Brownell
+ * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync)
  *
  * 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
@@ -35,6 +36,29 @@
 #include "usbnet.h"
 
 
+#if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
+
+static int is_rndis(struct usb_interface_descriptor *desc)
+{
+	return desc->bInterfaceClass == USB_CLASS_COMM
+		&& desc->bInterfaceSubClass == 2
+		&& desc->bInterfaceProtocol == 0xff;
+}
+
+static int is_activesync(struct usb_interface_descriptor *desc)
+{
+	return desc->bInterfaceClass == USB_CLASS_MISC
+		&& desc->bInterfaceSubClass == 1
+		&& desc->bInterfaceProtocol == 1;
+}
+
+#else
+
+#define is_rndis(desc)		0
+#define is_activesync(desc)	0
+
+#endif
+
 /*
  * probes control interface, claims data interface, collects the bulk
  * endpoints, activates data interface (if needed), maybe sets MTU.
@@ -71,7 +95,8 @@
 	/* this assumes that if there's a non-RNDIS vendor variant
 	 * of cdc-acm, it'll fail RNDIS requests cleanly.
 	 */
-	rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff);
+	rndis = is_rndis(&intf->cur_altsetting->desc)
+		|| is_activesync(&intf->cur_altsetting->desc);
 
 	memset(info, 0, sizeof *info);
 	info->control = intf;
@@ -99,6 +124,23 @@
 				goto bad_desc;
 			}
 			break;
+		case USB_CDC_ACM_TYPE:
+			/* paranoia:  disambiguate a "real" vendor-specific
+			 * modem interface from an RNDIS non-modem.
+			 */
+			if (rndis) {
+				struct usb_cdc_acm_descriptor *d;
+
+				d = (void *) buf;
+				if (d->bmCapabilities) {
+					dev_dbg(&intf->dev,
+						"ACM capabilities %02x, "
+						"not really RNDIS?\n",
+						d->bmCapabilities);
+					goto bad_desc;
+				}
+			}
+			break;
 		case USB_CDC_UNION_TYPE:
 			if (info->u) {
 				dev_dbg(&intf->dev, "extra CDC union\n");
@@ -171,7 +213,21 @@
 		buf += buf [0];
 	}
 
-	if (!info->header || !info->u || (!rndis && !info->ether)) {
+	/* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors,
+	 * so we'll hard-wire the interfaces and not check for descriptors.
+	 */
+	if (is_activesync(&intf->cur_altsetting->desc) && !info->u) {
+		info->control = usb_ifnum_to_if(dev->udev, 0);
+		info->data = usb_ifnum_to_if(dev->udev, 1);
+		if (!info->control || !info->data) {
+			dev_dbg(&intf->dev,
+				"activesync: master #0/%p slave #1/%p\n",
+				info->control,
+				info->data);
+			goto bad_desc;
+		}
+
+	} else if (!info->header || !info->u || (!rndis && !info->ether)) {
 		dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
 			info->header ? "" : "header ",
 			info->u ? "" : "union ",
diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c
index fa78326..36a9891 100644
--- a/drivers/usb/net/kaweth.c
+++ b/drivers/usb/net/kaweth.c
@@ -179,6 +179,7 @@
 	.suspend =	kaweth_suspend,
 	.resume =	kaweth_resume,
 	.id_table =     usb_klsi_table,
+	.supports_autosuspend =	1,
 };
 
 typedef __u8 eth_addr_t[6];
@@ -225,6 +226,7 @@
 	struct delayed_work lowmem_work;
 
 	struct usb_device *dev;
+	struct usb_interface *intf;
 	struct net_device *net;
 	wait_queue_head_t term_wait;
 
@@ -662,9 +664,14 @@
 
 	dbg("Opening network device.");
 
+	res = usb_autopm_get_interface(kaweth->intf);
+	if (res) {
+		err("Interface cannot be resumed.");
+		return -EIO;
+	}
 	res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
 	if (res)
-		return -EIO;
+		goto err_out;
 
 	usb_fill_int_urb(
 		kaweth->irq_urb,
@@ -681,7 +688,7 @@
 	res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL);
 	if (res) {
 		usb_kill_urb(kaweth->rx_urb);
-		return -EIO;
+		goto err_out;
 	}
 	kaweth->opened = 1;
 
@@ -689,10 +696,14 @@
 
 	kaweth_async_set_rx_mode(kaweth);
 	return 0;
+
+err_out:
+	usb_autopm_enable(kaweth->intf);
+	return -EIO;
 }
 
 /****************************************************************
- *     kaweth_close
+ *     kaweth_kill_urbs
  ****************************************************************/
 static void kaweth_kill_urbs(struct kaweth_device *kaweth)
 {
@@ -724,17 +735,29 @@
 
 	kaweth->status &= ~KAWETH_STATUS_CLOSING;
 
+	usb_autopm_enable(kaweth->intf);
+
 	return 0;
 }
 
 static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
+	struct kaweth_device *kaweth = netdev_priv(dev);
 
 	strlcpy(info->driver, driver_name, sizeof(info->driver));
+	usb_make_path(kaweth->dev, info->bus_info, sizeof (info->bus_info));
+}
+
+static u32 kaweth_get_link(struct net_device *dev)
+{
+	struct kaweth_device *kaweth = netdev_priv(dev);
+
+	return kaweth->linkstate;
 }
 
 static struct ethtool_ops ops = {
-	.get_drvinfo = kaweth_get_drvinfo
+	.get_drvinfo	= kaweth_get_drvinfo,
+	.get_link	= kaweth_get_link
 };
 
 /****************************************************************
@@ -908,6 +931,7 @@
 	struct kaweth_device *kaweth = usb_get_intfdata(intf);
 	unsigned long flags;
 
+	dbg("Suspending device");
 	spin_lock_irqsave(&kaweth->device_lock, flags);
 	kaweth->status |= KAWETH_STATUS_SUSPENDING;
 	spin_unlock_irqrestore(&kaweth->device_lock, flags);
@@ -924,6 +948,7 @@
 	struct kaweth_device *kaweth = usb_get_intfdata(intf);
 	unsigned long flags;
 
+	dbg("Resuming device");
 	spin_lock_irqsave(&kaweth->device_lock, flags);
 	kaweth->status &= ~KAWETH_STATUS_SUSPENDING;
 	spin_unlock_irqrestore(&kaweth->device_lock, flags);
@@ -1086,6 +1111,8 @@
 
 	dbg("Initializing net device.");
 
+	kaweth->intf = intf;
+
 	kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!kaweth->tx_urb)
 		goto err_free_netdev;
@@ -1265,7 +1292,7 @@
 {
         struct urb *urb;
         int retv;
-        int length;
+        int length = 0; /* shut up GCC */
 
         urb = usb_alloc_urb(0, GFP_NOIO);
         if (!urb)
diff --git a/drivers/usb/net/rndis_host.c b/drivers/usb/net/rndis_host.c
index a322a16..be888d2 100644
--- a/drivers/usb/net/rndis_host.c
+++ b/drivers/usb/net/rndis_host.c
@@ -49,6 +49,8 @@
  *    - In some cases, MS-Windows will emit undocumented requests; this
  *	matters more to peripheral implementations than host ones.
  *
+ * Moreover there's a no-open-specs variant of RNDIS called "ActiveSync".
+ *
  * For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in
  * favor of such non-proprietary alternatives as CDC Ethernet or the newer (and
  * currently rare) "Ethernet Emulation Model" (EEM).
@@ -61,6 +63,9 @@
  *  - control-in:  GET_ENCAPSULATED
  *
  * We'll try to ignore the RESPONSE_AVAILABLE notifications.
+ *
+ * REVISIT some RNDIS implementations seem to have curious issues still
+ * to be resolved.
  */
 struct rndis_msg_hdr {
 	__le32	msg_type;			/* RNDIS_MSG_* */
@@ -71,8 +76,14 @@
 	// ... and more
 } __attribute__ ((packed));
 
-/* RNDIS defines this (absurdly huge) control timeout */
-#define	RNDIS_CONTROL_TIMEOUT_MS	(10 * 1000)
+/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */
+#define	CONTROL_BUFFER_SIZE		1025
+
+/* RNDIS defines an (absurdly huge) 10 second control timeout,
+ * but ActiveSync seems to use a more usual 5 second timeout
+ * (which matches the USB 2.0 spec).
+ */
+#define	RNDIS_CONTROL_TIMEOUT_MS	(5 * 1000)
 
 
 #define ccpu2 __constant_cpu_to_le32
@@ -270,6 +281,7 @@
 static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
 {
 	struct cdc_state	*info = (void *) &dev->data;
+	int			master_ifnum;
 	int			retval;
 	unsigned		count;
 	__le32			rsp;
@@ -279,7 +291,7 @@
 	 * disconnect(): either serialize, or dispatch responses on xid
 	 */
 
-	/* Issue the request; don't bother byteswapping our xid */
+	/* Issue the request; xid is unique, don't bother byteswapping it */
 	if (likely(buf->msg_type != RNDIS_MSG_HALT
 			&& buf->msg_type != RNDIS_MSG_RESET)) {
 		xid = dev->xid++;
@@ -287,11 +299,12 @@
 			xid = dev->xid++;
 		buf->request_id = (__force __le32) xid;
 	}
+	master_ifnum = info->control->cur_altsetting->desc.bInterfaceNumber;
 	retval = usb_control_msg(dev->udev,
 		usb_sndctrlpipe(dev->udev, 0),
 		USB_CDC_SEND_ENCAPSULATED_COMMAND,
 		USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-		0, info->u->bMasterInterface0,
+		0, master_ifnum,
 		buf, le32_to_cpu(buf->msg_len),
 		RNDIS_CONTROL_TIMEOUT_MS);
 	if (unlikely(retval < 0 || xid == 0))
@@ -306,13 +319,13 @@
 	 */
 	rsp = buf->msg_type | RNDIS_MSG_COMPLETION;
 	for (count = 0; count < 10; count++) {
-		memset(buf, 0, 1024);
+		memset(buf, 0, CONTROL_BUFFER_SIZE);
 		retval = usb_control_msg(dev->udev,
 			usb_rcvctrlpipe(dev->udev, 0),
 			USB_CDC_GET_ENCAPSULATED_RESPONSE,
 			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-			0, info->u->bMasterInterface0,
-			buf, 1024,
+			0, master_ifnum,
+			buf, CONTROL_BUFFER_SIZE,
 			RNDIS_CONTROL_TIMEOUT_MS);
 		if (likely(retval >= 8)) {
 			msg_len = le32_to_cpu(buf->msg_len);
@@ -350,7 +363,7 @@
 					usb_sndctrlpipe(dev->udev, 0),
 					USB_CDC_SEND_ENCAPSULATED_COMMAND,
 					USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-					0, info->u->bMasterInterface0,
+					0, master_ifnum,
 					msg, sizeof *msg,
 					RNDIS_CONTROL_TIMEOUT_MS);
 				if (unlikely(retval < 0))
@@ -393,38 +406,64 @@
 	u32			tmp;
 
 	/* we can't rely on i/o from stack working, or stack allocation */
-	u.buf = kmalloc(1024, GFP_KERNEL);
+	u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
 	if (!u.buf)
 		return -ENOMEM;
 	retval = usbnet_generic_cdc_bind(dev, intf);
 	if (retval < 0)
 		goto fail;
 
-	net->hard_header_len += sizeof (struct rndis_data_hdr);
-
-	/* initialize; max transfer is 16KB at full speed */
 	u.init->msg_type = RNDIS_MSG_INIT;
 	u.init->msg_len = ccpu2(sizeof *u.init);
 	u.init->major_version = ccpu2(1);
 	u.init->minor_version = ccpu2(0);
-	u.init->max_transfer_size = ccpu2(net->mtu + net->hard_header_len);
 
+	/* max transfer (in spec) is 0x4000 at full speed, but for
+	 * TX we'll stick to one Ethernet packet plus RNDIS framing.
+	 * For RX we handle drivers that zero-pad to end-of-packet.
+	 * Don't let userspace change these settings.
+	 */
+	net->hard_header_len += sizeof (struct rndis_data_hdr);
+	dev->hard_mtu = net->mtu + net->hard_header_len;
+
+	dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1);
+	dev->rx_urb_size &= ~(dev->maxpacket - 1);
+	u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size);
+
+	net->change_mtu = NULL;
 	retval = rndis_command(dev, u.header);
 	if (unlikely(retval < 0)) {
 		/* it might not even be an RNDIS device!! */
 		dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
+ 		goto fail_and_release;
+	}
+	tmp = le32_to_cpu(u.init_c->max_transfer_size);
+	if (tmp < dev->hard_mtu) {
+		dev_err(&intf->dev,
+			"dev can't take %u byte packets (max %u)\n",
+			dev->hard_mtu, tmp);
 		goto fail_and_release;
 	}
-	dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size);
+
 	/* REVISIT:  peripheral "alignment" request is ignored ... */
-	dev_dbg(&intf->dev, "hard mtu %u, align %d\n", dev->hard_mtu,
+	dev_dbg(&intf->dev,
+		"hard mtu %u (%u from dev), rx buflen %Zu, align %d\n",
+		dev->hard_mtu, tmp, dev->rx_urb_size,
 		1 << le32_to_cpu(u.init_c->packet_alignment));
 
-	/* get designated host ethernet address */
-	memset(u.get, 0, sizeof *u.get);
+	/* Get designated host ethernet address.
+	 *
+	 * Adding a payload exactly the same size as the expected response
+	 * payload is an evident requirement MSFT added for ActiveSync.
+	 * This undocumented (and nonsensical) issue was found by sniffing
+	 * protocol requests from the ActiveSync 4.1 Windows driver.
+	 */
+	memset(u.get, 0, sizeof *u.get + 48);
 	u.get->msg_type = RNDIS_MSG_QUERY;
-	u.get->msg_len = ccpu2(sizeof *u.get);
+	u.get->msg_len = ccpu2(sizeof *u.get + 48);
 	u.get->oid = OID_802_3_PERMANENT_ADDRESS;
+	u.get->len = ccpu2(48);
+	u.get->offset = ccpu2(20);
 
 	retval = rndis_command(dev, u.header);
 	if (unlikely(retval < 0)) {
@@ -432,7 +471,7 @@
 		goto fail_and_release;
 	}
 	tmp = le32_to_cpu(u.get_c->offset);
-	if (unlikely((tmp + 8) > (1024 - ETH_ALEN)
+	if (unlikely((tmp + 8) > (CONTROL_BUFFER_SIZE - ETH_ALEN)
 			|| u.get_c->len != ccpu2(ETH_ALEN))) {
 		dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n",
 			tmp, le32_to_cpu(u.get_c->len));
@@ -598,6 +637,10 @@
 	/* RNDIS is MSFT's un-official variant of CDC ACM */
 	USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
 	.driver_info = (unsigned long) &rndis_info,
+}, {
+	/* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */
+	USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1),
+	.driver_info = (unsigned long) &rndis_info,
 },
 	{ },		// END
 };
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index 86bcf63..11dad42 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -572,8 +572,20 @@
 		schedule_work(&priv->rx_work);
 }
 
+static struct usb_driver aircable_driver = {
+	.name =		"aircable",
+	.probe =	usb_serial_probe,
+	.disconnect =	usb_serial_disconnect,
+	.id_table =	id_table,
+	.no_dynamic_id =	1,
+};
+
 static struct usb_serial_driver aircable_device = {
-	.description =		"aircable",
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"aircable",
+	},
+	.usb_driver = 		&aircable_driver,
 	.id_table = 		id_table,
 	.num_ports =		1,
 	.attach =		aircable_attach,
@@ -587,13 +599,6 @@
 	.unthrottle =		aircable_unthrottle,
 };
 
-static struct usb_driver aircable_driver = {
-	.name =		"aircable",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
 static int __init aircable_init (void)
 {
 	int retval;
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index f2ca76a..0af42e3 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -277,6 +277,7 @@
 		.owner =	THIS_MODULE,
 		.name =		"airprime",
 	},
+	.usb_driver =		&airprime_driver,
 	.id_table =		id_table,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 5261cd2..edd6857 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -444,6 +444,7 @@
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
+	.no_dynamic_id =	1,
 };
 
 static struct usb_serial_driver ark3116_device = {
@@ -452,6 +453,7 @@
 		.name =		"ark3116",
 	},
 	.id_table =		id_table,
+	.usb_driver =		&ark3116_driver,
 	.num_interrupt_in =	1,
 	.num_bulk_in =		1,
 	.num_bulk_out =		1,
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 38b4dae..3b800d2 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -126,6 +126,7 @@
 		.name =		"belkin",
 	},
 	.description =		"Belkin / Peracom / GoHubs USB Serial Adapter",
+	.usb_driver =		&belkin_driver,
 	.id_table =		id_table_combined,
 	.num_interrupt_in =	1,
 	.num_bulk_in =		1,
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index 6542f22..c08a384 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -103,11 +103,52 @@
 	return retval;
 }
 
+#ifdef CONFIG_HOTPLUG
+static ssize_t store_new_id(struct device_driver *driver,
+			    const char *buf, size_t count)
+{
+	struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
+	ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+
+	if (retval >= 0 && usb_drv->usb_driver != NULL)
+		retval = usb_store_new_id(&usb_drv->usb_driver->dynids,
+					  &usb_drv->usb_driver->drvwrap.driver,
+					  buf, count);
+	return retval;
+}
+
+static struct driver_attribute drv_attrs[] = {
+	__ATTR(new_id, S_IWUSR, NULL, store_new_id),
+	__ATTR_NULL,
+};
+
+static void free_dynids(struct usb_serial_driver *drv)
+{
+	struct usb_dynid *dynid, *n;
+
+	spin_lock(&drv->dynids.lock);
+	list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
+		list_del(&dynid->node);
+		kfree(dynid);
+	}
+	spin_unlock(&drv->dynids.lock);
+}
+
+#else
+static struct driver_attribute drv_attrs[] = {
+	__ATTR_NULL,
+};
+static inline void free_dynids(struct usb_driver *drv)
+{
+}
+#endif
+
 struct bus_type usb_serial_bus_type = {
 	.name =		"usb-serial",
 	.match =	usb_serial_device_match,
 	.probe =	usb_serial_device_probe,
 	.remove =	usb_serial_device_remove,
+	.drv_attrs = 	drv_attrs,
 };
 
 int usb_serial_bus_register(struct usb_serial_driver *driver)
@@ -115,6 +156,9 @@
 	int retval;
 
 	driver->driver.bus = &usb_serial_bus_type;
+	spin_lock_init(&driver->dynids.lock);
+	INIT_LIST_HEAD(&driver->dynids.list);
+
 	retval = driver_register(&driver->driver);
 
 	return retval;
@@ -122,6 +166,7 @@
 
 void usb_serial_bus_deregister(struct usb_serial_driver *driver)
 {
+	free_dynids(driver);
 	driver_unregister(&driver->driver);
 }
 
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index 7ebaffd..06b4fff 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -89,6 +89,7 @@
 		.owner =	THIS_MODULE,
 		.name = 	"cp2101",
 	},
+	.usb_driver		= &cp2101_driver,
 	.id_table		= id_table,
 	.num_interrupt_in	= 0,
 	.num_bulk_in		= 0,
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index a63c328..4167753 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -88,6 +88,7 @@
 		.name =		"cyberjack",
 	},
 	.description =		"Reiner SCT Cyberjack USB card reader",
+	.usb_driver = 		&cyberjack_driver,
 	.id_table =		id_table,
 	.num_interrupt_in =	1,
 	.num_bulk_in =		1,
@@ -98,7 +99,7 @@
 	.open =			cyberjack_open,
 	.close =		cyberjack_close,
 	.write =		cyberjack_write,
-	.write_room =	cyberjack_write_room,
+	.write_room =		cyberjack_write_room,
 	.read_int_callback =	cyberjack_read_int_callback,
 	.read_bulk_callback =	cyberjack_read_bulk_callback,
 	.write_bulk_callback =	cyberjack_write_bulk_callback,
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 6bc1f40..57b8e27 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -193,6 +193,7 @@
 		.name =			"earthmate",
 	},
 	.description =			"DeLorme Earthmate USB",
+	.usb_driver = 			&cypress_driver,
 	.id_table =			id_table_earthmate,
 	.num_interrupt_in = 		1,
 	.num_interrupt_out =		1,
@@ -222,6 +223,7 @@
 		.name =			"cyphidcom",
 	},
 	.description =			"HID->COM RS232 Adapter",
+	.usb_driver = 			&cypress_driver,
 	.id_table =			id_table_cyphidcomrs232,
 	.num_interrupt_in =		1,
 	.num_interrupt_out =		1,
@@ -251,6 +253,7 @@
                 .name =			"nokiaca42v2",
 	},
 	.description =			"Nokia CA-42 V2 Adapter",
+	.usb_driver = 			&cypress_driver,
 	.id_table =			id_table_nokiaca42v2,
 	.num_interrupt_in =		1,
 	.num_interrupt_out =		1,
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index efd9ce3..0b0fb51 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -509,6 +509,7 @@
 		.name =			"digi_2",
 	},
 	.description =			"Digi 2 port USB adapter",
+	.usb_driver = 			&digi_driver,
 	.id_table =			id_table_2,
 	.num_interrupt_in =		0,
 	.num_bulk_in =			4,
@@ -538,6 +539,7 @@
 		.name =			"digi_4",
 	},
 	.description =			"Digi 4 port USB adapter",
+	.usb_driver = 			&digi_driver,
 	.id_table =			id_table_4,
 	.num_interrupt_in =		0,
 	.num_bulk_in =			5,
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index 92beeb1..4703c8f 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -117,6 +117,7 @@
 		.name =		"empeg",
 	},
 	.id_table =		id_table,
+	.usb_driver = 		&empeg_driver,
 	.num_interrupt_in =	0,
 	.num_bulk_in =		1,
 	.num_bulk_out =		1,
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 6986e75..4695952 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -464,7 +464,6 @@
 	{ USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
 	{ USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
 	{ USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) },
-	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
 	{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) },
@@ -615,6 +614,7 @@
 		.name =		"ftdi_sio",
 	},
 	.description =		"FTDI USB Serial Device",
+	.usb_driver = 		&ftdi_driver ,
 	.id_table =		id_table_combined,
 	.num_interrupt_in =	0,
 	.num_bulk_in =		1,
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 40dd394..7eff1c0 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -364,7 +364,6 @@
  * USB-TTY activ, USB-TTY passiv.  Some PIDs are used by several devices
  * and I'm not entirely sure which are used by which.
  */
-#define FTDI_4N_GALAXY_DE_0_PID	0x8372
 #define FTDI_4N_GALAXY_DE_1_PID	0xF3C0
 #define FTDI_4N_GALAXY_DE_2_PID	0xF3C1
 
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
index 2bebd63..4092f6d 100644
--- a/drivers/usb/serial/funsoft.c
+++ b/drivers/usb/serial/funsoft.c
@@ -58,6 +58,7 @@
 		.name =		"funsoft",
 	},
 	.id_table =		id_table,
+	.usb_driver = 		&funsoft_driver,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 6530d39..74660a3 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -1566,6 +1566,7 @@
 		.name        = "garmin_gps",
 	},
 	.description         = "Garmin GPS usb/tty",
+	.usb_driver          = &garmin_driver,
 	.id_table            = id_table,
 	.num_interrupt_in    = 1,
 	.num_bulk_in         = 1,
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 3604293..601e064 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -20,6 +20,10 @@
 #include <linux/usb/serial.h>
 #include <asm/uaccess.h>
 
+static int generic_probe(struct usb_interface *interface,
+			 const struct usb_device_id *id);
+
+
 static int debug;
 
 #ifdef CONFIG_USB_SERIAL_GENERIC
@@ -34,6 +38,21 @@
 
 static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */
 
+/* we want to look at all devices, as the vendor/product id can change
+ * depending on the command line argument */
+static struct usb_device_id generic_serial_ids[] = {
+	{.driver_info = 42},
+	{}
+};
+
+static struct usb_driver generic_driver = {
+	.name =		"usbserial_generic",
+	.probe =	generic_probe,
+	.disconnect =	usb_serial_disconnect,
+	.id_table =	generic_serial_ids,
+	.no_dynamic_id =	1,
+};
+
 /* All of the device info needed for the Generic Serial Converter */
 struct usb_serial_driver usb_serial_generic_device = {
 	.driver = {
@@ -41,6 +60,7 @@
 		.name =		"generic",
 	},
 	.id_table =		generic_device_ids,
+	.usb_driver = 		&generic_driver,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,
@@ -48,13 +68,6 @@
 	.shutdown =		usb_serial_generic_shutdown,
 };
 
-/* we want to look at all devices, as the vendor/product id can change
- * depending on the command line argument */
-static struct usb_device_id generic_serial_ids[] = {
-	{.driver_info = 42},
-	{}
-};
-
 static int generic_probe(struct usb_interface *interface,
 			       const struct usb_device_id *id)
 {
@@ -65,14 +78,6 @@
 		return usb_serial_probe(interface, id);
 	return -ENODEV;
 }
-
-static struct usb_driver generic_driver = {
-	.name =		"usbserial_generic",
-	.probe =	generic_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	generic_serial_ids,
-	.no_dynamic_id = 	1,
-};
 #endif
 
 int usb_serial_generic_register (int _debug)
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
index ebcac70..6c6ebae 100644
--- a/drivers/usb/serial/hp4x.c
+++ b/drivers/usb/serial/hp4x.c
@@ -49,6 +49,7 @@
 		.name =		"hp4X",
 	},
 	.id_table =		id_table,
+	.usb_driver = 		&hp49gp_driver,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index f623d58..6a26a2e 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -146,6 +146,8 @@
 	struct edge_manuf_descriptor	manuf_descriptor;	/* the manufacturer descriptor */
 	struct edge_boot_descriptor	boot_descriptor;	/* the boot firmware descriptor */
 	struct edgeport_product_info	product_info;		/* Product Info */
+	struct edge_compatibility_descriptor epic_descriptor;	/* Edgeport compatible descriptor */
+	int			is_epic;			/* flag if EPiC device or not */
 
 	__u8			interrupt_in_endpoint;		/* the interrupt endpoint handle */
 	unsigned char *		interrupt_in_buffer;		/* the buffer we use for the interrupt endpoint */
@@ -240,14 +242,6 @@
 
 #include "io_tables.h"	/* all of the devices that this driver supports */
 
-static struct usb_driver io_driver = {
-	.name =		"io_edgeport",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table_combined,
-	.no_dynamic_id = 	1,
-};
-
 /* function prototypes for all of our local functions */
 static void  process_rcvd_data		(struct edgeport_serial *edge_serial, unsigned char *buffer, __u16 bufferLength);
 static void process_rcvd_status		(struct edgeport_serial *edge_serial, __u8 byte2, __u8 byte3);
@@ -397,6 +391,7 @@
 	unicode_to_ascii(string, buflen, pStringDesc->wData, pStringDesc->bLength/2);
 
 	kfree(pStringDesc);
+	dbg("%s - USB String %s", __FUNCTION__, string);
 	return strlen(string);
 }
 
@@ -434,6 +429,34 @@
 }
 #endif
 
+static void dump_product_info(struct edgeport_product_info *product_info)
+{
+	// Dump Product Info structure
+	dbg("**Product Information:");
+	dbg("  ProductId             %x", product_info->ProductId );
+	dbg("  NumPorts              %d", product_info->NumPorts );
+	dbg("  ProdInfoVer           %d", product_info->ProdInfoVer );
+	dbg("  IsServer              %d", product_info->IsServer);
+	dbg("  IsRS232               %d", product_info->IsRS232 );
+	dbg("  IsRS422               %d", product_info->IsRS422 );
+	dbg("  IsRS485               %d", product_info->IsRS485 );
+	dbg("  RomSize               %d", product_info->RomSize );
+	dbg("  RamSize               %d", product_info->RamSize );
+	dbg("  CpuRev                %x", product_info->CpuRev  );
+	dbg("  BoardRev              %x", product_info->BoardRev);
+	dbg("  BootMajorVersion      %d.%d.%d", product_info->BootMajorVersion,
+	    product_info->BootMinorVersion,
+	    le16_to_cpu(product_info->BootBuildNumber));
+	dbg("  FirmwareMajorVersion  %d.%d.%d", product_info->FirmwareMajorVersion,
+	    product_info->FirmwareMinorVersion,
+	    le16_to_cpu(product_info->FirmwareBuildNumber));
+	dbg("  ManufactureDescDate   %d/%d/%d", product_info->ManufactureDescDate[0],
+	    product_info->ManufactureDescDate[1],
+	    product_info->ManufactureDescDate[2]+1900);
+	dbg("  iDownloadFile         0x%x", product_info->iDownloadFile);
+	dbg("  EpicVer               %d", product_info->EpicVer);
+}
+
 static void get_product_info(struct edgeport_serial *edge_serial)
 {
 	struct edgeport_product_info *product_info = &edge_serial->product_info;
@@ -495,30 +518,60 @@
 			break;
 	}
 
-	// Dump Product Info structure
-	dbg("**Product Information:");
-	dbg("  ProductId             %x", product_info->ProductId );
-	dbg("  NumPorts              %d", product_info->NumPorts );
-	dbg("  ProdInfoVer           %d", product_info->ProdInfoVer );
-	dbg("  IsServer              %d", product_info->IsServer);
-	dbg("  IsRS232               %d", product_info->IsRS232 );
-	dbg("  IsRS422               %d", product_info->IsRS422 );
-	dbg("  IsRS485               %d", product_info->IsRS485 );
-	dbg("  RomSize               %d", product_info->RomSize );
-	dbg("  RamSize               %d", product_info->RamSize );
-	dbg("  CpuRev                %x", product_info->CpuRev  );
-	dbg("  BoardRev              %x", product_info->BoardRev);
-	dbg("  BootMajorVersion      %d.%d.%d", product_info->BootMajorVersion,
-	    product_info->BootMinorVersion,
-	    le16_to_cpu(product_info->BootBuildNumber));
-	dbg("  FirmwareMajorVersion  %d.%d.%d", product_info->FirmwareMajorVersion,
-	    product_info->FirmwareMinorVersion,
-	    le16_to_cpu(product_info->FirmwareBuildNumber));
-	dbg("  ManufactureDescDate   %d/%d/%d", product_info->ManufactureDescDate[0],
-	    product_info->ManufactureDescDate[1],
-	    product_info->ManufactureDescDate[2]+1900);
-	dbg("  iDownloadFile         0x%x",     product_info->iDownloadFile);
+	dump_product_info(product_info);
+}
 
+static int get_epic_descriptor(struct edgeport_serial *ep)
+{
+	int result;
+	struct usb_serial *serial = ep->serial;
+	struct edgeport_product_info *product_info = &ep->product_info;
+	struct edge_compatibility_descriptor *epic = &ep->epic_descriptor;
+	struct edge_compatibility_bits *bits;
+
+	ep->is_epic = 0;
+	result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+				 USB_REQUEST_ION_GET_EPIC_DESC,
+				 0xC0, 0x00, 0x00,
+				 &ep->epic_descriptor,
+				 sizeof(struct edge_compatibility_descriptor),
+				 300);
+
+	dbg("%s result = %d", __FUNCTION__, result);
+
+	if (result > 0) {
+		ep->is_epic = 1;
+		memset(product_info, 0, sizeof(struct edgeport_product_info));
+
+		product_info->NumPorts			= epic->NumPorts;
+		product_info->ProdInfoVer		= 0;
+		product_info->FirmwareMajorVersion	= epic->MajorVersion;
+		product_info->FirmwareMinorVersion	= epic->MinorVersion;
+		product_info->FirmwareBuildNumber	= epic->BuildNumber;
+		product_info->iDownloadFile		= epic->iDownloadFile;
+		product_info->EpicVer			= epic->EpicVer;
+		product_info->Epic			= epic->Supports;
+		product_info->ProductId			= ION_DEVICE_ID_EDGEPORT_COMPATIBLE;
+		dump_product_info(product_info);
+
+		bits = &ep->epic_descriptor.Supports;
+		dbg("**EPIC descriptor:");
+		dbg("  VendEnableSuspend: %s", bits->VendEnableSuspend	? "TRUE": "FALSE");
+		dbg("  IOSPOpen         : %s", bits->IOSPOpen		? "TRUE": "FALSE" );
+		dbg("  IOSPClose        : %s", bits->IOSPClose		? "TRUE": "FALSE" );
+		dbg("  IOSPChase        : %s", bits->IOSPChase		? "TRUE": "FALSE" );
+		dbg("  IOSPSetRxFlow    : %s", bits->IOSPSetRxFlow	? "TRUE": "FALSE" );
+		dbg("  IOSPSetTxFlow    : %s", bits->IOSPSetTxFlow	? "TRUE": "FALSE" );
+		dbg("  IOSPSetXChar     : %s", bits->IOSPSetXChar	? "TRUE": "FALSE" );
+		dbg("  IOSPRxCheck      : %s", bits->IOSPRxCheck	? "TRUE": "FALSE" );
+		dbg("  IOSPSetClrBreak  : %s", bits->IOSPSetClrBreak	? "TRUE": "FALSE" );
+		dbg("  IOSPWriteMCR     : %s", bits->IOSPWriteMCR	? "TRUE": "FALSE" );
+		dbg("  IOSPWriteLCR     : %s", bits->IOSPWriteLCR	? "TRUE": "FALSE" );
+		dbg("  IOSPSetBaudRate  : %s", bits->IOSPSetBaudRate	? "TRUE": "FALSE" );
+		dbg("  TrueEdgeport     : %s", bits->TrueEdgeport	? "TRUE": "FALSE" );
+	}
+
+	return result;
 }
 
 
@@ -1017,21 +1070,29 @@
 
 	edge_port->closePending = TRUE;
 
-	/* flush and chase */
-	edge_port->chaseResponsePending = TRUE;
+	if ((!edge_serial->is_epic) ||
+	    ((edge_serial->is_epic) &&
+	     (edge_serial->epic_descriptor.Supports.IOSPChase))) {
+		/* flush and chase */
+		edge_port->chaseResponsePending = TRUE;
 
-	dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
-	status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
-	if (status == 0) {
-		// block until chase finished
-		block_until_chase_response(edge_port);
-	} else {
-		edge_port->chaseResponsePending = FALSE;
+		dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
+		status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
+		if (status == 0) {
+			// block until chase finished
+			block_until_chase_response(edge_port);
+		} else {
+			edge_port->chaseResponsePending = FALSE;
+		}
 	}
 
-	/* close the port */
-	dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__);
-	send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
+	if ((!edge_serial->is_epic) ||
+	    ((edge_serial->is_epic) &&
+	     (edge_serial->epic_descriptor.Supports.IOSPClose))) {
+	       /* close the port */
+		dbg("%s - Sending IOSP_CMD_CLOSE_PORT", __FUNCTION__);
+		send_iosp_ext_cmd (edge_port, IOSP_CMD_CLOSE_PORT, 0);
+	}
 
 	//port->close = TRUE;
 	edge_port->closePending = FALSE;
@@ -1694,29 +1755,38 @@
 static void edge_break (struct usb_serial_port *port, int break_state)
 {
 	struct edgeport_port *edge_port = usb_get_serial_port_data(port);
+	struct edgeport_serial *edge_serial = usb_get_serial_data(port->serial);
 	int status;
 
-	/* flush and chase */
-	edge_port->chaseResponsePending = TRUE;
+	if ((!edge_serial->is_epic) ||
+	    ((edge_serial->is_epic) &&
+	     (edge_serial->epic_descriptor.Supports.IOSPChase))) {
+		/* flush and chase */
+		edge_port->chaseResponsePending = TRUE;
 
-	dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
-	status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
-	if (status == 0) {
-		// block until chase finished
-		block_until_chase_response(edge_port);
-	} else {
-		edge_port->chaseResponsePending = FALSE;
+		dbg("%s - Sending IOSP_CMD_CHASE_PORT", __FUNCTION__);
+		status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CHASE_PORT, 0);
+		if (status == 0) {
+			// block until chase finished
+			block_until_chase_response(edge_port);
+		} else {
+			edge_port->chaseResponsePending = FALSE;
+		}
 	}
 
-	if (break_state == -1) {
-		dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__);
-		status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0);
-	} else {
-		dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__);
-		status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0);
-	}
-	if (status) {
-		dbg("%s - error sending break set/clear command.", __FUNCTION__);
+	if ((!edge_serial->is_epic) ||
+	    ((edge_serial->is_epic) &&
+	     (edge_serial->epic_descriptor.Supports.IOSPSetClrBreak))) {
+		if (break_state == -1) {
+			dbg("%s - Sending IOSP_CMD_SET_BREAK", __FUNCTION__);
+			status = send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_BREAK, 0);
+		} else {
+			dbg("%s - Sending IOSP_CMD_CLEAR_BREAK", __FUNCTION__);
+			status = send_iosp_ext_cmd (edge_port, IOSP_CMD_CLEAR_BREAK, 0);
+		}
+		if (status) {
+			dbg("%s - error sending break set/clear command.", __FUNCTION__);
+		}
 	}
 
 	return;
@@ -2288,6 +2358,7 @@
  *****************************************************************************/
 static int send_cmd_write_baud_rate (struct edgeport_port *edge_port, int baudRate)
 {
+	struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
 	unsigned char *cmdBuffer;
 	unsigned char *currCmd;
 	int cmdLen = 0;
@@ -2295,6 +2366,14 @@
 	int status;
 	unsigned char number = edge_port->port->number - edge_port->port->serial->minor;
 
+	if ((!edge_serial->is_epic) ||
+	    ((edge_serial->is_epic) &&
+	     (!edge_serial->epic_descriptor.Supports.IOSPSetBaudRate))) {
+		dbg("SendCmdWriteBaudRate - NOT Setting baud rate for port = %d, baud = %d",
+		    edge_port->port->number, baudRate);
+		return 0;
+	}
+
 	dbg("%s - port = %d, baud = %d", __FUNCTION__, edge_port->port->number, baudRate);
 
 	status = calc_baud_rate_divisor (baudRate, &divisor);
@@ -2374,6 +2453,7 @@
  *****************************************************************************/
 static int send_cmd_write_uart_register (struct edgeport_port *edge_port, __u8 regNum, __u8 regValue)
 {
+	struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
 	unsigned char *cmdBuffer;
 	unsigned char *currCmd;
 	unsigned long cmdLen = 0;
@@ -2381,6 +2461,22 @@
 
 	dbg("%s - write to %s register 0x%02x", (regNum == MCR) ? "MCR" : "LCR", __FUNCTION__, regValue);
 
+	if ((!edge_serial->is_epic) ||
+	    ((edge_serial->is_epic) &&
+	     (!edge_serial->epic_descriptor.Supports.IOSPWriteMCR) &&
+	     (regNum == MCR))) {
+		dbg("SendCmdWriteUartReg - Not writting to MCR Register");
+		return 0;
+	}
+
+	if ((!edge_serial->is_epic) ||
+	    ((edge_serial->is_epic) &&
+	     (!edge_serial->epic_descriptor.Supports.IOSPWriteLCR) &&
+	     (regNum == LCR))) {
+		dbg ("SendCmdWriteUartReg - Not writting to LCR Register");
+		return 0;
+	}
+
 	// Alloc memory for the string of commands.
 	cmdBuffer = kmalloc (0x10, GFP_ATOMIC);
 	if (cmdBuffer == NULL ) {
@@ -2414,6 +2510,7 @@
 #endif
 static void change_port_settings (struct edgeport_port *edge_port, struct ktermios *old_termios)
 {
+	struct edgeport_serial *edge_serial = usb_get_serial_data(edge_port->port->serial);
 	struct tty_struct *tty;
 	int baud;
 	unsigned cflag;
@@ -2494,8 +2591,12 @@
 		unsigned char stop_char  = STOP_CHAR(tty);
 		unsigned char start_char = START_CHAR(tty);
 
-		send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XON_CHAR, start_char);
-		send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char);
+		if ((!edge_serial->is_epic) ||
+		    ((edge_serial->is_epic) &&
+		     (edge_serial->epic_descriptor.Supports.IOSPSetXChar))) {
+			send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XON_CHAR, start_char);
+			send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_XOFF_CHAR, stop_char);
+		}
 
 		/* if we are implementing INBOUND XON/XOFF */
 		if (I_IXOFF(tty)) {
@@ -2515,8 +2616,14 @@
 	}
 
 	/* Set flow control to the configured value */
-	send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow);
-	send_iosp_ext_cmd (edge_port, IOSP_CMD_SET_TX_FLOW, txFlow);
+	if ((!edge_serial->is_epic) ||
+	    ((edge_serial->is_epic) &&
+	     (edge_serial->epic_descriptor.Supports.IOSPSetRxFlow)))
+		send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_RX_FLOW, rxFlow);
+	if ((!edge_serial->is_epic) ||
+	    ((edge_serial->is_epic) &&
+	     (edge_serial->epic_descriptor.Supports.IOSPSetTxFlow)))
+		send_iosp_ext_cmd(edge_port, IOSP_CMD_SET_TX_FLOW, txFlow);
 
 
 	edge_port->shadowLCR &= ~(LCR_BITS_MASK | LCR_STOP_MASK | LCR_PAR_MASK);
@@ -2728,6 +2835,13 @@
 	struct edgeport_port *edge_port;
 	struct usb_device *dev;
 	int i, j;
+	int response;
+	int interrupt_in_found;
+	int bulk_in_found;
+	int bulk_out_found;
+	static __u32 descriptor[3] = {	EDGE_COMPATIBILITY_MASK0,
+					EDGE_COMPATIBILITY_MASK1,
+					EDGE_COMPATIBILITY_MASK2 };
 
 	dev = serial->dev;
 
@@ -2750,38 +2864,50 @@
 
 	dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name);
 
-	/* get the manufacturing descriptor for this device */
-	get_manufacturing_desc (edge_serial);
+	/* Read the epic descriptor */
+	if (get_epic_descriptor(edge_serial) <= 0) {
+		/* memcpy descriptor to Supports structures */
+		memcpy(&edge_serial->epic_descriptor.Supports, descriptor,
+		       sizeof(struct edge_compatibility_bits));
 
-	/* get the boot descriptor */
-	get_boot_desc (edge_serial);
+		/* get the manufacturing descriptor for this device */
+		get_manufacturing_desc (edge_serial);
 
-	get_product_info(edge_serial);
+		/* get the boot descriptor */
+		get_boot_desc (edge_serial);
+
+		get_product_info(edge_serial);
+	}
 
 	/* set the number of ports from the manufacturing description */
 	/* serial->num_ports = serial->product_info.NumPorts; */
-	if (edge_serial->product_info.NumPorts != serial->num_ports) {
-		warn("%s - Device Reported %d serial ports vs core "
-		     "thinking we have %d ports, email greg@kroah.com this info.",
-		     __FUNCTION__, edge_serial->product_info.NumPorts, 
-		     serial->num_ports);
+	if ((!edge_serial->is_epic) &&
+	    (edge_serial->product_info.NumPorts != serial->num_ports)) {
+		dev_warn(&serial->dev->dev, "Device Reported %d serial ports "
+			 "vs. core thinking we have %d ports, email "
+			 "greg@kroah.com this information.",
+			 edge_serial->product_info.NumPorts,
+			 serial->num_ports);
 	}
 
 	dbg("%s - time 1 %ld", __FUNCTION__, jiffies);
 
-	/* now load the application firmware into this device */
-	load_application_firmware (edge_serial);
+	/* If not an EPiC device */
+	if (!edge_serial->is_epic) {
+		/* now load the application firmware into this device */
+		load_application_firmware (edge_serial);
 
-	dbg("%s - time 2 %ld", __FUNCTION__, jiffies);
+		dbg("%s - time 2 %ld", __FUNCTION__, jiffies);
 
-	/* Check current Edgeport EEPROM and update if necessary */
-	update_edgeport_E2PROM (edge_serial);
-	
-	dbg("%s - time 3 %ld", __FUNCTION__, jiffies);
+		/* Check current Edgeport EEPROM and update if necessary */
+		update_edgeport_E2PROM (edge_serial);
 
-	/* set the configuration to use #1 */
-//	dbg("set_configuration 1");
-//	usb_set_configuration (dev, 1);
+		dbg("%s - time 3 %ld", __FUNCTION__, jiffies);
+
+		/* set the configuration to use #1 */
+//		dbg("set_configuration 1");
+//		usb_set_configuration (dev, 1);
+	}
 
 	/* we set up the pointers to the endpoints in the edge_open function, 
 	 * as the structures aren't created yet. */
@@ -2804,8 +2930,101 @@
 		edge_port->port = serial->port[i];
 		usb_set_serial_port_data(serial->port[i], edge_port);
 	}
-	
-	return 0;
+
+	response = 0;
+
+	if (edge_serial->is_epic) {
+		/* EPIC thing, set up our interrupt polling now and our read urb, so
+		 * that the device knows it really is connected. */
+		interrupt_in_found = bulk_in_found = bulk_out_found = FALSE;
+		for (i = 0; i < serial->interface->altsetting[0].desc.bNumEndpoints; ++i) {
+			struct usb_endpoint_descriptor *endpoint;
+			int buffer_size;
+
+			endpoint = &serial->interface->altsetting[0].endpoint[i].desc;
+			buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+			if ((!interrupt_in_found) &&
+			    (usb_endpoint_is_int_in(endpoint))) {
+				/* we found a interrupt in endpoint */
+				dbg("found interrupt in");
+
+				/* not set up yet, so do it now */
+				edge_serial->interrupt_read_urb = usb_alloc_urb(0, GFP_KERNEL);
+				if (!edge_serial->interrupt_read_urb) {
+					err("out of memory");
+					return -ENOMEM;
+				}
+				edge_serial->interrupt_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+				if (!edge_serial->interrupt_in_buffer) {
+					err("out of memory");
+					usb_free_urb(edge_serial->interrupt_read_urb);
+					return -ENOMEM;
+				}
+				edge_serial->interrupt_in_endpoint = endpoint->bEndpointAddress;
+
+				/* set up our interrupt urb */
+				usb_fill_int_urb(edge_serial->interrupt_read_urb,
+						 dev,
+						 usb_rcvintpipe(dev, endpoint->bEndpointAddress),
+						 edge_serial->interrupt_in_buffer,
+						 buffer_size,
+						 edge_interrupt_callback,
+						 edge_serial,
+						 endpoint->bInterval);
+
+				interrupt_in_found = TRUE;
+			}
+
+			if ((!bulk_in_found) &&
+			    (usb_endpoint_is_bulk_in(endpoint))) {
+				/* we found a bulk in endpoint */
+				dbg("found bulk in");
+
+				/* not set up yet, so do it now */
+				edge_serial->read_urb = usb_alloc_urb(0, GFP_KERNEL);
+				if (!edge_serial->read_urb) {
+					err("out of memory");
+					return -ENOMEM;
+				}
+				edge_serial->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
+				if (!edge_serial->bulk_in_buffer) {
+					err ("out of memory");
+					usb_free_urb(edge_serial->read_urb);
+					return -ENOMEM;
+				}
+				edge_serial->bulk_in_endpoint = endpoint->bEndpointAddress;
+
+				/* set up our bulk in urb */
+				usb_fill_bulk_urb(edge_serial->read_urb, dev,
+						  usb_rcvbulkpipe(dev, endpoint->bEndpointAddress),
+						  edge_serial->bulk_in_buffer,
+						  endpoint->wMaxPacketSize,
+						  edge_bulk_in_callback,
+						  edge_serial);
+				bulk_in_found = TRUE;
+			}
+
+			if ((!bulk_out_found) &&
+			    (usb_endpoint_is_bulk_out(endpoint))) {
+				/* we found a bulk out endpoint */
+				dbg("found bulk out");
+				edge_serial->bulk_out_endpoint = endpoint->bEndpointAddress;
+				bulk_out_found = TRUE;
+			}
+		}
+
+		if ((!interrupt_in_found) || (!bulk_in_found) || (!bulk_out_found)) {
+			err ("Error - the proper endpoints were not found!");
+			return -ENODEV;
+		}
+
+		/* start interrupt read for this edgeport this interrupt will
+		 * continue as long as the edgeport is connected */
+		response = usb_submit_urb(edge_serial->interrupt_read_urb, GFP_KERNEL);
+		if (response)
+			err("%s - Error %d submitting control urb", __FUNCTION__, response);
+	}
+	return response;
 }
 
 
@@ -2815,6 +3034,7 @@
  ****************************************************************************/
 static void edge_shutdown (struct usb_serial *serial)
 {
+	struct edgeport_serial *edge_serial = usb_get_serial_data(serial);
 	int i;
 
 	dbg("%s", __FUNCTION__);
@@ -2824,7 +3044,18 @@
 		kfree (usb_get_serial_port_data(serial->port[i]));
 		usb_set_serial_port_data(serial->port[i],  NULL);
 	}
-	kfree (usb_get_serial_data(serial));
+	/* free up our endpoint stuff */
+	if (edge_serial->is_epic) {
+		usb_unlink_urb(edge_serial->interrupt_read_urb);
+		usb_free_urb(edge_serial->interrupt_read_urb);
+		kfree(edge_serial->interrupt_in_buffer);
+
+		usb_unlink_urb(edge_serial->read_urb);
+		usb_free_urb(edge_serial->read_urb);
+		kfree(edge_serial->bulk_in_buffer);
+	}
+
+	kfree(edge_serial);
 	usb_set_serial_data(serial, NULL);
 }
 
@@ -2846,6 +3077,9 @@
 	retval = usb_serial_register(&edgeport_8port_device);
 	if (retval)
 		goto failed_8port_device_register;
+	retval = usb_serial_register(&epic_device);
+	if (retval)
+		goto failed_epic_device_register;
 	retval = usb_register(&io_driver);
 	if (retval) 
 		goto failed_usb_register;
@@ -2853,6 +3087,8 @@
 	return 0;
 
 failed_usb_register:
+	usb_serial_deregister(&epic_device);
+failed_epic_device_register:
 	usb_serial_deregister(&edgeport_8port_device);
 failed_8port_device_register:
 	usb_serial_deregister(&edgeport_4port_device);
@@ -2873,6 +3109,7 @@
 	usb_serial_deregister (&edgeport_2port_device);
 	usb_serial_deregister (&edgeport_4port_device);
 	usb_serial_deregister (&edgeport_8port_device);
+	usb_serial_deregister (&epic_device);
 }
 
 module_init(edgeport_init);
diff --git a/drivers/usb/serial/io_edgeport.h b/drivers/usb/serial/io_edgeport.h
index 123fa8a..29a913a 100644
--- a/drivers/usb/serial/io_edgeport.h
+++ b/drivers/usb/serial/io_edgeport.h
@@ -111,10 +111,12 @@
 	__le16	FirmwareBuildNumber;		/*				zzzz (LE format) */
 
 	__u8	ManufactureDescDate[3];		/* MM/DD/YY when descriptor template was compiled */
-	__u8	Unused1[1];			/* Available */
+	__u8	HardwareType;
 
 	__u8	iDownloadFile;			/* What to download to EPiC device */
-	__u8	Unused2[2];			/* Available */
+	__u8	EpicVer;			/* What version of EPiC spec this device supports */
+
+	struct edge_compatibility_bits Epic;
 };
 
 /*
diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h
index fad561c..6d30087 100644
--- a/drivers/usb/serial/io_tables.h
+++ b/drivers/usb/serial/io_tables.h
@@ -47,6 +47,18 @@
 	{ }
 };
 
+static struct usb_device_id Epic_port_id_table [] = {
+	{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) },
+	{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) },
+	{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) },
+	{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) },
+	{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) },
+	{ USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) },
+	{ USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) },
+	{ USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) },
+	{ }
+};
+
 /* Devices that this driver supports */
 static struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(USB_VENDOR_ID_ION,	ION_DEVICE_ID_EDGEPORT_4) },
@@ -70,17 +82,34 @@
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8R) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8RR) },
 	{ USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_412_8) },
+	{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) },
+	{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) },
+	{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) },
+	{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0311) },
+	{ USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0312) },
+	{ USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A758) },
+	{ USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A794) },
+	{ USB_DEVICE(USB_VENDOR_ID_AXIOHM, AXIOHM_DEVICE_ID_EPIC_A225) },
 	{ }							/* Terminating entry */
 };
 
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 
+static struct usb_driver io_driver = {
+	.name =		"io_edgeport",
+	.probe =	usb_serial_probe,
+	.disconnect =	usb_serial_disconnect,
+	.id_table =	id_table_combined,
+	.no_dynamic_id = 	1,
+};
+
 static struct usb_serial_driver edgeport_2port_device = {
 	.driver = {
 		.owner		= THIS_MODULE,
 		.name		= "edgeport_2",
 	},
 	.description		= "Edgeport 2 port adapter",
+	.usb_driver		= &io_driver,
 	.id_table		= edgeport_2port_id_table,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 1,
@@ -111,6 +140,7 @@
 		.name		= "edgeport_4",
 	},
 	.description		= "Edgeport 4 port adapter",
+	.usb_driver		= &io_driver,
 	.id_table		= edgeport_4port_id_table,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 1,
@@ -141,6 +171,7 @@
 		.name		= "edgeport_8",
 	},
 	.description		= "Edgeport 8 port adapter",
+	.usb_driver		= &io_driver,
 	.id_table		= edgeport_8port_id_table,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 1,
@@ -165,5 +196,35 @@
 	.write_bulk_callback	= edge_bulk_out_data_callback,
 };
 
+static struct usb_serial_driver epic_device = {
+	.driver = {
+		.owner		= THIS_MODULE,
+		.name		= "epic",
+	},
+	.description		= "EPiC device",
+	.id_table		= Epic_port_id_table,
+	.num_interrupt_in	= 1,
+	.num_bulk_in		= 1,
+	.num_bulk_out		= 1,
+	.num_ports		= 1,
+	.open			= edge_open,
+	.close			= edge_close,
+	.throttle		= edge_throttle,
+	.unthrottle		= edge_unthrottle,
+	.attach			= edge_startup,
+	.shutdown		= edge_shutdown,
+	.ioctl			= edge_ioctl,
+	.set_termios		= edge_set_termios,
+	.tiocmget		= edge_tiocmget,
+	.tiocmset		= edge_tiocmset,
+	.write			= edge_write,
+	.write_room		= edge_write_room,
+	.chars_in_buffer	= edge_chars_in_buffer,
+	.break_ctl		= edge_break,
+	.read_int_callback	= edge_interrupt_callback,
+	.read_bulk_callback	= edge_bulk_in_callback,
+	.write_bulk_callback	= edge_bulk_out_data_callback,
+};
+
 #endif
 
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 980285c..544098d 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -2979,6 +2979,7 @@
 		.name		= "edgeport_ti_1",
 	},
 	.description		= "Edgeport TI 1 port adapter",
+	.usb_driver		= &io_driver,
 	.id_table		= edgeport_1port_id_table,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 1,
@@ -3009,6 +3010,7 @@
 		.name		= "edgeport_ti_2",
 	},
 	.description		= "Edgeport TI 2 port adapter",
+	.usb_driver		= &io_driver,
 	.id_table		= edgeport_2port_id_table,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 2,
diff --git a/drivers/usb/serial/io_usbvend.h b/drivers/usb/serial/io_usbvend.h
index f1804fd..e57fa11 100644
--- a/drivers/usb/serial/io_usbvend.h
+++ b/drivers/usb/serial/io_usbvend.h
@@ -30,6 +30,7 @@
 
 #define	USB_VENDOR_ID_ION	0x1608		// Our VID
 #define	USB_VENDOR_ID_TI	0x0451		// TI VID
+#define USB_VENDOR_ID_AXIOHM	0x05D9		/* Axiohm VID */
 
 //
 // Definitions of USB product IDs (PID)
@@ -334,6 +335,10 @@
 
 };
 
+#define EDGE_COMPATIBILITY_MASK0	0x0001
+#define EDGE_COMPATIBILITY_MASK1	0x3FFF
+#define EDGE_COMPATIBILITY_MASK2	0x0001
+
 struct edge_compatibility_descriptor
 {
 	__u8	Length;				// Descriptor Length (per USB spec)
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 42f757a..a408184 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -563,6 +563,7 @@
 		.name =		"ipaq",
 	},
 	.description =		"PocketPC PDA",
+	.usb_driver = 		&ipaq_driver,
 	.id_table =		ipaq_id_table,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		1,
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index d3b9a35..1bc5860 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -442,6 +442,7 @@
 		.name =		"ipw",
 	},
 	.description =		"IPWireless converter",
+	.usb_driver = 		&usb_ipw_driver,
 	.id_table =		usb_ipw_ids,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		1,
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 8fdf486..9d847f6 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -138,6 +138,7 @@
 		.name =		"ir-usb",
 	},
 	.description =		"IR Dongle",
+	.usb_driver = 		&ir_driver,
 	.id_table =		id_table,
 	.num_interrupt_in =	1,
 	.num_bulk_in =		1,
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 9d2fdfd..e6966f1 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -1275,11 +1275,31 @@
 }
 
 /* Helper functions used by keyspan_setup_urbs */
+static struct usb_endpoint_descriptor const *find_ep(struct usb_serial const *serial,
+						     int endpoint)
+{
+	struct usb_host_interface *iface_desc;
+	struct usb_endpoint_descriptor *ep;
+	int i;
+
+	iface_desc = serial->interface->cur_altsetting;
+	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+		ep = &iface_desc->endpoint[i].desc;
+		if (ep->bEndpointAddress == endpoint)
+			return ep;
+	}
+	dev_warn(&serial->interface->dev, "found no endpoint descriptor for "
+		 "endpoint %x\n", endpoint);
+	return NULL;
+}
+
 static struct urb *keyspan_setup_urb (struct usb_serial *serial, int endpoint,
 				      int dir, void *ctx, char *buf, int len,
 				      void (*callback)(struct urb *))
 {
 	struct urb *urb;
+	struct usb_endpoint_descriptor const *ep_desc;
+	char const *ep_type_name;
 
 	if (endpoint == -1)
 		return NULL;		/* endpoint not needed */
@@ -1291,11 +1311,32 @@
 		return NULL;
 	}
 
-		/* Fill URB using supplied data. */
-	usb_fill_bulk_urb(urb, serial->dev,
-		      usb_sndbulkpipe(serial->dev, endpoint) | dir,
-		      buf, len, callback, ctx);
+	ep_desc = find_ep(serial, endpoint);
+	if (!ep_desc) {
+		/* leak the urb, something's wrong and the callers don't care */
+		return urb;
+	}
+	if (usb_endpoint_xfer_int(ep_desc)) {
+		ep_type_name = "INT";
+		usb_fill_int_urb(urb, serial->dev,
+				 usb_sndintpipe(serial->dev, endpoint) | dir,
+				 buf, len, callback, ctx,
+				 ep_desc->bInterval);
+	} else if (usb_endpoint_xfer_bulk(ep_desc)) {
+		ep_type_name = "BULK";
+		usb_fill_bulk_urb(urb, serial->dev,
+				  usb_sndbulkpipe(serial->dev, endpoint) | dir,
+				  buf, len, callback, ctx);
+	} else {
+		dev_warn(&serial->interface->dev,
+			 "unsupported endpoint type %x\n",
+			 ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+		usb_free_urb(urb);
+		return NULL;
+	}
 
+	dbg("%s - using urb %p for %s endpoint %x",
+	    __func__, urb, ep_type_name, endpoint);
 	return urb;
 }
 
diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h
index 6413d73..c6830cb 100644
--- a/drivers/usb/serial/keyspan.h
+++ b/drivers/usb/serial/keyspan.h
@@ -229,7 +229,6 @@
 #define	keyspan_usa28_product_id		0x010f
 #define	keyspan_usa28x_product_id		0x0110
 #define	keyspan_usa28xa_product_id		0x0115
-#define	keyspan_usa28xb_product_id		0x0110
 #define	keyspan_usa49w_product_id		0x010a
 #define	keyspan_usa49wlc_product_id		0x012a
 
@@ -511,7 +510,6 @@
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
-	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id)},
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
 	{ } /* Terminating entry */
@@ -559,7 +557,6 @@
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
 	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
-	{ USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xb_product_id) },
 	{ } /* Terminating entry */
 };
 
@@ -576,6 +573,7 @@
 		.name		= "keyspan_no_firm",
 	},
 	.description		= "Keyspan - (without firmware)",
+	.usb_driver		= &keyspan_driver,
 	.id_table		= keyspan_pre_ids,
 	.num_interrupt_in	= NUM_DONT_CARE,
 	.num_bulk_in		= NUM_DONT_CARE,
@@ -590,6 +588,7 @@
 		.name		= "keyspan_1",
 	},
 	.description		= "Keyspan 1 port adapter",
+	.usb_driver		= &keyspan_driver,
 	.id_table		= keyspan_1port_ids,
 	.num_interrupt_in	= NUM_DONT_CARE,
 	.num_bulk_in		= NUM_DONT_CARE,
@@ -617,6 +616,7 @@
 		.name		= "keyspan_2",
 	},
 	.description		= "Keyspan 2 port adapter",
+	.usb_driver		= &keyspan_driver,
 	.id_table		= keyspan_2port_ids,
 	.num_interrupt_in	= NUM_DONT_CARE,
 	.num_bulk_in		= NUM_DONT_CARE,
@@ -644,6 +644,7 @@
 		.name		= "keyspan_4",
 	},
 	.description		= "Keyspan 4 port adapter",
+	.usb_driver		= &keyspan_driver,
 	.id_table		= keyspan_4port_ids,
 	.num_interrupt_in	= NUM_DONT_CARE,
 	.num_bulk_in		= 5,
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 126b970..da514cb 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -793,6 +793,7 @@
 		.name =		"keyspan_pda_pre",
 	},
 	.description =		"Keyspan PDA - (prerenumeration)",
+	.usb_driver = 		&keyspan_pda_driver,
 	.id_table =		id_table_fake,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
@@ -809,6 +810,7 @@
 		.name =		"xircom_no_firm",
 	},
 	.description =		"Xircom / Entregra PGS - (prerenumeration)",
+	.usb_driver = 		&keyspan_pda_driver,
 	.id_table =		id_table_fake_xircom,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
@@ -824,6 +826,7 @@
 		.name =		"keyspan_pda",
 	},
 	.description =		"Keyspan PDA",
+	.usb_driver = 		&keyspan_pda_driver,
 	.id_table =		id_table_std,
 	.num_interrupt_in =	1,
 	.num_bulk_in =		0,
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index 5c4b06a..b2097c4 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -124,6 +124,7 @@
 		.name =		"kl5kusb105d",
 	},
 	.description =	     "KL5KUSB105D / PalmConnect",
+	.usb_driver =	     &kl5kusb105d_driver,
 	.id_table =	     id_table,
 	.num_interrupt_in =  1,
 	.num_bulk_in =	     1,
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index 62bea0c..0683b51 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -110,6 +110,7 @@
 		.name =		"kobil",
 	},
 	.description =		"KOBIL USB smart card terminal",
+	.usb_driver = 		&kobil_driver,
 	.id_table =		id_table,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		0,
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 38b1d17..4cd839b 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -137,6 +137,7 @@
 		.name =		"mct_u232",
 	},
 	.description =	     "MCT U232",
+	.usb_driver = 	     &mct_u232_driver,
 	.id_table =	     id_table_combined,
 	.num_interrupt_in =  2,
 	.num_bulk_in =	     0,
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index e55f4ed..6109c67 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -1605,12 +1605,21 @@
 	usb_set_serial_data(serial, NULL);
 }
 
+static struct usb_driver usb_driver = {
+	.name =		"moschip7720",
+	.probe =	usb_serial_probe,
+	.disconnect =	usb_serial_disconnect,
+	.id_table =	moschip_port_id_table,
+	.no_dynamic_id =	1,
+};
+
 static struct usb_serial_driver moschip7720_2port_driver = {
 	.driver = {
 		.owner =	THIS_MODULE,
 		.name =		"moschip7720",
 	},
 	.description		= "Moschip 2 port adapter",
+	.usb_driver		= &usb_driver,
 	.id_table		= moschip_port_id_table,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 2,
@@ -1631,13 +1640,6 @@
 	.read_bulk_callback	= mos7720_bulk_in_callback,
 };
 
-static struct usb_driver usb_driver = {
-	.name =		"moschip7720",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	moschip_port_id_table,
-};
-
 static int __init moschip7720_init(void)
 {
 	int retval;
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 83f6614..b2264a8 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -2834,12 +2834,21 @@
 
 }
 
+static struct usb_driver io_driver = {
+	.name = "mos7840",
+	.probe = usb_serial_probe,
+	.disconnect = usb_serial_disconnect,
+	.id_table = moschip_id_table_combined,
+	.no_dynamic_id = 1,
+};
+
 static struct usb_serial_driver moschip7840_4port_device = {
 	.driver = {
 		   .owner = THIS_MODULE,
 		   .name = "mos7840",
 		   },
 	.description = DRIVER_DESC,
+	.usb_driver = &io_driver,
 	.id_table = moschip_port_id_table,
 	.num_interrupt_in = 1,	//NUM_DONT_CARE,//1,
 #ifdef check
@@ -2869,13 +2878,6 @@
 	.read_int_callback = mos7840_interrupt_callback,
 };
 
-static struct usb_driver io_driver = {
-	.name = "mos7840",
-	.probe = usb_serial_probe,
-	.disconnect = usb_serial_disconnect,
-	.id_table = moschip_id_table_combined,
-};
-
 /****************************************************************************
  * moschip7840_init
  *	This is called by the module subsystem, or on startup to initialize us
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index 054abee..9070111 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -119,6 +119,7 @@
 		.name =		"navman",
 	},
 	.id_table =		id_table,
+	.usb_driver =		&navman_driver,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index bc91d3b..0216ac1 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -93,6 +93,7 @@
 		.name =		"omninet",
 	},
 	.description =		"ZyXEL - omni.net lcd plus usb",
+	.usb_driver =		&omninet_driver,
 	.id_table =		id_table,
 	.num_interrupt_in =	1,
 	.num_bulk_in =		1,
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index 0fed43a..ced9f32 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -135,6 +135,7 @@
 		.name =		"option1",
 	},
 	.description       = "GSM modem (1-port)",
+	.usb_driver        = &option_driver,
 	.id_table          = option_ids1,
 	.num_interrupt_in  = NUM_DONT_CARE,
 	.num_bulk_in       = NUM_DONT_CARE,
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 5dc2ac9..6c083d4 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -1118,6 +1118,7 @@
 		.name =		"pl2303",
 	},
 	.id_table =		id_table,
+	.usb_driver = 		&pl2303_driver,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		1,
 	.num_bulk_out =		1,
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 30b7ebc..5a03a3f 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -402,6 +402,7 @@
 		.name =		"safe_serial",
 	},
 	.id_table =		id_table,
+	.usb_driver =		&safe_driver,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index 6d8e91e..ecedd83 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -13,10 +13,9 @@
   Portions based on the option driver by Matthias Urlichs <smurf@smurf.noris.de>
   Whom based his on the Keyspan driver by Hugh Blemings <hugh@blemings.org>
 
-  History:
 */
 
-#define DRIVER_VERSION "v.1.0.5"
+#define DRIVER_VERSION "v.1.0.6"
 #define DRIVER_AUTHOR "Kevin Lloyd <linux@sierrawireless.com>"
 #define DRIVER_DESC "USB Driver for Sierra Wireless USB modems"
 
@@ -31,14 +30,15 @@
 
 
 static struct usb_device_id id_table [] = {
-	{ USB_DEVICE(0x1199, 0x0018) },	/* Sierra Wireless MC5720 */
-	{ USB_DEVICE(0x1199, 0x0020) },	/* Sierra Wireless MC5725 */
 	{ USB_DEVICE(0x1199, 0x0017) },	/* Sierra Wireless EM5625 */
-	{ USB_DEVICE(0x1199, 0x0019) },	/* Sierra Wireless AirCard 595 */
+	{ USB_DEVICE(0x1199, 0x0018) },	/* Sierra Wireless MC5720 */
 	{ USB_DEVICE(0x1199, 0x0218) },	/* Sierra Wireless MC5720 */
+	{ USB_DEVICE(0x1199, 0x0020) },	/* Sierra Wireless MC5725 */
+	{ USB_DEVICE(0x1199, 0x0019) },	/* Sierra Wireless AirCard 595 */
+	{ USB_DEVICE(0x1199, 0x0021) },	/* Sierra Wireless AirCard 597E */
 	{ USB_DEVICE(0x1199, 0x6802) },	/* Sierra Wireless MC8755 */
+	{ USB_DEVICE(0x1199, 0x6804) },	/* Sierra Wireless MC8755 */
 	{ USB_DEVICE(0x1199, 0x6803) },	/* Sierra Wireless MC8765 */
-	{ USB_DEVICE(0x1199, 0x6804) },	/* Sierra Wireless MC8755 for Europe */
 	{ USB_DEVICE(0x1199, 0x6812) },	/* Sierra Wireless MC8775 */
 	{ USB_DEVICE(0x1199, 0x6820) },	/* Sierra Wireless AirCard 875 */
 
@@ -55,14 +55,15 @@
 };
 
 static struct usb_device_id id_table_3port [] = {
-	{ USB_DEVICE(0x1199, 0x0018) },	/* Sierra Wireless MC5720 */
-	{ USB_DEVICE(0x1199, 0x0020) },	/* Sierra Wireless MC5725 */
 	{ USB_DEVICE(0x1199, 0x0017) },	/* Sierra Wireless EM5625 */
-	{ USB_DEVICE(0x1199, 0x0019) },	/* Sierra Wireless AirCard 595 */
+	{ USB_DEVICE(0x1199, 0x0018) },	/* Sierra Wireless MC5720 */
 	{ USB_DEVICE(0x1199, 0x0218) },	/* Sierra Wireless MC5720 */
+	{ USB_DEVICE(0x1199, 0x0020) },	/* Sierra Wireless MC5725 */
+	{ USB_DEVICE(0x1199, 0x0019) },	/* Sierra Wireless AirCard 595 */
+	{ USB_DEVICE(0x1199, 0x0021) },	/* Sierra Wireless AirCard 597E */
 	{ USB_DEVICE(0x1199, 0x6802) },	/* Sierra Wireless MC8755 */
+	{ USB_DEVICE(0x1199, 0x6804) },	/* Sierra Wireless MC8755 */
 	{ USB_DEVICE(0x1199, 0x6803) },	/* Sierra Wireless MC8765 */
-	{ USB_DEVICE(0x1199, 0x6804) },	/* Sierra Wireless MC8755 for Europe */
 	{ USB_DEVICE(0x1199, 0x6812) },	/* Sierra Wireless MC8775 */
 	{ USB_DEVICE(0x1199, 0x6820) },	/* Sierra Wireless AirCard 875 */
 	{ }
@@ -81,7 +82,7 @@
 
 /* per port private data */
 #define N_IN_URB	4
-#define N_OUT_URB	1
+#define N_OUT_URB	4
 #define IN_BUFLEN	4096
 #define OUT_BUFLEN	128
 
@@ -396,6 +397,8 @@
 	struct usb_serial *serial = port->serial;
 	int i, err;
 	struct urb *urb;
+	int result;
+	__u16 set_mode_dzero = 0x0000;
 
 	portdata = usb_get_serial_port_data(port);
 
@@ -442,6 +445,12 @@
 
 	port->tty->low_latency = 1;
 
+	/* set mode to D0 */
+	result = usb_control_msg(serial->dev,
+				 usb_rcvctrlpipe(serial->dev, 0),
+				 0x00, 0x40, set_mode_dzero, 0, NULL,
+				 0, USB_CTRL_SET_TIMEOUT);
+
 	sierra_send_setup(port);
 
 	return (0);
@@ -614,6 +623,7 @@
 	},
 	.description       = "Sierra USB modem (1 port)",
 	.id_table          = id_table_1port,
+	.usb_driver        = &sierra_driver,
 	.num_interrupt_in  = NUM_DONT_CARE,
 	.num_bulk_in       = 1,
 	.num_bulk_out      = 1,
@@ -642,6 +652,7 @@
 	},
 	.description       = "Sierra USB modem (3 port)",
 	.id_table          = id_table_3port,
+	.usb_driver        = &sierra_driver,
 	.num_interrupt_in  = NUM_DONT_CARE,
 	.num_bulk_in       = 3,
 	.num_bulk_out      = 3,
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 8318900..4203e2b 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -262,6 +262,7 @@
 		.name		= "ti_usb_3410_5052_1",
 	},
 	.description		= "TI USB 3410 1 port adapter",
+	.usb_driver		= &ti_usb_driver,
 	.id_table		= ti_id_table_3410,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 1,
@@ -292,6 +293,7 @@
 		.name		= "ti_usb_3410_5052_2",
 	},
 	.description		= "TI USB 5052 2 port adapter",
+	.usb_driver		= &ti_usb_driver,
 	.id_table		= ti_id_table_5052,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 2,
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 716f680..6bf22a2 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -59,14 +59,19 @@
 
 static int debug;
 static struct usb_serial *serial_table[SERIAL_TTY_MINORS];	/* initially all NULL */
+static spinlock_t table_lock;
 static LIST_HEAD(usb_serial_driver_list);
 
 struct usb_serial *usb_serial_get_by_index(unsigned index)
 {
-	struct usb_serial *serial = serial_table[index];
+	struct usb_serial *serial;
+
+	spin_lock(&table_lock);
+	serial = serial_table[index];
 
 	if (serial)
 		kref_get(&serial->kref);
+	spin_unlock(&table_lock);
 	return serial;
 }
 
@@ -78,6 +83,7 @@
 	dbg("%s %d", __FUNCTION__, num_ports);
 
 	*minor = 0;
+	spin_lock(&table_lock);
 	for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
 		if (serial_table[i])
 			continue;
@@ -96,8 +102,10 @@
 		dbg("%s - minor base = %d", __FUNCTION__, *minor);
 		for (i = *minor; (i < (*minor + num_ports)) && (i < SERIAL_TTY_MINORS); ++i)
 			serial_table[i] = serial;
+		spin_unlock(&table_lock);
 		return serial;
 	}
+	spin_unlock(&table_lock);
 	return NULL;
 }
 
@@ -110,9 +118,11 @@
 	if (serial == NULL)
 		return;
 
+	spin_lock(&table_lock);
 	for (i = 0; i < serial->num_ports; ++i) {
 		serial_table[serial->minor + i] = NULL;
 	}
+	spin_unlock(&table_lock);
 }
 
 static void destroy_serial(struct kref *kref)
@@ -271,7 +281,7 @@
 static int serial_write (struct tty_struct * tty, const unsigned char *buf, int count)
 {
 	struct usb_serial_port *port = tty->driver_data;
-	int retval = -EINVAL;
+	int retval = -ENODEV;
 
 	if (!port || port->serial->dev->state == USB_STATE_NOTATTACHED)
 		goto exit;
@@ -279,6 +289,7 @@
 	dbg("%s - port %d, %d byte(s)", __FUNCTION__, port->number, count);
 
 	if (!port->open_count) {
+		retval = -EINVAL;
 		dbg("%s - port not opened", __FUNCTION__);
 		goto exit;
 	}
@@ -559,15 +570,20 @@
 	port_free(port);
 }
 
-static void port_free(struct usb_serial_port *port)
+static void kill_traffic(struct usb_serial_port *port)
 {
 	usb_kill_urb(port->read_urb);
-	usb_free_urb(port->read_urb);
 	usb_kill_urb(port->write_urb);
-	usb_free_urb(port->write_urb);
 	usb_kill_urb(port->interrupt_in_urb);
-	usb_free_urb(port->interrupt_in_urb);
 	usb_kill_urb(port->interrupt_out_urb);
+}
+
+static void port_free(struct usb_serial_port *port)
+{
+	kill_traffic(port);
+	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);
 	kfree(port->bulk_in_buffer);
 	kfree(port->bulk_out_buffer);
@@ -596,6 +612,39 @@
 	return serial;
 }
 
+static const struct usb_device_id *match_dynamic_id(struct usb_interface *intf,
+						    struct usb_serial_driver *drv)
+{
+	struct usb_dynid *dynid;
+
+	spin_lock(&drv->dynids.lock);
+	list_for_each_entry(dynid, &drv->dynids.list, node) {
+		if (usb_match_one_id(intf, &dynid->id)) {
+			spin_unlock(&drv->dynids.lock);
+			return &dynid->id;
+		}
+	}
+	spin_unlock(&drv->dynids.lock);
+	return NULL;
+}
+
+static const struct usb_device_id *get_iface_id(struct usb_serial_driver *drv,
+						struct usb_interface *intf)
+{
+	const struct usb_device_id *id;
+
+	id = usb_match_id(intf, drv->id_table);
+	if (id) {
+		dbg("static descriptor matches");
+		goto exit;
+	}
+	id = match_dynamic_id(intf, drv);
+	if (id)
+		dbg("dynamic descriptor matches");
+exit:
+	return id;
+}
+
 static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
 {
 	struct list_head *p;
@@ -605,11 +654,9 @@
 	/* Check if the usb id matches a known device */
 	list_for_each(p, &usb_serial_driver_list) {
 		t = list_entry(p, struct usb_serial_driver, driver_list);
-		id = usb_match_id(iface, t->id_table);
-		if (id != NULL) {
-			dbg("descriptor matches");
+		id = get_iface_id(t, iface);
+		if (id)
 			return t;
-		}
 	}
 
 	return NULL;
@@ -639,14 +686,17 @@
 	int num_ports = 0;
 	int max_endpoints;
 
+	lock_kernel(); /* guard against unloading a serial driver module */
 	type = search_serial_device(interface);
 	if (!type) {
+		unlock_kernel();
 		dbg("none matched");
 		return -ENODEV;
 	}
 
 	serial = create_serial (dev, interface, type);
 	if (!serial) {
+		unlock_kernel();
 		dev_err(&interface->dev, "%s - out of memory\n", __FUNCTION__);
 		return -ENOMEM;
 	}
@@ -656,16 +706,18 @@
 		const struct usb_device_id *id;
 
 		if (!try_module_get(type->driver.owner)) {
+			unlock_kernel();
 			dev_err(&interface->dev, "module get failed, exiting\n");
 			kfree (serial);
 			return -EIO;
 		}
 
-		id = usb_match_id(interface, type->id_table);
+		id = get_iface_id(type, interface);
 		retval = type->probe(serial, id);
 		module_put(type->driver.owner);
 
 		if (retval) {
+			unlock_kernel();
 			dbg ("sub driver rejected device");
 			kfree (serial);
 			return retval;
@@ -735,6 +787,7 @@
 		 * properly during a later invocation of usb_serial_probe
 		 */
 		if (num_bulk_in == 0 || num_bulk_out == 0) {
+			unlock_kernel();
 			dev_info(&interface->dev, "PL-2303 hack: descriptors matched but endpoints did not\n");
 			kfree (serial);
 			return -ENODEV;
@@ -750,6 +803,7 @@
 	if (type == &usb_serial_generic_device) {
 		num_ports = num_bulk_out;
 		if (num_ports == 0) {
+			unlock_kernel();
 			dev_err(&interface->dev, "Generic device with no bulk out, not allowed.\n");
 			kfree (serial);
 			return -EIO;
@@ -760,6 +814,7 @@
 		/* if this device type has a calc_num_ports function, call it */
 		if (type->calc_num_ports) {
 			if (!try_module_get(type->driver.owner)) {
+				unlock_kernel();
 				dev_err(&interface->dev, "module get failed, exiting\n");
 				kfree (serial);
 				return -EIO;
@@ -771,12 +826,6 @@
 			num_ports = type->num_ports;
 	}
 
-	if (get_free_serial (serial, num_ports, &minor) == NULL) {
-		dev_err(&interface->dev, "No more free serial devices\n");
-		kfree (serial);
-		return -ENOMEM;
-	}
-
 	serial->minor = minor;
 	serial->num_ports = num_ports;
 	serial->num_bulk_in = num_bulk_in;
@@ -791,6 +840,8 @@
 	max_endpoints = max(max_endpoints, num_interrupt_out);
 	max_endpoints = max(max_endpoints, (int)serial->num_ports);
 	serial->num_port_pointers = max_endpoints;
+	unlock_kernel();
+
 	dbg("%s - setting up %d port structures for this device", __FUNCTION__, max_endpoints);
 	for (i = 0; i < max_endpoints; ++i) {
 		port = kzalloc(sizeof(struct usb_serial_port), GFP_KERNEL);
@@ -925,6 +976,11 @@
 		}
 	}
 
+	if (get_free_serial (serial, num_ports, &minor) == NULL) {
+		dev_err(&interface->dev, "No more free serial devices\n");
+		goto probe_error;
+	}
+
 	/* register all of the individual ports with the driver core */
 	for (i = 0; i < num_ports; ++i) {
 		port = serial->port[i];
@@ -1002,8 +1058,11 @@
 	if (serial) {
 		for (i = 0; i < serial->num_ports; ++i) {
 			port = serial->port[i];
-			if (port && port->tty)
-				tty_hangup(port->tty);
+			if (port) {
+				if (port->tty)
+					tty_hangup(port->tty);
+				kill_traffic(port);
+			}
 		}
 		/* let the last holder of this object 
 		 * cause it to be cleaned up */
@@ -1040,6 +1099,7 @@
 		return -ENOMEM;
 
 	/* Initialize our global data */
+	spin_lock_init(&table_lock);
 	for (i = 0; i < SERIAL_TTY_MINORS; ++i) {
 		serial_table[i] = NULL;
 	}
@@ -1138,7 +1198,7 @@
 	set_to_generic_if_null(device, shutdown);
 }
 
-int usb_serial_register(struct usb_serial_driver *driver)
+int usb_serial_register(struct usb_serial_driver *driver) /* must be called with BKL held */
 {
 	int retval;
 
@@ -1162,7 +1222,7 @@
 }
 
 
-void usb_serial_deregister(struct usb_serial_driver *device)
+void usb_serial_deregister(struct usb_serial_driver *device) /* must be called with BKL held */
 {
 	info("USB Serial deregistering driver %s", device->description);
 	list_del(&device->driver_list);
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index b09f060..2f59ff2 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -90,8 +90,6 @@
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID),
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
-	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID),
-		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID),
 		.driver_info = (kernel_ulong_t)&palm_os_4_probe },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID),
@@ -151,7 +149,6 @@
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_T_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TREO_650) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_TUNGSTEN_Z_ID) },
-	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE31_ID) },
 	{ USB_DEVICE(PALM_VENDOR_ID, PALM_ZIRE_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_3_5_ID) },
 	{ USB_DEVICE(SONY_VENDOR_ID, SONY_CLIE_4_0_ID) },
@@ -189,6 +186,7 @@
 		.name =		"visor",
 	},
 	.description =		"Handspring Visor / Palm OS",
+	.usb_driver =		&visor_driver,
 	.id_table =		id_table,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		2,
@@ -219,6 +217,7 @@
 		.name =		"clie_5",
 	},
 	.description =		"Sony Clie 5.0",
+	.usb_driver =		&visor_driver,
 	.id_table =		clie_id_5_table,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		2,
@@ -249,6 +248,7 @@
 		.name =		"clie_3.5",
 	},
 	.description =		"Sony Clie 3.5",
+	.usb_driver =		&visor_driver,
 	.id_table =		clie_id_3_5_table,
 	.num_interrupt_in =	0,
 	.num_bulk_in =		1,
diff --git a/drivers/usb/serial/visor.h b/drivers/usb/serial/visor.h
index 765118d..4ce6f62 100644
--- a/drivers/usb/serial/visor.h
+++ b/drivers/usb/serial/visor.h
@@ -32,7 +32,6 @@
 #define PALM_TUNGSTEN_T_ID		0x0060
 #define PALM_TREO_650			0x0061
 #define PALM_TUNGSTEN_Z_ID		0x0031
-#define PALM_ZIRE31_ID			0x0061
 #define PALM_ZIRE_ID			0x0070
 #define PALM_M100_ID			0x0080
 
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 5483d85..bf16e9e 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -161,6 +161,7 @@
 		.name =		"whiteheatnofirm",
 	},
 	.description =		"Connect Tech - WhiteHEAT - (prerenumeration)",
+	.usb_driver =		&whiteheat_driver,
 	.id_table =		id_table_prerenumeration,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
@@ -176,6 +177,7 @@
 		.name =		"whiteheat",
 	},
 	.description =		"Connect Tech - WhiteHEAT",
+	.usb_driver =		&whiteheat_driver,
 	.id_table =		id_table_std,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index e565d3d..6d3dad3 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -33,7 +33,6 @@
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/module.h>
-#include <linux/usb_ch9.h>
 #include <linux/usb/input.h>
 #include "usb.h"
 #include "onetouch.h"
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index e1072d5..70234f5 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -110,23 +110,6 @@
 	 * the end, scatter-gather buffers follow page boundaries. */
 	blk_queue_dma_alignment(sdev->request_queue, (512 - 1));
 
-	/* Set the SCSI level to at least 2.  We'll leave it at 3 if that's
-	 * what is originally reported.  We need this to avoid confusing
-	 * the SCSI layer with devices that report 0 or 1, but need 10-byte
-	 * commands (ala ATAPI devices behind certain bridges, or devices
-	 * which simply have broken INQUIRY data).
-	 *
-	 * NOTE: This means /dev/sg programs (ala cdrecord) will get the
-	 * actual information.  This seems to be the preference for
-	 * programs like that.
-	 *
-	 * NOTE: This also means that /proc/scsi/scsi and sysfs may report
-	 * the actual value or the modified one, depending on where the
-	 * data comes from.
-	 */
-	if (sdev->scsi_level < SCSI_2)
-		sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2;
-
 	/* Many devices have trouble transfering more than 32KB at a time,
 	 * while others have trouble with more than 64K. At this time we
 	 * are limiting both to 32K (64 sectores).
@@ -176,7 +159,9 @@
 		 * a Get-Max-LUN request, we won't lose much by setting the
 		 * revision level down to 2.  The only devices that would be
 		 * affected are those with sparse LUNs. */
-		sdev->scsi_level = sdev->sdev_target->scsi_level = SCSI_2;
+		if (sdev->scsi_level > SCSI_2)
+			sdev->sdev_target->scsi_level =
+					sdev->scsi_level = SCSI_2;
 
 		/* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
 		 * Hardware Error) when any low-level error occurs,
@@ -194,6 +179,16 @@
 		sdev->use_10_for_ms = 1;
 	}
 
+	/* The CB and CBI transports have no way to pass LUN values
+	 * other than the bits in the second byte of a CDB.  But those
+	 * bits don't get set to the LUN value if the device reports
+	 * scsi_level == 0 (UNKNOWN).  Hence such devices must necessarily
+	 * be single-LUN.
+	 */
+	if ((us->protocol == US_PR_CB || us->protocol == US_PR_CBI) &&
+			sdev->scsi_level == SCSI_UNKNOWN)
+		us->max_lun = 0;
+
 	/* Some devices choke when they receive a PREVENT-ALLOW MEDIUM
 	 * REMOVAL command, so suppress those commands. */
 	if (us->flags & US_FL_NOT_LOCKABLE)
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index b49f2a7..f49a62f 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -573,7 +573,7 @@
 #endif
 
 /* Submitted by Olaf Hering, <olh@suse.de> SuSE Bugzilla #49049 */
-UNUSUAL_DEV(  0x054c, 0x002c, 0x0501, 0x0501,
+UNUSUAL_DEV(  0x054c, 0x002c, 0x0501, 0x2000,
 		"Sony",
 		"USB Floppy Drive",
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
@@ -1325,13 +1325,6 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_CAPACITY ),
 
-/* Reported by Jan Mate <mate@fiit.stuba.sk> */
-UNUSUAL_DEV(  0x0fce, 0xe030, 0x0000, 0x0000,
-		"Sony Ericsson",
-		"P990i",
-		US_SC_DEVICE, US_PR_DEVICE, NULL,
-		US_FL_FIX_CAPACITY ),
-
 /* Reported by Kevin Cernekee <kpc-usbdev@gelato.uiuc.edu>
  * Tested on hardware version 1.10.
  * Entry is needed only for the initializer function override.
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index 7064450..7e7ec29 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -731,26 +731,27 @@
 	struct usb_endpoint_descriptor *ep_int = NULL;
 
 	/*
-	 * Find the endpoints we need.
+	 * Find the first endpoint of each type we need.
 	 * We are expecting a minimum of 2 endpoints - in and out (bulk).
-	 * An optional interrupt is OK (necessary for CBI protocol).
+	 * An optional interrupt-in is OK (necessary for CBI protocol).
 	 * We will ignore any others.
 	 */
 	for (i = 0; i < altsetting->desc.bNumEndpoints; i++) {
 		ep = &altsetting->endpoint[i].desc;
 
-		/* Is it a BULK endpoint? */
 		if (usb_endpoint_xfer_bulk(ep)) {
-			/* BULK in or out? */
-			if (usb_endpoint_dir_in(ep))
-				ep_in = ep;
-			else
-				ep_out = ep;
+			if (usb_endpoint_dir_in(ep)) {
+				if (!ep_in)
+					ep_in = ep;
+			} else {
+				if (!ep_out)
+					ep_out = ep;
+			}
 		}
 
-		/* Is it an interrupt endpoint? */
-		else if (usb_endpoint_xfer_int(ep)) {
-			ep_int = ep;
+		else if (usb_endpoint_is_int_in(ep)) {
+			if (!ep_int)
+				ep_int = ep;
 		}
 	}
 
diff --git a/include/linux/Kbuild b/include/linux/Kbuild
index 157db77..683513e 100644
--- a/include/linux/Kbuild
+++ b/include/linux/Kbuild
@@ -11,6 +11,7 @@
 header-y += netfilter_bridge/
 header-y += netfilter_ipv4/
 header-y += netfilter_ipv6/
+header-y += usb/
 
 header-y += affs_hardblocks.h
 header-y += aio_abi.h
@@ -326,7 +327,6 @@
 unifdef-y += uinput.h
 unifdef-y += uio.h
 unifdef-y += unistd.h
-unifdef-y += usb_ch9.h
 unifdef-y += usbdevice_fs.h
 unifdef-y += user.h
 unifdef-y += utsname.h
diff --git a/include/linux/hid.h b/include/linux/hid.h
index 93173fe..d26b08f 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -266,6 +266,7 @@
 #define HID_QUIRK_BAD_RELATIVE_KEYS		0x00010000
 #define HID_QUIRK_SKIP_OUTPUT_REPORTS		0x00020000
 #define HID_QUIRK_IGNORE_MOUSE			0x00040000
+#define HID_QUIRK_SONY_PS3_CONTROLLER		0x00080000
 
 /*
  * This is the global environment of the parser. This information is
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 733f38d..b5c226a 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -2,7 +2,7 @@
 #define __LINUX_USB_H
 
 #include <linux/mod_devicetable.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 
 #define USB_MAJOR			180
 #define USB_DEVICE_MAJOR		189
@@ -107,7 +107,8 @@
  * @needs_remote_wakeup: flag set when the driver requires remote-wakeup
  *	capability during autosuspend.
  * @dev: driver model's view of this device
- * @class_dev: driver model's class view of this device.
+ * @usb_dev: if an interface is bound to the USB major, this will point
+ *	to the sysfs representation for that device.
  * @pm_usage_cnt: PM usage counter for this interface; autosuspend is not
  *	allowed unless the counter is 0.
  *
@@ -152,7 +153,7 @@
 	unsigned needs_remote_wakeup:1;	/* driver requires remote wakeup */
 
 	struct device dev;		/* interface specific device info */
-	struct class_device *class_dev;
+	struct device *usb_dev;		/* pointer to the usb class's device, if any */
 	int pm_usage_cnt;		/* usage counter for autosuspend */
 };
 #define	to_usb_interface(d) container_of(d, struct usb_interface, dev)
@@ -372,7 +373,7 @@
 	char *serial;			/* iSerialNumber string, if present */
 
 	struct list_head filelist;
-	struct class_device *class_dev;
+	struct device *usbfs_dev;
 	struct dentry *usbfs_dentry;	/* usbfs dentry entry for the device */
 
 	/*
@@ -475,6 +476,8 @@
 			struct usb_interface *iface);
 const struct usb_device_id *usb_match_id(struct usb_interface *interface,
 					 const struct usb_device_id *id);
+extern int usb_match_one_id(struct usb_interface *interface,
+			    const struct usb_device_id *id);
 
 extern struct usb_interface *usb_find_interface(struct usb_driver *drv,
 		int minor);
@@ -554,6 +557,18 @@
 }
 
 /**
+ * usb_endpoint_xfer_control - check if the endpoint has control transfer type
+ * @epd: endpoint to be checked
+ *
+ * Returns true if the endpoint is of type control, otherwise it returns false.
+ */
+static inline int usb_endpoint_xfer_control(const struct usb_endpoint_descriptor *epd)
+{
+	return ((epd->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+		USB_ENDPOINT_XFER_CONTROL);
+}
+
+/**
  * usb_endpoint_xfer_int - check if the endpoint has interrupt transfer type
  * @epd: endpoint to be checked
  *
@@ -723,11 +738,21 @@
 
 /* ----------------------------------------------------------------------- */
 
+/* Stuff for dynamic usb ids */
 struct usb_dynids {
 	spinlock_t lock;
 	struct list_head list;
 };
 
+struct usb_dynid {
+	struct list_head node;
+	struct usb_device_id id;
+};
+
+extern ssize_t usb_store_new_id(struct usb_dynids *dynids,
+				struct device_driver *driver,
+				const char *buf, size_t count);
+
 /**
  * struct usbdrv_wrap - wrapper for driver-model structure
  * @driver: The driver-model core driver structure.
@@ -1086,7 +1111,6 @@
 	struct kref kref;		/* reference count of the URB */
 	spinlock_t lock;		/* lock for the URB */
 	void *hcpriv;			/* private data for host controller */
-	int bandwidth;			/* bandwidth for INT/ISO request */
 	atomic_t use_count;		/* concurrent submissions counter */
 	u8 reject;			/* submissions will fail */
 
diff --git a/include/linux/usb/Kbuild b/include/linux/usb/Kbuild
new file mode 100644
index 0000000..43f160c
--- /dev/null
+++ b/include/linux/usb/Kbuild
@@ -0,0 +1,5 @@
+unifdef-y += audio.h
+unifdef-y += cdc.h
+unifdef-y += ch9.h
+unifdef-y += midi.h
+
diff --git a/include/linux/usb_ch9.h b/include/linux/usb/ch9.h
similarity index 99%
rename from include/linux/usb_ch9.h
rename to include/linux/usb/ch9.h
index c720d10..ae78337 100644
--- a/include/linux/usb_ch9.h
+++ b/include/linux/usb/ch9.h
@@ -224,6 +224,7 @@
 #define USB_CLASS_CONTENT_SEC		0x0d	/* content security */
 #define USB_CLASS_VIDEO			0x0e
 #define USB_CLASS_WIRELESS_CONTROLLER	0xe0
+#define USB_CLASS_MISC			0xef
 #define USB_CLASS_APP_SPEC		0xfe
 #define USB_CLASS_VENDOR_SPEC		0xff
 
diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h
index 10f99e5..33dcd85 100644
--- a/include/linux/usb/serial.h
+++ b/include/linux/usb/serial.h
@@ -179,6 +179,9 @@
  *	memory structure allocation at this point in time.
  * @shutdown: pointer to the driver's shutdown function.  This will be
  *	called when the device is removed from the system.
+ * @usb_driver: pointer to the struct usb_driver that controls this
+ *	device.  This is necessary to allow dynamic ids to be added to
+ *	the driver from sysfs.
  *
  * This structure is defines a USB Serial driver.  It provides all of
  * the information that the USB serial core code needs.  If the function
@@ -202,6 +205,8 @@
 
 	struct list_head	driver_list;
 	struct device_driver	driver;
+	struct usb_driver	*usb_driver;
+	struct usb_dynids	dynids;
 
 	int (*probe) (struct usb_serial *serial, const struct usb_device_id *id);
 	int (*attach) (struct usb_serial *serial);
diff --git a/include/linux/usb_gadgetfs.h b/include/linux/usb_gadgetfs.h
index b53d6ae..8086d5a 100644
--- a/include/linux/usb_gadgetfs.h
+++ b/include/linux/usb_gadgetfs.h
@@ -2,7 +2,7 @@
 #include <asm/types.h>
 #include <asm/ioctl.h>
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 
 /*
  * Filesystem based user-mode API to USB Gadget controller hardware