Merge master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6
diff --git a/Documentation/DocBook/usb.tmpl b/Documentation/DocBook/usb.tmpl
index 705c442..15ce0f2 100644
--- a/Documentation/DocBook/usb.tmpl
+++ b/Documentation/DocBook/usb.tmpl
@@ -291,7 +291,7 @@
 
 !Edrivers/usb/core/hcd.c
 !Edrivers/usb/core/hcd-pci.c
-!Edrivers/usb/core/buffer.c
+!Idrivers/usb/core/buffer.c
     </chapter>
 
     <chapter>
diff --git a/Documentation/input/yealink.txt b/Documentation/input/yealink.txt
index 85f095a7..0962c5c 100644
--- a/Documentation/input/yealink.txt
+++ b/Documentation/input/yealink.txt
@@ -2,7 +2,6 @@
 
 0. Status
 ~~~~~~~~~
-
 The p1k is a relatively cheap usb 1.1 phone with:
   - keyboard		full support, yealink.ko / input event API
   - LCD			full support, yealink.ko / sysfs API
@@ -17,9 +16,8 @@
 
 1. Compilation (stand alone version)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
 Currently only kernel 2.6.x.y versions are supported.
-In order to build the yealink.ko module do:
+In order to build the yealink.ko module do
 
   make
 
@@ -28,6 +26,21 @@
 are located, default /usr/src/linux.
 
 
+1.1 Troubleshooting
+~~~~~~~~~~~~~~~~~~~
+Q: Module yealink compiled and installed without any problem but phone
+   is not initialized and does not react to any actions.
+A: If you see something like:
+   hiddev0: USB HID v1.00 Device [Yealink Network Technology Ltd. VOIP USB Phone
+   in dmesg, it means that the hid driver has grabbed the device first. Try to
+   load module yealink before any other usb hid driver. Please see the
+   instructions provided by your distribution on module configuration.
+
+Q: Phone is working now (displays version and accepts keypad input) but I can't
+   find the sysfs files.
+A: The sysfs files are located on the particular usb endpoint. On most
+   distributions you can do: "find /sys/ -name get_icons" for a hint.
+
 
 2. keyboard features
 ~~~~~~~~~~~~~~~~~~~~
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 971589a..90766b7 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1517,8 +1517,6 @@
 	uart6850=	[HW,OSS]
 			Format: <io>,<irq>
 
-	usb-handoff	[HW] Enable early USB BIOS -> OS handoff
-
 	usbhid.mousepoll=
 			[USBHID] The interval which mice are to be polled at.
 
diff --git a/MAINTAINERS b/MAINTAINERS
index 3928dc7..770155a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -116,12 +116,6 @@
 L:	linux-hams@vger.kernel.org
 S:	Maintained
 
-YEALINK PHONE DRIVER
-P:	Henk Vergonet
-M:	Henk.Vergonet@gmail.com
-L:	usbb2k-api-dev@nongnu.org
-S:	Maintained
-
 8139CP 10/100 FAST ETHERNET DRIVER
 P:	Jeff Garzik
 M:	jgarzik@pobox.com
@@ -2495,14 +2489,6 @@
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Supported
 
-USB BLUETOOTH TTY CONVERTER DRIVER
-P:	Greg Kroah-Hartman
-M:	greg@kroah.com
-L:	linux-usb-users@lists.sourceforge.net
-L:	linux-usb-devel@lists.sourceforge.net
-S:	Maintained
-W:	http://www.kroah.com/linux-usb/
-
 USB CDC ETHERNET DRIVER
 P:	Greg Kroah-Hartman
 M:	greg@kroah.com
@@ -2863,6 +2849,12 @@
 L:	linux-hams@vger.kernel.org
 S:	Maintained
 
+YEALINK PHONE DRIVER
+P:	Henk Vergonet
+M:	Henk.Vergonet@gmail.com
+L:	usbb2k-api-dev@nongnu.org
+S:	Maintained
+
 YMFPCI YAMAHA PCI SOUND (Use ALSA instead)
 P:	Pete Zaitcev
 M:	zaitcev@yahoo.com
diff --git a/drivers/Makefile b/drivers/Makefile
index 1a109a6..65670be 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -5,7 +5,7 @@
 # Rewritten to use lists instead of if-statements.
 #
 
-obj-$(CONFIG_PCI)		+= pci/
+obj-$(CONFIG_PCI)		+= pci/ usb/
 obj-$(CONFIG_PARISC)		+= parisc/
 obj-y				+= video/
 obj-$(CONFIG_ACPI)		+= acpi/
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c
index 15e6a8f..0d2e101 100644
--- a/drivers/base/power/main.c
+++ b/drivers/base/power/main.c
@@ -30,23 +30,6 @@
 DECLARE_MUTEX(dpm_sem);
 DECLARE_MUTEX(dpm_list_sem);
 
-/*
- * PM Reference Counting.
- */
-
-static inline void device_pm_hold(struct device * dev)
-{
-	if (dev)
-		atomic_inc(&dev->power.pm_users);
-}
-
-static inline void device_pm_release(struct device * dev)
-{
-	if (dev)
-		atomic_dec(&dev->power.pm_users);
-}
-
-
 /**
  *	device_pm_set_parent - Specify power dependency.
  *	@dev:		Device who needs power.
@@ -62,10 +45,8 @@
 
 void device_pm_set_parent(struct device * dev, struct device * parent)
 {
-	struct device * old_parent = dev->power.pm_parent;
-	device_pm_release(old_parent);
-	dev->power.pm_parent = parent;
-	device_pm_hold(parent);
+	put_device(dev->power.pm_parent);
+	dev->power.pm_parent = get_device(parent);
 }
 EXPORT_SYMBOL_GPL(device_pm_set_parent);
 
@@ -75,7 +56,6 @@
 
 	pr_debug("PM: Adding info for %s:%s\n",
 		 dev->bus ? dev->bus->name : "No Bus", dev->kobj.name);
-	atomic_set(&dev->power.pm_users, 0);
 	down(&dpm_list_sem);
 	list_add_tail(&dev->power.entry, &dpm_active);
 	device_pm_set_parent(dev, dev->parent);
@@ -91,7 +71,7 @@
 		 dev->bus ? dev->bus->name : "No Bus", dev->kobj.name);
 	down(&dpm_list_sem);
 	dpm_sysfs_remove(dev);
-	device_pm_release(dev->power.pm_parent);
+	put_device(dev->power.pm_parent);
 	list_del_init(&dev->power.entry);
 	up(&dpm_list_sem);
 }
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index 2e700d7..fb3d35a 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -67,9 +67,6 @@
  * runtime.c
  */
 
-extern int dpm_runtime_suspend(struct device *, pm_message_t);
-extern void dpm_runtime_resume(struct device *);
-
 #else /* CONFIG_PM */
 
 
@@ -82,14 +79,4 @@
 
 }
 
-static inline int dpm_runtime_suspend(struct device * dev, pm_message_t state)
-{
-	return 0;
-}
-
-static inline void dpm_runtime_resume(struct device * dev)
-{
-
-}
-
 #endif
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index e8f0519..adbc3148 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -36,6 +36,7 @@
 	runtime_resume(dev);
 	up(&dpm_sem);
 }
+EXPORT_SYMBOL(dpm_runtime_resume);
 
 
 /**
diff --git a/drivers/block/ub.c b/drivers/block/ub.c
index ed4d500..bfb23d5 100644
--- a/drivers/block/ub.c
+++ b/drivers/block/ub.c
@@ -1512,7 +1512,7 @@
 	scmd->nsg = 1;
 	sg = &scmd->sgv[0];
 	sg->page = virt_to_page(sc->top_sense);
-	sg->offset = (unsigned int)sc->top_sense & (PAGE_SIZE-1);
+	sg->offset = (unsigned long)sc->top_sense & (PAGE_SIZE-1);
 	sg->length = UB_SENSE_SIZE;
 	scmd->len = UB_SENSE_SIZE;
 	scmd->lun = cmd->lun;
@@ -1891,7 +1891,7 @@
 	cmd->nsg = 1;
 	sg = &cmd->sgv[0];
 	sg->page = virt_to_page(p);
-	sg->offset = (unsigned int)p & (PAGE_SIZE-1);
+	sg->offset = (unsigned long)p & (PAGE_SIZE-1);
 	sg->length = 8;
 	cmd->len = 8;
 	cmd->lun = lun;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index ee16059..bbd9c23 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -7,6 +7,9 @@
  *
  *  Copyright (c) 1999 Martin Mares <mj@ucw.cz>
  *
+ *  Init/reset quirks for USB host controllers should be in the
+ *  USB quirks file, where their drivers can access reuse it.
+ *
  *  The bridge optimization stuff has been removed. If you really
  *  have a silly BIOS which is unable to set your host bridge right,
  *  use the PowerTweak utility (see http://powertweak.sourceforge.net).
@@ -645,28 +648,6 @@
 DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq);
 
 /*
- * PIIX3 USB: We have to disable USB interrupts that are
- * hardwired to PIRQD# and may be shared with an
- * external device.
- *
- * Legacy Support Register (LEGSUP):
- *     bit13:  USB PIRQ Enable (USBPIRQDEN),
- *     bit4:   Trap/SMI On IRQ Enable (USBSMIEN).
- *
- * We mask out all r/wc bits, too.
- */
-static void __devinit quirk_piix3_usb(struct pci_dev *dev)
-{
-	u16 legsup;
-
-	pci_read_config_word(dev, 0xc0, &legsup);
-	legsup &= 0x50ef;
-	pci_write_config_word(dev, 0xc0, legsup);
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82371SB_2,	quirk_piix3_usb );
-DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL,	PCI_DEVICE_ID_INTEL_82371AB_2,	quirk_piix3_usb );
-
-/*
  * VIA VT82C598 has its device ID settable and many BIOSes
  * set it to the ID of VT82C597 for backward compatibility.
  * We need to switch it off to be able to recognize the real
@@ -1039,234 +1020,6 @@
 	pci_read_config_byte(dev, 0x77, &val);
 }
 
-
-#define UHCI_USBLEGSUP		0xc0		/* legacy support */
-#define UHCI_USBCMD		0		/* command register */
-#define UHCI_USBSTS		2		/* status register */
-#define UHCI_USBINTR		4		/* interrupt register */
-#define UHCI_USBLEGSUP_DEFAULT	0x2000		/* only PIRQ enable set */
-#define UHCI_USBCMD_RUN		(1 << 0)	/* RUN/STOP bit */
-#define UHCI_USBCMD_GRESET	(1 << 2)	/* Global reset */
-#define UHCI_USBCMD_CONFIGURE	(1 << 6)	/* config semaphore */
-#define UHCI_USBSTS_HALTED	(1 << 5)	/* HCHalted bit */
-
-#define OHCI_CONTROL		0x04
-#define OHCI_CMDSTATUS		0x08
-#define OHCI_INTRSTATUS		0x0c
-#define OHCI_INTRENABLE		0x10
-#define OHCI_INTRDISABLE	0x14
-#define OHCI_OCR		(1 << 3)	/* ownership change request */
-#define OHCI_CTRL_IR		(1 << 8)	/* interrupt routing */
-#define OHCI_INTR_OC		(1 << 30)	/* ownership change */
-
-#define EHCI_HCC_PARAMS		0x08		/* extended capabilities */
-#define EHCI_USBCMD		0		/* command register */
-#define EHCI_USBCMD_RUN		(1 << 0)	/* RUN/STOP bit */
-#define EHCI_USBSTS		4		/* status register */
-#define EHCI_USBSTS_HALTED	(1 << 12)	/* HCHalted bit */
-#define EHCI_USBINTR		8		/* interrupt register */
-#define EHCI_USBLEGSUP		0		/* legacy support register */
-#define EHCI_USBLEGSUP_BIOS	(1 << 16)	/* BIOS semaphore */
-#define EHCI_USBLEGSUP_OS	(1 << 24)	/* OS semaphore */
-#define EHCI_USBLEGCTLSTS	4		/* legacy control/status */
-#define EHCI_USBLEGCTLSTS_SOOE	(1 << 13)	/* SMI on ownership change */
-
-int usb_early_handoff __devinitdata = 0;
-static int __init usb_handoff_early(char *str)
-{
-	usb_early_handoff = 1;
-	return 0;
-}
-__setup("usb-handoff", usb_handoff_early);
-
-static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev)
-{
-	unsigned long base = 0;
-	int wait_time, delta;
-	u16 val, sts;
-	int i;
-
-	for (i = 0; i < PCI_ROM_RESOURCE; i++)
-		if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
-			base = pci_resource_start(pdev, i);
-			break;
-		}
-
-	if (!base)
-		return;
-
-	/*
-	 * stop controller
-	 */
-	sts = inw(base + UHCI_USBSTS);
-	val = inw(base + UHCI_USBCMD);
-	val &= ~(u16)(UHCI_USBCMD_RUN | UHCI_USBCMD_CONFIGURE);
-	outw(val, base + UHCI_USBCMD);
-
-	/*
-	 * wait while it stops if it was running
-	 */
-	if ((sts & UHCI_USBSTS_HALTED) == 0)
-	{
-		wait_time = 1000;
-		delta = 100;
-
-		do {
-			outw(0x1f, base + UHCI_USBSTS);
-			udelay(delta);
-			wait_time -= delta;
-			val = inw(base + UHCI_USBSTS);
-			if (val & UHCI_USBSTS_HALTED)
-				break;
-		} while (wait_time > 0);
-	}
-
-	/*
-	 * disable interrupts & legacy support
-	 */
-	outw(0, base + UHCI_USBINTR);
-	outw(0x1f, base + UHCI_USBSTS);
-	pci_read_config_word(pdev, UHCI_USBLEGSUP, &val);
-	if (val & 0xbf) 
-		pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_DEFAULT);
-		
-}
-
-static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
-{
-	void __iomem *base;
-	int wait_time;
-
-	base = ioremap_nocache(pci_resource_start(pdev, 0),
-				     pci_resource_len(pdev, 0));
-	if (base == NULL) return;
-
-	if (readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
-		wait_time = 500; /* 0.5 seconds */
-		writel(OHCI_INTR_OC, base + OHCI_INTRENABLE);
-		writel(OHCI_OCR, base + OHCI_CMDSTATUS);
-		while (wait_time > 0 && 
-				readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
-			wait_time -= 10;
-			msleep(10);
-		}
-	}
-
-	/*
-	 * disable interrupts
-	 */
-	writel(~(u32)0, base + OHCI_INTRDISABLE);
-	writel(~(u32)0, base + OHCI_INTRSTATUS);
-
-	iounmap(base);
-}
-
-static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
-{
-	int wait_time, delta;
-	void __iomem *base, *op_reg_base;
-	u32 hcc_params, val, temp;
-	u8 cap_length;
-
-	base = ioremap_nocache(pci_resource_start(pdev, 0),
-				pci_resource_len(pdev, 0));
-	if (base == NULL) return;
-
-	cap_length = readb(base);
-	op_reg_base = base + cap_length;
-	hcc_params = readl(base + EHCI_HCC_PARAMS);
-	hcc_params = (hcc_params >> 8) & 0xff;
-	if (hcc_params) {
-		pci_read_config_dword(pdev, 
-					hcc_params + EHCI_USBLEGSUP,
-					&val);
-		if (((val & 0xff) == 1) && (val & EHCI_USBLEGSUP_BIOS)) {
-			/*
-			 * Ok, BIOS is in smm mode, try to hand off...
-			 */
-			pci_read_config_dword(pdev,
-						hcc_params + EHCI_USBLEGCTLSTS,
-						&temp);
-			pci_write_config_dword(pdev,
-						hcc_params + EHCI_USBLEGCTLSTS,
-						temp | EHCI_USBLEGCTLSTS_SOOE);
-			val |= EHCI_USBLEGSUP_OS;
-			pci_write_config_dword(pdev, 
-						hcc_params + EHCI_USBLEGSUP, 
-						val);
-
-			wait_time = 500;
-			do {
-				msleep(10);
-				wait_time -= 10;
-				pci_read_config_dword(pdev,
-						hcc_params + EHCI_USBLEGSUP,
-						&val);
-			} while (wait_time && (val & EHCI_USBLEGSUP_BIOS));
-			if (!wait_time) {
-				/*
-				 * well, possibly buggy BIOS...
-				 */
-				printk(KERN_WARNING "EHCI early BIOS handoff "
-						"failed (BIOS bug ?)\n");
-				pci_write_config_dword(pdev,
-						hcc_params + EHCI_USBLEGSUP,
-						EHCI_USBLEGSUP_OS);
-				pci_write_config_dword(pdev,
-						hcc_params + EHCI_USBLEGCTLSTS,
-						0);
-			}
-		}
-	}
-
-	/*
-	 * halt EHCI & disable its interrupts in any case
-	 */
-	val = readl(op_reg_base + EHCI_USBSTS);
-	if ((val & EHCI_USBSTS_HALTED) == 0) {
-		val = readl(op_reg_base + EHCI_USBCMD);
-		val &= ~EHCI_USBCMD_RUN;
-		writel(val, op_reg_base + EHCI_USBCMD);
-
-		wait_time = 2000;
-		delta = 100;
-		do {
-			writel(0x3f, op_reg_base + EHCI_USBSTS);
-			udelay(delta);
-			wait_time -= delta;
-			val = readl(op_reg_base + EHCI_USBSTS);
-			if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) {
-				break;
-			}
-		} while (wait_time > 0);
-	}
-	writel(0, op_reg_base + EHCI_USBINTR);
-	writel(0x3f, op_reg_base + EHCI_USBSTS);
-
-	iounmap(base);
-
-	return;
-}
-
-
-
-static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
-{
-	if (!usb_early_handoff)
-		return;
-
-	if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x00)) { /* UHCI */
-		quirk_usb_handoff_uhci(pdev);
-	} else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x10)) { /* OHCI */
-		quirk_usb_handoff_ohci(pdev);
-	} else if (pdev->class == ((PCI_CLASS_SERIAL_USB << 8) | 0x20)) { /* EHCI */
-		quirk_usb_disable_ehci(pdev);
-	}
-
-	return;
-}
-DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
-
 /*
  * ... This is further complicated by the fact that some SiS96x south
  * bridges pretend to be 85C503/5513 instead.  In that case see if we
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index df014c2..a50c2bc 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -8,6 +8,7 @@
 
 obj-$(CONFIG_USB_MON)		+= mon/
 
+obj-$(CONFIG_PCI)		+= host/
 obj-$(CONFIG_USB_EHCI_HCD)	+= host/
 obj-$(CONFIG_USB_ISP116X_HCD)	+= host/
 obj-$(CONFIG_USB_OHCI_HCD)	+= host/
@@ -17,7 +18,6 @@
 
 obj-$(CONFIG_USB_ACM)		+= class/
 obj-$(CONFIG_USB_AUDIO)		+= class/
-obj-$(CONFIG_USB_BLUETOOTH_TTY)	+= class/
 obj-$(CONFIG_USB_MIDI)		+= class/
 obj-$(CONFIG_USB_PRINTER)	+= class/
 
diff --git a/drivers/usb/class/Kconfig b/drivers/usb/class/Kconfig
index 333e39b..ef105a9 100644
--- a/drivers/usb/class/Kconfig
+++ b/drivers/usb/class/Kconfig
@@ -28,29 +28,6 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called audio.
 
-comment "USB Bluetooth TTY can only be used with disabled Bluetooth subsystem"
-	depends on USB && BT
-
-config USB_BLUETOOTH_TTY
-	tristate "USB Bluetooth TTY support"
-	depends on USB && BT=n
-	---help---
-	  This driver implements a nonstandard tty interface to a Bluetooth
-	  device that can be used only by specialized Bluetooth HCI software.
-
-	  Say Y here if you want to use OpenBT Bluetooth stack (available
-	  at <http://developer.axis.com/software>), or other TTY based
-	  Bluetooth stacks, and want to connect a USB Bluetooth device
-	  to your computer's USB port.
-
-	  Do *not* enable this driver if you want to use generic Linux
-	  Bluetooth support.
-
-	  If in doubt, say N here.
-
-	  To compile this driver as a module, choose M here: the
-	  module will be called bluetty.
-
 config USB_MIDI
 	tristate "USB MIDI support"
 	depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER
diff --git a/drivers/usb/class/Makefile b/drivers/usb/class/Makefile
index 971e549..2294712 100644
--- a/drivers/usb/class/Makefile
+++ b/drivers/usb/class/Makefile
@@ -5,6 +5,5 @@
 
 obj-$(CONFIG_USB_ACM)		+= cdc-acm.o
 obj-$(CONFIG_USB_AUDIO)		+= audio.o
-obj-$(CONFIG_USB_BLUETOOTH_TTY)	+= bluetty.o
 obj-$(CONFIG_USB_MIDI)		+= usb-midi.o
 obj-$(CONFIG_USB_PRINTER)	+= usblp.o
diff --git a/drivers/usb/class/bluetty.c b/drivers/usb/class/bluetty.c
deleted file mode 100644
index 5240233..0000000
--- a/drivers/usb/class/bluetty.c
+++ /dev/null
@@ -1,1279 +0,0 @@
-/*
- * bluetty.c   Version 0.13
- *
- * Copyright (C) 2000, 2001 Greg Kroah-Hartman	<greg@kroah.com>
- * Copyright (C) 2000 Mark Douglas Corner	<mcorner@umich.edu>
- *
- * USB Bluetooth TTY driver, based on the Bluetooth Spec version 1.0B
- * 
- * (2001/11/30) Version 0.13 gkh
- *	- added locking patch from Masoodur Rahman <rmasoodu@in.ibm.com>
- *	- removed active variable, as open_count will do.
- *
- * (2001/07/09) Version 0.12 gkh
- *	- removed in_interrupt() call, as it doesn't make sense to do 
- *	  that anymore.
- *
- * (2001/06/05) Version 0.11 gkh
- *	- Fixed problem with read urb status saying that we have shutdown,
- *	  and that we shouldn't resubmit the urb.  Patch from unknown.
- *
- * (2001/05/28) Version 0.10 gkh
- *	- Fixed problem with using data from userspace in the bluetooth_write
- *	  function as found by the CHECKER project.
- *	- Added a buffer to the write_urb_pool which reduces the number of
- *	  buffers being created and destroyed for ever write.  Also cleans
- *	  up the logic a bit.
- *	- Added a buffer to the control_urb_pool which fixes a memory leak
- *	  when the device is removed from the system.
- *
- * (2001/05/28) Version 0.9 gkh
- *	Fixed problem with bluetooth==NULL for bluetooth_read_bulk_callback
- *	which was found by both the CHECKER project and Mikko Rahkonen.
- *
- * (08/04/2001) gb
- *	Identify version on module load.
- *
- * (2001/03/10) Version 0.8 gkh
- *	Fixed problem with not unlinking interrupt urb on device close
- *	and resubmitting the read urb on error with bluetooth struct.
- *	Thanks to Narayan Mohanram <narayan@RovingNetworks.com> for the
- *	fixes.
- *
- * (11/29/2000) Version 0.7 gkh
- *	Fixed problem with overrunning the tty flip buffer.
- *	Removed unneeded NULL pointer initialization.
- *
- * (10/05/2000) Version 0.6 gkh
- *	Fixed bug with urb->dev not being set properly, now that the usb
- *	core needs it.
- *	Got a real major id number and name.
- *
- * (08/06/2000) Version 0.5 gkh
- *	Fixed problem of not resubmitting the bulk read urb if there is
- *	an error in the callback.  Ericsson devices seem to need this.
- *
- * (07/11/2000) Version 0.4 gkh
- *	Fixed bug in disconnect for when we call tty_hangup
- *	Fixed bug in bluetooth_ctrl_msg where the bluetooth struct was not
- *	getting attached to the control urb properly.
- *	Fixed bug in bluetooth_write where we pay attention to the result
- *	of bluetooth_ctrl_msg.
- *
- * (08/03/2000) Version 0.3 gkh mdc
- *	Merged in Mark's changes to make the driver play nice with the Axis
- *	stack.
- *	Made the write bulk use an urb pool to enable larger transfers with
- *	fewer calls to the driver.
- *	Fixed off by one bug in acl pkt receive
- *	Made packet counters specific to each bluetooth device 
- *	Added checks for zero length callbacks
- *	Added buffers for int and bulk packets.  Had to do this otherwise 
- *	packet types could intermingle.
- *	Made a control urb pool for the control messages.
- *
- * (07/11/2000) Version 0.2 gkh
- *	Fixed a small bug found by Nils Faerber in the usb_bluetooth_probe 
- *	function.
- *
- * (07/09/2000) Version 0.1 gkh
- *	Initial release. Has support for sending ACL data (which is really just
- *	a HCI frame.) Raw HCI commands and HCI events are not supported.
- *	A ioctl will probably be needed for the HCI commands and events in the
- *	future. All isoch endpoints are ignored at this time also.
- *	This driver should work for all currently shipping USB Bluetooth 
- *	devices at this time :)
- * 
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * 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 <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/tty.h>
-#include <linux/tty_driver.h>
-#include <linux/tty_flip.h>
-#include <linux/module.h>
-#include <asm/uaccess.h>
-
-#define DEBUG
-#include <linux/usb.h>
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v0.13"
-#define DRIVER_AUTHOR "Greg Kroah-Hartman, Mark Douglas Corner"
-#define DRIVER_DESC "USB Bluetooth tty driver"
-
-/* define this if you have hardware that is not good */
-/*#define	BTBUGGYHARDWARE */
-
-/* Class, SubClass, and Protocol codes that describe a Bluetooth device */
-#define WIRELESS_CLASS_CODE			0xe0
-#define RF_SUBCLASS_CODE			0x01
-#define BLUETOOTH_PROGRAMMING_PROTOCOL_CODE	0x01
-
-
-#define BLUETOOTH_TTY_MAJOR	216	/* real device node major id */
-#define BLUETOOTH_TTY_MINORS	256	/* whole lotta bluetooth devices */
-
-#define USB_BLUETOOTH_MAGIC	0x6d02	/* magic number for bluetooth struct */
-
-#define BLUETOOTH_CONTROL_REQUEST_TYPE	0x20
-
-/* Bluetooth packet types */
-#define CMD_PKT			0x01
-#define ACL_PKT			0x02
-#define SCO_PKT			0x03
-#define EVENT_PKT		0x04
-#define ERROR_PKT		0x05
-#define NEG_PKT			0x06
-
-/* Message sizes */
-#define MAX_EVENT_SIZE		0xFF
-#define EVENT_HDR_SIZE		3	/* 2 for the header + 1 for the type indicator */
-#define EVENT_BUFFER_SIZE	(MAX_EVENT_SIZE + EVENT_HDR_SIZE)
-
-#define MAX_ACL_SIZE		0xFFFF
-#define ACL_HDR_SIZE		5	/* 4 for the header + 1 for the type indicator */
-#define ACL_BUFFER_SIZE		(MAX_ACL_SIZE + ACL_HDR_SIZE)
-
-/* parity check flag */
-#define RELEVANT_IFLAG(iflag)	(iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
-#define CHAR2INT16(c1,c0)	(((u32)((c1) & 0xff) << 8) + (u32)((c0) & 0xff))
-
-#define NUM_BULK_URBS		24
-#define NUM_CONTROL_URBS	16
-
-struct usb_bluetooth {
-	int			magic;
-	struct usb_device *	dev;
-	struct tty_driver *	tty_driver;	/* the tty_driver for this device */
-	struct tty_struct *	tty;		/* the corresponding tty for this port */
-
-	unsigned char		minor;		/* the starting minor number for this device */
-	int			throttle;	/* throttled by tty layer */
-	int			open_count;
-	
-	__u8			control_out_bInterfaceNum;
-	struct urb *		control_urb_pool[NUM_CONTROL_URBS];
-	struct usb_ctrlrequest	dr[NUM_CONTROL_URBS];
-
-	unsigned char *		interrupt_in_buffer;
-	struct urb *		interrupt_in_urb;
-	__u8			interrupt_in_endpointAddress;
-	__u8			interrupt_in_interval;
-	int			interrupt_in_buffer_size;
-
-	unsigned char *		bulk_in_buffer;
-	struct urb *		read_urb;
-	__u8			bulk_in_endpointAddress;
-	int			bulk_in_buffer_size;
-
-	int			bulk_out_buffer_size;
-	__u8			bulk_out_endpointAddress;
-
-	wait_queue_head_t	write_wait;
-
-	struct work_struct			work;	/* work queue entry for line discipline waking up */
-	
-	unsigned int		int_packet_pos;
-	unsigned char		int_buffer[EVENT_BUFFER_SIZE];
-	unsigned int		bulk_packet_pos;
-	unsigned char		bulk_buffer[ACL_BUFFER_SIZE];	/* 64k preallocated, fix? */
-	struct semaphore	lock;
-};
-
-
-/* local function prototypes */
-static int  bluetooth_open		(struct tty_struct *tty, struct file *filp);
-static void bluetooth_close		(struct tty_struct *tty, struct file *filp);
-static int  bluetooth_write		(struct tty_struct *tty, const unsigned char *buf, int count);
-static int  bluetooth_write_room	(struct tty_struct *tty);
-static int  bluetooth_chars_in_buffer	(struct tty_struct *tty);
-static void bluetooth_throttle		(struct tty_struct *tty);
-static void bluetooth_unthrottle	(struct tty_struct *tty);
-static int  bluetooth_ioctl		(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg);
-static void bluetooth_set_termios	(struct tty_struct *tty, struct termios *old);
-
-static void bluetooth_int_callback		(struct urb *urb, struct pt_regs *regs);
-static void bluetooth_ctrl_callback		(struct urb *urb, struct pt_regs *regs);
-static void bluetooth_read_bulk_callback	(struct urb *urb, struct pt_regs *regs);
-static void bluetooth_write_bulk_callback	(struct urb *urb, struct pt_regs *regs);
-
-static int usb_bluetooth_probe (struct usb_interface *intf, 
-				const struct usb_device_id *id);
-static void usb_bluetooth_disconnect	(struct usb_interface *intf);
-
-
-static struct usb_device_id usb_bluetooth_ids [] = {
-	{ USB_DEVICE_INFO(WIRELESS_CLASS_CODE, RF_SUBCLASS_CODE, BLUETOOTH_PROGRAMMING_PROTOCOL_CODE) },
-	{ }						/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, usb_bluetooth_ids);
-
-static struct usb_driver usb_bluetooth_driver = {
-	.owner =	THIS_MODULE,
-	.name =		"bluetty",
-	.probe =	usb_bluetooth_probe,
-	.disconnect =	usb_bluetooth_disconnect,
-	.id_table =	usb_bluetooth_ids,
-};
-
-static struct tty_driver	*bluetooth_tty_driver;
-static struct usb_bluetooth	*bluetooth_table[BLUETOOTH_TTY_MINORS];
-
-
-static inline int bluetooth_paranoia_check (struct usb_bluetooth *bluetooth, const char *function)
-{
-	if (!bluetooth) {
-		dbg("%s - bluetooth == NULL", function);
-		return -1;
-	}
-	if (bluetooth->magic != USB_BLUETOOTH_MAGIC) {
-		dbg("%s - bad magic number for bluetooth", function);
-		return -1;
-	}
-
-	return 0;
-}
-
-
-static inline struct usb_bluetooth* get_usb_bluetooth (struct usb_bluetooth *bluetooth, const char *function)
-{
-	if (!bluetooth || 
-	    bluetooth_paranoia_check (bluetooth, function)) { 
-		/* then say that we don't have a valid usb_bluetooth thing, which will
-		 * end up generating -ENODEV return values */
-		return NULL;
-	}
-
-	return bluetooth;
-}
-
-
-static inline struct usb_bluetooth *get_bluetooth_by_index (int index)
-{
-	return bluetooth_table[index];
-}
-
-
-static int bluetooth_ctrl_msg (struct usb_bluetooth *bluetooth, int request, int value, const unsigned char *buf, int len)
-{
-	struct urb *urb = NULL;
-	struct usb_ctrlrequest *dr = NULL;
-	int i;
-	int status;
-
-	dbg ("%s", __FUNCTION__);
-
-	/* try to find a free urb in our list */
-	for (i = 0; i < NUM_CONTROL_URBS; ++i) {
-		if (bluetooth->control_urb_pool[i]->status != -EINPROGRESS) {
-			urb = bluetooth->control_urb_pool[i];
-			dr = &bluetooth->dr[i];
-			break;
-		}
-	}
-	if (urb == NULL) {
-		dbg ("%s - no free urbs", __FUNCTION__);
-		return -ENOMEM;
-	}
-
-	/* keep increasing the urb transfer buffer to fit the size of the message */
-	if (urb->transfer_buffer == NULL) {
-		urb->transfer_buffer = kmalloc (len, GFP_KERNEL);
-		if (urb->transfer_buffer == NULL) {
-			err ("%s - out of memory", __FUNCTION__);
-			return -ENOMEM;
-		}
-	}
-	if (urb->transfer_buffer_length < len) {
-		kfree(urb->transfer_buffer);
-		urb->transfer_buffer = kmalloc (len, GFP_KERNEL);
-		if (urb->transfer_buffer == NULL) {
-			err ("%s - out of memory", __FUNCTION__);
-			return -ENOMEM;
-		}
-	}
-	memcpy (urb->transfer_buffer, buf, len);
-
-	dr->bRequestType= BLUETOOTH_CONTROL_REQUEST_TYPE;
-	dr->bRequest = request;
-	dr->wValue = cpu_to_le16((u16) value);
-	dr->wIndex = cpu_to_le16((u16) bluetooth->control_out_bInterfaceNum);
-	dr->wLength = cpu_to_le16((u16) len);
-	
-	usb_fill_control_urb (urb, bluetooth->dev, usb_sndctrlpipe(bluetooth->dev, 0),
-			  (unsigned char*)dr, urb->transfer_buffer, len, bluetooth_ctrl_callback, bluetooth);
-
-	/* send it down the pipe */
-	status = usb_submit_urb(urb, GFP_KERNEL);
-	if (status)
-		dbg("%s - usb_submit_urb(control) failed with status = %d", __FUNCTION__, status);
-	
-	return status;
-}
-
-
-
-
-
-/*****************************************************************************
- * Driver tty interface functions
- *****************************************************************************/
-static int bluetooth_open (struct tty_struct *tty, struct file * filp)
-{
-	struct usb_bluetooth *bluetooth;
-	int result;
-
-	dbg("%s", __FUNCTION__);
-
-	/* initialize the pointer incase something fails */
-	tty->driver_data = NULL;
-
-	/* get the bluetooth object associated with this tty pointer */
-	bluetooth = get_bluetooth_by_index (tty->index);
-
-	if (bluetooth_paranoia_check (bluetooth, __FUNCTION__)) {
-		return -ENODEV;
-	}
-
-	down (&bluetooth->lock);
- 
-	++bluetooth->open_count;
-	if (bluetooth->open_count == 1) {
-		/* set up our structure making the tty driver remember our object, and us it */
-		tty->driver_data = bluetooth;
-		bluetooth->tty = tty;
-
-		/* force low_latency on so that our tty_push actually forces the data through, 
-	 	* otherwise it is scheduled, and with high data rates (like with OHCI) data
-	 	* can get lost. */
-		bluetooth->tty->low_latency = 1;
-	
-		/* Reset the packet position counters */
-		bluetooth->int_packet_pos = 0;
-		bluetooth->bulk_packet_pos = 0;
-
-#ifndef BTBUGGYHARDWARE
-		/* Start reading from the device */
-		usb_fill_bulk_urb (bluetooth->read_urb, bluetooth->dev, 
-			       usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress),
-			       bluetooth->bulk_in_buffer,
-			       bluetooth->bulk_in_buffer_size,
-			       bluetooth_read_bulk_callback, bluetooth);
-		result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL);
-		if (result)
-			dbg("%s - usb_submit_urb(read bulk) failed with status %d", __FUNCTION__, result);
-#endif
-		usb_fill_int_urb (bluetooth->interrupt_in_urb, bluetooth->dev,
-			      usb_rcvintpipe(bluetooth->dev, bluetooth->interrupt_in_endpointAddress),
-			      bluetooth->interrupt_in_buffer,
-			      bluetooth->interrupt_in_buffer_size,
-			      bluetooth_int_callback, bluetooth,
-			      bluetooth->interrupt_in_interval);
-		result = usb_submit_urb(bluetooth->interrupt_in_urb, GFP_KERNEL);
-		if (result)
-			dbg("%s - usb_submit_urb(interrupt in) failed with status %d", __FUNCTION__, result);
-	}
-	
-	up(&bluetooth->lock);
-
-	return 0;
-}
-
-
-static void bluetooth_close (struct tty_struct *tty, struct file * filp)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
-
-	if (!bluetooth) {
-		return;
-	}
-
-	dbg("%s", __FUNCTION__);
-
-	if (!bluetooth->open_count) {
-		dbg ("%s - device not opened", __FUNCTION__);
-		return;
-	}
-
-	down (&bluetooth->lock);
- 
-	--bluetooth->open_count;
-	if (bluetooth->open_count <= 0) {
-		bluetooth->open_count = 0;
-
-		/* shutdown any in-flight urbs that we know about */
-		usb_kill_urb (bluetooth->read_urb);
-		usb_kill_urb (bluetooth->interrupt_in_urb);
-	}
-	up(&bluetooth->lock);
-}
-
-
-static int bluetooth_write (struct tty_struct * tty, const unsigned char *buf, int count)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
-	struct urb *urb = NULL;
-	unsigned char *temp_buffer = NULL;
-	const unsigned char *current_buffer;
-	unsigned char *urb_buffer;
-	int i;
-	int retval = 0;
-
-	if (!bluetooth) {
-		return -ENODEV;
-	}
-
-	dbg("%s - %d byte(s)", __FUNCTION__, count);
-
-	if (!bluetooth->open_count) {
-		dbg ("%s - device not opened", __FUNCTION__);
-		return -EINVAL;
-	}
-
-	if (count == 0) {
-		dbg("%s - write request of 0 bytes", __FUNCTION__);
-		return 0;
-	}
-	if (count == 1) {
-		dbg("%s - write request only included type %d", __FUNCTION__, buf[0]);
-		return 1;
-	}
-
-#ifdef DEBUG
-	printk (KERN_DEBUG __FILE__ ": %s - length = %d, data = ", __FUNCTION__, count);
-	for (i = 0; i < count; ++i) {
-		printk ("%.2x ", buf[i]);
-	}
-	printk ("\n");
-#endif
-
-	current_buffer = buf;
-
-	switch (*current_buffer) {
-		/* First byte indicates the type of packet */
-		case CMD_PKT:
-			/* dbg("%s- Send cmd_pkt len:%d", __FUNCTION__, count);*/
-
-			retval = bluetooth_ctrl_msg (bluetooth, 0x00, 0x00, &current_buffer[1], count-1);
-			if (retval) {
-				goto exit;
-			}
-			retval = count;
-			break;
-
-		case ACL_PKT:
-			++current_buffer;
-			--count;
-
-			urb_buffer = kmalloc (count, GFP_ATOMIC);
-			if (!urb_buffer) {
-				dev_err(&bluetooth->dev->dev, "out of memory\n");
-				retval = -ENOMEM;
-				goto exit;
-			}
-
-			urb = usb_alloc_urb(0, GFP_ATOMIC);
-			if (!urb) {
-				dev_err(&bluetooth->dev->dev, "no more free urbs\n");
-				kfree(urb_buffer);
-				retval = -ENOMEM;
-				goto exit;
-			}
-			memcpy (urb_buffer, current_buffer, count);
-
-			/* build up our urb */
-			usb_fill_bulk_urb(urb, bluetooth->dev, 
-					  usb_sndbulkpipe(bluetooth->dev,
-						  	  bluetooth->bulk_out_endpointAddress),
-					  urb_buffer,
-					  count,
-					  bluetooth_write_bulk_callback,
-					  bluetooth);
-
-
-			/* send it down the pipe */
-			retval = usb_submit_urb(urb, GFP_KERNEL);
-			if (retval) {
-				dbg("%s - usb_submit_urb(write bulk) failed with error = %d", __FUNCTION__, retval);
-				goto exit;
-			}
-
-			/* we are done with this urb, so let the host driver
-			 * really free it when it is finished with it */
-			usb_free_urb (urb);
-			retval = count + 1;
-			break;
-		
-		default :
-			dbg("%s - unsupported (at this time) write type", __FUNCTION__);
-			retval = -EINVAL;
-			break;
-	}
-
-exit:
-	kfree(temp_buffer);
-
-	return retval;
-} 
-
-
-static int bluetooth_write_room (struct tty_struct *tty) 
-{
-	dbg("%s", __FUNCTION__);
-
-	/*
-	 * We really can take anything the user throws at us
-	 * but let's pick a nice big number to tell the tty
-	 * layer that we have lots of free space
-	 */
-	return 2048;
-}
-
-
-static int bluetooth_chars_in_buffer (struct tty_struct *tty) 
-{
-	dbg("%s", __FUNCTION__);
-
-	/* 
-	 * We can't really account for how much data we
-	 * have sent out, but hasn't made it through to the
-	 * device, so just tell the tty layer that everything
-	 * is flushed.
-	 */
-	return 0;
-}
-
-
-static void bluetooth_throttle (struct tty_struct * tty)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
-
-	if (!bluetooth) {
-		return;
-	}
-
-	dbg("%s", __FUNCTION__);
-
-	if (!bluetooth->open_count) {
-		dbg ("%s - device not open", __FUNCTION__);
-		return;
-	}
-	
-	dbg("%s unsupported (at this time)", __FUNCTION__);
-
-	return;
-}
-
-
-static void bluetooth_unthrottle (struct tty_struct * tty)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
-
-	if (!bluetooth) {
-		return;
-	}
-
-	dbg("%s", __FUNCTION__);
-
-	if (!bluetooth->open_count) {
-		dbg ("%s - device not open", __FUNCTION__);
-		return;
-	}
-
-	dbg("%s unsupported (at this time)", __FUNCTION__);
-}
-
-
-static int bluetooth_ioctl (struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
-
-	if (!bluetooth) {
-		return -ENODEV;
-	}
-
-	dbg("%s - cmd 0x%.4x", __FUNCTION__, cmd);
-
-	if (!bluetooth->open_count) {
-		dbg ("%s - device not open", __FUNCTION__);
-		return -ENODEV;
-	}
-
-	/* FIXME!!! */
-	return -ENOIOCTLCMD;
-}
-
-
-static void bluetooth_set_termios (struct tty_struct *tty, struct termios * old)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
-
-	if (!bluetooth) {
-		return;
-	}
-
-	dbg("%s", __FUNCTION__);
-
-	if (!bluetooth->open_count) {
-		dbg ("%s - device not open", __FUNCTION__);
-		return;
-	}
-
-	/* FIXME!!! */
-
-	return;
-}
-
-
-#ifdef BTBUGGYHARDWARE
-void btusb_enable_bulk_read(struct tty_struct *tty){
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
-	int result;
-
-	if (!bluetooth) {
-		return;
-	}
-
-	dbg("%s", __FUNCTION__);
-
-	if (!bluetooth->open_count) {
-		dbg ("%s - device not open", __FUNCTION__);
-		return;
-	}
-
-	if (bluetooth->read_urb) {
-		usb_fill_bulk_urb(bluetooth->read_urb, bluetooth->dev, 
-			      usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress),
-			      bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, 
-			      bluetooth_read_bulk_callback, bluetooth);
-		result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL);
-		if (result)
-			err ("%s - failed submitting read urb, error %d", __FUNCTION__, result);
-	}
-}
-
-void btusb_disable_bulk_read(struct tty_struct *tty){
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)tty->driver_data, __FUNCTION__);
-
-	if (!bluetooth) {
-		return;
-	}
-
-	dbg("%s", __FUNCTION__);
-
-	if (!bluetooth->open_count) {
-		dbg ("%s - device not open", __FUNCTION__);
-		return;
-	}
-
-	if ((bluetooth->read_urb) && (bluetooth->read_urb->actual_length))
-		usb_kill_urb(bluetooth->read_urb);
-}
-#endif
-
-
-/*****************************************************************************
- * urb callback functions
- *****************************************************************************/
-
-
-static void bluetooth_int_callback (struct urb *urb, struct pt_regs *regs)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
-	unsigned char *data = urb->transfer_buffer;
-	unsigned int i;
-	unsigned int count = urb->actual_length;
-	unsigned int packet_size;
-	int status;
-
-	dbg("%s", __FUNCTION__);
-
-	if (!bluetooth) {
-		dbg("%s - bad bluetooth pointer, exiting", __FUNCTION__);
-		return;
-	}
-
-	switch (urb->status) {
-	case 0:
-		/* success */
-		break;
-	case -ECONNRESET:
-	case -ENOENT:
-	case -ESHUTDOWN:
-		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
-		return;
-	default:
-		dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
-		goto exit;
-	}
-
-	if (!count) {
-		dbg("%s - zero length int", __FUNCTION__);
-		goto exit;
-	}
-
-
-#ifdef DEBUG
-	if (count) {
-		printk (KERN_DEBUG __FILE__ ": %s- length = %d, data = ", __FUNCTION__, count);
-		for (i = 0; i < count; ++i) {
-			printk ("%.2x ", data[i]);
-		}
-		printk ("\n");
-	}
-#endif
-
-#ifdef BTBUGGYHARDWARE
-	if ((count >= 2) && (data[0] == 0xFF) && (data[1] == 0x00)) {
-		data += 2;
-		count -= 2;
-	}
-	if (count == 0) {
-		urb->actual_length = 0;
-		goto exit;
-	}
-#endif
-	/* We add  a packet type identifier to the beginning of each
-	   HCI frame.  This makes the data in the tty look like a
-	   serial USB devices.  Each HCI frame can be broken across
-	   multiple URBs so we buffer them until we have a full hci
-	   packet */
-
-	if (!bluetooth->int_packet_pos) {
-		bluetooth->int_buffer[0] = EVENT_PKT;
-		bluetooth->int_packet_pos++;
-	}
-	
-	if (bluetooth->int_packet_pos + count > EVENT_BUFFER_SIZE) {
-		err("%s - exceeded EVENT_BUFFER_SIZE", __FUNCTION__);
-		bluetooth->int_packet_pos = 0;
-		goto exit;
-	}
-
-	memcpy (&bluetooth->int_buffer[bluetooth->int_packet_pos],
-		urb->transfer_buffer, count);
-	bluetooth->int_packet_pos += count;
-	urb->actual_length = 0;
-
-	if (bluetooth->int_packet_pos >= EVENT_HDR_SIZE)
-		packet_size = bluetooth->int_buffer[2];
-	else
-		goto exit;
-
-	if (packet_size + EVENT_HDR_SIZE < bluetooth->int_packet_pos) {
-		err("%s - packet was too long", __FUNCTION__);
-		bluetooth->int_packet_pos = 0;
-		goto exit;
-	}
-
-	if (packet_size + EVENT_HDR_SIZE == bluetooth->int_packet_pos) {
-		for (i = 0; i < bluetooth->int_packet_pos; ++i) {
-			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them */
-			if (bluetooth->tty->flip.count >= TTY_FLIPBUF_SIZE) {
-				tty_flip_buffer_push(bluetooth->tty);
-			}
-			tty_insert_flip_char(bluetooth->tty, bluetooth->int_buffer[i], 0);
-		}
-		tty_flip_buffer_push(bluetooth->tty);
-
-		bluetooth->int_packet_pos = 0;
-	}
-
-exit:
-	status = usb_submit_urb (urb, GFP_ATOMIC);
-	if (status)
-		err ("%s - usb_submit_urb failed with result %d",
-		     __FUNCTION__, status);
-}
-
-
-static void bluetooth_ctrl_callback (struct urb *urb, struct pt_regs *regs)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
-
-	dbg("%s", __FUNCTION__);
-
-	if (!bluetooth) {
-		dbg("%s - bad bluetooth pointer, exiting", __FUNCTION__);
-		return;
-	}
-
-	if (urb->status) {
-		dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
-		return;
-	}
-}
-
-
-static void bluetooth_read_bulk_callback (struct urb *urb, struct pt_regs *regs)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
-	unsigned char *data = urb->transfer_buffer;
-	unsigned int count = urb->actual_length;
-	unsigned int i;
-	unsigned int packet_size;
-	int result;
-
-
-	dbg("%s", __FUNCTION__);
-
-	if (!bluetooth) {
-		dbg("%s - bad bluetooth pointer, exiting", __FUNCTION__);
-		return;
-	}
-
-	if (urb->status) {
-		dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
-		if (urb->status == -ENOENT) {                   
-			dbg("%s - URB canceled, won't reschedule", __FUNCTION__);
-			return;
-		}
-		goto exit;
-	}
-
-	if (!count) {
-		dbg("%s - zero length read bulk", __FUNCTION__);
-		goto exit;
-	}
-
-#ifdef DEBUG
-	if (count) {
-		printk (KERN_DEBUG __FILE__ ": %s- length = %d, data = ", __FUNCTION__, count);
-		for (i = 0; i < count; ++i) {
-			printk ("%.2x ", data[i]);
-		}
-		printk ("\n");
-	}
-#endif
-#ifdef BTBUGGYHARDWARE
-	if ((count == 4) && (data[0] == 0x00) && (data[1] == 0x00)
-	    && (data[2] == 0x00) && (data[3] == 0x00)) {
-		urb->actual_length = 0;
-		usb_fill_bulk_urb(bluetooth->read_urb, bluetooth->dev, 
-			      usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress),
-			      bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, 
-			      bluetooth_read_bulk_callback, bluetooth);
-		result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL);
-		if (result)
-			err ("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
-
-		return;
-	}
-#endif
-	/* We add  a packet type identifier to the beginning of each
-	   HCI frame.  This makes the data in the tty look like a
-	   serial USB devices.  Each HCI frame can be broken across
-	   multiple URBs so we buffer them until we have a full hci
-	   packet */
-	
-	if (!bluetooth->bulk_packet_pos) {
-		bluetooth->bulk_buffer[0] = ACL_PKT;
-		bluetooth->bulk_packet_pos++;
-	}
-
-	if (bluetooth->bulk_packet_pos + count > ACL_BUFFER_SIZE) {
-		err("%s - exceeded ACL_BUFFER_SIZE", __FUNCTION__);
-		bluetooth->bulk_packet_pos = 0;
-		goto exit;
-	}
-
-	memcpy (&bluetooth->bulk_buffer[bluetooth->bulk_packet_pos],
-		urb->transfer_buffer, count);
-	bluetooth->bulk_packet_pos += count;
-	urb->actual_length = 0;
-
-	if (bluetooth->bulk_packet_pos >= ACL_HDR_SIZE) {
-		packet_size = CHAR2INT16(bluetooth->bulk_buffer[4],bluetooth->bulk_buffer[3]);
-	} else {
-		goto exit;
-	}
-
-	if (packet_size + ACL_HDR_SIZE < bluetooth->bulk_packet_pos) {
-		err("%s - packet was too long", __FUNCTION__);
-		bluetooth->bulk_packet_pos = 0;
-		goto exit;
-	}
-
-	if (packet_size + ACL_HDR_SIZE == bluetooth->bulk_packet_pos) {
-		for (i = 0; i < bluetooth->bulk_packet_pos; ++i) {
-			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
-			if (bluetooth->tty->flip.count >= TTY_FLIPBUF_SIZE) {
-				tty_flip_buffer_push(bluetooth->tty);
-			}
-			tty_insert_flip_char(bluetooth->tty, bluetooth->bulk_buffer[i], 0);
-		}
-		tty_flip_buffer_push(bluetooth->tty);
-		bluetooth->bulk_packet_pos = 0;
-	}	
-
-exit:
-	if (!bluetooth || !bluetooth->open_count)
-		return;
-
-	usb_fill_bulk_urb(bluetooth->read_urb, bluetooth->dev, 
-		      usb_rcvbulkpipe(bluetooth->dev, bluetooth->bulk_in_endpointAddress),
-		      bluetooth->bulk_in_buffer, bluetooth->bulk_in_buffer_size, 
-		      bluetooth_read_bulk_callback, bluetooth);
-	result = usb_submit_urb(bluetooth->read_urb, GFP_KERNEL);
-	if (result)
-		err ("%s - failed resubmitting read urb, error %d", __FUNCTION__, result);
-
-	return;
-}
-
-
-static void bluetooth_write_bulk_callback (struct urb *urb, struct pt_regs *regs)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)urb->context, __FUNCTION__);
-
-	dbg("%s", __FUNCTION__);
-
-	/* free up the transfer buffer, as usb_free_urb() does not do this */
-	kfree(urb->transfer_buffer);
-
-	if (!bluetooth) {
-		dbg("%s - bad bluetooth pointer, exiting", __FUNCTION__);
-		return;
-	}
-
-	if (urb->status) {
-		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
-		return;
-	}
-
-	/* wake up our little function to let the tty layer know that something happened */
-	schedule_work(&bluetooth->work);
-}
-
-
-static void bluetooth_softint(void *private)
-{
-	struct usb_bluetooth *bluetooth = get_usb_bluetooth ((struct usb_bluetooth *)private, __FUNCTION__);
-
-	dbg("%s", __FUNCTION__);
-
-	if (!bluetooth)
-		return;
-
-	tty_wakeup(bluetooth->tty);
-}
-
-
-static int usb_bluetooth_probe (struct usb_interface *intf, 
-				const struct usb_device_id *id)
-{
-	struct usb_device *dev = interface_to_usbdev (intf);
-	struct usb_bluetooth *bluetooth = NULL;
-	struct usb_host_interface *interface;
-	struct usb_endpoint_descriptor *endpoint;
-	struct usb_endpoint_descriptor *interrupt_in_endpoint[8];
-	struct usb_endpoint_descriptor *bulk_in_endpoint[8];
-	struct usb_endpoint_descriptor *bulk_out_endpoint[8];
-	int control_out_endpoint;
-
-	int minor;
-	int buffer_size;
-	int i;
-	int num_interrupt_in = 0;
-	int num_bulk_in = 0;
-	int num_bulk_out = 0;
-
-	interface = intf->cur_altsetting;
-	control_out_endpoint = interface->desc.bInterfaceNumber;
-
-	/* find the endpoints that we need */
-	for (i = 0; i < interface->desc.bNumEndpoints; ++i) {
-		endpoint = &interface->endpoint[i].desc;
-
-		if ((endpoint->bEndpointAddress & 0x80) &&
-		    ((endpoint->bmAttributes & 3) == 0x02)) {
-			/* we found a bulk in endpoint */
-			dbg("found bulk in");
-			bulk_in_endpoint[num_bulk_in] = endpoint;
-			++num_bulk_in;
-		}
-
-		if (((endpoint->bEndpointAddress & 0x80) == 0x00) &&
-		    ((endpoint->bmAttributes & 3) == 0x02)) {
-			/* we found a bulk out endpoint */
-			dbg("found bulk out");
-			bulk_out_endpoint[num_bulk_out] = endpoint;
-			++num_bulk_out;
-		}
-
-		if ((endpoint->bEndpointAddress & 0x80) &&
-		    ((endpoint->bmAttributes & 3) == 0x03)) {
-			/* we found a interrupt in endpoint */
-			dbg("found interrupt in");
-			interrupt_in_endpoint[num_interrupt_in] = endpoint;
-			++num_interrupt_in;
-		}
-	}
-
-	/* according to the spec, we can only have 1 bulk_in, 1 bulk_out, and 1 interrupt_in endpoints */
-	if ((num_bulk_in != 1) ||
-	    (num_bulk_out != 1) ||
-	    (num_interrupt_in != 1)) {
-		dbg ("%s - improper number of endpoints. Bluetooth driver not bound.", __FUNCTION__);
-		return -EIO;
-	}
-
-	info("USB Bluetooth converter detected");
-
-	for (minor = 0; minor < BLUETOOTH_TTY_MINORS && bluetooth_table[minor]; ++minor)
-		;
-	if (bluetooth_table[minor]) {
-		err("No more free Bluetooth devices");
-		return -ENODEV;
-	}
-
-	if (!(bluetooth = kmalloc(sizeof(struct usb_bluetooth), GFP_KERNEL))) {
-		err("Out of memory");
-		return -ENOMEM;
-	}
-
-	memset(bluetooth, 0, sizeof(struct usb_bluetooth));
-
-	bluetooth->magic = USB_BLUETOOTH_MAGIC;
-	bluetooth->dev = dev;
-	bluetooth->minor = minor;
-	INIT_WORK(&bluetooth->work, bluetooth_softint, bluetooth);
-	init_MUTEX(&bluetooth->lock);
-
-	/* record the interface number for the control out */
-	bluetooth->control_out_bInterfaceNum = control_out_endpoint;
-	
-	/* create our control out urb pool */ 
-	for (i = 0; i < NUM_CONTROL_URBS; ++i) {
-		struct urb  *urb = usb_alloc_urb(0, GFP_KERNEL);
-		if (urb == NULL) {
-			err("No free urbs available");
-			goto probe_error;
-		}
-		urb->transfer_buffer = NULL;
-		bluetooth->control_urb_pool[i] = urb;
-	}
-
-	/* set up the endpoint information */
-	endpoint = bulk_in_endpoint[0];
-	bluetooth->read_urb = usb_alloc_urb (0, GFP_KERNEL);
-	if (!bluetooth->read_urb) {
-		err("No free urbs available");
-		goto probe_error;
-	}
-	bluetooth->bulk_in_buffer_size = buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
-	bluetooth->bulk_in_endpointAddress = endpoint->bEndpointAddress;
-	bluetooth->bulk_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
-	if (!bluetooth->bulk_in_buffer) {
-		err("Couldn't allocate bulk_in_buffer");
-		goto probe_error;
-	}
-	usb_fill_bulk_urb(bluetooth->read_urb, dev, usb_rcvbulkpipe(dev, endpoint->bEndpointAddress),
-		      bluetooth->bulk_in_buffer, buffer_size, bluetooth_read_bulk_callback, bluetooth);
-
-	endpoint = bulk_out_endpoint[0];
-	bluetooth->bulk_out_endpointAddress = endpoint->bEndpointAddress;
-	bluetooth->bulk_out_buffer_size = le16_to_cpu(endpoint->wMaxPacketSize) * 2;
-
-	endpoint = interrupt_in_endpoint[0];
-	bluetooth->interrupt_in_urb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!bluetooth->interrupt_in_urb) {
-		err("No free urbs available");
-		goto probe_error;
-	}
-	bluetooth->interrupt_in_buffer_size = buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
-	bluetooth->interrupt_in_endpointAddress = endpoint->bEndpointAddress;
-	bluetooth->interrupt_in_interval = endpoint->bInterval;
-	bluetooth->interrupt_in_buffer = kmalloc (buffer_size, GFP_KERNEL);
-	if (!bluetooth->interrupt_in_buffer) {
-		err("Couldn't allocate interrupt_in_buffer");
-		goto probe_error;
-	}
-	usb_fill_int_urb(bluetooth->interrupt_in_urb, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
-		     bluetooth->interrupt_in_buffer, buffer_size, bluetooth_int_callback,
-		     bluetooth, endpoint->bInterval);
-
-	/* initialize the devfs nodes for this device and let the user know what bluetooths we are bound to */
-	tty_register_device (bluetooth_tty_driver, minor, &intf->dev);
-	info("Bluetooth converter now attached to ttyUB%d (or usb/ttub/%d for devfs)", minor, minor);
-
-	bluetooth_table[minor] = bluetooth;
-
-	/* success */
-	usb_set_intfdata (intf, bluetooth);
-	return 0;
-
-probe_error:
-	if (bluetooth->read_urb)
-		usb_free_urb (bluetooth->read_urb);
-	if (bluetooth->bulk_in_buffer)
-		kfree (bluetooth->bulk_in_buffer);
-	if (bluetooth->interrupt_in_urb)
-		usb_free_urb (bluetooth->interrupt_in_urb);
-	if (bluetooth->interrupt_in_buffer)
-		kfree (bluetooth->interrupt_in_buffer);
-	for (i = 0; i < NUM_CONTROL_URBS; ++i) 
-		if (bluetooth->control_urb_pool[i]) {
-			if (bluetooth->control_urb_pool[i]->transfer_buffer)
-				kfree (bluetooth->control_urb_pool[i]->transfer_buffer);
-			usb_free_urb (bluetooth->control_urb_pool[i]);
-		}
-
-	bluetooth_table[minor] = NULL;
-
-	/* free up any memory that we allocated */
-	kfree (bluetooth);
-	return -EIO;
-}
-
-
-static void usb_bluetooth_disconnect(struct usb_interface *intf)
-{
-	struct usb_bluetooth *bluetooth = usb_get_intfdata (intf);
-	int i;
-
-	usb_set_intfdata (intf, NULL);
-	if (bluetooth) {
-		if ((bluetooth->open_count) && (bluetooth->tty))
-			tty_hangup(bluetooth->tty);
-
-		bluetooth->open_count = 0;
-
-		if (bluetooth->read_urb) {
-			usb_kill_urb (bluetooth->read_urb);
-			usb_free_urb (bluetooth->read_urb);
-		}
-		if (bluetooth->bulk_in_buffer)
-			kfree (bluetooth->bulk_in_buffer);
-
-		if (bluetooth->interrupt_in_urb) {
-			usb_kill_urb (bluetooth->interrupt_in_urb);
-			usb_free_urb (bluetooth->interrupt_in_urb);
-		}
-		if (bluetooth->interrupt_in_buffer)
-			kfree (bluetooth->interrupt_in_buffer);
-
-		tty_unregister_device (bluetooth_tty_driver, bluetooth->minor);
-
-		for (i = 0; i < NUM_CONTROL_URBS; ++i) {
-			if (bluetooth->control_urb_pool[i]) {
-				usb_kill_urb (bluetooth->control_urb_pool[i]);
-				if (bluetooth->control_urb_pool[i]->transfer_buffer)
-					kfree (bluetooth->control_urb_pool[i]->transfer_buffer);
-				usb_free_urb (bluetooth->control_urb_pool[i]);
-			}
-		}
-		
-		info("Bluetooth converter now disconnected from ttyUB%d", bluetooth->minor);
-
-		bluetooth_table[bluetooth->minor] = NULL;
-
-		/* free up any memory that we allocated */
-		kfree (bluetooth);
-	} else {
-		info("device disconnected");
-	}
-}
-
-static struct tty_operations bluetooth_ops = {
-	.open =			bluetooth_open,
-	.close =		bluetooth_close,
-	.write =		bluetooth_write,
-	.write_room =		bluetooth_write_room,
-	.ioctl =		bluetooth_ioctl,
-	.set_termios =		bluetooth_set_termios,
-	.throttle =		bluetooth_throttle,
-	.unthrottle =		bluetooth_unthrottle,
-	.chars_in_buffer =	bluetooth_chars_in_buffer,
-};
-
-static int usb_bluetooth_init(void)
-{
-	int i;
-	int result;
-
-	/* Initialize our global data */
-	for (i = 0; i < BLUETOOTH_TTY_MINORS; ++i) {
-		bluetooth_table[i] = NULL;
-	}
-
-	info ("USB Bluetooth support registered");
-
-	bluetooth_tty_driver = alloc_tty_driver(BLUETOOTH_TTY_MINORS);
-	if (!bluetooth_tty_driver)
-		return -ENOMEM;
-
-	bluetooth_tty_driver->owner = THIS_MODULE;
-	bluetooth_tty_driver->driver_name = "usb-bluetooth";
-	bluetooth_tty_driver->name = "ttyUB";
-	bluetooth_tty_driver->devfs_name = "usb/ttub/";
-	bluetooth_tty_driver->major = BLUETOOTH_TTY_MAJOR;
-	bluetooth_tty_driver->minor_start = 0;
-	bluetooth_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
-	bluetooth_tty_driver->subtype = SERIAL_TYPE_NORMAL;
-	bluetooth_tty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
-	bluetooth_tty_driver->init_termios = tty_std_termios;
-	bluetooth_tty_driver->init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-	tty_set_operations(bluetooth_tty_driver, &bluetooth_ops);
-	if (tty_register_driver (bluetooth_tty_driver)) {
-		err("%s - failed to register tty driver", __FUNCTION__);
-		put_tty_driver(bluetooth_tty_driver);
-		return -1;
-	}
-
-	/* register the USB driver */
-	result = usb_register(&usb_bluetooth_driver);
-	if (result < 0) {
-		tty_unregister_driver(bluetooth_tty_driver);
-		put_tty_driver(bluetooth_tty_driver);
-		err("usb_register failed for the USB bluetooth driver. Error number %d", result);
-		return -1;
-	}
-
-	info(DRIVER_DESC " " DRIVER_VERSION);
-
-	return 0;
-}
-
-
-static void usb_bluetooth_exit(void)
-{
-	usb_deregister(&usb_bluetooth_driver);
-	tty_unregister_driver(bluetooth_tty_driver);
-	put_tty_driver(bluetooth_tty_driver);
-}
-
-
-module_init(usb_bluetooth_init);
-module_exit(usb_bluetooth_exit);
-
-/* Module information */
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 16ecad3..1b47514 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -827,11 +827,10 @@
 		return -ENODEV;
 	}
 
-	if (!(acm = kmalloc(sizeof(struct acm), GFP_KERNEL))) {
-		dev_dbg(&intf->dev, "out of memory (acm kmalloc)\n");
+	if (!(acm = kzalloc(sizeof(struct acm), GFP_KERNEL))) {
+		dev_dbg(&intf->dev, "out of memory (acm kzalloc)\n");
 		goto alloc_fail;
 	}
-	memset(acm, 0, sizeof(struct acm));
 
 	ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
 	readsize = le16_to_cpu(epread->wMaxPacketSize);
diff --git a/drivers/usb/class/usblp.c b/drivers/usb/class/usblp.c
index e195709..357e753 100644
--- a/drivers/usb/class/usblp.c
+++ b/drivers/usb/class/usblp.c
@@ -844,9 +844,8 @@
 };
 
 static struct usb_class_driver usblp_class = {
-	.name =		"usb/lp%d",
+	.name =		"lp%d",
 	.fops =		&usblp_fops,
-	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
 	.minor_base =	USBLP_MINOR_BASE,
 };
 
diff --git a/drivers/usb/core/Kconfig b/drivers/usb/core/Kconfig
index 1a9ff61..ff03184 100644
--- a/drivers/usb/core/Kconfig
+++ b/drivers/usb/core/Kconfig
@@ -61,14 +61,17 @@
 	  If you are unsure about this, say N here.
 
 config USB_SUSPEND
-	bool "USB suspend/resume (EXPERIMENTAL)"
+	bool "USB selective suspend/resume and wakeup (EXPERIMENTAL)"
 	depends on USB && PM && EXPERIMENTAL
 	help
 	  If you say Y here, you can use driver calls or the sysfs
 	  "power/state" file to suspend or resume individual USB
-	  peripherals.  There are many related features, such as
-	  remote wakeup and driver-specific suspend processing, that
-	  may not yet work as expected.
+	  peripherals.
+
+	  Also, USB "remote wakeup" signaling is supported, whereby some
+	  USB devices (like keyboards and network adapters) can wake up
+	  their parent hub.  That wakeup cascades up the USB tree, and
+	  could wake the system from states like suspend-to-RAM.
 
 	  If you are unsure about this, say N here.
 
diff --git a/drivers/usb/core/Makefile b/drivers/usb/core/Makefile
index d5503cf..dd1c4d2 100644
--- a/drivers/usb/core/Makefile
+++ b/drivers/usb/core/Makefile
@@ -3,7 +3,7 @@
 #
 
 usbcore-objs	:= usb.o hub.o hcd.o urb.o message.o \
-			config.o file.o buffer.o sysfs.o devio.o
+			config.o file.o buffer.o sysfs.o devio.o notify.o
 
 ifeq ($(CONFIG_PCI),y)
 	usbcore-objs	+= hcd-pci.o
diff --git a/drivers/usb/core/config.c b/drivers/usb/core/config.c
index 99595e0..9930195 100644
--- a/drivers/usb/core/config.c
+++ b/drivers/usb/core/config.c
@@ -112,8 +112,12 @@
 	struct usb_interface_cache *intfc = ref_to_usb_interface_cache(ref);
 	int j;
 
-	for (j = 0; j < intfc->num_altsetting; j++)
-		kfree(intfc->altsetting[j].endpoint);
+	for (j = 0; j < intfc->num_altsetting; j++) {
+		struct usb_host_interface *alt = &intfc->altsetting[j];
+
+		kfree(alt->endpoint);
+		kfree(alt->string);
+	}
 	kfree(intfc);
 }
 
@@ -188,10 +192,9 @@
 	}
 
 	len = sizeof(struct usb_host_endpoint) * num_ep;
-	alt->endpoint = kmalloc(len, GFP_KERNEL);
+	alt->endpoint = kzalloc(len, GFP_KERNEL);
 	if (!alt->endpoint)
 		return -ENOMEM;
-	memset(alt->endpoint, 0, len);
 
 	/* Parse all the endpoint descriptors */
 	n = 0;
@@ -353,10 +356,9 @@
 		}
 
 		len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j;
-		config->intf_cache[i] = intfc = kmalloc(len, GFP_KERNEL);
+		config->intf_cache[i] = intfc = kzalloc(len, GFP_KERNEL);
 		if (!intfc)
 			return -ENOMEM;
-		memset(intfc, 0, len);
 		kref_init(&intfc->ref);
 	}
 
@@ -422,8 +424,6 @@
 		struct usb_host_config *cf = &dev->config[c];
 
 		kfree(cf->string);
-		cf->string = NULL;
-
 		for (i = 0; i < cf->desc.bNumInterfaces; i++) {
 			if (cf->intf_cache[i])
 				kref_put(&cf->intf_cache[i]->ref, 
@@ -459,16 +459,14 @@
 	}
 
 	length = ncfg * sizeof(struct usb_host_config);
-	dev->config = kmalloc(length, GFP_KERNEL);
+	dev->config = kzalloc(length, GFP_KERNEL);
 	if (!dev->config)
 		goto err2;
-	memset(dev->config, 0, length);
 
 	length = ncfg * sizeof(char *);
-	dev->rawdescriptors = kmalloc(length, GFP_KERNEL);
+	dev->rawdescriptors = kzalloc(length, GFP_KERNEL);
 	if (!dev->rawdescriptors)
 		goto err2;
-	memset(dev->rawdescriptors, 0, length);
 
 	buffer = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
 	if (!buffer)
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index befe0c7..942cd43 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -46,6 +46,7 @@
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/cdev.h>
+#include <linux/notifier.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 #include <linux/moduleparam.h>
@@ -209,10 +210,10 @@
 static struct async *alloc_async(unsigned int numisoframes)
 {
         unsigned int assize = sizeof(struct async) + numisoframes * sizeof(struct usb_iso_packet_descriptor);
-        struct async *as = kmalloc(assize, GFP_KERNEL);
+        struct async *as = kzalloc(assize, GFP_KERNEL);
+
         if (!as)
                 return NULL;
-        memset(as, 0, assize);
 	as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL);
 	if (!as->urb) {
 		kfree(as);
@@ -279,6 +280,28 @@
         return NULL;
 }
 
+static void snoop_urb(struct urb *urb, void __user *userurb)
+{
+	int j;
+	unsigned char *data = urb->transfer_buffer;
+
+	if (!usbfs_snoop)
+		return;
+
+	if (urb->pipe & USB_DIR_IN)
+		dev_info(&urb->dev->dev, "direction=IN\n");
+	else
+		dev_info(&urb->dev->dev, "direction=OUT\n");
+	dev_info(&urb->dev->dev, "userurb=%p\n", userurb);
+	dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n",
+		 urb->transfer_buffer_length);
+	dev_info(&urb->dev->dev, "actual_length=%d\n", urb->actual_length);
+	dev_info(&urb->dev->dev, "data: ");
+	for (j = 0; j < urb->transfer_buffer_length; ++j)
+		printk ("%02x ", data[j]);
+	printk("\n");
+}
+
 static void async_completed(struct urb *urb, struct pt_regs *regs)
 {
         struct async *as = (struct async *)urb->context;
@@ -296,7 +319,9 @@
 		kill_proc_info_as_uid(as->signr, &sinfo, as->pid, as->uid, 
 				      as->euid);
 	}
-        wake_up(&ps->wait);
+	snoop(&urb->dev->dev, "urb complete\n");
+	snoop_urb(urb, as->userurb);
+	wake_up(&ps->wait);
 }
 
 static void destroy_async (struct dev_state *ps, struct list_head *list)
@@ -493,6 +518,23 @@
 	return ret;
 }
 
+static struct usb_device *usbdev_lookup_minor(int minor)
+{
+	struct class_device *class_dev;
+	struct usb_device *dev = 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;
+			break;
+		}
+	}
+	up(&usb_device_class->sem);
+
+	return dev;
+};
+
 /*
  * file operations
  */
@@ -601,7 +643,7 @@
 			if (usbfs_snoop) {
 				dev_info(&dev->dev, "control read: data ");
 				for (j = 0; j < i; ++j)
-					printk ("%02x ", (unsigned char)(tbuf)[j]);
+					printk("%02x ", (unsigned char)(tbuf)[j]);
 				printk("\n");
 			}
 			if (copy_to_user(ctrl.data, tbuf, i)) {
@@ -624,7 +666,7 @@
 		if (usbfs_snoop) {
 			dev_info(&dev->dev, "control write: data: ");
 			for (j = 0; j < ctrl.wLength; ++j)
-				printk ("%02x ", (unsigned char)(tbuf)[j]);
+				printk("%02x ", (unsigned char)(tbuf)[j]);
 			printk("\n");
 		}
 		usb_unlock_device(dev);
@@ -649,7 +691,7 @@
 	unsigned int tmo, len1, pipe;
 	int len2;
 	unsigned char *tbuf;
-	int i, ret;
+	int i, j, ret;
 
 	if (copy_from_user(&bulk, arg, sizeof(bulk)))
 		return -EFAULT;
@@ -674,10 +716,18 @@
 			kfree(tbuf);
 			return -EINVAL;
 		}
+		snoop(&dev->dev, "bulk read: len=0x%02x timeout=%04d\n",
+			bulk.len, bulk.timeout);
 		usb_unlock_device(dev);
 		i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
 		usb_lock_device(dev);
 		if (!i && len2) {
+			if (usbfs_snoop) {
+				dev_info(&dev->dev, "bulk read: data ");
+				for (j = 0; j < len2; ++j)
+					printk("%02x ", (unsigned char)(tbuf)[j]);
+				printk("\n");
+			}
 			if (copy_to_user(bulk.data, tbuf, len2)) {
 				kfree(tbuf);
 				return -EFAULT;
@@ -690,6 +740,14 @@
 				return -EFAULT;
 			}
 		}
+		snoop(&dev->dev, "bulk write: len=0x%02x timeout=%04d\n",
+			bulk.len, bulk.timeout);
+		if (usbfs_snoop) {
+			dev_info(&dev->dev, "bulk write: data: ");
+			for (j = 0; j < len1; ++j)
+				printk("%02x ", (unsigned char)(tbuf)[j]);
+			printk("\n");
+		}
 		usb_unlock_device(dev);
 		i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
 		usb_lock_device(dev);
@@ -835,7 +893,6 @@
 	return status;
 }
 
-
 static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 			     struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
 			     void __user *arg)
@@ -896,6 +953,7 @@
 			kfree(dr);
 			return -EFAULT;
 		}
+		snoop(&ps->dev->dev, "control urb\n");
 		break;
 
 	case USBDEVFS_URB_TYPE_BULK:
@@ -910,6 +968,7 @@
 			return -EINVAL;
 		if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
 			return -EFAULT;
+		snoop(&ps->dev->dev, "bulk urb\n");
 		break;
 
 	case USBDEVFS_URB_TYPE_ISO:
@@ -939,6 +998,7 @@
 			return -EINVAL;
 		}
 		uurb->buffer_length = totlen;
+		snoop(&ps->dev->dev, "iso urb\n");
 		break;
 
 	case USBDEVFS_URB_TYPE_INTERRUPT:
@@ -954,6 +1014,7 @@
 			return -EINVAL;
 		if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
 			return -EFAULT;
+		snoop(&ps->dev->dev, "interrupt urb\n");
 		break;
 
 	default:
@@ -1003,6 +1064,8 @@
 			return -EFAULT;
 		}
 	}
+	snoop(&as->urb->dev->dev, "submit urb\n");
+	snoop_urb(as->urb, as->userurb);
         async_newpending(as);
         if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
 		dev_printk(KERN_DEBUG, &ps->dev->dev, "usbfs: usb_submit_urb returned %d\n", ret);
@@ -1238,23 +1301,20 @@
 	return 0;
 }
 
-static int proc_ioctl (struct dev_state *ps, void __user *arg)
+static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
 {
-	struct usbdevfs_ioctl	ctrl;
 	int			size;
 	void			*buf = NULL;
 	int			retval = 0;
 	struct usb_interface    *intf = NULL;
 	struct usb_driver       *driver = NULL;
 
-	/* get input parameters and alloc buffer */
-	if (copy_from_user(&ctrl, arg, sizeof (ctrl)))
-		return -EFAULT;
-	if ((size = _IOC_SIZE (ctrl.ioctl_code)) > 0) {
+	/* alloc buffer */
+	if ((size = _IOC_SIZE (ctl->ioctl_code)) > 0) {
 		if ((buf = kmalloc (size, GFP_KERNEL)) == NULL)
 			return -ENOMEM;
-		if ((_IOC_DIR(ctrl.ioctl_code) & _IOC_WRITE)) {
-			if (copy_from_user (buf, ctrl.data, size)) {
+		if ((_IOC_DIR(ctl->ioctl_code) & _IOC_WRITE)) {
+			if (copy_from_user (buf, ctl->data, size)) {
 				kfree(buf);
 				return -EFAULT;
 			}
@@ -1270,9 +1330,9 @@
 
 	if (ps->dev->state != USB_STATE_CONFIGURED)
 		retval = -EHOSTUNREACH;
-	else if (!(intf = usb_ifnum_to_if (ps->dev, ctrl.ifno)))
+	else if (!(intf = usb_ifnum_to_if (ps->dev, ctl->ifno)))
                retval = -EINVAL;
-	else switch (ctrl.ioctl_code) {
+	else switch (ctl->ioctl_code) {
 
 	/* disconnect kernel driver from interface */
 	case USBDEVFS_DISCONNECT:
@@ -1304,7 +1364,7 @@
 		if (driver == NULL || driver->ioctl == NULL) {
 			retval = -ENOTTY;
 		} else {
-			retval = driver->ioctl (intf, ctrl.ioctl_code, buf);
+			retval = driver->ioctl (intf, ctl->ioctl_code, buf);
 			if (retval == -ENOIOCTLCMD)
 				retval = -ENOTTY;
 		}
@@ -1313,15 +1373,42 @@
 
 	/* cleanup and return */
 	if (retval >= 0
-			&& (_IOC_DIR (ctrl.ioctl_code) & _IOC_READ) != 0
+			&& (_IOC_DIR (ctl->ioctl_code) & _IOC_READ) != 0
 			&& size > 0
-			&& copy_to_user (ctrl.data, buf, size) != 0)
+			&& copy_to_user (ctl->data, buf, size) != 0)
 		retval = -EFAULT;
 
 	kfree(buf);
 	return retval;
 }
 
+static int proc_ioctl_default(struct dev_state *ps, void __user *arg)
+{
+	struct usbdevfs_ioctl	ctrl;
+
+	if (copy_from_user(&ctrl, arg, sizeof (ctrl)))
+		return -EFAULT;
+	return proc_ioctl(ps, &ctrl);
+}
+
+#ifdef CONFIG_COMPAT
+static int proc_ioctl_compat(struct dev_state *ps, void __user *arg)
+{
+	struct usbdevfs_ioctl32 __user *uioc;
+	struct usbdevfs_ioctl ctrl;
+	u32 udata;
+
+	uioc = compat_ptr(arg);
+	if (get_user(ctrl.ifno, &uioc->ifno) ||
+	    get_user(ctrl.ioctl_code, &uioc->ioctl_code) ||
+	    __get_user(udata, &uioc->data))
+		return -EFAULT;
+	ctrl.data = compat_ptr(udata);
+
+	return proc_ioctl(ps, &ctrl);
+}
+#endif
+
 /*
  * NOTE:  All requests here that have interface numbers as parameters
  * are assuming that somehow the configuration has been prevented from
@@ -1422,6 +1509,10 @@
 		ret = proc_reapurbnonblock_compat(ps, p);
 		break;
 
+	case USBDEVFS_IOCTL32:
+		snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__);
+		ret = proc_ioctl_compat(ps, p);
+		break;
 #endif
 
 	case USBDEVFS_DISCARDURB:
@@ -1456,7 +1547,7 @@
 
 	case USBDEVFS_IOCTL:
 		snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__);
-		ret = proc_ioctl(ps, p);
+		ret = proc_ioctl_default(ps, p);
 		break;
 	}
 	usb_unlock_device(dev);
@@ -1488,24 +1579,7 @@
 	.release =	usbdev_release,
 };
 
-struct usb_device *usbdev_lookup_minor(int minor)
-{
-	struct class_device *class_dev;
-	struct usb_device *dev = 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;
-			break;
-		}
-	}
-	up(&usb_device_class->sem);
-
-	return dev;
-};
-
-void usbdev_add(struct usb_device *dev)
+static void usbdev_add(struct usb_device *dev)
 {
 	int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
 
@@ -1516,11 +1590,29 @@
 	dev->class_dev->class_data = dev;
 }
 
-void usbdev_remove(struct usb_device *dev)
+static void usbdev_remove(struct usb_device *dev)
 {
 	class_device_unregister(dev->class_dev);
 }
 
+static int usbdev_notify(struct notifier_block *self, unsigned long action,
+			 void *dev)
+{
+	switch (action) {
+	case USB_DEVICE_ADD:
+		usbdev_add(dev);
+		break;
+	case USB_DEVICE_REMOVE:
+		usbdev_remove(dev);
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block usbdev_nb = {
+	.notifier_call = 	usbdev_notify,
+};
+
 static struct cdev usb_device_cdev = {
 	.kobj   = {.name = "usb_device", },
 	.owner  = THIS_MODULE,
@@ -1540,24 +1632,32 @@
 	retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);
 	if (retval) {
 		err("unable to get usb_device major %d", USB_DEVICE_MAJOR);
-		unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
-		goto out;
+		goto error_cdev;
 	}
 	usb_device_class = class_create(THIS_MODULE, "usb_device");
 	if (IS_ERR(usb_device_class)) {
 		err("unable to register usb_device class");
 		retval = PTR_ERR(usb_device_class);
-		usb_device_class = NULL;
-		cdev_del(&usb_device_cdev);
-		unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
+		goto error_class;
 	}
 
+	usb_register_notify(&usbdev_nb);
+
 out:
 	return retval;
+
+error_class:
+	usb_device_class = NULL;
+	cdev_del(&usb_device_cdev);
+
+error_cdev:
+	unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
+	goto out;
 }
 
 void usbdev_cleanup(void)
 {
+	usb_unregister_notify(&usbdev_nb);
 	class_destroy(usb_device_class);
 	cdev_del(&usb_device_cdev);
 	unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
diff --git a/drivers/usb/core/file.c b/drivers/usb/core/file.c
index 78cb4be..e695308 100644
--- a/drivers/usb/core/file.c
+++ b/drivers/usb/core/file.c
@@ -17,7 +17,6 @@
 
 #include <linux/config.h>
 #include <linux/module.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/spinlock.h>
 #include <linux/errno.h>
 
@@ -88,8 +87,6 @@
 		goto out;
 	}
 
-	devfs_mk_dir("usb");
-
 out:
 	return error;
 }
@@ -97,7 +94,6 @@
 void usb_major_cleanup(void)
 {
 	class_destroy(usb_class);
-	devfs_remove("usb");
 	unregister_chrdev(USB_MAJOR, "usb");
 }
 
@@ -112,8 +108,7 @@
  * enabled, the minor number will be based on the next available free minor,
  * starting at the class_driver->minor_base.
  *
- * This function also creates the devfs file for the usb device, if devfs
- * is enabled, and creates a usb class device in the sysfs tree.
+ * This function also creates a usb class device in the sysfs tree.
  *
  * usb_deregister_dev() must be called when the driver is done with
  * the minor numbers given out by this function.
@@ -162,11 +157,8 @@
 
 	intf->minor = minor;
 
-	/* handle the devfs registration */
-	snprintf(name, BUS_ID_SIZE, class_driver->name, minor - minor_base);
-	devfs_mk_cdev(MKDEV(USB_MAJOR, minor), class_driver->mode, name);
-
 	/* create a usb class device for this usb interface */
+	snprintf(name, BUS_ID_SIZE, class_driver->name, minor - minor_base);
 	temp = strrchr(name, '/');
 	if (temp && (temp[1] != 0x00))
 		++temp;
@@ -179,7 +171,6 @@
 		spin_lock (&minor_lock);
 		usb_minors[intf->minor] = NULL;
 		spin_unlock (&minor_lock);
-		devfs_remove (name);
 		retval = PTR_ERR(intf->class_dev);
 	}
 exit:
@@ -197,9 +188,8 @@
  * call to usb_register_dev() (usually when the device is disconnected
  * from the system.)
  *
- * This function also cleans up the devfs file for the usb device, if devfs
- * is enabled, and removes the usb class device from the sysfs tree.
- * 
+ * This function also removes the usb class device from the sysfs tree.
+ *
  * This should be called by all drivers that use the USB major number.
  */
 void usb_deregister_dev(struct usb_interface *intf,
@@ -222,7 +212,6 @@
 	spin_unlock (&minor_lock);
 
 	snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
-	devfs_remove (name);
 	class_device_destroy(usb_class, MKDEV(USB_MAJOR, intf->minor));
 	intf->class_dev = NULL;
 	intf->minor = -1;
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 6385d1a..84d9e69 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -30,6 +30,8 @@
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <linux/usb.h>
+
+#include "usb.h"
 #include "hcd.h"
 
 
@@ -197,6 +199,26 @@
 
 	hcd = pci_get_drvdata(dev);
 
+	/* Root hub suspend should have stopped all downstream traffic,
+	 * and all bus master traffic.  And done so for both the interface
+	 * and the stub usb_device (which we check here).  But maybe it
+	 * didn't; writing sysfs power/state files ignores such rules...
+	 *
+	 * We must ignore the FREEZE vs SUSPEND distinction here, because
+	 * otherwise the swsusp will save (and restore) garbage state.
+	 */
+	if (hcd->self.root_hub->dev.power.power_state.event == PM_EVENT_ON)
+		return -EBUSY;
+
+	if (hcd->driver->suspend) {
+		retval = hcd->driver->suspend(hcd, message);
+		if (retval) {
+			dev_dbg (&dev->dev, "PCI pre-suspend fail, %d\n",
+				retval);
+			goto done;
+		}
+	}
+
 	/* FIXME until the generic PM interfaces change a lot more, this
 	 * can't use PCI D1 and D2 states.  For example, the confusion
 	 * between messages and states will need to vanish, and messages
@@ -215,31 +237,13 @@
 	 */
 	has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
 
-	switch (hcd->state) {
-
-	/* entry if root hub wasn't yet suspended ... from sysfs,
-	 * without autosuspend, or if USB_SUSPEND isn't configured.
+	/* Downstream ports from this root hub should already be quiesced, so
+	 * there will be no DMA activity.  Now we can shut down the upstream
+	 * link (except maybe for PME# resume signaling) and enter some PCI
+	 * low power state, if the hardware allows.
 	 */
-	case HC_STATE_RUNNING:
-		hcd->state = HC_STATE_QUIESCING;
-		retval = hcd->driver->suspend (hcd, message);
-		if (retval) {
-			dev_dbg (hcd->self.controller, 
-					"suspend fail, retval %d\n",
-					retval);
-			break;
-		}
-		hcd->state = HC_STATE_SUSPENDED;
-		/* FALLTHROUGH */
+	if (hcd->state == HC_STATE_SUSPENDED) {
 
-	/* entry with CONFIG_USB_SUSPEND, or hcds that autosuspend: the
-	 * controller and/or root hub will already have been suspended,
-	 * but it won't be ready for a PCI resume call.
-	 *
-	 * FIXME only CONFIG_USB_SUSPEND guarantees hub_suspend() will
-	 * have been called, otherwise root hub timers still run ...
-	 */
-	case HC_STATE_SUSPENDED:
 		/* no DMA or IRQs except when HC is active */
 		if (dev->current_state == PCI_D0) {
 			pci_save_state (dev);
@@ -248,7 +252,7 @@
 
 		if (!has_pci_pm) {
 			dev_dbg (hcd->self.controller, "--> PCI D0/legacy\n");
-			break;
+			goto done;
 		}
 
 		/* NOTE:  dev->current_state becomes nonzero only here, and
@@ -259,28 +263,29 @@
 		retval = pci_set_power_state (dev, PCI_D3hot);
 		if (retval == 0) {
 			dev_dbg (hcd->self.controller, "--> PCI D3\n");
-			retval = pci_enable_wake (dev, PCI_D3hot, hcd->remote_wakeup);
-			if (retval)
-				break;
-			retval = pci_enable_wake (dev, PCI_D3cold, hcd->remote_wakeup);
-		} else if (retval < 0) {
+
+			/* Ignore these return values.  We rely on pci code to
+			 * reject requests the hardware can't implement, rather
+			 * than coding the same thing.
+			 */
+			(void) pci_enable_wake (dev, PCI_D3hot, hcd->remote_wakeup);
+			(void) pci_enable_wake (dev, PCI_D3cold, hcd->remote_wakeup);
+		} else {
 			dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n",
 					retval);
 			(void) usb_hcd_pci_resume (dev);
-			break;
 		}
-		break;
-	default:
+
+	} else {
 		dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n",
 			hcd->state);
 		WARN_ON(1);
 		retval = -EINVAL;
-		break;
 	}
 
-	/* update power_state **ONLY** to make sysfs happier */
+done:
 	if (retval == 0)
-		dev->dev.power.power_state = message;
+		dev->dev.power.power_state = PMSG_SUSPEND;
 	return retval;
 }
 EXPORT_SYMBOL (usb_hcd_pci_suspend);
@@ -336,20 +341,9 @@
 				dev->current_state);
 		}
 #endif
-		retval = pci_enable_wake (dev, dev->current_state, 0);
-		if (retval) {
-			dev_err(hcd->self.controller,
-				"can't enable_wake to %d, %d!\n",
-				dev->current_state, retval);
-			return retval;
-		}
-		retval = pci_enable_wake (dev, PCI_D3cold, 0);
-		if (retval) {
-			dev_err(hcd->self.controller,
-				"can't enable_wake to %d, %d!\n",
-				PCI_D3cold, retval);
-			return retval;
-		}
+		/* yes, ignore these results too... */
+		(void) pci_enable_wake (dev, dev->current_state, 0);
+		(void) pci_enable_wake (dev, PCI_D3cold, 0);
 	} else {
 		/* Same basic cases: clean (powered/not), dirty */
 		dev_dbg(hcd->self.controller, "PCI legacy resume\n");
@@ -371,17 +365,17 @@
 
 	dev->dev.power.power_state = PMSG_ON;
 
-	hcd->state = HC_STATE_RESUMING;
 	hcd->saw_irq = 0;
 
-	retval = hcd->driver->resume (hcd);
-	if (!HC_IS_RUNNING (hcd->state)) {
-		dev_dbg (hcd->self.controller, 
-				"resume fail, retval %d\n", retval);
-		usb_hc_died (hcd);
+	if (hcd->driver->resume) {
+		retval = hcd->driver->resume(hcd);
+		if (retval) {
+			dev_err (hcd->self.controller,
+				"PCI post-resume error %d!\n", retval);
+			usb_hc_died (hcd);
+		}
 	}
 
-	retval = pci_enable_device(dev);
 	return retval;
 }
 EXPORT_SYMBOL (usb_hcd_pci_resume);
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 14c47a1..6c7ca5b 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -130,7 +130,7 @@
 	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
 	0x00,	    /*  __u8  bDeviceSubClass; */
 	0x01,       /*  __u8  bDeviceProtocol; [ usb 2.0 single TT ]*/
-	0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x40,       /*  __u8  bMaxPacketSize0; 64 Bytes */
 
 	0x00, 0x00, /*  __le16 idVendor; */
  	0x00, 0x00, /*  __le16 idProduct; */
@@ -153,7 +153,7 @@
 	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
 	0x00,	    /*  __u8  bDeviceSubClass; */
 	0x00,       /*  __u8  bDeviceProtocol; [ low/full speeds only ] */
-	0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x40,       /*  __u8  bMaxPacketSize0; 64 Bytes */
 
 	0x00, 0x00, /*  __le16 idVendor; */
  	0x00, 0x00, /*  __le16 idProduct; */
@@ -458,22 +458,18 @@
 
 	default:
 		/* non-generic request */
-		if (HC_IS_SUSPENDED (hcd->state))
-			status = -EAGAIN;
-		else {
-			switch (typeReq) {
-			case GetHubStatus:
-			case GetPortStatus:
-				len = 4;
-				break;
-			case GetHubDescriptor:
-				len = sizeof (struct usb_hub_descriptor);
-				break;
-			}
-			status = hcd->driver->hub_control (hcd,
-				typeReq, wValue, wIndex,
-				tbuf, wLength);
+		switch (typeReq) {
+		case GetHubStatus:
+		case GetPortStatus:
+			len = 4;
+			break;
+		case GetHubDescriptor:
+			len = sizeof (struct usb_hub_descriptor);
+			break;
 		}
+		status = hcd->driver->hub_control (hcd,
+			typeReq, wValue, wIndex,
+			tbuf, wLength);
 		break;
 error:
 		/* "protocol stall" on error */
@@ -487,7 +483,7 @@
 				"CTRL: TypeReq=0x%x val=0x%x "
 				"idx=0x%x len=%d ==> %d\n",
 				typeReq, wValue, wIndex,
-				wLength, urb->status);
+				wLength, status);
 		}
 	}
 	if (len) {
@@ -748,10 +744,9 @@
 {
 	struct usb_bus *bus;
 
-	bus = kmalloc (sizeof *bus, GFP_KERNEL);
+	bus = kzalloc (sizeof *bus, GFP_KERNEL);
 	if (!bus)
 		return NULL;
-	memset(bus, 0, sizeof(struct usb_bus));
 	usb_bus_init (bus);
 	bus->op = op;
 	return bus;
@@ -796,8 +791,7 @@
 	list_add (&bus->bus_list, &usb_bus_list);
 	up (&usb_bus_list_lock);
 
-	usbfs_add_bus (bus);
-	usbmon_notify_bus_add (bus);
+	usb_notify_add_bus(bus);
 
 	dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum);
 	return 0;
@@ -824,8 +818,7 @@
 	list_del (&bus->bus_list);
 	up (&usb_bus_list_lock);
 
-	usbmon_notify_bus_remove (bus);
-	usbfs_remove_bus (bus);
+	usb_notify_remove_bus(bus);
 
 	clear_bit (bus->busnum, busmap.busmap);
 
@@ -1143,10 +1136,20 @@
 	else switch (hcd->state) {
 	case HC_STATE_RUNNING:
 	case HC_STATE_RESUMING:
+doit:
 		usb_get_dev (urb->dev);
 		list_add_tail (&urb->urb_list, &ep->urb_list);
 		status = 0;
 		break;
+	case HC_STATE_SUSPENDED:
+		/* HC upstream links (register access, wakeup signaling) can work
+		 * even when the downstream links (and DMA etc) are quiesced; let
+		 * usbcore talk to the root hub.
+		 */
+		if (hcd->self.controller->power.power_state.event == PM_EVENT_ON
+				&& urb->dev->parent == NULL)
+			goto doit;
+		/* FALL THROUGH */
 	default:
 		status = -ESHUTDOWN;
 		break;
@@ -1294,12 +1297,6 @@
 		goto done;
 	}
 
-	/* running ~= hc unlink handshake works (irq, timer, etc)
-	 * halted ~= no unlink handshake is needed
-	 * suspended, resuming == should never happen
-	 */
-	WARN_ON (!HC_IS_RUNNING (hcd->state) && hcd->state != HC_STATE_HALT);
-
 	/* insist the urb is still queued */
 	list_for_each(tmp, &ep->urb_list) {
 		if (tmp == &urb->urb_list)
@@ -1431,28 +1428,92 @@
 
 /*-------------------------------------------------------------------------*/
 
-#ifdef	CONFIG_USB_SUSPEND
+#ifdef	CONFIG_PM
 
-static int hcd_hub_suspend (struct usb_bus *bus)
+int hcd_bus_suspend (struct usb_bus *bus)
 {
 	struct usb_hcd		*hcd;
+	int			status;
 
 	hcd = container_of (bus, struct usb_hcd, self);
-	if (hcd->driver->hub_suspend)
-		return hcd->driver->hub_suspend (hcd);
-	return 0;
+	if (!hcd->driver->bus_suspend)
+		return -ENOENT;
+	hcd->state = HC_STATE_QUIESCING;
+	status = hcd->driver->bus_suspend (hcd);
+	if (status == 0)
+		hcd->state = HC_STATE_SUSPENDED;
+	else
+		dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n",
+				"suspend", status);
+	return status;
 }
 
-static int hcd_hub_resume (struct usb_bus *bus)
+int hcd_bus_resume (struct usb_bus *bus)
 {
 	struct usb_hcd		*hcd;
+	int			status;
 
 	hcd = container_of (bus, struct usb_hcd, self);
-	if (hcd->driver->hub_resume)
-		return hcd->driver->hub_resume (hcd);
-	return 0;
+	if (!hcd->driver->bus_resume)
+		return -ENOENT;
+	if (hcd->state == HC_STATE_RUNNING)
+		return 0;
+	hcd->state = HC_STATE_RESUMING;
+	status = hcd->driver->bus_resume (hcd);
+	if (status == 0)
+		hcd->state = HC_STATE_RUNNING;
+	else {
+		dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n",
+				"resume", status);
+		usb_hc_died(hcd);
+	}
+	return status;
 }
 
+/*
+ * usb_hcd_suspend_root_hub - HCD autosuspends downstream ports
+ * @hcd: host controller for this root hub
+ *
+ * This call arranges that usb_hcd_resume_root_hub() is safe to call later;
+ * that the HCD's root hub polling is deactivated; and that the root's hub
+ * driver is suspended.  HCDs may call this to autosuspend when their root
+ * hub's downstream ports are all inactive:  unpowered, disconnected,
+ * disabled, or suspended.
+ *
+ * The HCD will autoresume on device connect change detection (using SRP
+ * or a D+/D- pullup).  The HCD also autoresumes on remote wakeup signaling
+ * from any ports that are suspended (if that is enabled).  In most cases,
+ * overcurrent signaling (on powered ports) will also start autoresume.
+ *
+ * Always called with IRQs blocked.
+ */
+void usb_hcd_suspend_root_hub (struct usb_hcd *hcd)
+{
+	struct urb	*urb;
+
+	spin_lock (&hcd_root_hub_lock);
+	usb_suspend_root_hub (hcd->self.root_hub);
+
+	/* force status urb to complete/unlink while suspended */
+	if (hcd->status_urb) {
+		urb = hcd->status_urb;
+		urb->status = -ECONNRESET;
+		urb->hcpriv = NULL;
+		urb->actual_length = 0;
+
+		del_timer (&hcd->rh_timer);
+		hcd->poll_pending = 0;
+		hcd->status_urb = NULL;
+	} else
+		urb = NULL;
+	spin_unlock (&hcd_root_hub_lock);
+	hcd->state = HC_STATE_SUSPENDED;
+
+	if (urb)
+		usb_hcd_giveback_urb (hcd, urb, NULL);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_suspend_root_hub);
+
 /**
  * usb_hcd_resume_root_hub - called by HCD to resume its root hub 
  * @hcd: host controller for this root hub
@@ -1460,7 +1521,7 @@
  * The USB host controller calls this function when its root hub is
  * suspended (with the remote wakeup feature enabled) and a remote
  * wakeup request is received.  It queues a request for khubd to
- * resume the root hub.
+ * resume the root hub (that is, manage its downstream ports again).
  */
 void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
 {
@@ -1471,14 +1532,10 @@
 		usb_resume_root_hub (hcd->self.root_hub);
 	spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
 }
-
-#else
-void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
-{
-}
-#endif
 EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
 
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 #ifdef	CONFIG_USB_OTG
@@ -1530,10 +1587,6 @@
 	.buffer_alloc =		hcd_buffer_alloc,
 	.buffer_free =		hcd_buffer_free,
 	.disable =		hcd_endpoint_disable,
-#ifdef	CONFIG_USB_SUSPEND
-	.hub_suspend =		hcd_hub_suspend,
-	.hub_resume =		hcd_hub_resume,
-#endif
 };
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/core/hcd.h b/drivers/usb/core/hcd.h
index 1f1ed62..24a62a2 100644
--- a/drivers/usb/core/hcd.h
+++ b/drivers/usb/core/hcd.h
@@ -154,10 +154,6 @@
 
 	void (*disable)(struct usb_device *udev,
 			struct usb_host_endpoint *ep);
-
-	/* global suspend/resume of bus */
-	int (*hub_suspend)(struct usb_bus *);
-	int (*hub_resume)(struct usb_bus *);
 };
 
 /* each driver provides one of these, and hardware init support */
@@ -182,12 +178,12 @@
 	int	(*start) (struct usb_hcd *hcd);
 
 	/* NOTE:  these suspend/resume calls relate to the HC as
-	 * a whole, not just the root hub; they're for bus glue.
+	 * a whole, not just the root hub; they're for PCI bus glue.
 	 */
-	/* called after all devices were suspended */
+	/* called after suspending the hub, before entering D3 etc */
 	int	(*suspend) (struct usb_hcd *hcd, pm_message_t message);
 
-	/* called before any devices get resumed */
+	/* called after entering D0 (etc), before resuming the hub */
 	int	(*resume) (struct usb_hcd *hcd);
 
 	/* cleanly make HCD stop writing memory and doing I/O */
@@ -212,8 +208,8 @@
 	int		(*hub_control) (struct usb_hcd *hcd,
 				u16 typeReq, u16 wValue, u16 wIndex,
 				char *buf, u16 wLength);
-	int		(*hub_suspend)(struct usb_hcd *);
-	int		(*hub_resume)(struct usb_hcd *);
+	int		(*bus_suspend)(struct usb_hcd *);
+	int		(*bus_resume)(struct usb_hcd *);
 	int		(*start_port_reset)(struct usb_hcd *, unsigned port_num);
 	void		(*hub_irq_enable)(struct usb_hcd *);
 		/* Needed only if port-change IRQs are level-triggered */
@@ -355,8 +351,6 @@
 
 extern struct usb_bus *usb_alloc_bus (struct usb_operations *);
 
-extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
-
 extern void usb_set_device_state(struct usb_device *udev,
 		enum usb_device_state new_state);
 
@@ -378,6 +372,33 @@
 
 #define usb_endpoint_out(ep_dir)	(!((ep_dir) & USB_DIR_IN))
 
+#ifdef CONFIG_PM
+extern void usb_hcd_suspend_root_hub (struct usb_hcd *hcd);
+extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
+extern int hcd_bus_suspend (struct usb_bus *bus);
+extern int hcd_bus_resume (struct usb_bus *bus);
+#else
+static inline void usb_hcd_suspend_root_hub(struct usb_hcd *hcd)
+{
+	return;
+}
+
+static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
+{
+	return;
+}
+
+static inline int hcd_bus_suspend(struct usb_bus *bus)
+{
+	return 0;
+}
+
+static inline int hcd_bus_resume (struct usb_bus *bus)
+{
+	return 0;
+}
+#endif /* CONFIG_PM */
+
 /*
  * USB device fs stuff
  */
@@ -388,23 +409,13 @@
  * these are expected to be called from the USB core/hub thread
  * with the kernel lock held
  */
-extern void usbfs_add_bus(struct usb_bus *bus);
-extern void usbfs_remove_bus(struct usb_bus *bus);
-extern void usbfs_add_device(struct usb_device *dev);
-extern void usbfs_remove_device(struct usb_device *dev);
 extern void usbfs_update_special (void);
-
 extern int usbfs_init(void);
 extern void usbfs_cleanup(void);
 
 #else /* CONFIG_USB_DEVICEFS */
 
-static inline void usbfs_add_bus(struct usb_bus *bus) {}
-static inline void usbfs_remove_bus(struct usb_bus *bus) {}
-static inline void usbfs_add_device(struct usb_device *dev) {}
-static inline void usbfs_remove_device(struct usb_device *dev) {}
 static inline void usbfs_update_special (void) {}
-
 static inline int usbfs_init(void) { return 0; }
 static inline void usbfs_cleanup(void) { }
 
@@ -419,8 +430,6 @@
 	void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err);
 	void (*urb_complete)(struct usb_bus *bus, struct urb *urb);
 	/* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */
-	void (*bus_add)(struct usb_bus *bus);
-	void (*bus_remove)(struct usb_bus *bus);
 };
 
 extern struct usb_mon_operations *mon_ops;
@@ -443,18 +452,6 @@
 	if (bus->monitored)
 		(*mon_ops->urb_complete)(bus, urb);
 }
- 
-static inline void usbmon_notify_bus_add(struct usb_bus *bus)
-{
-	if (mon_ops)
-		(*mon_ops->bus_add)(bus);
-}
-
-static inline void usbmon_notify_bus_remove(struct usb_bus *bus)
-{
-	if (mon_ops)
-		(*mon_ops->bus_remove)(bus);
-}
 
 int usb_mon_register(struct usb_mon_operations *ops);
 void usb_mon_deregister(void);
@@ -465,8 +462,6 @@
 static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
     int error) {}
 static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
-static inline void usbmon_notify_bus_add(struct usb_bus *bus) {}
-static inline void usbmon_notify_bus_remove(struct usb_bus *bus) {}
 
 #endif /* CONFIG_USB_MON */
 
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index c3e2024..256d9f6 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -436,9 +436,10 @@
 {
 	int port1;
 	unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2;
+	u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
 
 	/* if hub supports power switching, enable power on each port */
-	if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) < 2) {
+	if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2) {
 		dev_dbg(hub->intfdev, "enabling power on all ports\n");
 		for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++)
 			set_port_feature(hub->hdev, port1,
@@ -449,10 +450,18 @@
 	msleep(max(pgood_delay, (unsigned) 100));
 }
 
+static inline void __hub_quiesce(struct usb_hub *hub)
+{
+	/* (nonblocking) khubd and related activity won't re-trigger */
+	hub->quiescing = 1;
+	hub->activating = 0;
+	hub->resume_root_hub = 0;
+}
+
 static void hub_quiesce(struct usb_hub *hub)
 {
-	/* stop khubd and related activity */
-	hub->quiescing = 1;
+	/* (blocking) stop khubd and related activity */
+	__hub_quiesce(hub);
 	usb_kill_urb(hub->urb);
 	if (hub->has_indicators)
 		cancel_delayed_work(&hub->leds);
@@ -466,6 +475,7 @@
 
 	hub->quiescing = 0;
 	hub->activating = 1;
+	hub->resume_root_hub = 0;
 	status = usb_submit_urb(hub->urb, GFP_NOIO);
 	if (status < 0)
 		dev_err(hub->intfdev, "activate --> %d\n", status);
@@ -516,6 +526,7 @@
 	struct usb_device *hdev = hub->hdev;
 	struct device *hub_dev = hub->intfdev;
 	u16 hubstatus, hubchange;
+	u16 wHubCharacteristics;
 	unsigned int pipe;
 	int maxp, ret;
 	char *message;
@@ -561,9 +572,9 @@
 	dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
 		(hdev->maxchild == 1) ? "" : "s");
 
-	le16_to_cpus(&hub->descriptor->wHubCharacteristics);
+	wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
 
-	if (hub->descriptor->wHubCharacteristics & HUB_CHAR_COMPOUND) {
+	if (wHubCharacteristics & HUB_CHAR_COMPOUND) {
 		int	i;
 		char	portstr [USB_MAXCHILDREN + 1];
 
@@ -576,7 +587,7 @@
 	} else
 		dev_dbg(hub_dev, "standalone hub\n");
 
-	switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) {
+	switch (wHubCharacteristics & HUB_CHAR_LPSM) {
 		case 0x00:
 			dev_dbg(hub_dev, "ganged power switching\n");
 			break;
@@ -589,7 +600,7 @@
 			break;
 	}
 
-	switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_OCPM) {
+	switch (wHubCharacteristics & HUB_CHAR_OCPM) {
 		case 0x00:
 			dev_dbg(hub_dev, "global over-current protection\n");
 			break;
@@ -629,7 +640,7 @@
 	}
 
 	/* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */
-	switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_TTTT) {
+	switch (wHubCharacteristics & HUB_CHAR_TTTT) {
 		case HUB_TTTT_8_BITS:
 			if (hdev->descriptor.bDeviceProtocol != 0) {
 				hub->tt.think_time = 666;
@@ -659,7 +670,7 @@
 	}
 
 	/* probe() zeroes hub->indicator[] */
-	if (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND) {
+	if (wHubCharacteristics & HUB_CHAR_PORTIND) {
 		hub->has_indicators = 1;
 		dev_dbg(hub_dev, "Port indicators are supported\n");
 	}
@@ -704,7 +715,7 @@
 			(hubstatus & HUB_STATUS_LOCAL_POWER)
 			? "lost (inactive)" : "good");
 
-	if ((hub->descriptor->wHubCharacteristics & HUB_CHAR_OCPM) == 0)
+	if ((wHubCharacteristics & HUB_CHAR_OCPM) == 0)
 		dev_dbg(hub_dev, "%sover-current condition exists\n",
 			(hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
 
@@ -854,14 +865,12 @@
 	/* We found a hub */
 	dev_info (&intf->dev, "USB hub found\n");
 
-	hub = kmalloc(sizeof(*hub), GFP_KERNEL);
+	hub = kzalloc(sizeof(*hub), GFP_KERNEL);
 	if (!hub) {
 		dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n");
 		return -ENOMEM;
 	}
 
-	memset(hub, 0, sizeof(*hub));
-
 	INIT_LIST_HEAD(&hub->event_list);
 	hub->intfdev = &intf->dev;
 	hub->hdev = hdev;
@@ -1117,14 +1126,14 @@
 	 */
 	usb_disable_device(udev, 0);
 
+	usb_notify_remove_device(udev);
+
 	/* Free the device number, remove the /proc/bus/usb entry and
 	 * the sysfs attributes, and delete the parent's children[]
 	 * (or root_hub) pointer.
 	 */
 	dev_dbg (&udev->dev, "unregistering device\n");
 	release_address(udev);
-	usbfs_remove_device(udev);
-	usbdev_remove(udev);
 	usb_remove_sysfs_dev_files(udev);
 
 	/* Avoid races with recursively_mark_NOTATTACHED() */
@@ -1195,21 +1204,6 @@
 {}
 #endif
 
-static void get_string(struct usb_device *udev, char **string, int index)
-{
-	char *buf;
-
-	if (!index)
-		return;
-	buf = kmalloc(256, GFP_KERNEL);
-	if (!buf)
-		return;
-	if (usb_string(udev, index, buf, 256) > 0)
-		*string = buf;
-	else
-		kfree(buf);
-}
-
 
 #ifdef	CONFIG_USB_OTG
 #include "otg_whitelist.h"
@@ -1248,9 +1242,10 @@
 	}
 
 	/* read the standard strings and cache them if present */
-	get_string(udev, &udev->product, udev->descriptor.iProduct);
-	get_string(udev, &udev->manufacturer, udev->descriptor.iManufacturer);
-	get_string(udev, &udev->serial, udev->descriptor.iSerialNumber);
+	udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
+	udev->manufacturer = usb_cache_string(udev,
+			udev->descriptor.iManufacturer);
+	udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
 
 	/* Tell the world! */
 	dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
@@ -1322,11 +1317,9 @@
 		 * (Includes HNP test device.)
 		 */
 		if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {
-			static int __usb_suspend_device (struct usb_device *,
-						int port1, pm_message_t state);
-			err = __usb_suspend_device(udev,
-					udev->bus->otg_port,
-					PMSG_SUSPEND);
+			static int __usb_suspend_device(struct usb_device *,
+						int port1);
+			err = __usb_suspend_device(udev, udev->bus->otg_port);
 			if (err < 0)
 				dev_dbg(&udev->dev, "HNP fail, %d\n", err);
 		}
@@ -1362,10 +1355,8 @@
 	}
 
 	/* USB device state == configured ... usable */
+	usb_notify_add_device(udev);
 
-	/* add a /proc/bus/usb entry */
-	usbdev_add(udev);
-	usbfs_add_device(udev);
 	return 0;
 
 fail:
@@ -1516,7 +1507,7 @@
 	/* FIXME let caller ask to power down the port:
 	 *  - some devices won't enumerate without a VBUS power cycle
 	 *  - SRP saves power that way
-	 *  - usb_suspend_device(dev, PMSG_SUSPEND)
+	 *  - ... new call, TBD ...
 	 * That's easy if this hub can switch power per-port, and
 	 * khubd reactivates the port later (timer, SRP, etc).
 	 * Powerdown must be optional, because of reset/DFU.
@@ -1598,11 +1589,14 @@
  * Other than re-initializing the hub (plug/unplug, except for root hubs),
  * Linux (2.6) currently has NO mechanisms to initiate that:  no khubd
  * timer, no SRP, no requests through sysfs.
+ *
+ * If CONFIG_USB_SUSPEND isn't enabled, devices only really suspend when
+ * the root hub for their bus goes into global suspend ... so we don't
+ * (falsely) update the device power state to say it suspended.
  */
-static int __usb_suspend_device (struct usb_device *udev, int port1,
-				 pm_message_t state)
+static int __usb_suspend_device (struct usb_device *udev, int port1)
 {
-	int	status;
+	int	status = 0;
 
 	/* caller owns the udev device lock */
 	if (port1 < 0)
@@ -1613,95 +1607,39 @@
 		return 0;
 	}
 
-	/* suspend interface drivers; if this is a hub, it
-	 * suspends the child devices
-	 */
+	/* all interfaces must already be suspended */
 	if (udev->actconfig) {
 		int	i;
 
 		for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
 			struct usb_interface	*intf;
-			struct usb_driver	*driver;
 
 			intf = udev->actconfig->interface[i];
-			if (state.event <= intf->dev.power.power_state.event)
-				continue;
-			if (!intf->dev.driver)
-				continue;
-			driver = to_usb_driver(intf->dev.driver);
-
-			if (driver->suspend) {
-				status = driver->suspend(intf, state);
-				if (intf->dev.power.power_state.event != state.event
-						|| status)
-					dev_err(&intf->dev,
-						"suspend %d fail, code %d\n",
-						state.event, status);
-			}
-
-			/* only drivers with suspend() can ever resume();
-			 * and after power loss, even they won't.
-			 * bus_rescan_devices() can rebind drivers later.
-			 *
-			 * FIXME the PM core self-deadlocks when unbinding
-			 * drivers during suspend/resume ... everything grabs
-			 * dpm_sem (not a spinlock, ugh).  we want to unbind,
-			 * since we know every driver's probe/disconnect works
-			 * even for drivers that can't suspend.
-			 */
-			if (!driver->suspend || state.event > PM_EVENT_FREEZE) {
-#if 1
-				dev_warn(&intf->dev, "resume is unsafe!\n");
-#else
-				down_write(&usb_bus_type.rwsem);
-				device_release_driver(&intf->dev);
-				up_write(&usb_bus_type.rwsem);
-#endif
+			if (is_active(intf)) {
+				dev_dbg(&intf->dev, "nyet suspended\n");
+				return -EBUSY;
 			}
 		}
 	}
 
-	/*
-	 * FIXME this needs port power off call paths too, to help force
-	 * USB into the "generic" PM model.  At least for devices on
-	 * ports that aren't using ganged switching (usually root hubs).
-	 *
-	 * NOTE: SRP-capable links should adopt more aggressive poweroff
-	 * policies (when HNP doesn't apply) once we have mechanisms to
-	 * turn power back on!  (Likely not before 2.7...)
+	/* we only change a device's upstream USB link.
+	 * root hubs have no upstream USB link.
 	 */
-	if (state.event > PM_EVENT_FREEZE) {
-		dev_warn(&udev->dev, "no poweroff yet, suspending instead\n");
-	}
-
-	/* "global suspend" of the HC-to-USB interface (root hub), or
-	 * "selective suspend" of just one hub-device link.
-	 */
-	if (!udev->parent) {
-		struct usb_bus	*bus = udev->bus;
-		if (bus && bus->op->hub_suspend) {
-			status = bus->op->hub_suspend (bus);
-			if (status == 0) {
-				dev_dbg(&udev->dev, "usb suspend\n");
-				usb_set_device_state(udev,
-						USB_STATE_SUSPENDED);
-			}
-		} else
-			status = -EOPNOTSUPP;
-	} else
+	if (udev->parent)
 		status = hub_port_suspend(hdev_to_hub(udev->parent), port1,
 				udev);
 
 	if (status == 0)
-		udev->dev.power.power_state = state;
+		udev->dev.power.power_state = PMSG_SUSPEND;
 	return status;
 }
 
-/**
+#endif
+
+/*
  * usb_suspend_device - suspend a usb device
  * @udev: device that's no longer in active use
- * @state: PMSG_SUSPEND to suspend
- * Context: must be able to sleep; device not locked
+ * Context: must be able to sleep; device not locked; pm locks held
  *
  * Suspends a USB device that isn't in active use, conserving power.
  * Devices may wake out of a suspend, if anything important happens,
@@ -1709,37 +1647,50 @@
  * suspend by the host, using usb_resume_device().  It's also routine
  * to disconnect devices while they are suspended.
  *
+ * This only affects the USB hardware for a device; its interfaces
+ * (and, for hubs, child devices) must already have been suspended.
+ *
  * Suspending OTG devices may trigger HNP, if that's been enabled
  * between a pair of dual-role devices.  That will change roles, such
  * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral.
  *
  * Returns 0 on success, else negative errno.
  */
-int usb_suspend_device(struct usb_device *udev, pm_message_t state)
+int usb_suspend_device(struct usb_device *udev)
 {
+#ifdef	CONFIG_USB_SUSPEND
 	int	port1, status;
 
 	port1 = locktree(udev);
 	if (port1 < 0)
 		return port1;
 
-	status = __usb_suspend_device(udev, port1, state);
+	status = __usb_suspend_device(udev, port1);
 	usb_unlock_device(udev);
 	return status;
+#else
+	/* NOTE:  udev->state unchanged, it's not lying ... */
+	udev->dev.power.power_state = PMSG_SUSPEND;
+	return 0;
+#endif
 }
+EXPORT_SYMBOL_GPL(usb_suspend_device);
 
 /*
+ * If the USB "suspend" state is in use (rather than "global suspend"),
+ * many devices will be individually taken out of suspend state using
+ * special" resume" signaling.  These routines kick in shortly after
  * hardware resume signaling is finished, either because of selective
  * resume (by host) or remote wakeup (by device) ... now see what changed
  * in the tree that's rooted at this device.
  */
-static int finish_port_resume(struct usb_device *udev)
+static int finish_device_resume(struct usb_device *udev)
 {
 	int	status;
 	u16	devstatus;
 
 	/* caller owns the udev device lock */
-	dev_dbg(&udev->dev, "usb resume\n");
+	dev_dbg(&udev->dev, "finish resume\n");
 
 	/* usb ch9 identifies four variants of SUSPENDED, based on what
 	 * state the device resumes to.  Linux currently won't see the
@@ -1749,7 +1700,6 @@
 	usb_set_device_state(udev, udev->actconfig
 			? USB_STATE_CONFIGURED
 			: USB_STATE_ADDRESS);
-	udev->dev.power.power_state = PMSG_ON;
 
  	/* 10.5.4.5 says be sure devices in the tree are still there.
  	 * For now let's assume the device didn't go crazy on resume,
@@ -1762,9 +1712,11 @@
 			status);
 	else if (udev->actconfig) {
 		unsigned	i;
+		int		(*resume)(struct device *);
 
 		le16_to_cpus(&devstatus);
-		if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
+		if (devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)
+				&& udev->parent) {
 			status = usb_control_msg(udev,
 					usb_sndctrlpipe(udev, 0),
 					USB_REQ_CLEAR_FEATURE,
@@ -1780,33 +1732,11 @@
 		}
 
 		/* resume interface drivers; if this is a hub, it
-		 * resumes the child devices
+		 * may have a child resume event to deal with soon
 		 */
-		for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
-			struct usb_interface	*intf;
-			struct usb_driver	*driver;
-
-			intf = udev->actconfig->interface[i];
-			if (intf->dev.power.power_state.event == PM_EVENT_ON)
-				continue;
-			if (!intf->dev.driver) {
-				/* FIXME maybe force to alt 0 */
-				continue;
-			}
-			driver = to_usb_driver(intf->dev.driver);
-
-			/* bus_rescan_devices() may rebind drivers */
-			if (!driver->resume)
-				continue;
-
-			/* can we do better than just logging errors? */
-			status = driver->resume(intf);
-			if (intf->dev.power.power_state.event != PM_EVENT_ON
-					|| status)
-				dev_dbg(&intf->dev,
-					"resume fail, state %d code %d\n",
-					intf->dev.power.power_state.event, status);
-		}
+		resume = udev->dev.bus->resume;
+		for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++)
+			(void) resume(&udev->actconfig->interface[i]->dev);
 		status = 0;
 
 	} else if (udev->devnum <= 0) {
@@ -1816,6 +1746,8 @@
 	return status;
 }
 
+#ifdef	CONFIG_USB_SUSPEND
+
 static int
 hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
 {
@@ -1861,7 +1793,7 @@
 			/* TRSMRCY = 10 msec */
 			msleep(10);
 			if (udev)
-				status = finish_port_resume(udev);
+				status = finish_device_resume(udev);
 		}
 	}
 	if (status < 0)
@@ -1870,12 +1802,12 @@
 	return status;
 }
 
-static int hub_resume (struct usb_interface *intf);
+#endif
 
-/**
+/*
  * usb_resume_device - re-activate a suspended usb device
  * @udev: device to re-activate
- * Context: must be able to sleep; device not locked
+ * Context: must be able to sleep; device not locked; pm locks held
  *
  * This will re-activate the suspended device, increasing power usage
  * while letting drivers communicate again with its endpoints.
@@ -1893,35 +1825,22 @@
 	if (port1 < 0)
 		return port1;
 
-	/* "global resume" of the HC-to-USB interface (root hub), or
-	 * selective resume of one hub-to-device port
-	 */
-	if (!udev->parent) {
-		struct usb_bus	*bus = udev->bus;
-		if (bus && bus->op->hub_resume) {
-			status = bus->op->hub_resume (bus);
+#ifdef	CONFIG_USB_SUSPEND
+	/* selective resume of one downstream hub-to-device port */
+	if (udev->parent) {
+		if (udev->state == USB_STATE_SUSPENDED) {
+			// NOTE swsusp may bork us, device state being wrong...
+			// NOTE this fails if parent is also suspended...
+			status = hub_port_resume(hdev_to_hub(udev->parent),
+					port1, udev);
 		} else
-			status = -EOPNOTSUPP;
-		if (status == 0) {
-			dev_dbg(&udev->dev, "usb resume\n");
-			/* TRSMRCY = 10 msec */
-			msleep(10);
-			usb_set_device_state (udev, USB_STATE_CONFIGURED);
-			udev->dev.power.power_state = PMSG_ON;
-			status = hub_resume (udev
-					->actconfig->interface[0]);
-		}
-	} else if (udev->state == USB_STATE_SUSPENDED) {
-		// NOTE this fails if parent is also suspended...
-		status = hub_port_resume(hdev_to_hub(udev->parent),
-				port1, udev);
-	} else {
-		status = 0;
-	}
-	if (status < 0) {
+			status = 0;
+	} else
+#endif
+		status = finish_device_resume(udev);
+	if (status < 0)
 		dev_dbg(&udev->dev, "can't resume, status %d\n",
 			status);
-	}
 
 	usb_unlock_device(udev);
 
@@ -1938,6 +1857,8 @@
 {
 	int	status = 0;
 
+#ifdef	CONFIG_USB_SUSPEND
+
 	/* don't repeat RESUME sequence if this device
 	 * was already woken up by some other task
 	 */
@@ -1946,38 +1867,52 @@
 		dev_dbg(&udev->dev, "RESUME (wakeup)\n");
 		/* TRSMRCY = 10 msec */
 		msleep(10);
-		status = finish_port_resume(udev);
+		status = finish_device_resume(udev);
 	}
 	up(&udev->serialize);
+#endif
 	return status;
 }
 
-static int hub_suspend(struct usb_interface *intf, pm_message_t state)
+static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
 {
 	struct usb_hub		*hub = usb_get_intfdata (intf);
 	struct usb_device	*hdev = hub->hdev;
 	unsigned		port1;
-	int			status;
 
-	/* stop khubd and related activity */
-	hub_quiesce(hub);
-
-	/* then suspend every port */
+	/* fail if children aren't already suspended */
 	for (port1 = 1; port1 <= hdev->maxchild; port1++) {
 		struct usb_device	*udev;
 
 		udev = hdev->children [port1-1];
-		if (!udev)
-			continue;
-		down(&udev->serialize);
-		status = __usb_suspend_device(udev, port1, state);
-		up(&udev->serialize);
-		if (status < 0)
-			dev_dbg(&intf->dev, "suspend port %d --> %d\n",
-				port1, status);
+		if (udev && (udev->dev.power.power_state.event
+					== PM_EVENT_ON
+#ifdef	CONFIG_USB_SUSPEND
+				|| udev->state != USB_STATE_SUSPENDED
+#endif
+				)) {
+			dev_dbg(&intf->dev, "port %d nyet suspended\n", port1);
+			return -EBUSY;
+		}
 	}
 
-	intf->dev.power.power_state = state;
+	/* "global suspend" of the downstream HC-to-USB interface */
+	if (!hdev->parent) {
+		struct usb_bus	*bus = hdev->bus;
+		if (bus) {
+			int	status = hcd_bus_suspend (bus);
+
+			if (status != 0) {
+				dev_dbg(&hdev->dev, "'global' suspend %d\n",
+					status);
+				return status;
+			}
+		} else
+			return -EOPNOTSUPP;
+	}
+
+	/* stop khubd and related activity */
+	hub_quiesce(hub);
 	return 0;
 }
 
@@ -1985,11 +1920,35 @@
 {
 	struct usb_device	*hdev = interface_to_usbdev(intf);
 	struct usb_hub		*hub = usb_get_intfdata (intf);
-	unsigned		port1;
 	int			status;
 
-	if (intf->dev.power.power_state.event == PM_EVENT_ON)
-		return 0;
+	/* "global resume" of the downstream HC-to-USB interface */
+	if (!hdev->parent) {
+		struct usb_bus	*bus = hdev->bus;
+		if (bus) {
+			status = hcd_bus_resume (bus);
+			if (status) {
+				dev_dbg(&intf->dev, "'global' resume %d\n",
+					status);
+				return status;
+			}
+		} else
+			return -EOPNOTSUPP;
+		if (status == 0) {
+			/* TRSMRCY = 10 msec */
+			msleep(10);
+		}
+	}
+
+	hub_activate(hub);
+
+	/* REVISIT:  this recursion probably shouldn't exist.  Remove
+	 * this code sometime, after retesting with different root and
+	 * external hubs.
+	 */
+#ifdef	CONFIG_USB_SUSPEND
+	{
+	unsigned		port1;
 
 	for (port1 = 1; port1 <= hdev->maxchild; port1++) {
 		struct usb_device	*udev;
@@ -2015,7 +1974,7 @@
 		if (portstat & USB_PORT_STAT_SUSPEND)
 			status = hub_port_resume(hub, port1, udev);
 		else {
-			status = finish_port_resume(udev);
+			status = finish_device_resume(udev);
 			if (status < 0) {
 				dev_dbg(&intf->dev, "resume port %d --> %d\n",
 					port1, status);
@@ -2024,13 +1983,23 @@
 		}
 		up(&udev->serialize);
 	}
-	intf->dev.power.power_state = PMSG_ON;
-
-	hub->resume_root_hub = 0;
-	hub_activate(hub);
+	}
+#endif
 	return 0;
 }
 
+void usb_suspend_root_hub(struct usb_device *hdev)
+{
+	struct usb_hub *hub = hdev_to_hub(hdev);
+
+	/* This also makes any led blinker stop retriggering.  We're called
+	 * from irq, so the blinker might still be scheduled.  Caller promises
+	 * that the root hub status URB will be canceled.
+	 */
+	__hub_quiesce(hub);
+	mark_quiesced(to_usb_interface(hub->intfdev));
+}
+
 void usb_resume_root_hub(struct usb_device *hdev)
 {
 	struct usb_hub *hub = hdev_to_hub(hdev);
@@ -2039,28 +2008,6 @@
 	kick_khubd(hub);
 }
 
-#else	/* !CONFIG_USB_SUSPEND */
-
-int usb_suspend_device(struct usb_device *udev, pm_message_t state)
-{
-	return 0;
-}
-
-int usb_resume_device(struct usb_device *udev)
-{
-	return 0;
-}
-
-#define	hub_suspend		NULL
-#define	hub_resume		NULL
-#define	remote_wakeup(x)	0
-
-#endif	/* CONFIG_USB_SUSPEND */
-
-EXPORT_SYMBOL(usb_suspend_device);
-EXPORT_SYMBOL(usb_resume_device);
-
-
 
 /* USB 2.0 spec, 7.1.7.3 / fig 7-29:
  *
@@ -2469,6 +2416,7 @@
 {
 	struct usb_device *hdev = hub->hdev;
 	struct device *hub_dev = hub->intfdev;
+	u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
 	int status, i;
  
 	dev_dbg (hub_dev,
@@ -2506,8 +2454,7 @@
 	if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
 
 		/* maybe switch power back on (e.g. root hub was reset) */
-		if ((hub->descriptor->wHubCharacteristics
-					& HUB_CHAR_LPSM) < 2
+		if ((wHubCharacteristics & HUB_CHAR_LPSM) < 2
 				&& !(portstatus & (1 << USB_PORT_FEAT_POWER)))
 			set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
  
@@ -2686,21 +2633,28 @@
 		intf = to_usb_interface(hub->intfdev);
 		hub_dev = &intf->dev;
 
-		dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x\n",
+		i = hub->resume_root_hub;
+
+		dev_dbg(hub_dev, "state %d ports %d chg %04x evt %04x%s\n",
 				hdev->state, hub->descriptor
 					? hub->descriptor->bNbrPorts
 					: 0,
 				/* NOTE: expects max 15 ports... */
 				(u16) hub->change_bits[0],
-				(u16) hub->event_bits[0]);
+				(u16) hub->event_bits[0],
+				i ? ", resume root" : "");
 
 		usb_get_intf(intf);
-		i = hub->resume_root_hub;
 		spin_unlock_irq(&hub_event_lock);
 
-		/* Is this is a root hub wanting to be resumed? */
-		if (i)
-			usb_resume_device(hdev);
+		/* Is this is a root hub wanting to reactivate the downstream
+		 * ports?  If so, be sure the interface resumes even if its
+		 * stub "device" node was never suspended.
+		 */
+		if (i) {
+			dpm_runtime_resume(&hdev->dev);
+			dpm_runtime_resume(&intf->dev);
+		}
 
 		/* Lock the device, then check to see if we were
 		 * disconnected while waiting for the lock to succeed. */
diff --git a/drivers/usb/core/hub.h b/drivers/usb/core/hub.h
index e7fa9b5..bf23f89 100644
--- a/drivers/usb/core/hub.h
+++ b/drivers/usb/core/hub.h
@@ -131,7 +131,7 @@
 	__u8  bDescLength;
 	__u8  bDescriptorType;
 	__u8  bNbrPorts;
-	__u16 wHubCharacteristics;
+	__le16 wHubCharacteristics;
 	__u8  bPwrOn2PwrGood;
 	__u8  bHubContrCurrent;
 	    	/* add 1 bit for hub status change; round to bytes */
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index d07bba0..12f490f 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -39,6 +39,7 @@
 #include <linux/usbdevice_fs.h>
 #include <linux/smp_lock.h>
 #include <linux/parser.h>
+#include <linux/notifier.h>
 #include <asm/byteorder.h>
 #include "usb.h"
 #include "hcd.h"
@@ -619,7 +620,7 @@
 	}
 }
 
-void usbfs_add_bus(struct usb_bus *bus)
+static void usbfs_add_bus(struct usb_bus *bus)
 {
 	struct dentry *parent;
 	char name[8];
@@ -642,12 +643,9 @@
 		err ("error creating usbfs bus entry");
 		return;
 	}
-
-	usbfs_update_special();
-	usbfs_conn_disc_event();
 }
 
-void usbfs_remove_bus(struct usb_bus *bus)
+static void usbfs_remove_bus(struct usb_bus *bus)
 {
 	if (bus->usbfs_dentry) {
 		fs_remove_file (bus->usbfs_dentry);
@@ -659,12 +657,9 @@
 		remove_special_files();
 		num_buses = 0;
 	}
-
-	usbfs_update_special();
-	usbfs_conn_disc_event();
 }
 
-void usbfs_add_device(struct usb_device *dev)
+static void usbfs_add_device(struct usb_device *dev)
 {
 	char name[8];
 	int i;
@@ -690,12 +685,9 @@
 	}
 	if (dev->usbfs_dentry->d_inode)
 		dev->usbfs_dentry->d_inode->i_size = i_size;
-
-	usbfs_update_special();
-	usbfs_conn_disc_event();
 }
 
-void usbfs_remove_device(struct usb_device *dev)
+static void usbfs_remove_device(struct usb_device *dev)
 {
 	struct dev_state *ds;
 	struct siginfo sinfo;
@@ -716,10 +708,33 @@
 			kill_proc_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid);
 		}
 	}
+}
+
+static int usbfs_notify(struct notifier_block *self, unsigned long action, void *dev)
+{
+	switch (action) {
+	case USB_DEVICE_ADD:
+		usbfs_add_device(dev);
+		break;
+	case USB_DEVICE_REMOVE:
+		usbfs_remove_device(dev);
+		break;
+	case USB_BUS_ADD:
+		usbfs_add_bus(dev);
+		break;
+	case USB_BUS_REMOVE:
+		usbfs_remove_bus(dev);
+	}
+
 	usbfs_update_special();
 	usbfs_conn_disc_event();
+	return NOTIFY_OK;
 }
 
+static struct notifier_block usbfs_nb = {
+	.notifier_call = 	usbfs_notify,
+};
+
 /* --------------------------------------------------------------------- */
 
 static struct proc_dir_entry *usbdir = NULL;
@@ -732,6 +747,8 @@
 	if (retval)
 		return retval;
 
+	usb_register_notify(&usbfs_nb);
+
 	/* create mount point for usbfs */
 	usbdir = proc_mkdir("usb", proc_bus);
 
@@ -740,6 +757,7 @@
 
 void usbfs_cleanup(void)
 {
+	usb_unregister_notify(&usbfs_nb);
 	unregister_filesystem(&usb_fs_type);
 	if (usbdir)
 		remove_proc_entry("usb", proc_bus);
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index f9a81e8..644a3d4 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -187,21 +187,37 @@
  *      If a thread in your driver uses this call, make sure your disconnect()
  *      method can wait for it to complete.  Since you don't have a handle on
  *      the URB used, you can't cancel the request.
+ *
+ *	Because there is no usb_interrupt_msg() and no USBDEVFS_INTERRUPT
+ *	ioctl, users are forced to abuse this routine by using it to submit
+ *	URBs for interrupt endpoints.  We will take the liberty of creating
+ *	an interrupt URB (with the default interval) if the target is an
+ *	interrupt endpoint.
  */
 int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, 
 			void *data, int len, int *actual_length, int timeout)
 {
 	struct urb *urb;
+	struct usb_host_endpoint *ep;
 
-	if (len < 0)
+	ep = (usb_pipein(pipe) ? usb_dev->ep_in : usb_dev->ep_out)
+			[usb_pipeendpoint(pipe)];
+	if (!ep || len < 0)
 		return -EINVAL;
 
-	urb=usb_alloc_urb(0, GFP_KERNEL);
+	urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!urb)
 		return -ENOMEM;
 
-	usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
-			  usb_api_blocking_completion, NULL);
+	if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+			USB_ENDPOINT_XFER_INT) {
+		pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
+		usb_fill_int_urb(urb, usb_dev, pipe, data, len,
+				usb_api_blocking_completion, NULL,
+				ep->desc.bInterval);
+	} else
+		usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
+				usb_api_blocking_completion, NULL);
 
 	return usb_start_wait_urb(urb, timeout, actual_length);
 }
@@ -771,6 +787,31 @@
 	return err;
 }
 
+/**
+ * usb_cache_string - read a string descriptor and cache it for later use
+ * @udev: the device whose string descriptor is being read
+ * @index: the descriptor index
+ *
+ * Returns a pointer to a kmalloc'ed buffer containing the descriptor string,
+ * or NULL if the index is 0 or the string could not be read.
+ */
+char *usb_cache_string(struct usb_device *udev, int index)
+{
+	char *buf;
+	char *smallbuf = NULL;
+	int len;
+
+	if (index > 0 && (buf = kmalloc(256, GFP_KERNEL)) != NULL) {
+		if ((len = usb_string(udev, index, buf, 256)) > 0) {
+			if ((smallbuf = kmalloc(++len, GFP_KERNEL)) == NULL)
+				return buf;
+			memcpy(smallbuf, buf, len);
+		}
+		kfree(buf);
+	}
+	return smallbuf;
+}
+
 /*
  * usb_get_device_descriptor - (re)reads the device descriptor (usbcore)
  * @dev: the device whose device descriptor is being updated
@@ -992,8 +1033,6 @@
 			dev_dbg (&dev->dev, "unregistering interface %s\n",
 				interface->dev.bus_id);
 			usb_remove_sysfs_intf_files(interface);
-			kfree(interface->cur_altsetting->string);
-			interface->cur_altsetting->string = NULL;
 			device_del (&interface->dev);
 		}
 
@@ -1133,6 +1172,8 @@
 	 */
 
 	/* prevent submissions using previous endpoint settings */
+	if (device_is_registered(&iface->dev))
+		usb_remove_sysfs_intf_files(iface);
 	usb_disable_interface(dev, iface);
 
 	iface->cur_altsetting = alt;
@@ -1168,6 +1209,8 @@
 	 * (Likewise, EP0 never "halts" on well designed devices.)
 	 */
 	usb_enable_interface(dev, iface);
+	if (device_is_registered(&iface->dev))
+		usb_create_sysfs_intf_files(iface);
 
 	return 0;
 }
@@ -1217,10 +1260,8 @@
 			USB_REQ_SET_CONFIGURATION, 0,
 			config->desc.bConfigurationValue, 0,
 			NULL, 0, USB_CTRL_SET_TIMEOUT);
-	if (retval < 0) {
-		usb_set_device_state(dev, USB_STATE_ADDRESS);
+	if (retval < 0)
 		return retval;
-	}
 
 	dev->toggle[0] = dev->toggle[1] = 0;
 
@@ -1229,6 +1270,8 @@
 		struct usb_interface *intf = config->interface[i];
 		struct usb_host_interface *alt;
 
+		if (device_is_registered(&intf->dev))
+			usb_remove_sysfs_intf_files(intf);
 		alt = usb_altnum_to_altsetting(intf, 0);
 
 		/* No altsetting 0?  We'll assume the first altsetting.
@@ -1241,6 +1284,8 @@
 
 		intf->cur_altsetting = alt;
 		usb_enable_interface(dev, intf);
+		if (device_is_registered(&intf->dev))
+			usb_create_sysfs_intf_files(intf);
 	}
 	return 0;
 }
@@ -1328,7 +1373,7 @@
 		}
 
 		for (; n < nintf; ++n) {
-			new_interfaces[n] = kmalloc(
+			new_interfaces[n] = kzalloc(
 					sizeof(struct usb_interface),
 					GFP_KERNEL);
 			if (!new_interfaces[n]) {
@@ -1369,7 +1414,6 @@
 			struct usb_host_interface *alt;
 
 			cp->interface[i] = intf = new_interfaces[i];
-			memset(intf, 0, sizeof(*intf));
 			intfc = cp->intf_cache[i];
 			intf->altsetting = intfc->altsetting;
 			intf->num_altsetting = intfc->num_altsetting;
@@ -1393,6 +1437,7 @@
 			intf->dev.dma_mask = dev->dev.dma_mask;
 			intf->dev.release = release_interface;
 			device_initialize (&intf->dev);
+			mark_quiesced(intf);
 			sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
 				 dev->bus->busnum, dev->devpath,
 				 configuration,
@@ -1400,12 +1445,9 @@
 		}
 		kfree(new_interfaces);
 
-		if ((cp->desc.iConfiguration) &&
-		    (cp->string == NULL)) {
-			cp->string = kmalloc(256, GFP_KERNEL);
-			if (cp->string)
-				usb_string(dev, cp->desc.iConfiguration, cp->string, 256);
-		}
+		if (cp->string == NULL)
+			cp->string = usb_cache_string(dev,
+					cp->desc.iConfiguration);
 
 		/* Now that all the interfaces are set up, register them
 		 * to trigger binding of drivers to interfaces.  probe()
@@ -1415,13 +1457,12 @@
 		 */
 		for (i = 0; i < nintf; ++i) {
 			struct usb_interface *intf = cp->interface[i];
-			struct usb_interface_descriptor *desc;
+			struct usb_host_interface *alt = intf->cur_altsetting;
 
-			desc = &intf->altsetting [0].desc;
 			dev_dbg (&dev->dev,
 				"adding %s (config #%d, interface %d)\n",
 				intf->dev.bus_id, configuration,
-				desc->bInterfaceNumber);
+				alt->desc.bInterfaceNumber);
 			ret = device_add (&intf->dev);
 			if (ret != 0) {
 				dev_err(&dev->dev,
@@ -1430,13 +1471,6 @@
 					ret);
 				continue;
 			}
-			if ((intf->cur_altsetting->desc.iInterface) &&
-			    (intf->cur_altsetting->string == NULL)) {
-				intf->cur_altsetting->string = kmalloc(256, GFP_KERNEL);
-				if (intf->cur_altsetting->string)
-					usb_string(dev, intf->cur_altsetting->desc.iInterface,
-						   intf->cur_altsetting->string, 256);
-			}
 			usb_create_sysfs_intf_files (intf);
 		}
 	}
diff --git a/drivers/usb/core/notify.c b/drivers/usb/core/notify.c
new file mode 100644
index 0000000..37da059
--- /dev/null
+++ b/drivers/usb/core/notify.c
@@ -0,0 +1,120 @@
+/*
+ * All the USB notify logic
+ *
+ * (C) Copyright 2005 Greg Kroah-Hartman <gregkh@suse.de>
+ *
+ * notifier functions originally based on those in kernel/sys.c
+ * but fixed up to not be so broken.
+ *
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/notifier.h>
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
+#include <linux/usb.h>
+
+#include "usb.h"
+
+
+static struct notifier_block *usb_notifier_list;
+static DECLARE_MUTEX(usb_notifier_lock);
+
+static void usb_notifier_chain_register(struct notifier_block **list,
+					struct notifier_block *n)
+{
+	down(&usb_notifier_lock);
+	while (*list) {
+		if (n->priority > (*list)->priority)
+			break;
+		list = &((*list)->next);
+	}
+	n->next = *list;
+	*list = n;
+	up(&usb_notifier_lock);
+}
+
+static void usb_notifier_chain_unregister(struct notifier_block **nl,
+				   struct notifier_block *n)
+{
+	down(&usb_notifier_lock);
+	while ((*nl)!=NULL) {
+		if ((*nl)==n) {
+			*nl = n->next;
+			goto exit;
+		}
+		nl=&((*nl)->next);
+	}
+exit:
+	up(&usb_notifier_lock);
+}
+
+static int usb_notifier_call_chain(struct notifier_block **n,
+				   unsigned long val, void *v)
+{
+	int ret=NOTIFY_DONE;
+	struct notifier_block *nb = *n;
+
+	down(&usb_notifier_lock);
+	while (nb) {
+		ret = nb->notifier_call(nb,val,v);
+		if (ret&NOTIFY_STOP_MASK) {
+			goto exit;
+		}
+		nb = nb->next;
+	}
+exit:
+	up(&usb_notifier_lock);
+	return ret;
+}
+
+/**
+ * usb_register_notify - register a notifier callback whenever a usb change happens
+ * @nb: pointer to the notifier block for the callback events.
+ *
+ * These changes are either USB devices or busses being added or removed.
+ */
+void usb_register_notify(struct notifier_block *nb)
+{
+	usb_notifier_chain_register(&usb_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(usb_register_notify);
+
+/**
+ * usb_unregister_notify - unregister a notifier callback
+ * @nb: pointer to the notifier block for the callback events.
+ *
+ * usb_register_notifier() must have been previously called for this function
+ * to work properly.
+ */
+void usb_unregister_notify(struct notifier_block *nb)
+{
+	usb_notifier_chain_unregister(&usb_notifier_list, nb);
+}
+EXPORT_SYMBOL_GPL(usb_unregister_notify);
+
+
+void usb_notify_add_device(struct usb_device *udev)
+{
+	usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_ADD, udev);
+}
+
+void usb_notify_remove_device(struct usb_device *udev)
+{
+	usb_notifier_call_chain(&usb_notifier_list, USB_DEVICE_REMOVE, udev);
+}
+
+void usb_notify_add_bus(struct usb_bus *ubus)
+{
+	usb_notifier_call_chain(&usb_notifier_list, USB_BUS_ADD, ubus);
+}
+
+void usb_notify_remove_bus(struct usb_bus *ubus)
+{
+	usb_notifier_call_chain(&usb_notifier_list, USB_BUS_REMOVE, ubus);
+}
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 00297f1..edd83e0 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -22,9 +22,207 @@
 
 #include "usb.h"
 
+/* endpoint stuff */
+struct ep_object {
+	struct usb_endpoint_descriptor *desc;
+	struct usb_device *udev;
+	struct kobject kobj;
+};
+#define to_ep_object(_kobj) \
+	container_of(_kobj, struct ep_object, kobj)
+
+struct ep_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct usb_device *,
+			struct usb_endpoint_descriptor *, char *);
+};
+#define to_ep_attribute(_attr) \
+	container_of(_attr, struct ep_attribute, attr)
+
+#define EP_ATTR(_name)						\
+struct ep_attribute ep_##_name = {				\
+	.attr = {.name = #_name, .owner = THIS_MODULE,		\
+			.mode = S_IRUGO},			\
+	.show = show_ep_##_name}
+
+#define usb_ep_attr(field, format_string)			\
+static ssize_t show_ep_##field(struct usb_device *udev,		\
+		struct usb_endpoint_descriptor *desc, 		\
+		char *buf)					\
+{								\
+	return sprintf(buf, format_string, desc->field);	\
+}								\
+static EP_ATTR(field);
+
+usb_ep_attr(bLength, "%02x\n")
+usb_ep_attr(bEndpointAddress, "%02x\n")
+usb_ep_attr(bmAttributes, "%02x\n")
+usb_ep_attr(bInterval, "%02x\n")
+
+static ssize_t show_ep_wMaxPacketSize(struct usb_device *udev,
+		struct usb_endpoint_descriptor *desc, char *buf)
+{
+	return sprintf(buf, "%04x\n",
+			le16_to_cpu(desc->wMaxPacketSize) & 0x07ff);
+}
+static EP_ATTR(wMaxPacketSize);
+
+static ssize_t show_ep_type(struct usb_device *udev,
+		struct usb_endpoint_descriptor *desc, char *buf)
+{
+	char *type = "unknown";
+
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		type = "Control";
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		type = "Isoc";
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		type = "Bulk";
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		type = "Interrupt";
+		break;
+	}
+	return sprintf(buf, "%s\n", type);
+}
+static EP_ATTR(type);
+
+static ssize_t show_ep_interval(struct usb_device *udev,
+		struct usb_endpoint_descriptor *desc, char *buf)
+{
+	char unit;
+	unsigned interval = 0;
+	unsigned in;
+
+	in = (desc->bEndpointAddress & USB_DIR_IN);
+
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		if (udev->speed == USB_SPEED_HIGH) 	/* uframes per NAK */
+			interval = desc->bInterval;
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		interval = 1 << (desc->bInterval - 1);
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		if (udev->speed == USB_SPEED_HIGH && !in) /* uframes per NAK */
+			interval = desc->bInterval;
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		if (udev->speed == USB_SPEED_HIGH)
+			interval = 1 << (desc->bInterval - 1);
+		else
+			interval = desc->bInterval;
+		break;
+	}
+	interval *= (udev->speed == USB_SPEED_HIGH) ? 125 : 1000;
+	if (interval % 1000)
+		unit = 'u';
+	else {
+		unit = 'm';
+		interval /= 1000;
+	}
+
+	return sprintf(buf, "%d%cs\n", interval, unit);
+}
+static EP_ATTR(interval);
+
+static ssize_t show_ep_direction(struct usb_device *udev,
+		struct usb_endpoint_descriptor *desc, char *buf)
+{
+	char *direction;
+
+	if ((desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) ==
+			USB_ENDPOINT_XFER_CONTROL)
+		direction = "both";
+	else if (desc->bEndpointAddress & USB_DIR_IN)
+		direction = "in";
+	else
+		direction = "out";
+	return sprintf(buf, "%s\n", direction);
+}
+static EP_ATTR(direction);
+
+static struct attribute *ep_attrs[] = {
+	&ep_bLength.attr,
+	&ep_bEndpointAddress.attr,
+	&ep_bmAttributes.attr,
+	&ep_bInterval.attr,
+	&ep_wMaxPacketSize.attr,
+	&ep_type.attr,
+	&ep_interval.attr,
+	&ep_direction.attr,
+	NULL,
+};
+
+static void ep_object_release(struct kobject *kobj)
+{
+	kfree(to_ep_object(kobj));
+}
+
+static ssize_t ep_object_show(struct kobject *kobj, struct attribute *attr,
+		char *buf)
+{
+	struct ep_object *ep_obj = to_ep_object(kobj);
+	struct ep_attribute *ep_attr = to_ep_attribute(attr);
+
+	return (ep_attr->show)(ep_obj->udev, ep_obj->desc, buf);
+}
+
+static struct sysfs_ops ep_object_sysfs_ops = {
+	.show =			ep_object_show,
+};
+
+static struct kobj_type ep_object_ktype = {
+	.release =		ep_object_release,
+	.sysfs_ops =		&ep_object_sysfs_ops,
+	.default_attrs =	ep_attrs,
+};
+
+static void usb_create_ep_files(struct kobject *parent,
+		struct usb_host_endpoint *endpoint,
+		struct usb_device *udev)
+{
+	struct ep_object *ep_obj;
+	struct kobject *kobj;
+
+	ep_obj = kzalloc(sizeof(struct ep_object), GFP_KERNEL);
+	if (!ep_obj)
+		return;
+
+	ep_obj->desc = &endpoint->desc;
+	ep_obj->udev = udev;
+
+	kobj = &ep_obj->kobj;
+	kobject_set_name(kobj, "ep_%02x", endpoint->desc.bEndpointAddress);
+	kobj->parent = parent;
+	kobj->ktype = &ep_object_ktype;
+
+	/* Don't use kobject_register, because it generates a hotplug event */
+	kobject_init(kobj);
+	if (kobject_add(kobj) == 0)
+		endpoint->kobj = kobj;
+	else
+		kobject_put(kobj);
+}
+
+static void usb_remove_ep_files(struct usb_host_endpoint *endpoint)
+{
+
+	if (endpoint->kobj) {
+		kobject_del(endpoint->kobj);
+		kobject_put(endpoint->kobj);
+		endpoint->kobj = NULL;
+	}
+}
+
 /* Active configuration fields */
 #define usb_actconfig_show(field, multiplier, format_string)		\
-static ssize_t  show_##field (struct device *dev, struct device_attribute *attr, char *buf)		\
+static ssize_t  show_##field (struct device *dev,			\
+		struct device_attribute *attr, char *buf)		\
 {									\
 	struct usb_device *udev;					\
 	struct usb_host_config *actconfig;				\
@@ -46,22 +244,17 @@
 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)
+static ssize_t show_configuration_string(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
 	struct usb_device *udev;
 	struct usb_host_config *actconfig;
-	int len;
 
 	udev = to_usb_device (dev);
 	actconfig = udev->actconfig;
 	if ((!actconfig) || (!actconfig->string))
 		return 0;
-	len = sprintf(buf, actconfig->string, PAGE_SIZE);
-	if (len < 0)
-		return 0;
-	buf[len] = '\n';
-	buf[len+1] = 0;
-	return len+1;
+	return sprintf(buf, "%s\n", actconfig->string);
 }
 static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
 
@@ -69,7 +262,8 @@
 usb_actconfig_show(bConfigurationValue, 1, "%u\n");
 
 static ssize_t
-set_bConfigurationValue (struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+set_bConfigurationValue (struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
 {
 	struct usb_device	*udev = udev = to_usb_device (dev);
 	int			config, value;
@@ -87,18 +281,13 @@
 
 /* String fields */
 #define usb_string_attr(name)						\
-static ssize_t  show_##name(struct device *dev, struct device_attribute *attr, char *buf)		\
+static ssize_t  show_##name(struct device *dev,				\
+		struct device_attribute *attr, char *buf)		\
 {									\
 	struct usb_device *udev;					\
-	int len;							\
 									\
 	udev = to_usb_device (dev);					\
-	len = snprintf(buf, 256, "%s", udev->name);			\
-	if (len < 0)							\
-		return 0;						\
-	buf[len] = '\n';						\
-	buf[len+1] = 0;							\
-	return len+1;							\
+	return sprintf(buf, "%s\n", udev->name);			\
 }									\
 static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
 
@@ -167,7 +356,8 @@
 /* Descriptor fields */
 #define usb_descriptor_attr_le16(field, format_string)			\
 static ssize_t								\
-show_##field (struct device *dev, struct device_attribute *attr, char *buf)				\
+show_##field (struct device *dev, struct device_attribute *attr,	\
+		char *buf)						\
 {									\
 	struct usb_device *udev;					\
 									\
@@ -183,7 +373,8 @@
 
 #define usb_descriptor_attr(field, format_string)			\
 static ssize_t								\
-show_##field (struct device *dev, struct device_attribute *attr, char *buf)				\
+show_##field (struct device *dev, struct device_attribute *attr,	\
+		char *buf)						\
 {									\
 	struct usb_device *udev;					\
 									\
@@ -236,19 +427,21 @@
 	if (udev->serial)
 		device_create_file (dev, &dev_attr_serial);
 	device_create_file (dev, &dev_attr_configuration);
+	usb_create_ep_files(&dev->kobj, &udev->ep0, udev);
 }
 
 void usb_remove_sysfs_dev_files (struct usb_device *udev)
 {
 	struct device *dev = &udev->dev;
 
+	usb_remove_ep_files(&udev->ep0);
 	sysfs_remove_group(&dev->kobj, &dev_attr_grp);
 
-	if (udev->descriptor.iManufacturer)
+	if (udev->manufacturer)
 		device_remove_file(dev, &dev_attr_manufacturer);
-	if (udev->descriptor.iProduct)
+	if (udev->product)
 		device_remove_file(dev, &dev_attr_product);
-	if (udev->descriptor.iSerialNumber)
+	if (udev->serial)
 		device_remove_file(dev, &dev_attr_serial);
 	device_remove_file (dev, &dev_attr_configuration);
 }
@@ -256,11 +449,13 @@
 /* Interface fields */
 #define usb_intf_attr(field, format_string)				\
 static ssize_t								\
-show_##field (struct device *dev, struct device_attribute *attr, char *buf)				\
+show_##field (struct device *dev, struct device_attribute *attr,	\
+		char *buf)						\
 {									\
 	struct usb_interface *intf = to_usb_interface (dev);		\
 									\
-	return sprintf (buf, format_string, intf->cur_altsetting->desc.field); \
+	return sprintf (buf, format_string,				\
+			intf->cur_altsetting->desc.field); 		\
 }									\
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
 
@@ -271,7 +466,8 @@
 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)
+static ssize_t show_interface_string(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
 	struct usb_interface *intf;
 	struct usb_device *udev;
@@ -288,34 +484,28 @@
 }
 static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL);
 
-static ssize_t show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_modalias(struct device *dev,
+		struct device_attribute *attr, char *buf)
 {
 	struct usb_interface *intf;
 	struct usb_device *udev;
-	int len;
+	struct usb_host_interface *alt;
 
 	intf = to_usb_interface(dev);
 	udev = interface_to_usbdev(intf);
+	alt = intf->cur_altsetting;
 
-	len = sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic",
-			       le16_to_cpu(udev->descriptor.idVendor),
-			       le16_to_cpu(udev->descriptor.idProduct),
-			       le16_to_cpu(udev->descriptor.bcdDevice),
-			       udev->descriptor.bDeviceClass,
-			       udev->descriptor.bDeviceSubClass,
-			       udev->descriptor.bDeviceProtocol);
-	buf += len;
-
-	if (udev->descriptor.bDeviceClass == 0) {
-		struct usb_host_interface *alt = intf->cur_altsetting;
-
-		return len + sprintf(buf, "%02Xisc%02Xip%02X\n",
-			       alt->desc.bInterfaceClass,
-			       alt->desc.bInterfaceSubClass,
-			       alt->desc.bInterfaceProtocol);
- 	} else {
-		return len + sprintf(buf, "*isc*ip*\n");
-	}
+	return sprintf(buf, "usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02X"
+			"ic%02Xisc%02Xip%02X\n",
+			le16_to_cpu(udev->descriptor.idVendor),
+			le16_to_cpu(udev->descriptor.idProduct),
+			le16_to_cpu(udev->descriptor.bcdDevice),
+			udev->descriptor.bDeviceClass,
+			udev->descriptor.bDeviceSubClass,
+			udev->descriptor.bDeviceProtocol,
+			alt->desc.bInterfaceClass,
+			alt->desc.bInterfaceSubClass,
+			alt->desc.bInterfaceProtocol);
 }
 static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
 
@@ -333,20 +523,47 @@
 	.attrs = intf_attrs,
 };
 
+static inline void usb_create_intf_ep_files(struct usb_interface *intf,
+		struct usb_device *udev)
+{
+	struct usb_host_interface *iface_desc;
+	int i;
+
+	iface_desc = intf->cur_altsetting;
+	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i)
+		usb_create_ep_files(&intf->dev.kobj, &iface_desc->endpoint[i],
+				udev);
+}
+
+static inline void usb_remove_intf_ep_files(struct usb_interface *intf)
+{
+	struct usb_host_interface *iface_desc;
+	int i;
+
+	iface_desc = intf->cur_altsetting;
+	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i)
+		usb_remove_ep_files(&iface_desc->endpoint[i]);
+}
+
 void usb_create_sysfs_intf_files (struct usb_interface *intf)
 {
+	struct usb_device *udev = interface_to_usbdev(intf);
+	struct usb_host_interface *alt = intf->cur_altsetting;
+
 	sysfs_create_group(&intf->dev.kobj, &intf_attr_grp);
 
-	if (intf->cur_altsetting->string)
+	if (alt->string == NULL)
+		alt->string = usb_cache_string(udev, alt->desc.iInterface);
+	if (alt->string)
 		device_create_file(&intf->dev, &dev_attr_interface);
-		
+	usb_create_intf_ep_files(intf, udev);
 }
 
 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);
 
 	if (intf->cur_altsetting->string)
 		device_remove_file(&intf->dev, &dev_attr_interface);
-
 }
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index b32898e..f2a1fed 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -237,7 +237,8 @@
 	    (dev->state < USB_STATE_DEFAULT) ||
 	    (!dev->bus) || (dev->devnum <= 0))
 		return -ENODEV;
-	if (dev->state == USB_STATE_SUSPENDED)
+	if (dev->bus->controller->power.power_state.event != PM_EVENT_ON
+			|| dev->state == USB_STATE_SUSPENDED)
 		return -EHOSTUNREACH;
 	if (!(op = dev->bus->op) || !op->submit_urb)
 		return -ENODEV;
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 4c57f3f..0eefff7 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -107,10 +107,19 @@
 	id = usb_match_id (intf, driver->id_table);
 	if (id) {
 		dev_dbg (dev, "%s - got id\n", __FUNCTION__);
+
+		/* Interface "power state" doesn't correspond to any hardware
+		 * state whatsoever.  We use it to record when it's bound to
+		 * a driver that may start I/0:  it's not frozen/quiesced.
+		 */
+		mark_active(intf);
 		intf->condition = USB_INTERFACE_BINDING;
 		error = driver->probe (intf, id);
-		intf->condition = error ? USB_INTERFACE_UNBOUND :
-				USB_INTERFACE_BOUND;
+		if (error) {
+			mark_quiesced(intf);
+			intf->condition = USB_INTERFACE_UNBOUND;
+		} else
+			intf->condition = USB_INTERFACE_BOUND;
 	}
 
 	return error;
@@ -136,6 +145,7 @@
 			0);
 	usb_set_intfdata(intf, NULL);
 	intf->condition = USB_INTERFACE_UNBOUND;
+	mark_quiesced(intf);
 
 	return 0;
 }
@@ -299,6 +309,7 @@
 	dev->driver = &driver->driver;
 	usb_set_intfdata(iface, priv);
 	iface->condition = USB_INTERFACE_BOUND;
+	mark_active(iface);
 
 	/* if interface was already added, bind now; else let
 	 * the future device_add() bind it, bypassing probe()
@@ -345,6 +356,7 @@
 	dev->driver = NULL;
 	usb_set_intfdata(iface, NULL);
 	iface->condition = USB_INTERFACE_UNBOUND;
+	mark_quiesced(iface);
 }
 
 /**
@@ -557,6 +569,7 @@
 {
 	struct usb_interface *intf;
 	struct usb_device *usb_dev;
+	struct usb_host_interface *alt;
 	int i = 0;
 	int length = 0;
 
@@ -573,7 +586,8 @@
 
 	intf = to_usb_interface(dev);
 	usb_dev = interface_to_usbdev (intf);
-	
+	alt = intf->cur_altsetting;
+
 	if (usb_dev->devnum < 0) {
 		pr_debug ("usb %s: already deleted?\n", dev->bus_id);
 		return -ENODEV;
@@ -615,46 +629,27 @@
 				usb_dev->descriptor.bDeviceProtocol))
 		return -ENOMEM;
 
-	if (usb_dev->descriptor.bDeviceClass == 0) {
-		struct usb_host_interface *alt = intf->cur_altsetting;
+	if (add_hotplug_env_var(envp, num_envp, &i,
+				buffer, buffer_size, &length,
+				"INTERFACE=%d/%d/%d",
+				alt->desc.bInterfaceClass,
+				alt->desc.bInterfaceSubClass,
+				alt->desc.bInterfaceProtocol))
+		return -ENOMEM;
 
-		/* 2.4 only exposed interface zero.  in 2.5, hotplug
-		 * agents are called for all interfaces, and can use
-		 * $DEVPATH/bInterfaceNumber if necessary.
-		 */
-		if (add_hotplug_env_var(envp, num_envp, &i,
-					buffer, buffer_size, &length,
-					"INTERFACE=%d/%d/%d",
-					alt->desc.bInterfaceClass,
-					alt->desc.bInterfaceSubClass,
-					alt->desc.bInterfaceProtocol))
-			return -ENOMEM;
-
-		if (add_hotplug_env_var(envp, num_envp, &i,
-					buffer, buffer_size, &length,
-					"MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
-					le16_to_cpu(usb_dev->descriptor.idVendor),
-					le16_to_cpu(usb_dev->descriptor.idProduct),
-					le16_to_cpu(usb_dev->descriptor.bcdDevice),
-					usb_dev->descriptor.bDeviceClass,
-					usb_dev->descriptor.bDeviceSubClass,
-					usb_dev->descriptor.bDeviceProtocol,
-					alt->desc.bInterfaceClass,
-					alt->desc.bInterfaceSubClass,
-					alt->desc.bInterfaceProtocol))
-			return -ENOMEM;
- 	} else {
-		if (add_hotplug_env_var(envp, num_envp, &i,
-					buffer, buffer_size, &length,
-					"MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic*isc*ip*",
-					le16_to_cpu(usb_dev->descriptor.idVendor),
-					le16_to_cpu(usb_dev->descriptor.idProduct),
-					le16_to_cpu(usb_dev->descriptor.bcdDevice),
-					usb_dev->descriptor.bDeviceClass,
-					usb_dev->descriptor.bDeviceSubClass,
-					usb_dev->descriptor.bDeviceProtocol))
-			return -ENOMEM;
-	}
+	if (add_hotplug_env_var(envp, num_envp, &i,
+				buffer, buffer_size, &length,
+				"MODALIAS=usb:v%04Xp%04Xd%04Xdc%02Xdsc%02Xdp%02Xic%02Xisc%02Xip%02X",
+				le16_to_cpu(usb_dev->descriptor.idVendor),
+				le16_to_cpu(usb_dev->descriptor.idProduct),
+				le16_to_cpu(usb_dev->descriptor.bcdDevice),
+				usb_dev->descriptor.bDeviceClass,
+				usb_dev->descriptor.bDeviceSubClass,
+				usb_dev->descriptor.bDeviceProtocol,
+				alt->desc.bInterfaceClass,
+				alt->desc.bInterfaceSubClass,
+				alt->desc.bInterfaceProtocol))
+		return -ENOMEM;
 
 	envp[i] = NULL;
 
@@ -709,12 +704,10 @@
 {
 	struct usb_device *dev;
 
-	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev)
 		return NULL;
 
-	memset(dev, 0, sizeof(*dev));
-
 	bus = usb_bus_get(bus);
 	if (!bus) {
 		kfree(dev);
@@ -1402,13 +1395,30 @@
 			usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
+static int verify_suspended(struct device *dev, void *unused)
+{
+	return (dev->power.power_state.event == PM_EVENT_ON) ? -EBUSY : 0;
+}
+
 static int usb_generic_suspend(struct device *dev, pm_message_t message)
 {
-	struct usb_interface *intf;
-	struct usb_driver *driver;
+	struct usb_interface	*intf;
+	struct usb_driver	*driver;
+	int			status;
 
-	if (dev->driver == &usb_generic_driver)
-		return usb_suspend_device (to_usb_device(dev), message);
+	/* USB devices enter SUSPEND state through their hubs, but can be
+	 * marked for FREEZE as soon as their children are already idled.
+	 * But those semantics are useless, so we equate the two (sigh).
+	 */
+	if (dev->driver == &usb_generic_driver) {
+		if (dev->power.power_state.event == message.event)
+			return 0;
+		/* we need to rule out bogus requests through sysfs */
+		status = device_for_each_child(dev, NULL, verify_suspended);
+		if (status)
+			return status;
+ 		return usb_suspend_device (to_usb_device(dev));
+	}
 
 	if ((dev->driver == NULL) ||
 	    (dev->driver_data == &usb_generic_driver_data))
@@ -1417,23 +1427,44 @@
 	intf = to_usb_interface(dev);
 	driver = to_usb_driver(dev->driver);
 
-	/* there's only one USB suspend state */
-	if (intf->dev.power.power_state.event)
+	/* with no hardware, USB interfaces only use FREEZE and ON states */
+	if (!is_active(intf))
 		return 0;
 
-	if (driver->suspend)
-		return driver->suspend(intf, message);
-	return 0;
+	if (driver->suspend && driver->resume) {
+		status = driver->suspend(intf, message);
+		if (status)
+			dev_err(dev, "%s error %d\n", "suspend", status);
+		else
+			mark_quiesced(intf);
+	} else {
+		// FIXME else if there's no suspend method, disconnect...
+		dev_warn(dev, "no %s?\n", "suspend");
+		status = 0;
+	}
+	return status;
 }
 
 static int usb_generic_resume(struct device *dev)
 {
-	struct usb_interface *intf;
-	struct usb_driver *driver;
+	struct usb_interface	*intf;
+	struct usb_driver	*driver;
+	struct usb_device	*udev;
+	int			status;
 
-	/* devices resume through their hub */
-	if (dev->driver == &usb_generic_driver)
+	if (dev->power.power_state.event == PM_EVENT_ON)
+		return 0;
+
+	/* mark things as "on" immediately, no matter what errors crop up */
+	dev->power.power_state.event = PM_EVENT_ON;
+
+	/* devices resume through their hubs */
+	if (dev->driver == &usb_generic_driver) {
+		udev = to_usb_device(dev);
+		if (udev->state == USB_STATE_NOTATTACHED)
+			return 0;
 		return usb_resume_device (to_usb_device(dev));
+	}
 
 	if ((dev->driver == NULL) ||
 	    (dev->driver_data == &usb_generic_driver_data))
@@ -1442,8 +1473,22 @@
 	intf = to_usb_interface(dev);
 	driver = to_usb_driver(dev->driver);
 
-	if (driver->resume)
-		return driver->resume(intf);
+	udev = interface_to_usbdev(intf);
+	if (udev->state == USB_STATE_NOTATTACHED)
+		return 0;
+
+	/* if driver was suspended, it has a resume method;
+	 * however, sysfs can wrongly mark things as suspended
+	 * (on the "no suspend method" FIXME path above)
+	 */
+	if (driver->resume) {
+		status = driver->resume(intf);
+		if (status) {
+			dev_err(dev, "%s error %d\n", "resume", status);
+			mark_quiesced(intf);
+		}
+	} else
+		dev_warn(dev, "no %s?\n", "resume");
 	return 0;
 }
 
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index e6504f3..1c4a684 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -13,12 +13,14 @@
 
 extern int usb_get_device_descriptor(struct usb_device *dev,
 		unsigned int size);
+extern char *usb_cache_string(struct usb_device *udev, int index);
 extern int usb_set_configuration(struct usb_device *dev, int configuration);
 
 extern void usb_lock_all_devices(void);
 extern void usb_unlock_all_devices(void);
 
 extern void usb_kick_khubd(struct usb_device *dev);
+extern void usb_suspend_root_hub(struct usb_device *hdev);
 extern void usb_resume_root_hub(struct usb_device *dev);
 
 extern int  usb_hub_init(void);
@@ -28,6 +30,28 @@
 extern int usb_host_init(void);
 extern void usb_host_cleanup(void);
 
+extern int usb_suspend_device(struct usb_device *dev);
+extern int usb_resume_device(struct usb_device *dev);
+
+
+/* Interfaces and their "power state" are owned by usbcore */
+
+static inline void mark_active(struct usb_interface *f)
+{
+	f->dev.power.power_state.event = PM_EVENT_ON;
+}
+
+static inline void mark_quiesced(struct usb_interface *f)
+{
+	f->dev.power.power_state.event = PM_EVENT_FREEZE;
+}
+
+static inline int is_active(struct usb_interface *f)
+{
+	return f->dev.power.power_state.event == PM_EVENT_ON;
+}
+
+
 /* for labeling diagnostics */
 extern const char *usbcore_name;
 
@@ -39,9 +63,6 @@
 
 extern int usbdev_init(void);
 extern void usbdev_cleanup(void);
-extern void usbdev_add(struct usb_device *dev);
-extern void usbdev_remove(struct usb_device *dev);
-extern struct usb_device *usbdev_lookup_minor(int minor);
 
 struct dev_state {
 	struct list_head list;      /* state list */
@@ -58,3 +79,9 @@
 	unsigned long ifclaimed;
 };
 
+/* internal notify stuff */
+extern void usb_notify_add_device(struct usb_device *udev);
+extern void usb_notify_remove_device(struct usb_device *udev);
+extern void usb_notify_add_bus(struct usb_bus *ubus);
+extern void usb_notify_remove_bus(struct usb_bus *ubus);
+
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index 5032017..02106be 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -967,6 +967,7 @@
 
 static struct device_driver dummy_udc_driver = {
 	.name		= (char *) gadget_name,
+	.owner		= THIS_MODULE,
 	.bus		= &platform_bus_type,
 	.probe		= dummy_udc_probe,
 	.remove		= dummy_udc_remove,
@@ -1751,7 +1752,7 @@
 	return retval;
 }
 
-static int dummy_hub_suspend (struct usb_hcd *hcd)
+static int dummy_bus_suspend (struct usb_hcd *hcd)
 {
 	struct dummy *dum = hcd_to_dummy (hcd);
 
@@ -1762,7 +1763,7 @@
 	return 0;
 }
 
-static int dummy_hub_resume (struct usb_hcd *hcd)
+static int dummy_bus_resume (struct usb_hcd *hcd)
 {
 	struct dummy *dum = hcd_to_dummy (hcd);
 
@@ -1894,8 +1895,8 @@
 
 	.hub_status_data = 	dummy_hub_status,
 	.hub_control = 		dummy_hub_control,
-	.hub_suspend =		dummy_hub_suspend,
-	.hub_resume =		dummy_hub_resume,
+	.bus_suspend =		dummy_bus_suspend,
+	.bus_resume =		dummy_bus_resume,
 };
 
 static int dummy_hcd_probe (struct device *dev)
@@ -1936,13 +1937,6 @@
 	dev_dbg (dev, "%s\n", __FUNCTION__);
 	hcd = dev_get_drvdata (dev);
 
-#ifndef CONFIG_USB_SUSPEND
-	/* Otherwise this would never happen */
-	usb_lock_device (hcd->self.root_hub);
-	dummy_hub_suspend (hcd);
-	usb_unlock_device (hcd->self.root_hub);
-#endif
-
 	hcd->state = HC_STATE_SUSPENDED;
 	return 0;
 }
@@ -1955,19 +1949,13 @@
 	hcd = dev_get_drvdata (dev);
 	hcd->state = HC_STATE_RUNNING;
 
-#ifndef CONFIG_USB_SUSPEND
-	/* Otherwise this would never happen */
-	usb_lock_device (hcd->self.root_hub);
-	dummy_hub_resume (hcd);
-	usb_unlock_device (hcd->self.root_hub);
-#endif
-
 	usb_hcd_poll_rh_status (hcd);
 	return 0;
 }
 
 static struct device_driver dummy_hcd_driver = {
 	.name		= (char *) driver_name,
+	.owner		= THIS_MODULE,
 	.bus		= &platform_bus_type,
 	.probe		= dummy_hcd_probe,
 	.remove		= dummy_hcd_remove,
diff --git a/drivers/usb/gadget/ether.c b/drivers/usb/gadget/ether.c
index f1024e8..8f402f8 100644
--- a/drivers/usb/gadget/ether.c
+++ b/drivers/usb/gadget/ether.c
@@ -2533,6 +2533,7 @@
 
 	.driver 	= {
 		.name		= (char *) shortname,
+		.owner		= THIS_MODULE,
 		// .shutdown = ...
 		// .suspend = ...
 		// .resume = ...
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index a41d9d4..ea09aaa 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -224,6 +224,7 @@
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
+#include <linux/kthread.h>
 #include <linux/limits.h>
 #include <linux/list.h>
 #include <linux/module.h>
@@ -669,7 +670,6 @@
 	wait_queue_head_t	thread_wqh;
 	int			thread_wakeup_needed;
 	struct completion	thread_notifier;
-	int			thread_pid;
 	struct task_struct	*thread_task;
 	sigset_t		thread_signal_mask;
 
@@ -1084,7 +1084,6 @@
 static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state)
 {
 	unsigned long		flags;
-	struct task_struct	*thread_task;
 
 	/* Do nothing if a higher-priority exception is already in progress.
 	 * If a lower-or-equal priority exception is in progress, preempt it
@@ -1093,9 +1092,9 @@
 	if (fsg->state <= new_state) {
 		fsg->exception_req_tag = fsg->ep0_req_tag;
 		fsg->state = new_state;
-		thread_task = fsg->thread_task;
-		if (thread_task)
-			send_sig_info(SIGUSR1, SEND_SIG_FORCED, thread_task);
+		if (fsg->thread_task)
+			send_sig_info(SIGUSR1, SEND_SIG_FORCED,
+					fsg->thread_task);
 	}
 	spin_unlock_irqrestore(&fsg->lock, flags);
 }
@@ -3383,11 +3382,6 @@
 {
 	struct fsg_dev		*fsg = (struct fsg_dev *) fsg_;
 
-	fsg->thread_task = current;
-
-	/* Release all our userspace resources */
-	daemonize("file-storage-gadget");
-
 	/* Allow the thread to be killed by a signal, but set the signal mask
 	 * to block everything but INT, TERM, KILL, and USR1. */
 	siginitsetinv(&fsg->thread_signal_mask, sigmask(SIGINT) |
@@ -3400,9 +3394,6 @@
 	 * that expects a __user pointer and it will work okay. */
 	set_fs(get_ds());
 
-	/* Wait for the gadget registration to finish up */
-	wait_for_completion(&fsg->thread_notifier);
-
 	/* The main loop */
 	while (fsg->state != FSG_STATE_TERMINATED) {
 		if (exception_in_progress(fsg) || signal_pending(current)) {
@@ -3440,8 +3431,9 @@
 		spin_unlock_irq(&fsg->lock);
 		}
 
+	spin_lock_irq(&fsg->lock);
 	fsg->thread_task = NULL;
-	flush_signals(current);
+	spin_unlock_irq(&fsg->lock);
 
 	/* In case we are exiting because of a signal, unregister the
 	 * gadget driver and close the backing file. */
@@ -3831,12 +3823,11 @@
 
 	/* Create the LUNs, open their backing files, and register the
 	 * LUN devices in sysfs. */
-	fsg->luns = kmalloc(i * sizeof(struct lun), GFP_KERNEL);
+	fsg->luns = kzalloc(i * sizeof(struct lun), GFP_KERNEL);
 	if (!fsg->luns) {
 		rc = -ENOMEM;
 		goto out;
 	}
-	memset(fsg->luns, 0, i * sizeof(struct lun));
 	fsg->nluns = i;
 
 	for (i = 0; i < fsg->nluns; ++i) {
@@ -3959,10 +3950,12 @@
 		sprintf(&serial[i], "%02X", c);
 	}
 
-	if ((rc = kernel_thread(fsg_main_thread, fsg, (CLONE_VM | CLONE_FS |
-			CLONE_FILES))) < 0)
+	fsg->thread_task = kthread_create(fsg_main_thread, fsg,
+			"file-storage-gadget");
+	if (IS_ERR(fsg->thread_task)) {
+		rc = PTR_ERR(fsg->thread_task);
 		goto out;
-	fsg->thread_pid = rc;
+	}
 
 	INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
 	INFO(fsg, "Number of LUNs=%d\n", fsg->nluns);
@@ -3994,7 +3987,12 @@
 	DBG(fsg, "removable=%d, stall=%d, buflen=%u\n",
 			mod_data.removable, mod_data.can_stall,
 			mod_data.buflen);
-	DBG(fsg, "I/O thread pid: %d\n", fsg->thread_pid);
+	DBG(fsg, "I/O thread pid: %d\n", fsg->thread_task->pid);
+
+	set_bit(REGISTERED, &fsg->atomic_bitflags);
+
+	/* Tell the thread to start working */
+	wake_up_process(fsg->thread_task);
 	return 0;
 
 autoconf_fail:
@@ -4046,6 +4044,7 @@
 
 	.driver		= {
 		.name		= (char *) shortname,
+		.owner		= THIS_MODULE,
 		// .release = ...
 		// .suspend = ...
 		// .resume = ...
@@ -4057,10 +4056,9 @@
 {
 	struct fsg_dev		*fsg;
 
-	fsg = kmalloc(sizeof *fsg, GFP_KERNEL);
+	fsg = kzalloc(sizeof *fsg, GFP_KERNEL);
 	if (!fsg)
 		return -ENOMEM;
-	memset(fsg, 0, sizeof *fsg);
 	spin_lock_init(&fsg->lock);
 	init_rwsem(&fsg->filesem);
 	init_waitqueue_head(&fsg->thread_wqh);
@@ -4086,15 +4084,9 @@
 	if ((rc = fsg_alloc()) != 0)
 		return rc;
 	fsg = the_fsg;
-	if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0) {
+	if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0)
 		fsg_free(fsg);
-		return rc;
-	}
-	set_bit(REGISTERED, &fsg->atomic_bitflags);
-
-	/* Tell the thread to start working */
-	complete(&fsg->thread_notifier);
-	return 0;
+	return rc;
 }
 module_init(fsg_init);
 
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index b0f3cd6..6544697 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -1970,6 +1970,7 @@
 static struct pci_driver goku_pci_driver = {
 	.name =		(char *) driver_name,
 	.id_table =	pci_ids,
+	.owner =	THIS_MODULE,
 
 	.probe =	goku_probe,
 	.remove =	goku_remove,
diff --git a/drivers/usb/gadget/lh7a40x_udc.c b/drivers/usb/gadget/lh7a40x_udc.c
index 012d1e5..9b36739 100644
--- a/drivers/usb/gadget/lh7a40x_udc.c
+++ b/drivers/usb/gadget/lh7a40x_udc.c
@@ -2140,6 +2140,7 @@
 
 static struct device_driver udc_driver = {
 	.name = (char *)driver_name,
+	.owner = THIS_MODULE,
 	.bus = &platform_bus_type,
 	.probe = lh7a40x_udc_probe,
 	.remove = lh7a40x_udc_remove
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index c32e1f7..0dc6bb0 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -2948,6 +2948,7 @@
 static struct pci_driver net2280_pci_driver = {
 	.name =		(char *) driver_name,
 	.id_table =	pci_ids,
+	.owner =	THIS_MODULE,
 
 	.probe =	net2280_probe,
 	.remove =	net2280_remove,
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index b7885dc..41c96b0 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -691,7 +691,7 @@
 }
 
 static void
-finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status)
+finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status, int one)
 {
 	u16	count;
 
@@ -699,6 +699,8 @@
 		ep->dma_counter = (u16) (req->req.dma + req->req.actual);
 	count = dma_dest_len(ep, req->req.dma + req->req.actual);
 	count += req->req.actual;
+	if (one)
+		count--;
 	if (count <= req->req.length)
 		req->req.actual = count;
 
@@ -747,7 +749,7 @@
 		if (!list_empty(&ep->queue)) {
 			req = container_of(ep->queue.next,
 					struct omap_req, queue);
-			finish_out_dma(ep, req, 0);
+			finish_out_dma(ep, req, 0, dman_stat & UDC_DMA_RX_SB);
 		}
 		UDC_IRQ_SRC_REG = UDC_RXN_EOT;
 
@@ -925,7 +927,7 @@
 		while (UDC_RXDMA_CFG_REG & mask)
 			udelay(10);
 		if (req)
-			finish_out_dma(ep, req, -ECONNRESET);
+			finish_out_dma(ep, req, -ECONNRESET, 0);
 	}
 	omap_free_dma(ep->lch);
 	ep->dma_channel = 0;
@@ -1786,8 +1788,12 @@
 					udc->driver->suspend(&udc->gadget);
 					spin_lock(&udc->lock);
 				}
+				if (udc->transceiver)
+					otg_set_suspend(udc->transceiver, 1);
 			} else {
 				VDBG("resume\n");
+				if (udc->transceiver)
+					otg_set_suspend(udc->transceiver, 0);
 				if (udc->gadget.speed == USB_SPEED_FULL
 						&& udc->driver->resume) {
 					spin_unlock(&udc->lock);
@@ -2943,6 +2949,7 @@
 
 static struct device_driver udc_driver = {
 	.name		= (char *) driver_name,
+	.owner		= THIS_MODULE,
 	.bus		= &platform_bus_type,
 	.probe		= omap_udc_probe,
 	.remove		= __exit_p(omap_udc_remove),
diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
index 6470285..f83a926 100644
--- a/drivers/usb/gadget/pxa2xx_udc.c
+++ b/drivers/usb/gadget/pxa2xx_udc.c
@@ -2631,6 +2631,7 @@
 
 static struct device_driver udc_driver = {
 	.name		= "pxa2xx-udc",
+	.owner		= THIS_MODULE,
 	.bus		= &platform_bus_type,
 	.probe		= pxa2xx_udc_probe,
 	.shutdown	= pxa2xx_udc_shutdown,
diff --git a/drivers/usb/gadget/zero.c b/drivers/usb/gadget/zero.c
index ec9c424..6c58636 100644
--- a/drivers/usb/gadget/zero.c
+++ b/drivers/usb/gadget/zero.c
@@ -1302,6 +1302,7 @@
 
 	.driver 	= {
 		.name		= (char *) shortname,
+		.owner		= THIS_MODULE,
 		// .shutdown = ...
 		// .suspend = ...
 		// .resume = ...
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 350d14f..58321d3 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -1,8 +1,9 @@
 #
-# Makefile for USB Host Controller Driver
-# framework and drivers
+# Makefile for USB Host Controller Drivers
 #
 
+obj-$(CONFIG_PCI)		+= pci-quirks.o
+
 obj-$(CONFIG_USB_EHCI_HCD)	+= ehci-hcd.o
 obj-$(CONFIG_USB_ISP116X_HCD)	+= isp116x-hcd.o
 obj-$(CONFIG_USB_OHCI_HCD)	+= ohci-hcd.o
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index f5eb9e7..af3c05e 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -182,6 +182,9 @@
 {
 	u32	temp = readl (&ehci->regs->status);
 
+	/* disable any irqs left enabled by previous code */
+	writel (0, &ehci->regs->intr_enable);
+
 	if ((temp & STS_HALT) != 0)
 		return 0;
 
@@ -297,50 +300,17 @@
 	spin_unlock_irqrestore (&ehci->lock, flags);
 }
 
-#ifdef	CONFIG_PCI
-
-/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/...
- * off the controller (maybe it can boot from highspeed USB disks).
+/* Reboot notifiers kick in for silicon on any bus (not just pci, etc).
+ * This forcibly disables dma and IRQs, helping kexec and other cases
+ * where the next system software may expect clean state.
  */
-static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap)
-{
-	struct pci_dev *pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
-
-	/* always say Linux will own the hardware */
-	pci_write_config_byte(pdev, where + 3, 1);
-
-	/* maybe wait a while for BIOS to respond */
-	if (cap & (1 << 16)) {
-		int msec = 5000;
-
-		do {
-			msleep(10);
-			msec -= 10;
-			pci_read_config_dword(pdev, where, &cap);
-		} while ((cap & (1 << 16)) && msec);
-		if (cap & (1 << 16)) {
-			ehci_err(ehci, "BIOS handoff failed (%d, %08x)\n",
-				where, cap);
-			// some BIOS versions seem buggy...
-			// return 1;
-			ehci_warn (ehci, "continuing after BIOS bug...\n");
-			/* disable all SMIs, and clear "BIOS owns" flag */
-			pci_write_config_dword(pdev, where + 4, 0);
-			pci_write_config_byte(pdev, where + 2, 0);
-		} else
-			ehci_dbg(ehci, "BIOS handoff succeeded\n");
-	}
-	return 0;
-}
-
-#endif
-
 static int
 ehci_reboot (struct notifier_block *self, unsigned long code, void *null)
 {
 	struct ehci_hcd		*ehci;
 
 	ehci = container_of (self, struct ehci_hcd, reboot_notifier);
+	(void) ehci_halt (ehci);
 
 	/* make BIOS/etc use companion controller during reboot */
 	writel (0, &ehci->regs->configured_flag);
@@ -363,156 +333,90 @@
 	msleep(20);
 }
 
+/*-------------------------------------------------------------------------*/
 
-/* called by khubd or root hub init threads */
-
-static int ehci_hc_reset (struct usb_hcd *hcd)
+/*
+ * ehci_work is called from some interrupts, timers, and so on.
+ * it calls driver completion functions, after dropping ehci->lock.
+ */
+static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs)
 {
-	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	u32			temp;
-	unsigned		count = 256/4;
+	timer_action_done (ehci, TIMER_IO_WATCHDOG);
+	if (ehci->reclaim_ready)
+		end_unlink_async (ehci, regs);
 
-	spin_lock_init (&ehci->lock);
+	/* another CPU may drop ehci->lock during a schedule scan while
+	 * it reports urb completions.  this flag guards against bogus
+	 * attempts at re-entrant schedule scanning.
+	 */
+	if (ehci->scanning)
+		return;
+	ehci->scanning = 1;
+	scan_async (ehci, regs);
+	if (ehci->next_uframe != -1)
+		scan_periodic (ehci, regs);
+	ehci->scanning = 0;
 
-	ehci->caps = hcd->regs;
-	ehci->regs = hcd->regs + HC_LENGTH (readl (&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);
-
-#ifdef	CONFIG_PCI
-	if (hcd->self.controller->bus == &pci_bus_type) {
-		struct pci_dev	*pdev = to_pci_dev(hcd->self.controller);
-
-		switch (pdev->vendor) {
-		case PCI_VENDOR_ID_TDI:
-			if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
-				ehci->is_tdi_rh_tt = 1;
-				tdi_reset (ehci);
-			}
-			break;
-		case PCI_VENDOR_ID_AMD:
-			/* AMD8111 EHCI doesn't work, according to AMD errata */
-			if (pdev->device == 0x7463) {
-				ehci_info (ehci, "ignoring AMD8111 (errata)\n");
-				return -EIO;
-			}
-			break;
-		case PCI_VENDOR_ID_NVIDIA:
-			/* NVidia reports that certain chips don't handle
-			 * QH, ITD, or SITD addresses above 2GB.  (But TD,
-			 * data buffer, and periodic schedule are normal.)
-			 */
-			switch (pdev->device) {
-			case 0x003c:	/* MCP04 */
-			case 0x005b:	/* CK804 */
-			case 0x00d8:	/* CK8 */
-			case 0x00e8:	/* CK8S */
-				if (pci_set_consistent_dma_mask(pdev,
-							DMA_31BIT_MASK) < 0)
-					ehci_warn (ehci, "can't enable NVidia "
-						"workaround for >2GB RAM\n");
-				break;
-			}
-			break;
-		}
-
-		/* optional debug port, normally in the first BAR */
-		temp = pci_find_capability (pdev, 0x0a);
-		if (temp) {
-			pci_read_config_dword(pdev, temp, &temp);
-			temp >>= 16;
-			if ((temp & (3 << 13)) == (1 << 13)) {
-				temp &= 0x1fff;
-				ehci->debug = hcd->regs + temp;
-				temp = readl (&ehci->debug->control);
-				ehci_info (ehci, "debug port %d%s\n",
-					HCS_DEBUG_PORT(ehci->hcs_params),
-					(temp & DBGP_ENABLED)
-						? " IN USE"
-						: "");
-				if (!(temp & DBGP_ENABLED))
-					ehci->debug = NULL;
-			}
-		}
-
-		temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
-	} else
-		temp = 0;
-
-	/* EHCI 0.96 and later may have "extended capabilities" */
-	while (temp && count--) {
-		u32		cap;
-
-		pci_read_config_dword (to_pci_dev(hcd->self.controller),
-				temp, &cap);
-		ehci_dbg (ehci, "capability %04x at %02x\n", cap, temp);
-		switch (cap & 0xff) {
-		case 1:			/* BIOS/SMM/... handoff */
-			if (bios_handoff (ehci, temp, cap) != 0)
-				return -EOPNOTSUPP;
-			break;
-		case 0:			/* illegal reserved capability */
-			ehci_warn (ehci, "illegal capability!\n");
-			cap = 0;
-			/* FALLTHROUGH */
-		default:		/* unknown */
-			break;
-		}
-		temp = (cap >> 8) & 0xff;
-	}
-	if (!count) {
-		ehci_err (ehci, "bogus capabilities ... PCI problems!\n");
-		return -EIO;
-	}
-	if (ehci_is_TDI(ehci))
-		ehci_reset (ehci);
-#endif
-
-	ehci_port_power (ehci, 0);
-
-	/* at least the Genesys GL880S needs fixup here */
-	temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
-	temp &= 0x0f;
-	if (temp && HCS_N_PORTS(ehci->hcs_params) > temp) {
-		ehci_dbg (ehci, "bogus port configuration: "
-			"cc=%d x pcc=%d < ports=%d\n",
-			HCS_N_CC(ehci->hcs_params),
-			HCS_N_PCC(ehci->hcs_params),
-			HCS_N_PORTS(ehci->hcs_params));
-
-#ifdef	CONFIG_PCI
-		if (hcd->self.controller->bus == &pci_bus_type) {
-			struct pci_dev	*pdev;
-
-			pdev = to_pci_dev(hcd->self.controller);
-			switch (pdev->vendor) {
-			case 0x17a0:		/* GENESYS */
-				/* GL880S: should be PORTS=2 */
-				temp |= (ehci->hcs_params & ~0xf);
-				ehci->hcs_params = temp;
-				break;
-			case PCI_VENDOR_ID_NVIDIA:
-				/* NF4: should be PCC=10 */
-				break;
-			}
-		}
-#endif
-	}
-
-	/* force HC to halt state */
-	return ehci_halt (ehci);
+	/* the IO watchdog guards against hardware or driver bugs that
+	 * misplace IRQs, and should let us run completely without IRQs.
+	 * such lossage has been observed on both VT6202 and VT8235.
+	 */
+	if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state) &&
+			(ehci->async->qh_next.ptr != NULL ||
+			 ehci->periodic_sched != 0))
+		timer_action (ehci, TIMER_IO_WATCHDOG);
 }
 
-static int ehci_start (struct usb_hcd *hcd)
+static void ehci_stop (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+
+	ehci_dbg (ehci, "stop\n");
+
+	/* Turn off port power on all root hub ports. */
+	ehci_port_power (ehci, 0);
+
+	/* no more interrupts ... */
+	del_timer_sync (&ehci->watchdog);
+
+	spin_lock_irq(&ehci->lock);
+	if (HC_IS_RUNNING (hcd->state))
+		ehci_quiesce (ehci);
+
+	ehci_reset (ehci);
+	writel (0, &ehci->regs->intr_enable);
+	spin_unlock_irq(&ehci->lock);
+
+	/* let companion controllers work when we aren't */
+	writel (0, &ehci->regs->configured_flag);
+	unregister_reboot_notifier (&ehci->reboot_notifier);
+
+	remove_debug_files (ehci);
+
+	/* root hub is shut down separately (first, when possible) */
+	spin_lock_irq (&ehci->lock);
+	if (ehci->async)
+		ehci_work (ehci, NULL);
+	spin_unlock_irq (&ehci->lock);
+	ehci_mem_cleanup (ehci);
+
+#ifdef	EHCI_STATS
+	ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n",
+		ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim,
+		ehci->stats.lost_iaa);
+	ehci_dbg (ehci, "complete %ld unlink %ld\n",
+		ehci->stats.complete, ehci->stats.unlink);
+#endif
+
+	dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
+}
+
+static int ehci_run (struct usb_hcd *hcd)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	u32			temp;
 	int			retval;
 	u32			hcc_params;
-	u8                      sbrn = 0;
 	int			first;
 
 	/* skip some things on restart paths */
@@ -551,27 +455,6 @@
 	}
 	writel (ehci->periodic_dma, &ehci->regs->frame_list);
 
-#ifdef	CONFIG_PCI
-	if (hcd->self.controller->bus == &pci_bus_type) {
-		struct pci_dev		*pdev;
-		u16			port_wake;
-
-		pdev = to_pci_dev(hcd->self.controller);
-
-		/* Serial Bus Release Number is at PCI 0x60 offset */
-		pci_read_config_byte(pdev, 0x60, &sbrn);
-
-		/* port wake capability, reported by boot firmware */
-		pci_read_config_word(pdev, 0x62, &port_wake);
-		hcd->can_wakeup = (port_wake & 1) != 0;
-
-		/* help hc dma work well with cachelines */
-		retval = pci_set_mwi(pdev);
-		if (retval)
-			ehci_dbg(ehci, "unable to enable MWI - not fatal.\n");
-	}
-#endif
-
 	/*
 	 * dedicate a qh for the async ring head, since we couldn't unlink
 	 * a 'real' qh without stopping the async schedule [4.8].  use it
@@ -667,7 +550,7 @@
 	temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
 	ehci_info (ehci,
 		"USB %x.%x %s, EHCI %x.%02x, driver %s\n",
-		((sbrn & 0xf0)>>4), (sbrn & 0x0f),
+		((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
 		first ? "initialized" : "restarted",
 		temp >> 8, temp & 0xff, DRIVER_VERSION);
 
@@ -679,188 +562,6 @@
 	return 0;
 }
 
-/* always called by thread; normally rmmod */
-
-static void ehci_stop (struct usb_hcd *hcd)
-{
-	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-
-	ehci_dbg (ehci, "stop\n");
-
-	/* Turn off port power on all root hub ports. */
-	ehci_port_power (ehci, 0);
-
-	/* no more interrupts ... */
-	del_timer_sync (&ehci->watchdog);
-
-	spin_lock_irq(&ehci->lock);
-	if (HC_IS_RUNNING (hcd->state))
-		ehci_quiesce (ehci);
-
-	ehci_reset (ehci);
-	writel (0, &ehci->regs->intr_enable);
-	spin_unlock_irq(&ehci->lock);
-
-	/* let companion controllers work when we aren't */
-	writel (0, &ehci->regs->configured_flag);
-	unregister_reboot_notifier (&ehci->reboot_notifier);
-
-	remove_debug_files (ehci);
-
-	/* root hub is shut down separately (first, when possible) */
-	spin_lock_irq (&ehci->lock);
-	if (ehci->async)
-		ehci_work (ehci, NULL);
-	spin_unlock_irq (&ehci->lock);
-	ehci_mem_cleanup (ehci);
-
-#ifdef	EHCI_STATS
-	ehci_dbg (ehci, "irq normal %ld err %ld reclaim %ld (lost %ld)\n",
-		ehci->stats.normal, ehci->stats.error, ehci->stats.reclaim,
-		ehci->stats.lost_iaa);
-	ehci_dbg (ehci, "complete %ld unlink %ld\n",
-		ehci->stats.complete, ehci->stats.unlink);
-#endif
-
-	dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
-}
-
-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;
-}
-
-/*-------------------------------------------------------------------------*/
-
-#ifdef	CONFIG_PM
-
-/* suspend/resume, section 4.3 */
-
-/* These routines rely on the bus (pci, platform, etc)
- * to handle powerdown and wakeup, and currently also on
- * transceivers that don't need any software attention to set up
- * the right sort of wakeup.  
- */
-
-static int ehci_suspend (struct usb_hcd *hcd, pm_message_t message)
-{
-	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-
-	if (time_before (jiffies, ehci->next_statechange))
-		msleep (100);
-
-#ifdef	CONFIG_USB_SUSPEND
-	(void) usb_suspend_device (hcd->self.root_hub, message);
-#else
-	usb_lock_device (hcd->self.root_hub);
-	(void) ehci_hub_suspend (hcd);
-	usb_unlock_device (hcd->self.root_hub);
-#endif
-
-	// save (PCI) FLADJ in case of Vaux power loss
-	// ... we'd only use it to handle clock skew
-
-	return 0;
-}
-
-static int ehci_resume (struct usb_hcd *hcd)
-{
-	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	unsigned		port;
-	struct usb_device	*root = hcd->self.root_hub;
-	int			retval = -EINVAL;
-
-	// maybe restore (PCI) FLADJ
-
-	if (time_before (jiffies, ehci->next_statechange))
-		msleep (100);
-
-	/* If any port is suspended (or owned by the companion),
-	 * we know we can/must resume the HC (and mustn't reset it).
-	 */
-	for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) {
-		u32	status;
-		port--;
-		status = readl (&ehci->regs->port_status [port]);
-		if (!(status & PORT_POWER))
-			continue;
-		if (status & (PORT_SUSPEND | PORT_OWNER)) {
-			down (&hcd->self.root_hub->serialize);
-			retval = ehci_hub_resume (hcd);
-			up (&hcd->self.root_hub->serialize);
-			break;
-		}
-		if (!root->children [port])
-			continue;
-		dbg_port (ehci, __FUNCTION__, port + 1, status);
-		usb_set_device_state (root->children[port],
-					USB_STATE_NOTATTACHED);
-	}
-
-	/* Else reset, to cope with power loss or flush-to-storage
-	 * style "resume" having activated BIOS during reboot.
-	 */
-	if (port == 0) {
-		(void) ehci_halt (ehci);
-		(void) ehci_reset (ehci);
-		(void) ehci_hc_reset (hcd);
-
-		/* emptying the schedule aborts any urbs */
-		spin_lock_irq (&ehci->lock);
-		if (ehci->reclaim)
-			ehci->reclaim_ready = 1;
-		ehci_work (ehci, NULL);
-		spin_unlock_irq (&ehci->lock);
-
-		/* restart; khubd will disconnect devices */
-		retval = ehci_start (hcd);
-
-		/* here we "know" root ports should always stay powered;
-		 * but some controllers may lose all power.
-		 */
-		ehci_port_power (ehci, 1);
-	}
-
-	return retval;
-}
-
-#endif
-
-/*-------------------------------------------------------------------------*/
-
-/*
- * ehci_work is called from some interrupts, timers, and so on.
- * it calls driver completion functions, after dropping ehci->lock.
- */
-static void ehci_work (struct ehci_hcd *ehci, struct pt_regs *regs)
-{
-	timer_action_done (ehci, TIMER_IO_WATCHDOG);
-	if (ehci->reclaim_ready)
-		end_unlink_async (ehci, regs);
-
-	/* another CPU may drop ehci->lock during a schedule scan while
-	 * it reports urb completions.  this flag guards against bogus
-	 * attempts at re-entrant schedule scanning.
-	 */
-	if (ehci->scanning)
-		return;
-	ehci->scanning = 1;
-	scan_async (ehci, regs);
-	if (ehci->next_uframe != -1)
-		scan_periodic (ehci, regs);
-	ehci->scanning = 0;
-
-	/* the IO watchdog guards against hardware or driver bugs that
-	 * misplace IRQs, and should let us run completely without IRQs.
-	 * such lossage has been observed on both VT6202 and VT8235. 
-	 */
-	if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state) &&
-			(ehci->async->qh_next.ptr != NULL ||
-			 ehci->periodic_sched != 0))
-		timer_action (ehci, TIMER_IO_WATCHDOG);
-}
-
 /*-------------------------------------------------------------------------*/
 
 static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
@@ -1171,106 +872,24 @@
 	return;
 }
 
-/*-------------------------------------------------------------------------*/
-
-static const struct hc_driver ehci_driver = {
-	.description =		hcd_name,
-	.product_desc =		"EHCI Host Controller",
-	.hcd_priv_size =	sizeof(struct ehci_hcd),
-
-	/*
-	 * generic hardware linkage
-	 */
-	.irq =			ehci_irq,
-	.flags =		HCD_MEMORY | HCD_USB2,
-
-	/*
-	 * basic lifecycle operations
-	 */
-	.reset =		ehci_hc_reset,
-	.start =		ehci_start,
-#ifdef	CONFIG_PM
-	.suspend =		ehci_suspend,
-	.resume =		ehci_resume,
-#endif
-	.stop =			ehci_stop,
-
-	/*
-	 * managing i/o requests and associated device resources
-	 */
-	.urb_enqueue =		ehci_urb_enqueue,
-	.urb_dequeue =		ehci_urb_dequeue,
-	.endpoint_disable =	ehci_endpoint_disable,
-
-	/*
-	 * scheduling support
-	 */
-	.get_frame_number =	ehci_get_frame,
-
-	/*
-	 * root hub support
-	 */
-	.hub_status_data =	ehci_hub_status_data,
-	.hub_control =		ehci_hub_control,
-	.hub_suspend =		ehci_hub_suspend,
-	.hub_resume =		ehci_hub_resume,
-};
+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;
+}
 
 /*-------------------------------------------------------------------------*/
 
-/* EHCI 1.0 doesn't require PCI */
-
-#ifdef	CONFIG_PCI
-
-/* PCI driver selection metadata; PCI hotplugging uses this */
-static const struct pci_device_id pci_ids [] = { {
-	/* handle any USB 2.0 EHCI controller */
-	PCI_DEVICE_CLASS(((PCI_CLASS_SERIAL_USB << 8) | 0x20), ~0),
-	.driver_data =	(unsigned long) &ehci_driver,
-	},
-	{ /* end: all zeroes */ }
-};
-MODULE_DEVICE_TABLE (pci, pci_ids);
-
-/* pci driver glue; this is a "new style" PCI driver module */
-static struct pci_driver ehci_pci_driver = {
-	.name =		(char *) hcd_name,
-	.id_table =	pci_ids,
-
-	.probe =	usb_hcd_pci_probe,
-	.remove =	usb_hcd_pci_remove,
-
-#ifdef	CONFIG_PM
-	.suspend =	usb_hcd_pci_suspend,
-	.resume =	usb_hcd_pci_resume,
-#endif
-};
-
-#endif	/* PCI */
-
-
 #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
 
 MODULE_DESCRIPTION (DRIVER_INFO);
 MODULE_AUTHOR (DRIVER_AUTHOR);
 MODULE_LICENSE ("GPL");
 
-static int __init init (void) 
-{
-	if (usb_disabled())
-		return -ENODEV;
+#ifdef CONFIG_PCI
+#include "ehci-pci.c"
+#endif
 
-	pr_debug ("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n",
-		hcd_name,
-		sizeof (struct ehci_qh), sizeof (struct ehci_qtd),
-		sizeof (struct ehci_itd), sizeof (struct ehci_sitd));
-
-	return pci_register_driver (&ehci_pci_driver);
-}
-module_init (init);
-
-static void __exit cleanup (void) 
-{	
-	pci_unregister_driver (&ehci_pci_driver);
-}
-module_exit (cleanup);
+#if !defined(CONFIG_PCI)
+#error "missing bus glue for ehci-hcd"
+#endif
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 18d3f22..88cb4ad 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -30,7 +30,7 @@
 
 #ifdef	CONFIG_PM
 
-static int ehci_hub_suspend (struct usb_hcd *hcd)
+static int ehci_bus_suspend (struct usb_hcd *hcd)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	int			port;
@@ -83,7 +83,7 @@
 
 
 /* caller has locked the root hub, and should reset/reinit on error */
-static int ehci_hub_resume (struct usb_hcd *hcd)
+static int ehci_bus_resume (struct usb_hcd *hcd)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	u32			temp;
@@ -159,8 +159,8 @@
 
 #else
 
-#define ehci_hub_suspend	NULL
-#define ehci_hub_resume		NULL
+#define ehci_bus_suspend	NULL
+#define ehci_bus_resume		NULL
 
 #endif	/* CONFIG_PM */
 
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
new file mode 100644
index 0000000..1450088
--- /dev/null
+++ b/drivers/usb/host/ehci-pci.c
@@ -0,0 +1,415 @@
+/*
+ * EHCI HCD (Host Controller Driver) PCI Bus Glue.
+ *
+ * Copyright (c) 2000-2004 by David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef CONFIG_PCI
+#error "This file is PCI bus glue.  CONFIG_PCI must be defined."
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* EHCI 0.96 (and later) section 5.1 says how to kick BIOS/SMM/...
+ * off the controller (maybe it can boot from highspeed USB disks).
+ */
+static int bios_handoff (struct ehci_hcd *ehci, int where, u32 cap)
+{
+	struct pci_dev *pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
+
+	/* always say Linux will own the hardware */
+	pci_write_config_byte(pdev, where + 3, 1);
+
+	/* maybe wait a while for BIOS to respond */
+	if (cap & (1 << 16)) {
+		int msec = 5000;
+
+		do {
+			msleep(10);
+			msec -= 10;
+			pci_read_config_dword(pdev, where, &cap);
+		} while ((cap & (1 << 16)) && msec);
+		if (cap & (1 << 16)) {
+			ehci_err(ehci, "BIOS handoff failed (%d, %08x)\n",
+				where, cap);
+			// some BIOS versions seem buggy...
+			// return 1;
+			ehci_warn (ehci, "continuing after BIOS bug...\n");
+			/* disable all SMIs, and clear "BIOS owns" flag */
+			pci_write_config_dword(pdev, where + 4, 0);
+			pci_write_config_byte(pdev, where + 2, 0);
+		} else
+			ehci_dbg(ehci, "BIOS handoff succeeded\n");
+	}
+	return 0;
+}
+
+/* called by khubd or root hub init threads */
+static int ehci_pci_reset (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	u32			temp;
+	unsigned		count = 256/4;
+
+	spin_lock_init (&ehci->lock);
+
+	ehci->caps = hcd->regs;
+	ehci->regs = hcd->regs + HC_LENGTH (readl (&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);
+
+	if (hcd->self.controller->bus == &pci_bus_type) {
+		struct pci_dev	*pdev = to_pci_dev(hcd->self.controller);
+
+		switch (pdev->vendor) {
+		case PCI_VENDOR_ID_TDI:
+			if (pdev->device == PCI_DEVICE_ID_TDI_EHCI) {
+				ehci->is_tdi_rh_tt = 1;
+				tdi_reset (ehci);
+			}
+			break;
+		case PCI_VENDOR_ID_AMD:
+			/* AMD8111 EHCI doesn't work, according to AMD errata */
+			if (pdev->device == 0x7463) {
+				ehci_info (ehci, "ignoring AMD8111 (errata)\n");
+				return -EIO;
+			}
+			break;
+		case PCI_VENDOR_ID_NVIDIA:
+			/* NVidia reports that certain chips don't handle
+			 * QH, ITD, or SITD addresses above 2GB.  (But TD,
+			 * data buffer, and periodic schedule are normal.)
+			 */
+			switch (pdev->device) {
+			case 0x003c:	/* MCP04 */
+			case 0x005b:	/* CK804 */
+			case 0x00d8:	/* CK8 */
+			case 0x00e8:	/* CK8S */
+				if (pci_set_consistent_dma_mask(pdev,
+							DMA_31BIT_MASK) < 0)
+					ehci_warn (ehci, "can't enable NVidia "
+						"workaround for >2GB RAM\n");
+				break;
+			}
+			break;
+		}
+
+		/* optional debug port, normally in the first BAR */
+		temp = pci_find_capability (pdev, 0x0a);
+		if (temp) {
+			pci_read_config_dword(pdev, temp, &temp);
+			temp >>= 16;
+			if ((temp & (3 << 13)) == (1 << 13)) {
+				temp &= 0x1fff;
+				ehci->debug = hcd->regs + temp;
+				temp = readl (&ehci->debug->control);
+				ehci_info (ehci, "debug port %d%s\n",
+					HCS_DEBUG_PORT(ehci->hcs_params),
+					(temp & DBGP_ENABLED)
+						? " IN USE"
+						: "");
+				if (!(temp & DBGP_ENABLED))
+					ehci->debug = NULL;
+			}
+		}
+
+		temp = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
+	} else
+		temp = 0;
+
+	/* EHCI 0.96 and later may have "extended capabilities" */
+	while (temp && count--) {
+		u32		cap;
+
+		pci_read_config_dword (to_pci_dev(hcd->self.controller),
+				temp, &cap);
+		ehci_dbg (ehci, "capability %04x at %02x\n", cap, temp);
+		switch (cap & 0xff) {
+		case 1:			/* BIOS/SMM/... handoff */
+			if (bios_handoff (ehci, temp, cap) != 0)
+				return -EOPNOTSUPP;
+			break;
+		case 0:			/* illegal reserved capability */
+			ehci_warn (ehci, "illegal capability!\n");
+			cap = 0;
+			/* FALLTHROUGH */
+		default:		/* unknown */
+			break;
+		}
+		temp = (cap >> 8) & 0xff;
+	}
+	if (!count) {
+		ehci_err (ehci, "bogus capabilities ... PCI problems!\n");
+		return -EIO;
+	}
+	if (ehci_is_TDI(ehci))
+		ehci_reset (ehci);
+
+	ehci_port_power (ehci, 0);
+
+	/* at least the Genesys GL880S needs fixup here */
+	temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
+	temp &= 0x0f;
+	if (temp && HCS_N_PORTS(ehci->hcs_params) > temp) {
+		ehci_dbg (ehci, "bogus port configuration: "
+			"cc=%d x pcc=%d < ports=%d\n",
+			HCS_N_CC(ehci->hcs_params),
+			HCS_N_PCC(ehci->hcs_params),
+			HCS_N_PORTS(ehci->hcs_params));
+
+		if (hcd->self.controller->bus == &pci_bus_type) {
+			struct pci_dev	*pdev;
+
+			pdev = to_pci_dev(hcd->self.controller);
+			switch (pdev->vendor) {
+			case 0x17a0:		/* GENESYS */
+				/* GL880S: should be PORTS=2 */
+				temp |= (ehci->hcs_params & ~0xf);
+				ehci->hcs_params = temp;
+				break;
+			case PCI_VENDOR_ID_NVIDIA:
+				/* NF4: should be PCC=10 */
+				break;
+			}
+		}
+	}
+
+	/* force HC to halt state */
+	return ehci_halt (ehci);
+}
+
+static int ehci_pci_start (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	int result = 0;
+
+	if (hcd->self.controller->bus == &pci_bus_type) {
+		struct pci_dev		*pdev;
+		u16			port_wake;
+
+		pdev = to_pci_dev(hcd->self.controller);
+
+		/* Serial Bus Release Number is at PCI 0x60 offset */
+		pci_read_config_byte(pdev, 0x60, &ehci->sbrn);
+
+		/* port wake capability, reported by boot firmware */
+		pci_read_config_word(pdev, 0x62, &port_wake);
+		hcd->can_wakeup = (port_wake & 1) != 0;
+
+		/* help hc dma work well with cachelines */
+		result = pci_set_mwi(pdev);
+		if (result)
+			ehci_dbg(ehci, "unable to enable MWI - not fatal.\n");
+	}
+
+	return ehci_run (hcd);
+}
+
+/* always called by thread; normally rmmod */
+
+static void ehci_pci_stop (struct usb_hcd *hcd)
+{
+	ehci_stop (hcd);
+}
+
+/*-------------------------------------------------------------------------*/
+
+#ifdef	CONFIG_PM
+
+/* suspend/resume, section 4.3 */
+
+/* These routines rely on the bus (pci, platform, etc)
+ * to handle powerdown and wakeup, and currently also on
+ * transceivers that don't need any software attention to set up
+ * the right sort of wakeup.
+ */
+
+static int ehci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+
+	if (time_before (jiffies, ehci->next_statechange))
+		msleep (100);
+
+#ifdef	CONFIG_USB_SUSPEND
+	(void) usb_suspend_device (hcd->self.root_hub);
+#else
+	usb_lock_device (hcd->self.root_hub);
+	(void) ehci_bus_suspend (hcd);
+	usb_unlock_device (hcd->self.root_hub);
+#endif
+
+	// save (PCI) FLADJ in case of Vaux power loss
+	// ... we'd only use it to handle clock skew
+
+	return 0;
+}
+
+static int ehci_pci_resume (struct usb_hcd *hcd)
+{
+	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
+	unsigned		port;
+	struct usb_device	*root = hcd->self.root_hub;
+	int			retval = -EINVAL;
+
+	// maybe restore (PCI) FLADJ
+
+	if (time_before (jiffies, ehci->next_statechange))
+		msleep (100);
+
+	/* If any port is suspended (or owned by the companion),
+	 * we know we can/must resume the HC (and mustn't reset it).
+	 */
+	for (port = HCS_N_PORTS (ehci->hcs_params); port > 0; ) {
+		u32	status;
+		port--;
+		status = readl (&ehci->regs->port_status [port]);
+		if (!(status & PORT_POWER))
+			continue;
+		if (status & (PORT_SUSPEND | PORT_OWNER)) {
+			down (&hcd->self.root_hub->serialize);
+			retval = ehci_bus_resume (hcd);
+			up (&hcd->self.root_hub->serialize);
+			break;
+		}
+		if (!root->children [port])
+			continue;
+		dbg_port (ehci, __FUNCTION__, port + 1, status);
+		usb_set_device_state (root->children[port],
+					USB_STATE_NOTATTACHED);
+	}
+
+	/* Else reset, to cope with power loss or flush-to-storage
+	 * style "resume" having activated BIOS during reboot.
+	 */
+	if (port == 0) {
+		(void) ehci_halt (ehci);
+		(void) ehci_reset (ehci);
+		(void) ehci_pci_reset (hcd);
+
+		/* emptying the schedule aborts any urbs */
+		spin_lock_irq (&ehci->lock);
+		if (ehci->reclaim)
+			ehci->reclaim_ready = 1;
+		ehci_work (ehci, NULL);
+		spin_unlock_irq (&ehci->lock);
+
+		/* restart; khubd will disconnect devices */
+		retval = ehci_run (hcd);
+
+		/* here we "know" root ports should always stay powered;
+		 * but some controllers may lose all power.
+		 */
+		ehci_port_power (ehci, 1);
+	}
+
+	return retval;
+}
+#endif
+
+static const struct hc_driver ehci_pci_hc_driver = {
+	.description =		hcd_name,
+	.product_desc =		"EHCI Host Controller",
+	.hcd_priv_size =	sizeof(struct ehci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ehci_irq,
+	.flags =		HCD_MEMORY | HCD_USB2,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset =		ehci_pci_reset,
+	.start =		ehci_pci_start,
+#ifdef	CONFIG_PM
+	.suspend =		ehci_pci_suspend,
+	.resume =		ehci_pci_resume,
+#endif
+	.stop =			ehci_pci_stop,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ehci_urb_enqueue,
+	.urb_dequeue =		ehci_urb_dequeue,
+	.endpoint_disable =	ehci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ehci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ehci_hub_status_data,
+	.hub_control =		ehci_hub_control,
+	.bus_suspend =		ehci_bus_suspend,
+	.bus_resume =		ehci_bus_resume,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* PCI driver selection metadata; PCI hotplugging uses this */
+static const struct pci_device_id pci_ids [] = { {
+	/* handle any USB 2.0 EHCI controller */
+	PCI_DEVICE_CLASS(((PCI_CLASS_SERIAL_USB << 8) | 0x20), ~0),
+	.driver_data =	(unsigned long) &ehci_pci_hc_driver,
+	},
+	{ /* end: all zeroes */ }
+};
+MODULE_DEVICE_TABLE (pci, pci_ids);
+
+/* pci driver glue; this is a "new style" PCI driver module */
+static struct pci_driver ehci_pci_driver = {
+	.name =		(char *) hcd_name,
+	.id_table =	pci_ids,
+	.owner = 	THIS_MODULE,
+
+	.probe =	usb_hcd_pci_probe,
+	.remove =	usb_hcd_pci_remove,
+
+#ifdef	CONFIG_PM
+	.suspend =	usb_hcd_pci_suspend,
+	.resume =	usb_hcd_pci_resume,
+#endif
+};
+
+static int __init ehci_hcd_pci_init (void)
+{
+	if (usb_disabled())
+		return -ENODEV;
+
+	pr_debug ("%s: block sizes: qh %Zd qtd %Zd itd %Zd sitd %Zd\n",
+		hcd_name,
+		sizeof (struct ehci_qh), sizeof (struct ehci_qtd),
+		sizeof (struct ehci_itd), sizeof (struct ehci_sitd));
+
+	return pci_register_driver (&ehci_pci_driver);
+}
+module_init (ehci_hcd_pci_init);
+
+static void __exit ehci_hcd_pci_cleanup (void)
+{
+	pci_unregister_driver (&ehci_pci_driver);
+}
+module_exit (ehci_hcd_pci_cleanup);
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index f34a051..18e257c 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -97,6 +97,7 @@
 #else
 #	define COUNT(x) do {} while (0)
 #endif
+	u8			sbrn;		/* packed release number */
 };
 
 /* convert between an HCD pointer and the corresponding EHCI_HCD */ 
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 642f350..ddb8fc5 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -638,7 +638,7 @@
 				  + msecs_to_jiffies(20) + 1);
 		if (intstat & HCINT_RD) {
 			DBG("---- remote wakeup\n");
-			schedule_work(&isp116x->rh_resume);
+			usb_hcd_resume_root_hub(hcd);
 			ret = IRQ_HANDLED;
 		}
 		irqstat &= ~HCuPINT_OPR;
@@ -1160,7 +1160,7 @@
 
 #ifdef	CONFIG_PM
 
-static int isp116x_hub_suspend(struct usb_hcd *hcd)
+static int isp116x_bus_suspend(struct usb_hcd *hcd)
 {
 	struct isp116x *isp116x = hcd_to_isp116x(hcd);
 	unsigned long flags;
@@ -1200,7 +1200,7 @@
 	return ret;
 }
 
-static int isp116x_hub_resume(struct usb_hcd *hcd)
+static int isp116x_bus_resume(struct usb_hcd *hcd)
 {
 	struct isp116x *isp116x = hcd_to_isp116x(hcd);
 	u32 val;
@@ -1263,21 +1263,11 @@
 	return 0;
 }
 
-static void isp116x_rh_resume(void *_hcd)
-{
-	struct usb_hcd *hcd = _hcd;
-
-	usb_resume_device(hcd->self.root_hub);
-}
 
 #else
 
-#define	isp116x_hub_suspend	NULL
-#define	isp116x_hub_resume	NULL
-
-static void isp116x_rh_resume(void *_hcd)
-{
-}
+#define	isp116x_bus_suspend	NULL
+#define	isp116x_bus_resume	NULL
 
 #endif
 
@@ -1636,8 +1626,8 @@
 
 	.hub_status_data = isp116x_hub_status_data,
 	.hub_control = isp116x_hub_control,
-	.hub_suspend = isp116x_hub_suspend,
-	.hub_resume = isp116x_hub_resume,
+	.bus_suspend = isp116x_bus_suspend,
+	.bus_resume = isp116x_bus_resume,
 };
 
 /*----------------------------------------------------------------*/
@@ -1732,7 +1722,6 @@
 	isp116x->addr_reg = addr_reg;
 	spin_lock_init(&isp116x->lock);
 	INIT_LIST_HEAD(&isp116x->async);
-	INIT_WORK(&isp116x->rh_resume, isp116x_rh_resume, hcd);
 	isp116x->board = dev->platform_data;
 
 	if (!isp116x->board) {
@@ -1777,16 +1766,10 @@
 static int isp116x_suspend(struct device *dev, pm_message_t state)
 {
 	int ret = 0;
-	struct usb_hcd *hcd = dev_get_drvdata(dev);
 
 	VDBG("%s: state %x\n", __func__, state);
 
-	ret = usb_suspend_device(hcd->self.root_hub, state);
-	if (!ret) {
-		dev->power.power_state = state;
-		INFO("%s suspended\n", hcd_name);
-	} else
-		ERR("%s suspend failed\n", hcd_name);
+	dev->power.power_state = state;
 
 	return ret;
 }
@@ -1797,15 +1780,11 @@
 static int isp116x_resume(struct device *dev)
 {
 	int ret = 0;
-	struct usb_hcd *hcd = dev_get_drvdata(dev);
 
 	VDBG("%s:  state %x\n", __func__, dev->power.power_state);
 
-	ret = usb_resume_device(hcd->self.root_hub);
-	if (!ret) {
-		dev->power.power_state = PMSG_ON;
-		VDBG("%s resumed\n", (char *)hcd_name);
-	}
+	dev->power.power_state = PMSG_ON;
+
 	return ret;
 }
 
diff --git a/drivers/usb/host/isp116x.h b/drivers/usb/host/isp116x.h
index 5887347..c6fec96 100644
--- a/drivers/usb/host/isp116x.h
+++ b/drivers/usb/host/isp116x.h
@@ -253,7 +253,6 @@
 
 struct isp116x {
 	spinlock_t lock;
-	struct work_struct rh_resume;
 
 	void __iomem *addr_reg;
 	void __iomem *data_reg;
diff --git a/drivers/usb/host/ohci-au1xxx.c b/drivers/usb/host/ohci-au1xxx.c
index 3981bf1..a277e25 100644
--- a/drivers/usb/host/ohci-au1xxx.c
+++ b/drivers/usb/host/ohci-au1xxx.c
@@ -214,6 +214,11 @@
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
+#ifdef	CONFIG_PM
+	.bus_suspend =		ohci_bus_suspend,
+	.bus_resume =		ohci_bus_resume,
+#endif
+	.start_port_reset =	ohci_start_port_reset,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -259,6 +264,7 @@
 
 static struct device_driver ohci_hcd_au1xxx_driver = {
 	.name		= "au1xxx-ohci",
+	.owner		= THIS_MODULE,
 	.bus		= &platform_bus_type,
 	.probe		= ohci_hcd_au1xxx_drv_probe,
 	.remove		= ohci_hcd_au1xxx_drv_remove,
diff --git a/drivers/usb/host/ohci-dbg.c b/drivers/usb/host/ohci-dbg.c
index 7924c74..7bfffcbb 100644
--- a/drivers/usb/host/ohci-dbg.c
+++ b/drivers/usb/host/ohci-dbg.c
@@ -193,10 +193,6 @@
 
 	maybe_print_eds (controller, "donehead",
 			ohci_readl (controller, &regs->donehead), next, size);
-
-	/* broken fminterval means traffic won't flow! */ 
-	ohci_dbg (controller, "fminterval %08x\n", 
-			ohci_readl (controller, &regs->fminterval));
 }
 
 #define dbg_port_sw(hc,num,value,next,size) \
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index f8da8c7..5c0c6c8 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -723,7 +723,7 @@
 		ohci_vdbg (ohci, "resume detect\n");
 		ohci_writel (ohci, OHCI_INTR_RD, &regs->intrstatus);
 		if (hcd->state != HC_STATE_QUIESCING)
-			schedule_work(&ohci->rh_resume);
+			usb_hcd_resume_root_hub(hcd);
 	}
 
 	if (ints & OHCI_INTR_WDH) {
@@ -791,7 +791,7 @@
 
 /* must not be called from interrupt context */
 
-#if	defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM)
+#ifdef	CONFIG_PM
 
 static int ohci_restart (struct ohci_hcd *ohci)
 {
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index ce7b28d..e01e77b 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -36,7 +36,7 @@
 
 /*-------------------------------------------------------------------------*/
 
-#if	defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM)
+#ifdef	CONFIG_PM
 
 #define OHCI_SCHED_ENABLES \
 	(OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
@@ -45,7 +45,7 @@
 static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *);
 static int ohci_restart (struct ohci_hcd *ohci);
 
-static int ohci_hub_suspend (struct usb_hcd *hcd)
+static int ohci_bus_suspend (struct usb_hcd *hcd)
 {
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 	int			status = 0;
@@ -73,7 +73,6 @@
 	ohci_dbg (ohci, "suspend root hub\n");
 
 	/* First stop any processing */
-	hcd->state = HC_STATE_QUIESCING;
 	if (ohci->hc_control & OHCI_SCHED_ENABLES) {
 		int		limit;
 
@@ -108,7 +107,9 @@
 	else
 		ohci->hc_control &= ~OHCI_CTRL_RWE;
 
-	/* Suspend hub */
+	/* Suspend hub ... this is the "global (to this bus) suspend" mode,
+	 * which doesn't imply ports will first be individually suspended.
+	 */
 	ohci->hc_control &= ~OHCI_CTRL_HCFS;
 	ohci->hc_control |= OHCI_USB_SUSPEND;
 	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
@@ -118,8 +119,9 @@
 	ohci->next_statechange = jiffies + msecs_to_jiffies (5);
 
 done:
+	/* external suspend vs self autosuspend ... same effect */
 	if (status == 0)
-		hcd->state = HC_STATE_SUSPENDED;
+		usb_hcd_suspend_root_hub(hcd);
 	spin_unlock_irqrestore (&ohci->lock, flags);
 	return status;
 }
@@ -133,7 +135,7 @@
 }
 
 /* caller has locked the root hub */
-static int ohci_hub_resume (struct usb_hcd *hcd)
+static int ohci_bus_resume (struct usb_hcd *hcd)
 {
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 	u32			temp, enables;
@@ -146,7 +148,7 @@
 	ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
 
 	if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
-		/* this can happen after suspend-to-disk */
+		/* this can happen after resuming a swsusp snapshot */
 		if (hcd->state == HC_STATE_RESUMING) {
 			ohci_dbg (ohci, "BIOS/SMM active, control %03x\n",
 					ohci->hc_control);
@@ -169,11 +171,12 @@
 		ohci_info (ohci, "wakeup\n");
 		break;
 	case OHCI_USB_OPER:
-		ohci_dbg (ohci, "already resumed\n");
-		status = 0;
+		/* this can happen after resuming a swsusp snapshot */
+		ohci_dbg (ohci, "snapshot resume? reinit\n");
+		status = -EBUSY;
 		break;
 	default:		/* RESET, we lost power */
-		ohci_dbg (ohci, "root hub hardware reset\n");
+		ohci_dbg (ohci, "lost power\n");
 		status = -EBUSY;
 	}
 	spin_unlock_irq (&ohci->lock);
@@ -198,8 +201,7 @@
 	}
 
 	/* Some controllers (lucent erratum) need extra-long delays */
-	hcd->state = HC_STATE_RESUMING;
-	mdelay (20 /* usb 11.5.1.10 */ + 15);
+	msleep (20 /* usb 11.5.1.10 */ + 12 /* 32 msec counter */ + 1);
 
 	temp = ohci_readl (ohci, &ohci->regs->control);
 	temp &= OHCI_CTRL_HCFS;
@@ -273,28 +275,10 @@
 		(void) ohci_readl (ohci, &ohci->regs->control);
 	}
 
-	hcd->state = HC_STATE_RUNNING;
 	return 0;
 }
 
-static void ohci_rh_resume (void *_hcd)
-{
-	struct usb_hcd	*hcd = _hcd;
-
-	usb_lock_device (hcd->self.root_hub);
-	(void) ohci_hub_resume (hcd);
-	usb_unlock_device (hcd->self.root_hub);
-}
-
-#else
-
-static void ohci_rh_resume (void *_hcd)
-{
-	struct ohci_hcd	*ohci = hcd_to_ohci (_hcd);
-	ohci_dbg(ohci, "rh_resume ??\n");
-}
-
-#endif	/* CONFIG_USB_SUSPEND || CONFIG_PM */
+#endif	/* CONFIG_PM */
 
 /*-------------------------------------------------------------------------*/
 
@@ -367,7 +351,6 @@
 #ifdef CONFIG_PM
 	/* save power by suspending idle root hubs;
 	 * INTR_RD wakes us when there's work
-	 * NOTE: if we can do this, we don't need a root hub timer!
 	 */
 	if (can_suspend
 			&& !changed
@@ -379,8 +362,7 @@
 			&& usb_trylock_device (hcd->self.root_hub)
 			) {
 		ohci_vdbg (ohci, "autosuspend\n");
-		(void) ohci_hub_suspend (hcd);
-		hcd->state = HC_STATE_RUNNING;
+		(void) ohci_bus_suspend (hcd);
 		usb_unlock_device (hcd->self.root_hub);
 	}
 #endif
@@ -554,7 +536,7 @@
 			temp = RH_PS_POCI;
 			if ((ohci->hc_control & OHCI_CTRL_HCFS)
 					!= OHCI_USB_OPER)
-				schedule_work (&ohci->rh_resume);
+				usb_hcd_resume_root_hub(hcd);
 			break;
 		case USB_PORT_FEAT_C_SUSPEND:
 			temp = RH_PS_PSSC;
diff --git a/drivers/usb/host/ohci-lh7a404.c b/drivers/usb/host/ohci-lh7a404.c
index 859aca7b..238fa4a 100644
--- a/drivers/usb/host/ohci-lh7a404.c
+++ b/drivers/usb/host/ohci-lh7a404.c
@@ -193,6 +193,11 @@
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
+#ifdef	CONFIG_PM
+	.bus_suspend =		ohci_bus_suspend,
+	.bus_resume =		ohci_bus_resume,
+#endif
+	.start_port_reset =	ohci_start_port_reset,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -239,6 +244,7 @@
 
 static struct device_driver ohci_hcd_lh7a404_driver = {
 	.name		= "lh7a404-ohci",
+	.owner		= THIS_MODULE,
 	.bus		= &platform_bus_type,
 	.probe		= ohci_hcd_lh7a404_drv_probe,
 	.remove		= ohci_hcd_lh7a404_drv_remove,
diff --git a/drivers/usb/host/ohci-mem.c b/drivers/usb/host/ohci-mem.c
index 9fb83df..bfbe328 100644
--- a/drivers/usb/host/ohci-mem.c
+++ b/drivers/usb/host/ohci-mem.c
@@ -28,7 +28,6 @@
 	ohci->next_statechange = jiffies;
 	spin_lock_init (&ohci->lock);
 	INIT_LIST_HEAD (&ohci->pending);
-	INIT_WORK (&ohci->rh_resume, ohci_rh_resume, ohci_to_hcd(ohci));
 	ohci->reboot_notifier.notifier_call = ohci_reboot;
 }
 
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index a574216..45efeed 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -420,9 +420,9 @@
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
-#ifdef	CONFIG_USB_SUSPEND
-	.hub_suspend =		ohci_hub_suspend,
-	.hub_resume =		ohci_hub_resume,
+#ifdef	CONFIG_PM
+	.bus_suspend =		ohci_bus_suspend,
+	.bus_resume =		ohci_bus_resume,
 #endif
 	.start_port_reset =	ohci_start_port_reset,
 };
@@ -458,41 +458,29 @@
 static int ohci_omap_suspend(struct device *dev, pm_message_t message)
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci(dev_get_drvdata(dev));
-	int		status = -EINVAL;
 
-	down(&ohci_to_hcd(ohci)->self.root_hub->serialize);
-	status = ohci_hub_suspend(ohci_to_hcd(ohci));
-	if (status == 0) {
-		omap_ohci_clock_power(0);
-		ohci_to_hcd(ohci)->self.root_hub->state =
-			USB_STATE_SUSPENDED;
-		ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
-		dev->power.power_state = PMSG_SUSPEND;
-	}
-	up(&ohci_to_hcd(ohci)->self.root_hub->serialize);
-	return status;
+	if (time_before(jiffies, ohci->next_statechange))
+		msleep(5);
+	ohci->next_statechange = jiffies;
+
+	omap_ohci_clock_power(0);
+	ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
+	dev->power.power_state = PMSG_SUSPEND;
+	return 0;
 }
 
 static int ohci_omap_resume(struct device *dev)
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci(dev_get_drvdata(dev));
-	int		status = 0;
 
 	if (time_before(jiffies, ohci->next_statechange))
 		msleep(5);
 	ohci->next_statechange = jiffies;
+
 	omap_ohci_clock_power(1);
-#ifdef	CONFIG_USB_SUSPEND
-	/* get extra cleanup even if remote wakeup isn't in use */
-	status = usb_resume_device(ohci_to_hcd(ohci)->self.root_hub);
-#else
-	down(&ohci_to_hcd(ohci)->self.root_hub->serialize);
-	status = ohci_hub_resume(ohci_to_hcd(ohci));
-	up(&ohci_to_hcd(ohci)->self.root_hub->serialize);
-#endif
-	if (status == 0)
-		dev->power.power_state = PMSG_ON;
-	return status;
+	dev->power.power_state = PMSG_ON;
+	usb_hcd_resume_root_hub(dev_get_drvdata(dev));
+	return 0;
 }
 
 #endif
@@ -504,6 +492,7 @@
  */
 static struct device_driver ohci_hcd_omap_driver = {
 	.name		= "ohci",
+	.owner		= THIS_MODULE,
 	.bus		= &platform_bus_type,
 	.probe		= ohci_hcd_omap_drv_probe,
 	.remove		= ohci_hcd_omap_drv_remove,
diff --git a/drivers/usb/host/ohci-pci.c b/drivers/usb/host/ohci-pci.c
index eede6be..bf1d5ab 100644
--- a/drivers/usb/host/ohci-pci.c
+++ b/drivers/usb/host/ohci-pci.c
@@ -112,23 +112,13 @@
 
 static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
 {
-	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+	/* root hub was already suspended */
 
-	/* suspend root hub, hoping it keeps power during suspend */
-	if (time_before (jiffies, ohci->next_statechange))
-		msleep (100);
-
-#ifdef	CONFIG_USB_SUSPEND
-	(void) usb_suspend_device (hcd->self.root_hub, message);
-#else
-	usb_lock_device (hcd->self.root_hub);
-	(void) ohci_hub_suspend (hcd);
-	usb_unlock_device (hcd->self.root_hub);
-#endif
-
-	/* let things settle down a bit */
-	msleep (100);
-	
+	/* FIXME these PMAC things get called in the wrong places.  ASIC
+	 * clocks should be turned off AFTER entering D3, and on BEFORE
+	 * trying to enter D0.  Evidently the PCI layer doesn't currently
+	 * provide the right sort of platform hooks for this ...
+	 */
 #ifdef CONFIG_PPC_PMAC
 	if (_machine == _MACH_Pmac) {
 	   	struct device_node	*of_node;
@@ -145,9 +135,6 @@
 
 static int ohci_pci_resume (struct usb_hcd *hcd)
 {
-	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
-	int			retval = 0;
-
 #ifdef CONFIG_PPC_PMAC
 	if (_machine == _MACH_Pmac) {
 		struct device_node *of_node;
@@ -159,19 +146,8 @@
 	}
 #endif /* CONFIG_PPC_PMAC */
 
-	/* resume root hub */
-	if (time_before (jiffies, ohci->next_statechange))
-		msleep (100);
-#ifdef	CONFIG_USB_SUSPEND
-	/* get extra cleanup even if remote wakeup isn't in use */
-	retval = usb_resume_device (hcd->self.root_hub);
-#else
-	usb_lock_device (hcd->self.root_hub);
-	retval = ohci_hub_resume (hcd);
-	usb_unlock_device (hcd->self.root_hub);
-#endif
-
-	return retval;
+	usb_hcd_resume_root_hub(hcd);
+	return 0;
 }
 
 #endif	/* CONFIG_PM */
@@ -218,9 +194,9 @@
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
-#ifdef	CONFIG_USB_SUSPEND
-	.hub_suspend =		ohci_hub_suspend,
-	.hub_resume =		ohci_hub_resume,
+#ifdef	CONFIG_PM
+	.bus_suspend =		ohci_bus_suspend,
+	.bus_resume =		ohci_bus_resume,
 #endif
 	.start_port_reset =	ohci_start_port_reset,
 };
@@ -240,6 +216,7 @@
 static struct pci_driver ohci_pci_driver = {
 	.name =		(char *) hcd_name,
 	.id_table =	pci_ids,
+	.owner =	THIS_MODULE,
 
 	.probe =	usb_hcd_pci_probe,
 	.remove =	usb_hcd_pci_remove,
diff --git a/drivers/usb/host/ohci-ppc-soc.c b/drivers/usb/host/ohci-ppc-soc.c
index 2515333..4832e57 100644
--- a/drivers/usb/host/ohci-ppc-soc.c
+++ b/drivers/usb/host/ohci-ppc-soc.c
@@ -163,9 +163,9 @@
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
-#ifdef	CONFIG_USB_SUSPEND
-	.hub_suspend =		ohci_hub_suspend,
-	.hub_resume =		ohci_hub_resume,
+#ifdef	CONFIG_PM
+	.bus_suspend =		ohci_bus_suspend,
+	.bus_resume =		ohci_bus_resume,
 #endif
 	.start_port_reset =	ohci_start_port_reset,
 };
@@ -193,10 +193,11 @@
 
 static struct device_driver ohci_hcd_ppc_soc_driver = {
 	.name		= "ppc-soc-ohci",
+	.owner		= THIS_MODULE,
 	.bus		= &platform_bus_type,
 	.probe		= ohci_hcd_ppc_soc_drv_probe,
 	.remove		= ohci_hcd_ppc_soc_drv_remove,
-#if	defined(CONFIG_USB_SUSPEND) || defined(CONFIG_PM)
+#ifdef	CONFIG_PM
 	/*.suspend	= ohci_hcd_ppc_soc_drv_suspend,*/
 	/*.resume	= ohci_hcd_ppc_soc_drv_resume,*/
 #endif
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index f042261..d287dcc 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -278,10 +278,11 @@
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
-#ifdef  CONFIG_USB_SUSPEND
-	.hub_suspend =		ohci_hub_suspend,
-	.hub_resume =		ohci_hub_resume,
+#ifdef  CONFIG_PM
+	.bus_suspend =		ohci_bus_suspend,
+	.bus_resume =		ohci_bus_resume,
 #endif
+	.start_port_reset =	ohci_start_port_reset,
 };
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index da7d547..fab420a 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -448,11 +448,11 @@
 	 */
 	.hub_status_data =	ohci_s3c2410_hub_status_data,
 	.hub_control =		ohci_s3c2410_hub_control,
-
-#if defined(CONFIG_USB_SUSPEND) && 0
-	.hub_suspend =		ohci_hub_suspend,
-	.hub_resume =		ohci_hub_resume,
+#ifdef	CONFIG_PM
+	.bus_suspend =		ohci_bus_suspend,
+	.bus_resume =		ohci_bus_resume,
 #endif
+	.start_port_reset =	ohci_start_port_reset,
 };
 
 /* device driver */
@@ -474,6 +474,7 @@
 
 static struct device_driver ohci_hcd_s3c2410_driver = {
 	.name		= "s3c2410-ohci",
+	.owner		= THIS_MODULE,
 	.bus		= &platform_bus_type,
 	.probe		= ohci_hcd_s3c2410_drv_probe,
 	.remove		= ohci_hcd_s3c2410_drv_remove,
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index 814d2be..fb3221e 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -235,10 +235,11 @@
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
-#ifdef	CONFIG_USB_SUSPEND
-	.hub_suspend =		ohci_hub_suspend,
-	.hub_resume =		ohci_hub_resume,
+#ifdef	CONFIG_PM
+	.bus_suspend =		ohci_bus_suspend,
+	.bus_resume =		ohci_bus_resume,
 #endif
+	.start_port_reset =	ohci_start_port_reset,
 };
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 8a9b9d9..caacf14 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -389,7 +389,6 @@
 	unsigned long		next_statechange;	/* suspend/resume */
 	u32			fminterval;		/* saved register */
 
-	struct work_struct	rh_resume;
 	struct notifier_block	reboot_notifier;
 
 	unsigned long		flags;		/* for HC bugs */
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
new file mode 100644
index 0000000..b7fd3f6
--- /dev/null
+++ b/drivers/usb/host/pci-quirks.c
@@ -0,0 +1,296 @@
+/*
+ * This file contains code to reset and initialize USB host controllers.
+ * Some of it includes work-arounds for PCI hardware and BIOS quirks.
+ * It may need to run early during booting -- before USB would normally
+ * initialize -- to ensure that Linux doesn't use any legacy modes.
+ *
+ *  Copyright (c) 1999 Martin Mares <mj@ucw.cz>
+ *  (and others)
+ */
+
+#include <linux/config.h>
+#ifdef CONFIG_USB_DEBUG
+#define DEBUG
+#else
+#undef DEBUG
+#endif
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/acpi.h>
+
+
+#define UHCI_USBLEGSUP		0xc0		/* legacy support */
+#define UHCI_USBCMD		0		/* command register */
+#define UHCI_USBINTR		4		/* interrupt register */
+#define UHCI_USBLEGSUP_RWC	0x8f00		/* the R/WC bits */
+#define UHCI_USBLEGSUP_RO	0x5040		/* R/O and reserved bits */
+#define UHCI_USBCMD_RUN		0x0001		/* RUN/STOP bit */
+#define UHCI_USBCMD_HCRESET	0x0002		/* Host Controller reset */
+#define UHCI_USBCMD_EGSM	0x0008		/* Global Suspend Mode */
+#define UHCI_USBCMD_CONFIGURE	0x0040		/* Config Flag */
+#define UHCI_USBINTR_RESUME	0x0002		/* Resume interrupt enable */
+
+#define OHCI_CONTROL		0x04
+#define OHCI_CMDSTATUS		0x08
+#define OHCI_INTRSTATUS		0x0c
+#define OHCI_INTRENABLE		0x10
+#define OHCI_INTRDISABLE	0x14
+#define OHCI_OCR		(1 << 3)	/* ownership change request */
+#define OHCI_CTRL_RWC		(1 << 9)	/* remote wakeup connected */
+#define OHCI_CTRL_IR		(1 << 8)	/* interrupt routing */
+#define OHCI_INTR_OC		(1 << 30)	/* ownership change */
+
+#define EHCI_HCC_PARAMS		0x08		/* extended capabilities */
+#define EHCI_USBCMD		0		/* command register */
+#define EHCI_USBCMD_RUN		(1 << 0)	/* RUN/STOP bit */
+#define EHCI_USBSTS		4		/* status register */
+#define EHCI_USBSTS_HALTED	(1 << 12)	/* HCHalted bit */
+#define EHCI_USBINTR		8		/* interrupt register */
+#define EHCI_USBLEGSUP		0		/* legacy support register */
+#define EHCI_USBLEGSUP_BIOS	(1 << 16)	/* BIOS semaphore */
+#define EHCI_USBLEGSUP_OS	(1 << 24)	/* OS semaphore */
+#define EHCI_USBLEGCTLSTS	4		/* legacy control/status */
+#define EHCI_USBLEGCTLSTS_SOOE	(1 << 13)	/* SMI on ownership change */
+
+
+/*
+ * Make sure the controller is completely inactive, unable to
+ * generate interrupts or do DMA.
+ */
+void uhci_reset_hc(struct pci_dev *pdev, unsigned long base)
+{
+	/* Turn off PIRQ enable and SMI enable.  (This also turns off the
+	 * BIOS's USB Legacy Support.)  Turn off all the R/WC bits too.
+	 */
+	pci_write_config_word(pdev, UHCI_USBLEGSUP, UHCI_USBLEGSUP_RWC);
+
+	/* Reset the HC - this will force us to get a
+	 * new notification of any already connected
+	 * ports due to the virtual disconnect that it
+	 * implies.
+	 */
+	outw(UHCI_USBCMD_HCRESET, base + UHCI_USBCMD);
+	mb();
+	udelay(5);
+	if (inw(base + UHCI_USBCMD) & UHCI_USBCMD_HCRESET)
+		dev_warn(&pdev->dev, "HCRESET not completed yet!\n");
+
+	/* Just to be safe, disable interrupt requests and
+	 * make sure the controller is stopped.
+	 */
+	outw(0, base + UHCI_USBINTR);
+	outw(0, base + UHCI_USBCMD);
+}
+EXPORT_SYMBOL_GPL(uhci_reset_hc);
+
+/*
+ * Initialize a controller that was newly discovered or has just been
+ * resumed.  In either case we can't be sure of its previous state.
+ *
+ * Returns: 1 if the controller was reset, 0 otherwise.
+ */
+int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base)
+{
+	u16 legsup;
+	unsigned int cmd, intr;
+
+	/*
+	 * When restarting a suspended controller, we expect all the
+	 * settings to be the same as we left them:
+	 *
+	 *	PIRQ and SMI disabled, no R/W bits set in USBLEGSUP;
+	 *	Controller is stopped and configured with EGSM set;
+	 *	No interrupts enabled except possibly Resume Detect.
+	 *
+	 * If any of these conditions are violated we do a complete reset.
+	 */
+	pci_read_config_word(pdev, UHCI_USBLEGSUP, &legsup);
+	if (legsup & ~(UHCI_USBLEGSUP_RO | UHCI_USBLEGSUP_RWC)) {
+		dev_dbg(&pdev->dev, "%s: legsup = 0x%04x\n",
+				__FUNCTION__, legsup);
+		goto reset_needed;
+	}
+
+	cmd = inw(base + UHCI_USBCMD);
+	if ((cmd & UHCI_USBCMD_RUN) || !(cmd & UHCI_USBCMD_CONFIGURE) ||
+			!(cmd & UHCI_USBCMD_EGSM)) {
+		dev_dbg(&pdev->dev, "%s: cmd = 0x%04x\n",
+				__FUNCTION__, cmd);
+		goto reset_needed;
+	}
+
+	intr = inw(base + UHCI_USBINTR);
+	if (intr & (~UHCI_USBINTR_RESUME)) {
+		dev_dbg(&pdev->dev, "%s: intr = 0x%04x\n",
+				__FUNCTION__, intr);
+		goto reset_needed;
+	}
+	return 0;
+
+reset_needed:
+	dev_dbg(&pdev->dev, "Performing full reset\n");
+	uhci_reset_hc(pdev, base);
+	return 1;
+}
+EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc);
+
+static void __devinit quirk_usb_handoff_uhci(struct pci_dev *pdev)
+{
+	unsigned long base = 0;
+	int i;
+
+	for (i = 0; i < PCI_ROM_RESOURCE; i++)
+		if ((pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
+			base = pci_resource_start(pdev, i);
+			break;
+		}
+
+	if (base)
+		uhci_check_and_reset_hc(pdev, base);
+}
+
+static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
+{
+	void __iomem *base;
+	int wait_time;
+	u32 control;
+
+	base = ioremap_nocache(pci_resource_start(pdev, 0),
+				     pci_resource_len(pdev, 0));
+	if (base == NULL) return;
+
+/* On PA-RISC, PDC can leave IR set incorrectly; ignore it there. */
+#ifndef __hppa__
+	control = readl(base + OHCI_CONTROL);
+	if (control & OHCI_CTRL_IR) {
+		wait_time = 500; /* arbitrary; 5 seconds */
+		writel(OHCI_INTR_OC, base + OHCI_INTRENABLE);
+		writel(OHCI_OCR, base + OHCI_CMDSTATUS);
+		while (wait_time > 0 &&
+				readl(base + OHCI_CONTROL) & OHCI_CTRL_IR) {
+			wait_time -= 10;
+			msleep(10);
+		}
+		if (wait_time <= 0)
+			printk(KERN_WARNING "%s %s: early BIOS handoff "
+					"failed (BIOS bug ?)\n",
+					pdev->dev.bus_id, "OHCI");
+
+		/* reset controller, preserving RWC */
+		writel(control & OHCI_CTRL_RWC, base + OHCI_CONTROL);
+	}
+#endif
+
+	/*
+	 * disable interrupts
+	 */
+	writel(~(u32)0, base + OHCI_INTRDISABLE);
+	writel(~(u32)0, base + OHCI_INTRSTATUS);
+
+	iounmap(base);
+}
+
+static void __devinit quirk_usb_disable_ehci(struct pci_dev *pdev)
+{
+	int wait_time, delta;
+	void __iomem *base, *op_reg_base;
+	u32 hcc_params, val, temp;
+	u8 cap_length;
+
+	base = ioremap_nocache(pci_resource_start(pdev, 0),
+				pci_resource_len(pdev, 0));
+	if (base == NULL) return;
+
+	cap_length = readb(base);
+	op_reg_base = base + cap_length;
+	hcc_params = readl(base + EHCI_HCC_PARAMS);
+	hcc_params = (hcc_params >> 8) & 0xff;
+	if (hcc_params) {
+		pci_read_config_dword(pdev,
+					hcc_params + EHCI_USBLEGSUP,
+					&val);
+		if (((val & 0xff) == 1) && (val & EHCI_USBLEGSUP_BIOS)) {
+			/*
+			 * Ok, BIOS is in smm mode, try to hand off...
+			 */
+			pci_read_config_dword(pdev,
+						hcc_params + EHCI_USBLEGCTLSTS,
+						&temp);
+			pci_write_config_dword(pdev,
+						hcc_params + EHCI_USBLEGCTLSTS,
+						temp | EHCI_USBLEGCTLSTS_SOOE);
+			val |= EHCI_USBLEGSUP_OS;
+			pci_write_config_dword(pdev,
+						hcc_params + EHCI_USBLEGSUP,
+						val);
+
+			wait_time = 500;
+			do {
+				msleep(10);
+				wait_time -= 10;
+				pci_read_config_dword(pdev,
+						hcc_params + EHCI_USBLEGSUP,
+						&val);
+			} while (wait_time && (val & EHCI_USBLEGSUP_BIOS));
+			if (!wait_time) {
+				/*
+				 * well, possibly buggy BIOS...
+				 */
+				printk(KERN_WARNING "%s %s: early BIOS handoff "
+						"failed (BIOS bug ?)\n",
+					pdev->dev.bus_id, "EHCI");
+				pci_write_config_dword(pdev,
+						hcc_params + EHCI_USBLEGSUP,
+						EHCI_USBLEGSUP_OS);
+				pci_write_config_dword(pdev,
+						hcc_params + EHCI_USBLEGCTLSTS,
+						0);
+			}
+		}
+	}
+
+	/*
+	 * halt EHCI & disable its interrupts in any case
+	 */
+	val = readl(op_reg_base + EHCI_USBSTS);
+	if ((val & EHCI_USBSTS_HALTED) == 0) {
+		val = readl(op_reg_base + EHCI_USBCMD);
+		val &= ~EHCI_USBCMD_RUN;
+		writel(val, op_reg_base + EHCI_USBCMD);
+
+		wait_time = 2000;
+		delta = 100;
+		do {
+			writel(0x3f, op_reg_base + EHCI_USBSTS);
+			udelay(delta);
+			wait_time -= delta;
+			val = readl(op_reg_base + EHCI_USBSTS);
+			if ((val == ~(u32)0) || (val & EHCI_USBSTS_HALTED)) {
+				break;
+			}
+		} while (wait_time > 0);
+	}
+	writel(0, op_reg_base + EHCI_USBINTR);
+	writel(0x3f, op_reg_base + EHCI_USBSTS);
+
+	iounmap(base);
+
+	return;
+}
+
+
+
+static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
+{
+	if (pdev->class == PCI_CLASS_SERIAL_USB_UHCI)
+		quirk_usb_handoff_uhci(pdev);
+	else if (pdev->class == PCI_CLASS_SERIAL_USB_OHCI)
+		quirk_usb_handoff_ohci(pdev);
+	else if (pdev->class == PCI_CLASS_SERIAL_USB_EHCI)
+		quirk_usb_disable_ehci(pdev);
+}
+DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index b5e7a47..40169d9 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1363,7 +1363,7 @@
 #ifdef	CONFIG_PM
 
 static int
-sl811h_hub_suspend(struct usb_hcd *hcd)
+sl811h_bus_suspend(struct usb_hcd *hcd)
 {
 	// SOFs off
 	DBG("%s\n", __FUNCTION__);
@@ -1371,7 +1371,7 @@
 }
 
 static int
-sl811h_hub_resume(struct usb_hcd *hcd)
+sl811h_bus_resume(struct usb_hcd *hcd)
 {
 	// SOFs on
 	DBG("%s\n", __FUNCTION__);
@@ -1380,8 +1380,8 @@
 
 #else
 
-#define	sl811h_hub_suspend	NULL
-#define	sl811h_hub_resume	NULL
+#define	sl811h_bus_suspend	NULL
+#define	sl811h_bus_resume	NULL
 
 #endif
 
@@ -1623,8 +1623,8 @@
 	 */
 	.hub_status_data =	sl811h_hub_status_data,
 	.hub_control =		sl811h_hub_control,
-	.hub_suspend =		sl811h_hub_suspend,
-	.hub_resume =		sl811h_hub_resume,
+	.bus_suspend =		sl811h_bus_suspend,
+	.bus_resume =		sl811h_bus_resume,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -1791,7 +1791,7 @@
 	int		retval = 0;
 
 	if (state.event == PM_EVENT_FREEZE)
-		retval = sl811h_hub_suspend(hcd);
+		retval = sl811h_bus_suspend(hcd);
 	else if (state.event == PM_EVENT_SUSPEND)
 		port_power(sl811, 0);
 	if (retval == 0)
@@ -1816,7 +1816,7 @@
 	}
 
 	dev->power.power_state = PMSG_ON;
-	return sl811h_hub_resume(hcd);
+	return sl811h_bus_resume(hcd);
 }
 
 #else
@@ -1831,6 +1831,7 @@
 struct device_driver sl811h_driver = {
 	.name =		(char *) hcd_name,
 	.bus =		&platform_bus_type,
+	.owner =	THIS_MODULE,
 
 	.probe =	sl811h_probe,
 	.remove =	__devexit_p(sl811h_remove),
diff --git a/drivers/usb/host/uhci-debug.c b/drivers/usb/host/uhci-debug.c
index 4538a98..151154d 100644
--- a/drivers/usb/host/uhci-debug.c
+++ b/drivers/usb/host/uhci-debug.c
@@ -348,7 +348,6 @@
 
 	if (urbp->urb->status != -EINPROGRESS)
 		out += sprintf(out, "Status=%d ", urbp->urb->status);
-	//out += sprintf(out, "Inserttime=%lx ",urbp->inserttime);
 	//out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime);
 
 	count = 0;
@@ -446,11 +445,11 @@
 	out += sprintf(out, "Frame List\n");
 	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
 		int shown = 0;
-		td = uhci->fl->frame_cpu[i];
+		td = uhci->frame_cpu[i];
 		if (!td)
 			continue;
 
-		if (td->dma_handle != (dma_addr_t)uhci->fl->frame[i]) {
+		if (td->dma_handle != (dma_addr_t)uhci->frame[i]) {
 			show_frame_num();
 			out += sprintf(out, "    frame list does not match td->dma_handle!\n");
 		}
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 0c02489..15e0a51 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -101,37 +101,16 @@
 #include "uhci-q.c"
 #include "uhci-hub.c"
 
+extern void uhci_reset_hc(struct pci_dev *pdev, unsigned long base);
+extern int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base);
+
 /*
- * Make sure the controller is completely inactive, unable to
- * generate interrupts or do DMA.
+ * Finish up a host controller reset and update the recorded state.
  */
-static void reset_hc(struct uhci_hcd *uhci)
+static void finish_reset(struct uhci_hcd *uhci)
 {
 	int port;
 
-	/* Turn off PIRQ enable and SMI enable.  (This also turns off the
-	 * BIOS's USB Legacy Support.)  Turn off all the R/WC bits too.
-	 */
-	pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
-			USBLEGSUP_RWC);
-
-	/* Reset the HC - this will force us to get a
-	 * new notification of any already connected
-	 * ports due to the virtual disconnect that it
-	 * implies.
-	 */
-	outw(USBCMD_HCRESET, uhci->io_addr + USBCMD);
-	mb();
-	udelay(5);
-	if (inw(uhci->io_addr + USBCMD) & USBCMD_HCRESET)
-		dev_warn(uhci_dev(uhci), "HCRESET not completed yet!\n");
-
-	/* Just to be safe, disable interrupt requests and
-	 * make sure the controller is stopped.
-	 */
-	outw(0, uhci->io_addr + USBINTR);
-	outw(0, uhci->io_addr + USBCMD);
-
 	/* HCRESET doesn't affect the Suspend, Reset, and Resume Detect
 	 * bits in the port status and control registers.
 	 * We have to clear them by hand.
@@ -153,7 +132,8 @@
  */
 static void hc_died(struct uhci_hcd *uhci)
 {
-	reset_hc(uhci);
+	uhci_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr);
+	finish_reset(uhci);
 	uhci->hc_inaccessible = 1;
 }
 
@@ -163,44 +143,8 @@
  */
 static void check_and_reset_hc(struct uhci_hcd *uhci)
 {
-	u16 legsup;
-	unsigned int cmd, intr;
-
-	/*
-	 * When restarting a suspended controller, we expect all the
-	 * settings to be the same as we left them:
-	 *
-	 *	PIRQ and SMI disabled, no R/W bits set in USBLEGSUP;
-	 *	Controller is stopped and configured with EGSM set;
-	 *	No interrupts enabled except possibly Resume Detect.
-	 *
-	 * If any of these conditions are violated we do a complete reset.
-	 */
-	pci_read_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, &legsup);
-	if (legsup & ~(USBLEGSUP_RO | USBLEGSUP_RWC)) {
-		dev_dbg(uhci_dev(uhci), "%s: legsup = 0x%04x\n",
-				__FUNCTION__, legsup);
-		goto reset_needed;
-	}
-
-	cmd = inw(uhci->io_addr + USBCMD);
-	if ((cmd & USBCMD_RS) || !(cmd & USBCMD_CF) || !(cmd & USBCMD_EGSM)) {
-		dev_dbg(uhci_dev(uhci), "%s: cmd = 0x%04x\n",
-				__FUNCTION__, cmd);
-		goto reset_needed;
-	}
-
-	intr = inw(uhci->io_addr + USBINTR);
-	if (intr & (~USBINTR_RESUME)) {
-		dev_dbg(uhci_dev(uhci), "%s: intr = 0x%04x\n",
-				__FUNCTION__, intr);
-		goto reset_needed;
-	}
-	return;
-
-reset_needed:
-	dev_dbg(uhci_dev(uhci), "Performing full reset\n");
-	reset_hc(uhci);
+	if (uhci_check_and_reset_hc(to_pci_dev(uhci_dev(uhci)), uhci->io_addr))
+		finish_reset(uhci);
 }
 
 /*
@@ -212,13 +156,13 @@
 	outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF);
 
 	/* Store the frame list base address */
-	outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD);
+	outl(uhci->frame_dma_handle, uhci->io_addr + USBFLBASEADD);
 
 	/* Set the current frame number */
 	outw(uhci->frame_number, uhci->io_addr + USBFRNUM);
 
-	/* Mark controller as running before we enable interrupts */
-	uhci_to_hcd(uhci)->state = HC_STATE_RUNNING;
+	/* Mark controller as not halted before we enable interrupts */
+	uhci_to_hcd(uhci)->state = HC_STATE_SUSPENDED;
 	mb();
 
 	/* Enable PIRQ */
@@ -319,6 +263,7 @@
 
 static void start_rh(struct uhci_hcd *uhci)
 {
+	uhci_to_hcd(uhci)->state = HC_STATE_RUNNING;
 	uhci->is_stopped = 0;
 	smp_wmb();
 
@@ -437,36 +382,21 @@
 	int i;
 
 	for (i = 0; i < UHCI_NUM_SKELQH; i++)
-		if (uhci->skelqh[i]) {
-			uhci_free_qh(uhci, uhci->skelqh[i]);
-			uhci->skelqh[i] = NULL;
-		}
+		uhci_free_qh(uhci, uhci->skelqh[i]);
 
-	if (uhci->term_td) {
-		uhci_free_td(uhci, uhci->term_td);
-		uhci->term_td = NULL;
-	}
+	uhci_free_td(uhci, uhci->term_td);
 
-	if (uhci->qh_pool) {
-		dma_pool_destroy(uhci->qh_pool);
-		uhci->qh_pool = NULL;
-	}
+	dma_pool_destroy(uhci->qh_pool);
 
-	if (uhci->td_pool) {
-		dma_pool_destroy(uhci->td_pool);
-		uhci->td_pool = NULL;
-	}
+	dma_pool_destroy(uhci->td_pool);
 
-	if (uhci->fl) {
-		dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
-				uhci->fl, uhci->fl->dma_handle);
-		uhci->fl = NULL;
-	}
+	kfree(uhci->frame_cpu);
 
-	if (uhci->dentry) {
-		debugfs_remove(uhci->dentry);
-		uhci->dentry = NULL;
-	}
+	dma_free_coherent(uhci_dev(uhci),
+			UHCI_NUMFRAMES * sizeof(*uhci->frame),
+			uhci->frame, uhci->frame_dma_handle);
+
+	debugfs_remove(uhci->dentry);
 }
 
 static int uhci_reset(struct usb_hcd *hcd)
@@ -545,7 +475,6 @@
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 	int retval = -EBUSY;
 	int i;
-	dma_addr_t dma_handle;
 	struct dentry *dentry;
 
 	hcd->uses_new_polling = 1;
@@ -579,17 +508,23 @@
 
 	init_waitqueue_head(&uhci->waitqh);
 
-	uhci->fl = dma_alloc_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
-			&dma_handle, 0);
-	if (!uhci->fl) {
+	uhci->frame = dma_alloc_coherent(uhci_dev(uhci),
+			UHCI_NUMFRAMES * sizeof(*uhci->frame),
+			&uhci->frame_dma_handle, 0);
+	if (!uhci->frame) {
 		dev_err(uhci_dev(uhci), "unable to allocate "
 				"consistent memory for frame list\n");
-		goto err_alloc_fl;
+		goto err_alloc_frame;
 	}
+	memset(uhci->frame, 0, UHCI_NUMFRAMES * sizeof(*uhci->frame));
 
-	memset((void *)uhci->fl, 0, sizeof(*uhci->fl));
-
-	uhci->fl->dma_handle = dma_handle;
+	uhci->frame_cpu = kcalloc(UHCI_NUMFRAMES, sizeof(*uhci->frame_cpu),
+			GFP_KERNEL);
+	if (!uhci->frame_cpu) {
+		dev_err(uhci_dev(uhci), "unable to allocate "
+				"memory for frame pointers\n");
+		goto err_alloc_frame_cpu;
+	}
 
 	uhci->td_pool = dma_pool_create("uhci_td", uhci_dev(uhci),
 			sizeof(struct uhci_td), 16, 0);
@@ -672,7 +607,7 @@
 			irq = 7;
 
 		/* Only place we don't use the frame list routines */
-		uhci->fl->frame[i] = UHCI_PTR_QH |
+		uhci->frame[i] = UHCI_PTR_QH |
 				cpu_to_le32(uhci->skelqh[irq]->dma_handle);
 	}
 
@@ -690,31 +625,29 @@
  * error exits:
  */
 err_alloc_skelqh:
-	for (i = 0; i < UHCI_NUM_SKELQH; i++)
-		if (uhci->skelqh[i]) {
+	for (i = 0; i < UHCI_NUM_SKELQH; i++) {
+		if (uhci->skelqh[i])
 			uhci_free_qh(uhci, uhci->skelqh[i]);
-			uhci->skelqh[i] = NULL;
-		}
+	}
 
 	uhci_free_td(uhci, uhci->term_td);
-	uhci->term_td = NULL;
 
 err_alloc_term_td:
 	dma_pool_destroy(uhci->qh_pool);
-	uhci->qh_pool = NULL;
 
 err_create_qh_pool:
 	dma_pool_destroy(uhci->td_pool);
-	uhci->td_pool = NULL;
 
 err_create_td_pool:
-	dma_free_coherent(uhci_dev(uhci), sizeof(*uhci->fl),
-			uhci->fl, uhci->fl->dma_handle);
-	uhci->fl = NULL;
+	kfree(uhci->frame_cpu);
 
-err_alloc_fl:
+err_alloc_frame_cpu:
+	dma_free_coherent(uhci_dev(uhci),
+			UHCI_NUMFRAMES * sizeof(*uhci->frame),
+			uhci->frame, uhci->frame_dma_handle);
+
+err_alloc_frame:
 	debugfs_remove(uhci->dentry);
-	uhci->dentry = NULL;
 
 err_create_debug_entry:
 	return retval;
@@ -726,7 +659,7 @@
 
 	spin_lock_irq(&uhci->lock);
 	if (!uhci->hc_inaccessible)
-		reset_hc(uhci);
+		hc_died(uhci);
 	uhci_scan_schedule(uhci, NULL);
 	spin_unlock_irq(&uhci->lock);
 
@@ -774,14 +707,8 @@
 	if (uhci->hc_inaccessible)	/* Dead or already suspended */
 		goto done;
 
-#ifndef CONFIG_USB_SUSPEND
-	/* Otherwise this would never happen */
-	suspend_rh(uhci, UHCI_RH_SUSPENDED);
-#endif
-
 	if (uhci->rh_state > UHCI_RH_SUSPENDED) {
 		dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n");
-		hcd->state = HC_STATE_RUNNING;
 		rc = -EBUSY;
 		goto done;
 	};
@@ -820,10 +747,6 @@
 	check_and_reset_hc(uhci);
 	configure_hc(uhci);
 
-#ifndef CONFIG_USB_SUSPEND
-	/* Otherwise this would never happen */
-	wakeup_rh(uhci);
-#endif
 	if (uhci->rh_state == UHCI_RH_RESET)
 		suspend_rh(uhci, UHCI_RH_SUSPENDED);
 
@@ -881,8 +804,8 @@
 #ifdef CONFIG_PM
 	.suspend =		uhci_suspend,
 	.resume =		uhci_resume,
-	.hub_suspend =		uhci_rh_suspend,
-	.hub_resume =		uhci_rh_resume,
+	.bus_suspend =		uhci_rh_suspend,
+	.bus_resume =		uhci_rh_resume,
 #endif
 	.stop =			uhci_stop,
 
@@ -908,6 +831,7 @@
 static struct pci_driver uhci_pci_driver = {
 	.name =		(char *)hcd_name,
 	.id_table =	uhci_pci_ids,
+	.owner =	THIS_MODULE,
 
 	.probe =	usb_hcd_pci_probe,
 	.remove =	usb_hcd_pci_remove,
diff --git a/drivers/usb/host/uhci-hcd.h b/drivers/usb/host/uhci-hcd.h
index 282f40b..e576db5 100644
--- a/drivers/usb/host/uhci-hcd.h
+++ b/drivers/usb/host/uhci-hcd.h
@@ -7,6 +7,7 @@
 #define usb_packetid(pipe)	(usb_pipein(pipe) ? USB_PID_IN : USB_PID_OUT)
 #define PIPE_DEVEP_MASK		0x0007ff00
 
+
 /*
  * Universal Host Controller Interface data structures and defines
  */
@@ -82,15 +83,10 @@
 #define UHCI_MAX_SOF_NUMBER	2047	/* in an SOF packet */
 #define CAN_SCHEDULE_FRAMES	1000	/* how far future frames can be scheduled */
 
-struct uhci_frame_list {
-	__le32 frame[UHCI_NUMFRAMES];
 
-	void *frame_cpu[UHCI_NUMFRAMES];
-
-	dma_addr_t dma_handle;
-};
-
-struct urb_priv;
+/*
+ *	Queue Headers
+ */
 
 /*
  * One role of a QH is to hold a queue of TDs for some endpoint.  Each QH is
@@ -116,13 +112,13 @@
 
 	struct urb_priv *urbp;
 
-	struct list_head list;		/* P: uhci->frame_list_lock */
-	struct list_head remove_list;	/* P: uhci->remove_list_lock */
+	struct list_head list;
+	struct list_head remove_list;
 } __attribute__((aligned(16)));
 
 /*
  * We need a special accessor for the element pointer because it is
- * subject to asynchronous updates by the controller
+ * subject to asynchronous updates by the controller.
  */
 static __le32 inline qh_element(struct uhci_qh *qh) {
 	__le32 element = qh->element;
@@ -131,6 +127,11 @@
 	return element;
 }
 
+
+/*
+ *	Transfer Descriptors
+ */
+
 /*
  * for TD <status>:
  */
@@ -183,17 +184,10 @@
  *
  * That's silly, the hardware doesn't care. The hardware only cares that
  * the hardware words are 16-byte aligned, and we can have any amount of
- * sw space after the TD entry as far as I can tell.
- *
- * But let's just go with the documentation, at least for 32-bit machines.
- * On 64-bit machines we probably want to take advantage of the fact that
- * hw doesn't really care about the size of the sw-only area.
- *
- * Alas, not anymore, we have more than 4 words for software, woops.
- * Everything still works tho, surprise! -jerdfelt
+ * sw space after the TD entry.
  *
  * td->link points to either another TD (not necessarily for the same urb or
- * even the same endpoint), or nothing (PTR_TERM), or a QH (for queued urbs)
+ * even the same endpoint), or nothing (PTR_TERM), or a QH (for queued urbs).
  */
 struct uhci_td {
 	/* Hardware fields */
@@ -205,18 +199,16 @@
 	/* Software fields */
 	dma_addr_t dma_handle;
 
-	struct urb *urb;
-
-	struct list_head list;		/* P: urb->lock */
-	struct list_head remove_list;	/* P: uhci->td_remove_list_lock */
+	struct list_head list;
+	struct list_head remove_list;
 
 	int frame;			/* for iso: what frame? */
-	struct list_head fl_list;	/* P: uhci->frame_list_lock */
+	struct list_head fl_list;
 } __attribute__((aligned(16)));
 
 /*
  * We need a special accessor for the control/status word because it is
- * subject to asynchronous updates by the controller
+ * subject to asynchronous updates by the controller.
  */
 static u32 inline td_status(struct uhci_td *td) {
 	__le32 status = td->status;
@@ -227,6 +219,10 @@
 
 
 /*
+ *	Skeleton Queue Headers
+ */
+
+/*
  * The UHCI driver places Interrupt, Control and Bulk into QH's both
  * to group together TD's for one transfer, and also to faciliate queuing
  * of URB's. To make it easy to insert entries into the schedule, we have
@@ -256,15 +252,15 @@
  *
  * The terminating QH is used for 2 reasons:
  * - To place a terminating TD which is used to workaround a PIIX bug
- *   (see Intel errata for explanation)
+ *   (see Intel errata for explanation), and
  * - To loop back to the full-speed control queue for full-speed bandwidth
- *   reclamation
+ *   reclamation.
  *
  * Isochronous transfers are stored before the start of the skeleton
  * schedule and don't use QH's. While the UHCI spec doesn't forbid the
- * use of QH's for Isochronous, it doesn't use them either. Since we don't
- * need to use them either, we follow the spec diagrams in hope that it'll
- * be more compatible with future UHCI implementations.
+ * use of QH's for Isochronous, it doesn't use them either. And the spec
+ * says that queues never advance on an error completion status, which
+ * makes them totally unsuitable for Isochronous transfers.
  */
 
 #define UHCI_NUM_SKELQH		12
@@ -314,8 +310,13 @@
 	return 0;				/* int128 for 128-255 ms (Max.) */
 }
 
+
 /*
- * States for the root hub.
+ *	The UHCI controller and root hub
+ */
+
+/*
+ * States for the root hub:
  *
  * To prevent "bouncing" in the presence of electrical noise,
  * when there are no devices attached we delay for 1 second in the
@@ -326,7 +327,7 @@
  */
 enum uhci_rh_state {
 	/* In the following states the HC must be halted.
-	 * These two must come first */
+	 * These two must come first. */
 	UHCI_RH_RESET,
 	UHCI_RH_SUSPENDED,
 
@@ -338,13 +339,13 @@
 	UHCI_RH_SUSPENDING,
 
 	/* In the following states it's an error if the HC is halted.
-	 * These two must come last */
+	 * These two must come last. */
 	UHCI_RH_RUNNING,		/* The normal state */
 	UHCI_RH_RUNNING_NODEVS,		/* Running with no devices attached */
 };
 
 /*
- * This describes the full uhci information.
+ * The full UHCI controller information:
  */
 struct uhci_hcd {
 
@@ -361,7 +362,11 @@
 	struct uhci_qh *skelqh[UHCI_NUM_SKELQH];	/* Skeleton QH's */
 
 	spinlock_t lock;
-	struct uhci_frame_list *fl;		/* P: uhci->lock */
+
+	dma_addr_t frame_dma_handle;		/* Hardware frame list */
+	__le32 *frame;
+	void **frame_cpu;			/* CPU's frame list */
+
 	int fsbr;				/* Full-speed bandwidth reclamation */
 	unsigned long fsbrtimeout;		/* FSBR delay */
 
@@ -385,22 +390,22 @@
 	unsigned long ports_timeout;		/* Time to stop signalling */
 
 	/* Main list of URB's currently controlled by this HC */
-	struct list_head urb_list;		/* P: uhci->lock */
+	struct list_head urb_list;
 
 	/* List of QH's that are done, but waiting to be unlinked (race) */
-	struct list_head qh_remove_list;	/* P: uhci->lock */
+	struct list_head qh_remove_list;
 	unsigned int qh_remove_age;		/* Age in frames */
 
 	/* List of TD's that are done, but waiting to be freed (race) */
-	struct list_head td_remove_list;	/* P: uhci->lock */
+	struct list_head td_remove_list;
 	unsigned int td_remove_age;		/* Age in frames */
 
 	/* List of asynchronously unlinked URB's */
-	struct list_head urb_remove_list;	/* P: uhci->lock */
+	struct list_head urb_remove_list;
 	unsigned int urb_remove_age;		/* Age in frames */
 
 	/* List of URB's awaiting completion callback */
-	struct list_head complete_list;		/* P: uhci->lock */
+	struct list_head complete_list;
 
 	int rh_numports;			/* Number of root-hub ports */
 
@@ -419,13 +424,17 @@
 
 #define uhci_dev(u)	(uhci_to_hcd(u)->self.controller)
 
+
+/*
+ *	Private per-URB data
+ */
 struct urb_priv {
 	struct list_head urb_list;
 
 	struct urb *urb;
 
 	struct uhci_qh *qh;		/* QH for this URB */
-	struct list_head td_list;	/* P: urb->lock */
+	struct list_head td_list;
 
 	unsigned fsbr : 1;		/* URB turned on FSBR */
 	unsigned fsbr_timeout : 1;	/* URB timed out on FSBR */
@@ -434,12 +443,12 @@
 						/*  a control transfer, retrigger */
 						/*  the status phase */
 
-	unsigned long inserttime;	/* In jiffies */
 	unsigned long fsbrtime;		/* In jiffies */
 
-	struct list_head queue_list;	/* P: uhci->frame_list_lock */
+	struct list_head queue_list;
 };
 
+
 /*
  * Locking in uhci.c
  *
@@ -459,6 +468,5 @@
 
 #define PCI_VENDOR_ID_GENESYS		0x17a0
 #define PCI_DEVICE_ID_GL880S_UHCI	0x8083
-#define PCI_DEVICE_ID_GL880S_EHCI	0x8084
 
 #endif
diff --git a/drivers/usb/host/uhci-q.c b/drivers/usb/host/uhci-q.c
index 4e0fbe2..7e46887 100644
--- a/drivers/usb/host/uhci-q.c
+++ b/drivers/usb/host/uhci-q.c
@@ -89,10 +89,10 @@
 	td->frame = framenum;
 
 	/* Is there a TD already mapped there? */
-	if (uhci->fl->frame_cpu[framenum]) {
+	if (uhci->frame_cpu[framenum]) {
 		struct uhci_td *ftd, *ltd;
 
-		ftd = uhci->fl->frame_cpu[framenum];
+		ftd = uhci->frame_cpu[framenum];
 		ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list);
 
 		list_add_tail(&td->fl_list, &ftd->fl_list);
@@ -101,29 +101,32 @@
 		wmb();
 		ltd->link = cpu_to_le32(td->dma_handle);
 	} else {
-		td->link = uhci->fl->frame[framenum];
+		td->link = uhci->frame[framenum];
 		wmb();
-		uhci->fl->frame[framenum] = cpu_to_le32(td->dma_handle);
-		uhci->fl->frame_cpu[framenum] = td;
+		uhci->frame[framenum] = cpu_to_le32(td->dma_handle);
+		uhci->frame_cpu[framenum] = td;
 	}
 }
 
-static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td)
+static inline void uhci_remove_td_frame_list(struct uhci_hcd *uhci,
+		struct uhci_td *td)
 {
 	/* If it's not inserted, don't remove it */
-	if (td->frame == -1 && list_empty(&td->fl_list))
+	if (td->frame == -1) {
+		WARN_ON(!list_empty(&td->fl_list));
 		return;
+	}
 
-	if (td->frame != -1 && uhci->fl->frame_cpu[td->frame] == td) {
+	if (uhci->frame_cpu[td->frame] == td) {
 		if (list_empty(&td->fl_list)) {
-			uhci->fl->frame[td->frame] = td->link;
-			uhci->fl->frame_cpu[td->frame] = NULL;
+			uhci->frame[td->frame] = td->link;
+			uhci->frame_cpu[td->frame] = NULL;
 		} else {
 			struct uhci_td *ntd;
 
 			ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
-			uhci->fl->frame[td->frame] = cpu_to_le32(ntd->dma_handle);
-			uhci->fl->frame_cpu[td->frame] = ntd;
+			uhci->frame[td->frame] = cpu_to_le32(ntd->dma_handle);
+			uhci->frame_cpu[td->frame] = ntd;
 		}
 	} else {
 		struct uhci_td *ptd;
@@ -132,13 +135,20 @@
 		ptd->link = td->link;
 	}
 
-	wmb();
-	td->link = UHCI_PTR_TERM;
-
 	list_del_init(&td->fl_list);
 	td->frame = -1;
 }
 
+static void unlink_isochronous_tds(struct uhci_hcd *uhci, struct urb *urb)
+{
+	struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
+	struct uhci_td *td;
+
+	list_for_each_entry(td, &urbp->td_list, list)
+		uhci_remove_td_frame_list(uhci, td);
+	wmb();
+}
+
 /*
  * Inserts a td list into qh.
  */
@@ -443,7 +453,6 @@
 
 	memset((void *)urbp, 0, sizeof(*urbp));
 
-	urbp->inserttime = jiffies;
 	urbp->fsbrtime = jiffies;
 	urbp->urb = urb;
 	
@@ -462,8 +471,6 @@
 {
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 
-	td->urb = urb;
-
 	list_add_tail(&td->list, &urbp->td_list);
 }
 
@@ -473,8 +480,6 @@
 		return;
 
 	list_del_init(&td->list);
-
-	td->urb = NULL;
 }
 
 static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
@@ -503,7 +508,6 @@
 
 	list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
 		uhci_remove_td_from_urb(td);
-		uhci_remove_td(uhci, td);
 		list_add(&td->remove_list, &uhci->td_remove_list);
 	}
 
@@ -1073,6 +1077,7 @@
 	struct uhci_td *td;
 	int i, ret, frame;
 	int status, destination;
+	struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
 
 	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
 	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
@@ -1081,11 +1086,7 @@
 	if (ret)
 		return ret;
 
-	frame = urb->start_frame;
-	for (i = 0; i < urb->number_of_packets; i++, frame += urb->interval) {
-		if (!urb->iso_frame_desc[i].length)
-			continue;
-
+	for (i = 0; i < urb->number_of_packets; i++) {
 		td = uhci_alloc_td(uhci);
 		if (!td)
 			return -ENOMEM;
@@ -1096,8 +1097,12 @@
 
 		if (i + 1 >= urb->number_of_packets)
 			td->status |= cpu_to_le32(TD_CTRL_IOC);
+	}
 
+	frame = urb->start_frame;
+	list_for_each_entry(td, &urbp->td_list, list) {
 		uhci_insert_td_frame_list(uhci, td, frame);
+		frame += urb->interval;
 	}
 
 	return -EINPROGRESS;
@@ -1110,7 +1115,7 @@
 	int status;
 	int i, ret = 0;
 
-	urb->actual_length = 0;
+	urb->actual_length = urb->error_count = 0;
 
 	i = 0;
 	list_for_each_entry(td, &urbp->td_list, list) {
@@ -1134,6 +1139,7 @@
 
 		i++;
 	}
+	unlink_isochronous_tds(uhci, urb);
 
 	return ret;
 }
@@ -1366,6 +1372,8 @@
 		goto done;
 	list_del_init(&urbp->urb_list);
 
+	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
+		unlink_isochronous_tds(uhci, urb);
 	uhci_unlink_generic(uhci, urb);
 
 	uhci_get_current_frame_number(uhci);
diff --git a/drivers/usb/image/mdc800.c b/drivers/usb/image/mdc800.c
index a330a4b..1d973bc 100644
--- a/drivers/usb/image/mdc800.c
+++ b/drivers/usb/image/mdc800.c
@@ -425,9 +425,8 @@
 static struct usb_driver mdc800_usb_driver;
 static struct file_operations mdc800_device_ops;
 static struct usb_class_driver mdc800_class = {
-	.name =		"usb/mdc800%d",
+	.name =		"mdc800%d",
 	.fops =		&mdc800_device_ops,
-	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
 	.minor_base =	MDC800_DEVICE_MINOR_BASE,
 };
 
@@ -976,13 +975,13 @@
 	Init and Cleanup this driver (Main Functions)
 *************************************************************************/
 
-#define try(A)           if (!(A)) goto cleanup_on_fail;
-
 static int __init usb_mdc800_init (void)
 {
 	int retval = -ENODEV;
 	/* Allocate Memory */
-	try (mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL));
+	mdc800=kmalloc (sizeof (struct mdc800_data), GFP_KERNEL);
+	if (!mdc800)
+		goto cleanup_on_fail;
 
 	memset(mdc800, 0, sizeof(struct mdc800_data));
 	mdc800->dev = NULL;
@@ -998,13 +997,25 @@
 	mdc800->downloaded = 0;
 	mdc800->written = 0;
 
-	try (mdc800->irq_urb_buffer=kmalloc (8, GFP_KERNEL));
-	try (mdc800->write_urb_buffer=kmalloc (8, GFP_KERNEL));
-	try (mdc800->download_urb_buffer=kmalloc (64, GFP_KERNEL));
+	mdc800->irq_urb_buffer=kmalloc (8, GFP_KERNEL);
+	if (!mdc800->irq_urb_buffer)
+		goto cleanup_on_fail;
+	mdc800->write_urb_buffer=kmalloc (8, GFP_KERNEL);
+	if (!mdc800->write_urb_buffer)
+		goto cleanup_on_fail;
+	mdc800->download_urb_buffer=kmalloc (64, GFP_KERNEL);
+	if (!mdc800->download_urb_buffer)
+		goto cleanup_on_fail;
 
-	try (mdc800->irq_urb=usb_alloc_urb (0, GFP_KERNEL));
-	try (mdc800->download_urb=usb_alloc_urb (0, GFP_KERNEL));
-	try (mdc800->write_urb=usb_alloc_urb (0, GFP_KERNEL));
+	mdc800->irq_urb=usb_alloc_urb (0, GFP_KERNEL);
+	if (!mdc800->irq_urb)
+		goto cleanup_on_fail;
+	mdc800->download_urb=usb_alloc_urb (0, GFP_KERNEL);
+	if (!mdc800->download_urb)
+		goto cleanup_on_fail;
+	mdc800->write_urb=usb_alloc_urb (0, GFP_KERNEL);
+	if (!mdc800->write_urb)
+		goto cleanup_on_fail;
 
 	/* Register the driver */
 	retval = usb_register(&mdc800_usb_driver);
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index c84e148..c89d076 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -773,11 +773,10 @@
 	}
 	
 	
-	new_desc = kmalloc(sizeof(struct mts_desc), GFP_KERNEL);
+	new_desc = kzalloc(sizeof(struct mts_desc), GFP_KERNEL);
 	if (!new_desc)
 		goto out;
 
-	memset(new_desc, 0, sizeof(*new_desc));
 	new_desc->urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!new_desc->urb)
 		goto out_kfree;
diff --git a/drivers/usb/input/aiptek.c b/drivers/usb/input/aiptek.c
index 1c52053..1c3b472 100644
--- a/drivers/usb/input/aiptek.c
+++ b/drivers/usb/input/aiptek.c
@@ -2154,7 +2154,7 @@
 	 * input_handles associated with this input device.
 	 * What identifies an evdev input_handler is that it begins
 	 * with 'event', continues with a digit, and that in turn
-	 * is mapped to /{devfs}/input/eventN.
+	 * is mapped to input/eventN.
 	 */
 	list_for_each_safe(node, next, &inputdev->h_list) {
 		inputhandle = to_handle(node);
diff --git a/drivers/usb/input/hid-core.c b/drivers/usb/input/hid-core.c
index 411a064..79ddce4 100644
--- a/drivers/usb/input/hid-core.c
+++ b/drivers/usb/input/hid-core.c
@@ -1784,6 +1784,9 @@
 	hid->urbctrl->transfer_dma = hid->ctrlbuf_dma;
 	hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
 
+	/* May be needed for some devices */
+	usb_clear_halt(hid->dev, hid->urbin->pipe);
+
 	return hid;
 
 fail:
@@ -1887,7 +1890,6 @@
 	struct hid_device *hid = usb_get_intfdata (intf);
 
 	usb_kill_urb(hid->urbin);
-	intf->dev.power.power_state = PMSG_SUSPEND;
 	dev_dbg(&intf->dev, "suspend\n");
 	return 0;
 }
@@ -1897,7 +1899,6 @@
 	struct hid_device *hid = usb_get_intfdata (intf);
 	int status;
 
-	intf->dev.power.power_state = PMSG_ON;
 	if (hid->open)
 		status = usb_submit_urb(hid->urbin, GFP_NOIO);
 	else
diff --git a/drivers/usb/input/hiddev.c b/drivers/usb/input/hiddev.c
index d324278..440377c 100644
--- a/drivers/usb/input/hiddev.c
+++ b/drivers/usb/input/hiddev.c
@@ -732,9 +732,8 @@
 };
 
 static struct usb_class_driver hiddev_class = {
-	.name =		"usb/hid/hiddev%d",
+	.name =		"hiddev%d",
 	.fops =		&hiddev_fops,
-	.mode =		S_IFCHR | S_IRUGO | S_IWUSR,
 	.minor_base =	HIDDEV_MINOR_BASE,
 };
 
diff --git a/drivers/usb/input/map_to_7segment.h b/drivers/usb/input/map_to_7segment.h
index 52ff27f..a424094 100644
--- a/drivers/usb/input/map_to_7segment.h
+++ b/drivers/usb/input/map_to_7segment.h
@@ -79,7 +79,7 @@
 
 static inline int map_to_seg7(struct seg7_conversion_map *map, int c)
 {
-	return c & 0x7f ? map->table[c] : -EINVAL;
+	return c >= 0 && c < sizeof(map->table) ? map->table[c] : -EINVAL;
 }
 
 #define SEG7_CONVERSION_MAP(_name, _map)	\
diff --git a/drivers/usb/input/touchkitusb.c b/drivers/usb/input/touchkitusb.c
index 3766ccc..0043e6e 100644
--- a/drivers/usb/input/touchkitusb.c
+++ b/drivers/usb/input/touchkitusb.c
@@ -75,7 +75,9 @@
 
 static struct usb_device_id touchkit_devices[] = {
 	{USB_DEVICE(0x3823, 0x0001)},
+	{USB_DEVICE(0x0123, 0x0001)},
 	{USB_DEVICE(0x0eef, 0x0001)},
+	{USB_DEVICE(0x0eef, 0x0002)},
 	{}
 };
 
diff --git a/drivers/usb/media/dabusb.c b/drivers/usb/media/dabusb.c
index 6ca2fae..27b23c5 100644
--- a/drivers/usb/media/dabusb.c
+++ b/drivers/usb/media/dabusb.c
@@ -707,9 +707,8 @@
 };
 
 static struct usb_class_driver dabusb_class = {
-	.name =		"usb/dabusb%d",
+	.name =		"dabusb%d",
 	.fops =		&dabusb_fops,
-	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
 	.minor_base =	DABUSB_MINOR,
 };
 
diff --git a/drivers/usb/misc/auerswald.c b/drivers/usb/misc/auerswald.c
index ae4681f..5f33f7c 100644
--- a/drivers/usb/misc/auerswald.c
+++ b/drivers/usb/misc/auerswald.c
@@ -1873,9 +1873,8 @@
 };
 
 static struct usb_class_driver auerswald_class = {
-	.name =		"usb/auer%d",
+	.name =		"auer%d",
 	.fops =		&auerswald_fops,
-	.mode =		S_IFCHR | S_IRUGO | S_IWUGO,
 	.minor_base =	AUER_MINOR_BASE,
 };
 
diff --git a/drivers/usb/misc/idmouse.c b/drivers/usb/misc/idmouse.c
index 733acc2..3944a55 100644
--- a/drivers/usb/misc/idmouse.c
+++ b/drivers/usb/misc/idmouse.c
@@ -105,11 +105,10 @@
 	.release = idmouse_release,
 };
 
-/* class driver information for devfs */
+/* class driver information */
 static struct usb_class_driver idmouse_class = {
-	.name = "usb/idmouse%d",
+	.name = "idmouse%d",
 	.fops = &idmouse_fops,
-	.mode = S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, /* filemode (char, 444) */
 	.minor_base = USB_IDMOUSE_MINOR_BASE,
 };
 
diff --git a/drivers/usb/misc/legousbtower.c b/drivers/usb/misc/legousbtower.c
index 7d06105..2703e20 100644
--- a/drivers/usb/misc/legousbtower.c
+++ b/drivers/usb/misc/legousbtower.c
@@ -271,12 +271,11 @@
 
 /*
  * usb class driver info in order to get a minor number from the usb core,
- * and to have the device registered with devfs and the driver core
+ * and to have the device registered with the driver core
  */
 static struct usb_class_driver tower_class = {
-	.name =		"usb/legousbtower%d",
+	.name =		"legousbtower%d",
 	.fops =		&tower_fops,
-	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
 	.minor_base =	LEGO_USB_TOWER_MINOR_BASE,
 };
 
diff --git a/drivers/usb/misc/rio500.c b/drivers/usb/misc/rio500.c
index 26f77e2..7d02d8e 100644
--- a/drivers/usb/misc/rio500.c
+++ b/drivers/usb/misc/rio500.c
@@ -443,9 +443,8 @@
 };
 
 static struct usb_class_driver usb_rio_class = {
-	.name =		"usb/rio500%d",
+	.name =		"rio500%d",
 	.fops =		&usb_rio_fops,
-	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
 	.minor_base =	RIO_MINOR,
 };
 
diff --git a/drivers/usb/misc/sisusbvga/sisusb.c b/drivers/usb/misc/sisusbvga/sisusb.c
index 39db315..c946c9a 100644
--- a/drivers/usb/misc/sisusbvga/sisusb.c
+++ b/drivers/usb/misc/sisusbvga/sisusb.c
@@ -2440,7 +2440,7 @@
 sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
 {
 	int ret = 0, slot = sisusb->font_slot, i;
-	struct font_desc *myfont;
+	const struct font_desc *myfont;
 	u8 *tempbuf;
 	u16 *tempbufb;
 	size_t written;
@@ -3239,12 +3239,7 @@
 };
 
 static struct usb_class_driver usb_sisusb_class = {
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,13)
-	.name =		"usb/sisusbvga%d",
-	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
-#else
 	.name =		"sisusbvga%d",
-#endif
 	.fops =		&usb_sisusb_fops,
 	.minor_base =	SISUSB_MINOR
 };
diff --git a/drivers/usb/misc/usblcd.c b/drivers/usb/misc/usblcd.c
index 096ab30..85f3725 100644
--- a/drivers/usb/misc/usblcd.c
+++ b/drivers/usb/misc/usblcd.c
@@ -251,13 +251,12 @@
 };
 
 /*
- *  * usb class driver info in order to get a minor number from the usb core,
- *   * and to have the device registered with devfs and the driver core
- *    */
+ * usb class driver info in order to get a minor number from the usb core,
+ * and to have the device registered with the driver core
+ */
 static struct usb_class_driver lcd_class = {
-        .name =         "usb/lcd%d",
+        .name =         "lcd%d",
         .fops =         &lcd_fops,
-        .mode =         S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
         .minor_base =   USBLCD_MINOR,
 };
 
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 54799eb..90a9625 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -983,6 +983,7 @@
 		reqp->number = i % NUM_SUBCASES;
 		reqp->expected = expected;
 		u->setup_packet = (char *) &reqp->setup;
+		u->transfer_flags |= URB_NO_SETUP_DMA_MAP;
 
 		u->context = &context;
 		u->complete = ctrl_complete;
@@ -1948,21 +1949,11 @@
 
 static int usbtest_suspend (struct usb_interface *intf, pm_message_t message)
 {
-	struct usbtest_dev	*dev = usb_get_intfdata (intf);
-
-	down (&dev->sem);
-	intf->dev.power.power_state = PMSG_SUSPEND;
-	up (&dev->sem);
 	return 0;
 }
 
 static int usbtest_resume (struct usb_interface *intf)
 {
-	struct usbtest_dev	*dev = usb_get_intfdata (intf);
-
-	down (&dev->sem);
-	intf->dev.power.power_state = PMSG_ON;
-	up (&dev->sem);
 	return 0;
 }
 
diff --git a/drivers/usb/mon/mon_main.c b/drivers/usb/mon/mon_main.c
index 508a210..c34944c 100644
--- a/drivers/usb/mon/mon_main.c
+++ b/drivers/usb/mon/mon_main.c
@@ -11,6 +11,7 @@
 #include <linux/usb.h>
 #include <linux/debugfs.h>
 #include <linux/smp_lock.h>
+#include <linux/notifier.h>
 
 #include "usb_mon.h"
 #include "../core/hcd.h"
@@ -205,6 +206,23 @@
 	up(&mon_lock);
 }
 
+static int mon_notify(struct notifier_block *self, unsigned long action,
+		      void *dev)
+{
+	switch (action) {
+	case USB_BUS_ADD:
+		mon_bus_add(dev);
+		break;
+	case USB_BUS_REMOVE:
+		mon_bus_remove(dev);
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block mon_nb = {
+	.notifier_call = 	mon_notify,
+};
+
 /*
  * Ops
  */
@@ -212,8 +230,6 @@
 	.urb_submit =	mon_submit,
 	.urb_submit_error = mon_submit_error,
 	.urb_complete =	mon_complete,
-	.bus_add =	mon_bus_add,
-	.bus_remove =	mon_bus_remove,
 };
 
 /*
@@ -329,6 +345,8 @@
 	}
 	// MOD_INC_USE_COUNT(which_module?);
 
+	usb_register_notify(&mon_nb);
+
 	down(&usb_bus_list_lock);
 	list_for_each_entry (ubus, &usb_bus_list, bus_list) {
 		mon_bus_init(mondir, ubus);
@@ -342,6 +360,7 @@
 	struct mon_bus *mbus;
 	struct list_head *p;
 
+	usb_unregister_notify(&mon_nb);
 	usb_mon_deregister();
 
 	down(&mon_lock);
diff --git a/drivers/usb/net/Kconfig b/drivers/usb/net/Kconfig
index 8c010bb..efd6ca7 100644
--- a/drivers/usb/net/Kconfig
+++ b/drivers/usb/net/Kconfig
@@ -294,7 +294,7 @@
 	  This also supports some related device firmware, as used in some
 	  PDAs from Olympus and some cell phones from Motorola.
 
-	  If you install an alternate ROM image, such as the Linux 2.6 based
+	  If you install an alternate image, such as the Linux 2.6 based
 	  versions of OpenZaurus, you should no longer need to support this
 	  protocol.  Only the "eth-fd" or "net_fd" drivers in these devices
 	  really need this non-conformant variant of CDC Ethernet (or in
diff --git a/drivers/usb/net/kaweth.c b/drivers/usb/net/kaweth.c
index c82655d..6bef1be 100644
--- a/drivers/usb/net/kaweth.c
+++ b/drivers/usb/net/kaweth.c
@@ -469,7 +469,7 @@
 				0,
 				KAWETH_CONTROL_TIMEOUT);
 
-	udelay(10000);
+	mdelay(10);
 
 	kaweth_dbg("kaweth_reset() returns %d.",result);
 
diff --git a/drivers/usb/net/pegasus.c b/drivers/usb/net/pegasus.c
index 6a4ffe6..537eb18 100644
--- a/drivers/usb/net/pegasus.c
+++ b/drivers/usb/net/pegasus.c
@@ -1384,7 +1384,6 @@
 		usb_kill_urb(pegasus->rx_urb);
 		usb_kill_urb(pegasus->intr_urb);
 	}
-	intf->dev.power.power_state = PMSG_SUSPEND;
 	return 0;
 }
 
@@ -1392,7 +1391,6 @@
 {
 	struct pegasus *pegasus = usb_get_intfdata(intf);
 
-	intf->dev.power.power_state = PMSG_ON;
 	netif_device_attach (pegasus->net);
 	if (netif_running(pegasus->net)) {
 		pegasus->rx_urb->status = 0;
diff --git a/drivers/usb/net/pegasus.h b/drivers/usb/net/pegasus.h
index b98f2a8..9fbd59b 100644
--- a/drivers/usb/net/pegasus.h
+++ b/drivers/usb/net/pegasus.h
@@ -181,6 +181,8 @@
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
+PEGASUS_DEV( "Philips USB 10/100 Ethernet", VENDOR_ACCTON, 0xb004,
+		DEFAULT_GPIO_RESET | PEGASUS_II )
 PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
 		VENDOR_ADMTEK, 0x8511,
 		DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
diff --git a/drivers/usb/net/rtl8150.c b/drivers/usb/net/rtl8150.c
index c3d4e35..787dd35 100644
--- a/drivers/usb/net/rtl8150.c
+++ b/drivers/usb/net/rtl8150.c
@@ -909,6 +909,7 @@
 	usb_set_intfdata(intf, NULL);
 	if (dev) {
 		set_bit(RTL8150_UNPLUG, &dev->flags);
+		tasklet_disable(&dev->tl);
 		unregister_netdev(dev->netdev);
 		unlink_all_urbs(dev);
 		free_all_urbs(dev);
diff --git a/drivers/usb/net/usbnet.c b/drivers/usb/net/usbnet.c
index fce81d7..74f05c9 100644
--- a/drivers/usb/net/usbnet.c
+++ b/drivers/usb/net/usbnet.c
@@ -1185,7 +1185,6 @@
 	netif_device_detach (dev->net);
 	(void) unlink_urbs (dev, &dev->rxq);
 	(void) unlink_urbs (dev, &dev->txq);
-	intf->dev.power.power_state = PMSG_SUSPEND;
 	return 0;
 }
 EXPORT_SYMBOL_GPL(usbnet_suspend);
@@ -1194,7 +1193,6 @@
 {
 	struct usbnet		*dev = usb_get_intfdata(intf);
 
-	intf->dev.power.power_state = PMSG_ON;
 	netif_device_attach (dev->net);
 	tasklet_schedule (&dev->bh);
 	return 0;
diff --git a/drivers/usb/serial/ChangeLog.old b/drivers/usb/serial/ChangeLog.old
new file mode 100644
index 0000000..c1b2799
--- /dev/null
+++ b/drivers/usb/serial/ChangeLog.old
@@ -0,0 +1,730 @@
+This is the contents of some of the drivers/usb/serial/ files that had  old
+changelog comments.  They were quite old, and out of date, and we don't keep
+them anymore, so I've put them here, away from the source files, in case
+people still care to see them.
+
+- Greg Kroah-Hartman <greg@kroah.com> October 20, 2005
+
+-----------------------------------------------------------------------
+usb-serial.h Change Log comments:
+
+ (03/26/2002) gkh
+	removed the port->tty check from port_paranoia_check() due to serial
+	consoles not having a tty device assigned to them.
+
+ (12/03/2001) gkh
+	removed active from the port structure.
+	added documentation to the usb_serial_device_type structure
+
+ (10/10/2001) gkh
+	added vendor and product to serial structure.  Needed to determine device
+	owner when the device is disconnected.
+
+ (05/30/2001) gkh
+	added sem to port structure and removed port_lock
+
+ (10/05/2000) gkh
+	Added interrupt_in_endpointAddress and bulk_in_endpointAddress to help
+	fix bug with urb->dev not being set properly, now that the usb core
+	needs it.
+
+ (09/11/2000) gkh
+	Added usb_serial_debug_data function to help get rid of #DEBUG in the
+	drivers.
+
+ (08/28/2000) gkh
+	Added port_lock to port structure.
+
+ (08/08/2000) gkh
+	Added open_count to port structure.
+
+ (07/23/2000) gkh
+	Added bulk_out_endpointAddress to port structure.
+
+ (07/19/2000) gkh, pberger, and borchers
+	Modifications to allow usb-serial drivers to be modules.
+
+-----------------------------------------------------------------------
+usb-serial.c Change Log comments:
+
+ (12/10/2002) gkh
+	Split the ports off into their own struct device, and added a
+	usb-serial bus driver.
+
+ (11/19/2002) gkh
+	removed a few #ifdefs for the generic code and cleaned up the failure
+	logic in initialization.
+
+ (10/02/2002) gkh
+	moved the console code to console.c and out of this file.
+
+ (06/05/2002) gkh
+	moved location of startup() call in serial_probe() until after all
+	of the port information and endpoints are initialized.  This makes
+	things easier for some drivers.
+
+ (04/10/2002) gkh
+	added serial_read_proc function which creates a
+	/proc/tty/driver/usb-serial file.
+
+ (03/27/2002) gkh
+	Got USB serial console code working properly and merged into the main
+	version of the tree.  Thanks to Randy Dunlap for the initial version
+	of this code, and for pushing me to finish it up.
+	The USB serial console works with any usb serial driver device.
+
+ (03/21/2002) gkh
+	Moved all manipulation of port->open_count into the core.  Now the
+	individual driver's open and close functions are called only when the
+	first open() and last close() is called.  Making the drivers a bit
+	smaller and simpler.
+	Fixed a bug if a driver didn't have the owner field set.
+
+ (02/26/2002) gkh
+	Moved all locking into the main serial_* functions, instead of having
+	the individual drivers have to grab the port semaphore.  This should
+	reduce races.
+	Reworked the MOD_INC logic a bit to always increment and decrement, even
+	if the generic driver is being used.
+
+ (10/10/2001) gkh
+	usb_serial_disconnect() now sets the serial->dev pointer is to NULL to
+	help prevent child drivers from accessing the device since it is now
+	gone.
+
+ (09/13/2001) gkh
+	Moved generic driver initialize after we have registered with the USB
+	core.  Thanks to Randy Dunlap for pointing this problem out.
+
+ (07/03/2001) gkh
+	Fixed module paramater size.  Thanks to John Brockmeyer for the pointer.
+	Fixed vendor and product getting defined through the MODULE_PARM macro
+	if the Generic driver wasn't compiled in.
+	Fixed problem with generic_shutdown() not being called for drivers that
+	don't have a shutdown() function.
+
+ (06/06/2001) gkh
+	added evil hack that is needed for the prolific pl2303 device due to the
+	crazy way its endpoints are set up.
+
+ (05/30/2001) gkh
+	switched from using spinlock to a semaphore, which fixes lots of problems.
+
+ (04/08/2001) gb
+	Identify version on module load.
+
+ 2001_02_05 gkh
+	Fixed buffer overflows bug with the generic serial driver.  Thanks to
+	Todd Squires <squirest@ct0.com> for fixing this.
+
+ (01/10/2001) gkh
+	Fixed bug where the generic serial adaptor grabbed _any_ device that was
+	offered to it.
+
+ (12/12/2000) gkh
+	Removed MOD_INC and MOD_DEC from poll and disconnect functions, and
+	moved them to the serial_open and serial_close functions.
+	Also fixed bug with there not being a MOD_DEC for the generic driver
+	(thanks to Gary Brubaker for finding this.)
+
+ (11/29/2000) gkh
+	Small NULL pointer initialization cleanup which saves a bit of disk image
+
+ (11/01/2000) Adam J. Richter
+	instead of using idVendor/idProduct pairs, usb serial drivers
+	now identify their hardware interest with usb_device_id tables,
+	which they usually have anyhow for use with MODULE_DEVICE_TABLE.
+
+ (10/05/2000) gkh
+	Fixed bug with urb->dev not being set properly, now that the usb
+	core needs it.
+
+ (09/11/2000) gkh
+	Removed DEBUG #ifdefs with call to usb_serial_debug_data
+
+ (08/28/2000) gkh
+	Added port_lock to port structure.
+	Added locks for SMP safeness to generic driver
+	Fixed the ability to open a generic device's port more than once.
+
+ (07/23/2000) gkh
+	Added bulk_out_endpointAddress to port structure.
+
+ (07/19/2000) gkh, pberger, and borchers
+	Modifications to allow usb-serial drivers to be modules.
+
+ (07/03/2000) gkh
+	Added more debugging to serial_ioctl call
+
+ (06/25/2000) gkh
+	Changed generic_write_bulk_callback to not call wake_up_interruptible
+	directly, but to have port_softint do it at a safer time.
+
+ (06/23/2000) gkh
+	Cleaned up debugging statements in a quest to find UHCI timeout bug.
+
+ (05/22/2000) gkh
+	Changed the makefile, enabling the big CONFIG_USB_SERIAL_SOMTHING to be
+	removed from the individual device source files.
+
+ (05/03/2000) gkh
+	Added the Digi Acceleport driver from Al Borchers and Peter Berger.
+
+ (05/02/2000) gkh
+	Changed devfs and tty register code to work properly now. This was based on
+	the ACM driver changes by Vojtech Pavlik.
+
+ (04/27/2000) Ryan VanderBijl
+ 	Put calls to *_paranoia_checks into one function.
+
+ (04/23/2000) gkh
+	Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports.
+	Moved when the startup code printed out the devices that are supported.
+
+ (04/19/2000) gkh
+	Added driver for ZyXEL omni.net lcd plus ISDN TA
+	Made startup info message specify which drivers were compiled in.
+
+ (04/03/2000) gkh
+	Changed the probe process to remove the module unload races.
+	Changed where the tty layer gets initialized to have devfs work nicer.
+	Added initial devfs support.
+
+ (03/26/2000) gkh
+	Split driver up into device specific pieces.
+
+ (03/19/2000) gkh
+	Fixed oops that could happen when device was removed while a program
+	was talking to the device.
+	Removed the static urbs and now all urbs are created and destroyed
+	dynamically.
+	Reworked the internal interface. Now everything is based on the
+	usb_serial_port structure instead of the larger usb_serial structure.
+	This fixes the bug that a multiport device could not have more than
+	one port open at one time.
+
+ (03/17/2000) gkh
+	Added config option for debugging messages.
+	Added patch for keyspan pda from Brian Warner.
+
+ (03/06/2000) gkh
+	Added the keyspan pda code from Brian Warner <warner@lothar.com>
+	Moved a bunch of the port specific stuff into its own structure. This
+	is in anticipation of the true multiport devices (there's a bug if you
+	try to access more than one port of any multiport device right now)
+
+ (02/21/2000) gkh
+	Made it so that any serial devices only have to specify which functions
+	they want to overload from the generic function calls (great,
+	inheritance in C, in a driver, just what I wanted...)
+	Added support for set_termios and ioctl function calls. No drivers take
+	advantage of this yet.
+	Removed the #ifdef MODULE, now there is no module specific code.
+	Cleaned up a few comments in usb-serial.h that were wrong (thanks again
+	to Miles Lott).
+	Small fix to get_free_serial.
+
+ (02/14/2000) gkh
+	Removed the Belkin and Peracom functionality from the driver due to
+	the lack of support from the vendor, and me not wanting people to
+	accidenatly buy the device, expecting it to work with Linux.
+	Added read_bulk_callback and write_bulk_callback to the type structure
+	for the needs of the FTDI and WhiteHEAT driver.
+	Changed all reverences to FTDI to FTDI_SIO at the request of Bill
+	Ryder.
+	Changed the output urb size back to the max endpoint size to make
+	the ftdi_sio driver have it easier, and due to the fact that it didn't
+	really increase the speed any.
+
+ (02/11/2000) gkh
+	Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a
+	patch from Miles Lott (milos@insync.net).
+	Fixed bug with not restoring the minor range that a device grabs, if
+	the startup function fails (thanks Miles for finding this).
+
+ (02/05/2000) gkh
+	Added initial framework for the Keyspan PDA serial converter so that
+	Brian Warner has a place to put his code.
+	Made the ezusb specific functions generic enough that different
+	devices can use them (whiteheat and keyspan_pda both need them).
+	Split out a whole bunch of structure and other stuff to a separate
+	usb-serial.h file.
+	Made the Visor connection messages a little more understandable, now
+	that Miles Lott (milos@insync.net) has gotten the Generic channel to
+	work. Also made them always show up in the log file.
+
+ (01/25/2000) gkh
+	Added initial framework for FTDI serial converter so that Bill Ryder
+	has a place to put his code.
+	Added the vendor specific info from Handspring. Now we can print out
+	informational debug messages as well as understand what is happening.
+
+ (01/23/2000) gkh
+	Fixed problem of crash when trying to open a port that didn't have a
+	device assigned to it. Made the minor node finding a little smarter,
+	now it looks to find a continuous space for the new device.
+
+ (01/21/2000) gkh
+	Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net)
+	Fixed get_serial_by_minor which was all messed up for multi port
+	devices. Fixed multi port problem for generic devices. Now the number
+	of ports is determined by the number of bulk out endpoints for the
+	generic device.
+
+ (01/19/2000) gkh
+	Removed lots of cruft that was around from the old (pre urb) driver
+	interface.
+	Made the serial_table dynamic. This should save lots of memory when
+	the number of minor nodes goes up to 256.
+	Added initial support for devices that have more than one port.
+	Added more debugging comments for the Visor, and added a needed
+	set_configuration call.
+
+ (01/17/2000) gkh
+	Fixed the WhiteHEAT firmware (my processing tool had a bug)
+	and added new debug loader firmware for it.
+	Removed the put_char function as it isn't really needed.
+	Added visor startup commands as found by the Win98 dump.
+
+ (01/13/2000) gkh
+	Fixed the vendor id for the generic driver to the one I meant it to be.
+
+ (01/12/2000) gkh
+	Forget the version numbering...that's pretty useless...
+	Made the driver able to be compiled so that the user can select which
+	converter they want to use. This allows people who only want the Visor
+	support to not pay the memory size price of the WhiteHEAT.
+	Fixed bug where the generic driver (idVendor=0000 and idProduct=0000)
+	grabbed the root hub. Not good.
+
+ version 0.4.0 (01/10/2000) gkh
+	Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT
+	device. Added startup function to allow firmware to be downloaded to
+	a device if it needs to be.
+	Added firmware download logic to the WhiteHEAT device.
+	Started to add #defines to split up the different drivers for potential
+	configuration option.
+
+ version 0.3.1 (12/30/99) gkh
+      Fixed problems with urb for bulk out.
+      Added initial support for multiple sets of endpoints. This enables
+      the Handspring Visor to be attached successfully. Only the first
+      bulk in / bulk out endpoint pair is being used right now.
+
+ version 0.3.0 (12/27/99) gkh
+	Added initial support for the Handspring Visor based on a patch from
+	Miles Lott (milos@sneety.insync.net)
+	Cleaned up the code a bunch and converted over to using urbs only.
+
+ version 0.2.3 (12/21/99) gkh
+	Added initial support for the Connect Tech WhiteHEAT converter.
+	Incremented the number of ports in expectation of getting the
+	WhiteHEAT to work properly (4 ports per connection).
+	Added notification on insertion and removal of what port the
+	device is/was connected to (and what kind of device it was).
+
+ version 0.2.2 (12/16/99) gkh
+	Changed major number to the new allocated number. We're legal now!
+
+ version 0.2.1 (12/14/99) gkh
+	Fixed bug that happens when device node is opened when there isn't a
+	device attached to it. Thanks to marek@webdesign.no for noticing this.
+
+ version 0.2.0 (11/10/99) gkh
+	Split up internals to make it easier to add different types of serial
+	converters to the code.
+	Added a "generic" driver that gets it's vendor and product id
+	from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net)
+	for the idea and sample code (from the usb scanner driver.)
+	Cleared up any licensing questions by releasing it under the GNU GPL.
+
+ version 0.1.2 (10/25/99) gkh
+ 	Fixed bug in detecting device.
+
+ version 0.1.1 (10/05/99) gkh
+ 	Changed the major number to not conflict with anything else.
+
+ version 0.1 (09/28/99) gkh
+ 	Can recognize the two different devices and start up a read from
+	device when asked to. Writes also work. No control signals yet, this
+	all is vendor specific data (i.e. no spec), also no control for
+	different baud rates or other bit settings.
+	Currently we are using the same devid as the acm driver. This needs
+	to change.
+
+-----------------------------------------------------------------------
+visor.c Change Log comments:
+
+ (06/03/2003) Judd Montgomery <judd at jpilot.org>
+     Added support for module parameter options for untested/unknown
+     devices.
+
+ (03/09/2003) gkh
+	Added support for the Sony Clie NZ90V device.  Thanks to Martin Brachtl
+	<brachtl@redgrep.cz> for the information.
+
+ (03/05/2003) gkh
+	Think Treo support is now working.
+
+ (04/03/2002) gkh
+	Added support for the Sony OS 4.1 devices.  Thanks to Hiroyuki ARAKI
+	<hiro@zob.ne.jp> for the information.
+
+ (03/27/2002) gkh
+	Removed assumptions that port->tty was always valid (is not true
+	for usb serial console devices.)
+
+ (03/23/2002) gkh
+	Added support for the Palm i705 device, thanks to Thomas Riemer
+	<tom@netmech.com> for the information.
+
+ (03/21/2002) gkh
+	Added support for the Palm m130 device, thanks to Udo Eisenbarth
+	<udo.eisenbarth@web.de> for the information.
+
+ (02/27/2002) gkh
+	Reworked the urb handling logic.  We have no more pool, but dynamically
+	allocate the urb and the transfer buffer on the fly.  In testing this
+	does not incure any measurable overhead.  This also relies on the fact
+	that we have proper reference counting logic for urbs.
+
+ (02/21/2002) SilaS
+  Added initial support for the Palm m515 devices.
+
+ (02/14/2002) gkh
+	Added support for the Clie S-360 device.
+
+ (12/18/2001) gkh
+	Added better Clie support for 3.5 devices.  Thanks to Geoffrey Levand
+	for the patch.
+
+ (11/11/2001) gkh
+	Added support for the m125 devices, and added check to prevent oopses
+	for Clié devices that lie about the number of ports they have.
+
+ (08/30/2001) gkh
+	Added support for the Clie devices, both the 3.5 and 4.0 os versions.
+	Many thanks to Daniel Burke, and Bryan Payne for helping with this.
+
+ (08/23/2001) gkh
+	fixed a few potential bugs pointed out by Oliver Neukum.
+
+ (05/30/2001) gkh
+	switched from using spinlock to a semaphore, which fixes lots of problems.
+
+ (05/28/2000) gkh
+	Added initial support for the Palm m500 and Palm m505 devices.
+
+ (04/08/2001) gb
+	Identify version on module load.
+
+ (01/21/2000) gkh
+	Added write_room and chars_in_buffer, as they were previously using the
+	generic driver versions which is all wrong now that we are using an urb
+	pool.  Thanks to Wolfgang Grandegger for pointing this out to me.
+	Removed count assignment in the write function, which was not needed anymore
+	either.  Thanks to Al Borchers for pointing this out.
+
+ (12/12/2000) gkh
+	Moved MOD_DEC to end of visor_close to be nicer, as the final write
+	message can sleep.
+
+ (11/12/2000) gkh
+	Fixed bug with data being dropped on the floor by forcing tty->low_latency
+	to be on.  Hopefully this fixes the OHCI issue!
+
+ (11/01/2000) Adam J. Richter
+	usb_device_id table support
+
+ (10/05/2000) gkh
+	Fixed bug with urb->dev not being set properly, now that the usb
+	core needs it.
+
+ (09/11/2000) gkh
+	Got rid of always calling kmalloc for every urb we wrote out to the
+	device.
+	Added visor_read_callback so we can keep track of bytes in and out for
+	those people who like to know the speed of their device.
+	Removed DEBUG #ifdefs with call to usb_serial_debug_data
+
+ (09/06/2000) gkh
+	Fixed oops in visor_exit.  Need to uncomment usb_unlink_urb call _after_
+	the host controller drivers set urb->dev = NULL when the urb is finished.
+
+ (08/28/2000) gkh
+	Added locks for SMP safeness.
+
+ (08/08/2000) gkh
+	Fixed endian problem in visor_startup.
+	Fixed MOD_INC and MOD_DEC logic and the ability to open a port more
+	than once.
+
+ (07/23/2000) gkh
+	Added pool of write urbs to speed up transfers to the visor.
+
+ (07/19/2000) gkh
+	Added module_init and module_exit functions to handle the fact that this
+	driver is a loadable module now.
+
+ (07/03/2000) gkh
+	Added visor_set_ioctl and visor_set_termios functions (they don't do much
+	of anything, but are good for debugging.)
+
+ (06/25/2000) gkh
+	Fixed bug in visor_unthrottle that should help with the disconnect in PPP
+	bug that people have been reporting.
+
+ (06/23/2000) gkh
+	Cleaned up debugging statements in a quest to find UHCI timeout bug.
+
+ (04/27/2000) Ryan VanderBijl
+ 	Fixed memory leak in visor_close
+
+ (03/26/2000) gkh
+	Split driver up into device specific pieces.
+
+-----------------------------------------------------------------------
+pl2303.c Change Log comments:
+
+ 2002_Mar_26 gkh
+	allowed driver to work properly if there is no tty assigned to a port
+	(this happens for serial console devices.)
+
+ 2001_Oct_06 gkh
+	Added RTS and DTR line control.  Thanks to joe@bndlg.de for parts of it.
+
+ 2001_Sep_19 gkh
+	Added break support.
+
+ 2001_Aug_30 gkh
+	fixed oops in write_bulk_callback.
+
+ 2001_Aug_28 gkh
+	reworked buffer logic to be like other usb-serial drivers.  Hopefully
+	removing some reported problems.
+
+ 2001_Jun_06 gkh
+	finished porting to 2.4 format.
+
+
+-----------------------------------------------------------------------
+io_edgeport.c Change Log comments:
+
+ 2003_04_03 al borchers
+  - fixed a bug (that shows up with dosemu) where the tty struct is
+    used in a callback after it has been freed
+
+ 2.3 2002_03_08 greg kroah-hartman
+	- fixed bug when multiple devices were attached at the same time.
+
+ 2.2 2001_11_14 greg kroah-hartman
+	- fixed bug in edge_close that kept the port from being used more
+	  than once.
+	- fixed memory leak on device removal.
+	- fixed potential double free of memory when command urb submitting
+	  failed.
+	- other small cleanups when the device is removed
+
+ 2.1 2001_07_09 greg kroah-hartman
+	- added support for TIOCMBIS and TIOCMBIC.
+
+     (04/08/2001) gb
+	- Identify version on module load.
+
+ 2.0 2001_03_05 greg kroah-hartman
+	- reworked entire driver to fit properly in with the other usb-serial
+	  drivers.  Occasional oopses still happen, but it's a good start.
+
+ 1.2.3 (02/23/2001) greg kroah-hartman
+	- changed device table to work properly for 2.4.x final format.
+	- fixed problem with dropping data at high data rates.
+
+ 1.2.2 (11/27/2000) greg kroah-hartman
+	- cleaned up more NTisms.
+	- Added device table for 2.4.0-test11
+
+ 1.2.1 (11/08/2000) greg kroah-hartman
+	- Started to clean up NTisms.
+	- Fixed problem with dev field of urb for kernels >= 2.4.0-test9
+
+ 1.2 (10/17/2000) David Iacovelli
+ 	Remove all EPIC code and GPL source
+  Fix RELEVANT_IFLAG macro to include flow control
+  changes port configuration changes.
+  Fix redefinition of SERIAL_MAGIC
+  Change all timeout values to 5 seconds
+  Tried to fix the UHCI multiple urb submission, but failed miserably.
+  it seems to work fine with OHCI.
+  ( Greg take a look at the #if 0 at end of WriteCmdUsb() we must
+    find a way to work arount this UHCI bug )
+
+ 1.1 (10/11/2000) David Iacovelli
+  Fix XON/XOFF flow control to support both IXON and IXOFF
+
+ 0.9.27 (06/30/2000) David Iacovelli
+  Added transmit queue and now allocate urb for command writes.
+
+ 0.9.26 (06/29/2000) David Iacovelli
+  Add support for 80251 based edgeport
+
+ 0.9.25 (06/27/2000) David Iacovelli
+  Do not close the port if it has multiple opens.
+
+ 0.9.24 (05/26/2000) David Iacovelli
+  Add IOCTLs to support RXTX and JAVA POS
+  and first cut at running BlackBox Demo
+
+ 0.9.23 (05/24/2000) David Iacovelli
+  Add IOCTLs to support RXTX and JAVA POS
+
+ 0.9.22 (05/23/2000) David Iacovelli
+  fixed bug in enumeration.  If epconfig turns on mapping by
+  path after a device is already plugged in, we now update
+  the mapping correctly
+
+ 0.9.21 (05/16/2000) David Iacovelli
+  Added BlockUntilChaseResp() to also wait for txcredits
+  Updated the way we allocate and handle write URBs
+	Add debug code to dump buffers
+
+ 0.9.20 (05/01/2000) David Iacovelli
+	change driver to use usb/tts/
+
+ 0.9.19 (05/01/2000) David Iacovelli
+  Update code to compile if DEBUG is off
+
+ 0.9.18 (04/28/2000) David Iacovelli
+  cleanup and test tty_register with devfs
+
+ 0.9.17 (04/27/2000) greg kroah-hartman
+ 	changed tty_register around to be like the way it
+ 	was before, but now it works properly with devfs.
+
+ 0.9.16 (04/26/2000) david iacovelli
+  Fixed bug in GetProductInfo()
+
+ 0.9.15 (04/25/2000) david iacovelli
+	Updated enumeration
+
+ 0.9.14 (04/24/2000) david iacovelli
+  Removed all config/status IOCTLS and
+  converted to using /proc/edgeport
+  still playing with devfs
+
+ 0.9.13 (04/24/2000) david iacovelli
+  Removed configuration based on ttyUSB0
+  Added support for configuration using /prod/edgeport
+  first attempt at using devfs (not working yet!)
+  Added IOCTL to GetProductInfo()
+  Added support for custom baud rates
+	Add support for random port numbers
+
+ 0.9.12 (04/18/2000) david iacovelli
+	added additional configuration IOCTLs
+  use ttyUSB0 for configuration
+
+ 0.9.11 (04/17/2000) greg kroah-hartman
+	fixed module initialization race conditions.
+	made all urbs dynamically allocated.
+	made driver devfs compatible. now it only registers the tty device
+	when the device is actually plugged in.
+
+ 0.9.10 (04/13/2000) greg kroah-hartman
+	added proc interface framework.
+
+ 0.9.9 (04/13/2000) david iacovelli
+	added enumeration code and ioctls to configure the device
+
+ 0.9.8 (04/12/2000) david iacovelli
+  Change interrupt read start when device is plugged in
+  and stop when device is removed
+	process interrupt reads when all ports are closed
+  (keep value of rxBytesAvail consistent with the edgeport)
+  set the USB_BULK_QUEUE flag so that we can shove a bunch
+  of urbs at once down the pipe
+
+ 0.9.7 (04/10/2000) david iacovelli
+ 	start to add enumeration code.
+  generate serial number for epic devices
+  add support for kdb
+
+ 0.9.6 (03/30/2000) david iacovelli
+  add IOCTL to get string, manufacture, and boot descriptors
+
+ 0.9.5 (03/14/2000) greg kroah-hartman
+	more error checking added to SerialOpen to try to fix UHCI open problem
+
+ 0.9.4 (03/09/2000) greg kroah-hartman
+	added more error checking to handle oops when data is hanging
+	around and tty is abruptly closed.
+
+ 0.9.3 (03/09/2000) david iacovelli
+	Add epic support for xon/xoff chars
+	play with performance
+
+ 0.9.2 (03/08/2000) greg kroah-hartman
+	changed most "info" calls to "dbg"
+	implemented flow control properly in the termios call
+
+ 0.9.1 (03/08/2000) david iacovelli
+	added EPIC support
+	enabled bootloader update
+
+ 0.9 (03/08/2000) greg kroah-hartman
+	Release to IO networks.
+	Integrated changes that David made
+  made getting urbs for writing SMP safe
+
+ 0.8 (03/07/2000) greg kroah-hartman
+	Release to IO networks.
+	Fixed problems that were seen in code by David.
+  Now both Edgeport/4 and Edgeport/2 works properly.
+  Changed most of the functions to use port instead of serial.
+
+ 0.7 (02/27/2000) greg kroah-hartman
+	Milestone 3 release.
+	Release to IO Networks
+	ioctl for waiting on line change implemented.
+	ioctl for getting statistics implemented.
+	multiport support working.
+	lsr and msr registers are now handled properly.
+	change break now hooked up and working.
+	support for all known Edgeport devices.
+
+ 0.6 (02/22/2000) greg kroah-hartman
+	Release to IO networks.
+	CHASE is implemented correctly when port is closed.
+	SerialOpen now blocks correctly until port is fully opened.
+
+ 0.5 (02/20/2000) greg kroah-hartman
+	Release to IO networks.
+	Known problems:
+		modem status register changes are not sent on to the user
+		CHASE is not implemented when the port is closed.
+
+ 0.4 (02/16/2000) greg kroah-hartman
+	Second cut at the CeBit demo.
+	Doesn't leak memory on every write to the port
+	Still small leaks on startup.
+	Added support for Edgeport/2 and Edgeport/8
+
+ 0.3 (02/15/2000) greg kroah-hartman
+	CeBit demo release.
+	Force the line settings to 4800, 8, 1, e for the demo.
+	Warning! This version leaks memory like crazy!
+
+ 0.2 (01/30/2000) greg kroah-hartman
+	Milestone 1 release.
+	Device is found by USB subsystem, enumerated, fimware is downloaded
+	and the descriptors are printed to the debug log, config is set, and
+	green light starts to blink. Open port works, and data can be sent
+	and received at the default settings of the UART. Loopback connector
+	and debug log confirms this.
+
+ 0.1 (01/23/2000) greg kroah-hartman
+	Initial release to help IO Networks try to set up their test system.
+	Edgeport4 is recognized, firmware is downloaded, config is set so
+	device blinks green light every 3 sec. Port is bound, but opening,
+	closing, and sending data do not work properly.
+
+
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 9438909..7b5e8e4 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -394,6 +394,15 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called mct_u232.
 
+config USB_SERIAL_NOKIA_DKU2
+	tristate "USB Nokia DKU2 Driver"
+	depends on USB_SERIAL
+	help
+	  Say Y here if you want to use a Nokia DKU2 device.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called nokia_dku2.
+
 config USB_SERIAL_PL2303
 	tristate "USB Prolific 2303 Single Port Serial Driver"
 	depends on USB_SERIAL
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 6c7cdcc..55fd461 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -31,6 +31,7 @@
 obj-$(CONFIG_USB_SERIAL_KLSI)			+= kl5kusb105.o
 obj-$(CONFIG_USB_SERIAL_KOBIL_SCT)		+= kobil_sct.o
 obj-$(CONFIG_USB_SERIAL_MCT_U232)		+= mct_u232.o
+obj-$(CONFIG_USB_SERIAL_NOKIA_DKU2)		+= nokia_dku2.o
 obj-$(CONFIG_USB_SERIAL_OMNINET)		+= omninet.o
 obj-$(CONFIG_USB_SERIAL_OPTION)			+= option.o
 obj-$(CONFIG_USB_SERIAL_PL2303)			+= pl2303.o
diff --git a/drivers/usb/serial/airprime.c b/drivers/usb/serial/airprime.c
index 926d4c2..1f29d88 100644
--- a/drivers/usb/serial/airprime.c
+++ b/drivers/usb/serial/airprime.c
@@ -30,9 +30,11 @@
 	.id_table =	id_table,
 };
 
-static struct usb_serial_device_type airprime_device = {
-	.owner =		THIS_MODULE,
-	.name =			"airprime",
+static struct usb_serial_driver airprime_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"airprime",
+	},
 	.id_table =		id_table,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index abb1b2c..84bc0ee 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -121,10 +121,12 @@
 };
 
 /* All of the device info needed for the serial converters */
-static struct usb_serial_device_type belkin_device = {
-	.owner =		THIS_MODULE,
-	.name =			"Belkin / Peracom / GoHubs USB Serial Adapter",
-	.short_name =		"belkin",
+static struct usb_serial_driver belkin_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"belkin",
+	},
+	.description =		"Belkin / Peracom / GoHubs USB Serial Adapter",
 	.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 2f612c2..664139a 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -18,7 +18,7 @@
 
 static int usb_serial_device_match (struct device *dev, struct device_driver *drv)
 {
-	struct usb_serial_device_type *driver;
+	struct usb_serial_driver *driver;
 	const struct usb_serial_port *port;
 
 	/*
@@ -44,7 +44,7 @@
 
 static int usb_serial_device_probe (struct device *dev)
 {
-	struct usb_serial_device_type *driver;
+	struct usb_serial_driver *driver;
 	struct usb_serial_port *port;
 	int retval = 0;
 	int minor;
@@ -57,13 +57,13 @@
 
 	driver = port->serial->type;
 	if (driver->port_probe) {
-		if (!try_module_get(driver->owner)) {
+		if (!try_module_get(driver->driver.owner)) {
 			dev_err(dev, "module get failed, exiting\n");
 			retval = -EIO;
 			goto exit;
 		}
 		retval = driver->port_probe (port);
-		module_put(driver->owner);
+		module_put(driver->driver.owner);
 		if (retval)
 			goto exit;
 	}
@@ -72,7 +72,7 @@
 	tty_register_device (usb_serial_tty_driver, minor, dev);
 	dev_info(&port->serial->dev->dev, 
 		 "%s converter now attached to ttyUSB%d\n",
-		 driver->name, minor);
+		 driver->description, minor);
 
 exit:
 	return retval;
@@ -80,7 +80,7 @@
 
 static int usb_serial_device_remove (struct device *dev)
 {
-	struct usb_serial_device_type *driver;
+	struct usb_serial_driver *driver;
 	struct usb_serial_port *port;
 	int retval = 0;
 	int minor;
@@ -92,43 +92,38 @@
 
 	driver = port->serial->type;
 	if (driver->port_remove) {
-		if (!try_module_get(driver->owner)) {
+		if (!try_module_get(driver->driver.owner)) {
 			dev_err(dev, "module get failed, exiting\n");
 			retval = -EIO;
 			goto exit;
 		}
 		retval = driver->port_remove (port);
-		module_put(driver->owner);
+		module_put(driver->driver.owner);
 	}
 exit:
 	minor = port->number;
 	tty_unregister_device (usb_serial_tty_driver, minor);
 	dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",
-		 driver->name, minor);
+		 driver->description, minor);
 
 	return retval;
 }
 
-int usb_serial_bus_register(struct usb_serial_device_type *device)
+int usb_serial_bus_register(struct usb_serial_driver *driver)
 {
 	int retval;
 
-	if (device->short_name)
-		device->driver.name = (char *)device->short_name;
-	else
-		device->driver.name = (char *)device->name;
-	device->driver.bus = &usb_serial_bus_type;
-	device->driver.probe = usb_serial_device_probe;
-	device->driver.remove = usb_serial_device_remove;
-	device->driver.owner = device->owner;
+	driver->driver.bus = &usb_serial_bus_type;
+	driver->driver.probe = usb_serial_device_probe;
+	driver->driver.remove = usb_serial_device_remove;
 
-	retval = driver_register(&device->driver);
+	retval = driver_register(&driver->driver);
 
 	return retval;
 }
 
-void usb_serial_bus_deregister(struct usb_serial_device_type *device)
+void usb_serial_bus_deregister(struct usb_serial_driver *driver)
 {
-	driver_unregister (&device->driver);
+	driver_unregister(&driver->driver);
 }
 
diff --git a/drivers/usb/serial/cp2101.c b/drivers/usb/serial/cp2101.c
index 97c78c2..c5334dd 100644
--- a/drivers/usb/serial/cp2101.c
+++ b/drivers/usb/serial/cp2101.c
@@ -67,15 +67,17 @@
 
 static struct usb_driver cp2101_driver = {
 	.owner		= THIS_MODULE,
-	.name		= "CP2101",
+	.name		= "cp2101",
 	.probe		= usb_serial_probe,
 	.disconnect	= usb_serial_disconnect,
 	.id_table	= id_table,
 };
 
-static struct usb_serial_device_type cp2101_device = {
-	.owner			= THIS_MODULE,
-	.name			= "CP2101",
+static struct usb_serial_driver cp2101_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name = 	"cp2101",
+	},
 	.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 b5b4310..e581e4a 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -83,10 +83,12 @@
 	.id_table =	id_table,
 };
 
-static struct usb_serial_device_type cyberjack_device = {
-	.owner =		THIS_MODULE,
-	.name =			"Reiner SCT Cyberjack USB card reader",
-	.short_name =		"cyberjack",
+static struct usb_serial_driver cyberjack_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"cyberjack",
+	},
+	.description =		"Reiner SCT Cyberjack USB card reader",
 	.id_table =		id_table,
 	.num_interrupt_in =	1,
 	.num_bulk_in =		1,
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 9ee1aaf..af9290e 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -176,10 +176,12 @@
 static unsigned int	  cypress_buf_get(struct cypress_buf *cb, char *buf, unsigned int count);
 
 
-static struct usb_serial_device_type cypress_earthmate_device = {
-	.owner =			THIS_MODULE,
-	.name =				"DeLorme Earthmate USB",
-	.short_name =			"earthmate",
+static struct usb_serial_driver cypress_earthmate_device = {
+	.driver = {
+		.owner =		THIS_MODULE,
+		.name =			"earthmate",
+	},
+	.description =			"DeLorme Earthmate USB",
 	.id_table =			id_table_earthmate,
 	.num_interrupt_in = 		1,
 	.num_interrupt_out =		1,
@@ -203,10 +205,12 @@
 	.write_int_callback =		cypress_write_int_callback,
 };
 
-static struct usb_serial_device_type cypress_hidcom_device = {
-	.owner =			THIS_MODULE,
-	.name =				"HID->COM RS232 Adapter",
-	.short_name =			"cyphidcom",
+static struct usb_serial_driver cypress_hidcom_device = {
+	.driver = {
+		.owner =		THIS_MODULE,
+		.name =			"cyphidcom",
+	},
+	.description =			"HID->COM RS232 Adapter",
 	.id_table =			id_table_cyphidcomrs232,
 	.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 a19a47f..dc74644 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -503,10 +503,12 @@
 
 /* device info needed for the Digi serial converter */
 
-static struct usb_serial_device_type digi_acceleport_2_device = {
-	.owner =			THIS_MODULE,
-	.name =				"Digi 2 port USB adapter",
-	.short_name =			"digi_2",
+static struct usb_serial_driver digi_acceleport_2_device = {
+	.driver = {
+		.owner =		THIS_MODULE,
+		.name =			"digi_2",
+	},
+	.description =			"Digi 2 port USB adapter",
 	.id_table =			id_table_2,
 	.num_interrupt_in =		0,
 	.num_bulk_in =			4,
@@ -530,10 +532,12 @@
 	.shutdown =			digi_shutdown,
 };
 
-static struct usb_serial_device_type digi_acceleport_4_device = {
-	.owner =			THIS_MODULE,
-	.name =				"Digi 4 port USB adapter",
-	.short_name =			"digi_4",
+static struct usb_serial_driver digi_acceleport_4_device = {
+	.driver = {
+		.owner =		THIS_MODULE,
+		.name =			"digi_4",
+	},
+	.description =			"Digi 4 port USB adapter",
 	.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 8d562ab..0b0546d 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -112,9 +112,11 @@
 	.id_table =	id_table,
 };
 
-static struct usb_serial_device_type empeg_device = {
-	.owner =		THIS_MODULE,
-	.name =			"Empeg",
+static struct usb_serial_driver empeg_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"empeg",
+	},
 	.id_table =		id_table,
 	.num_interrupt_in =	0,
 	.num_bulk_in =		1,
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index 5a8631c..61204bf 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -411,6 +411,8 @@
 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UM100_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_UR100_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_ELV_ALC8500_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_PYRAMID_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1000PC_PID) },
 	/*
 	 * These will probably use user-space drivers.  Uncomment them if
 	 * you need them or use the user-specified vendor/product module
@@ -428,7 +430,6 @@
 	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_T1100_PID) }, */
 	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCD200_PID) }, */
 	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_ULA200_PID) }, */
-	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_FHZ1000PC_PID) }, */
 	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_CSI8_PID) }, */
 	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_EM1000DL_PID) }, */
 	/* { USB_DEVICE(FTDI_VID, FTDI_ELV_PCK100_PID) }, */
@@ -471,6 +472,9 @@
 	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_Y6_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_MHAM_Y8_PID) },
 	{ USB_DEVICE(EVOLUTION_VID, EVOLUTION_ER1_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_ARTEMIS_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16_PID) },
+	{ USB_DEVICE(FTDI_VID, FTDI_ATIK_ATK16HR_PID) },
 	{ },					/* Optional parameter entry */
 	{ }					/* Terminating entry */
 };
@@ -558,10 +562,12 @@
 static __u32 ftdi_232bm_baud_base_to_divisor (int baud, int base);
 static __u32 ftdi_232bm_baud_to_divisor (int baud);
 
-static struct usb_serial_device_type ftdi_sio_device = {
-	.owner =		THIS_MODULE,
-	.name =			"FTDI USB Serial Device",
-	.short_name =		"ftdi_sio",
+static struct usb_serial_driver ftdi_sio_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"ftdi_sio",
+	},
+	.description =		"FTDI USB Serial Device",
 	.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 2c35d74..ddb63df 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -199,6 +199,19 @@
 #define FTDI_PIEGROUP_PID	0xF208	/* Product Id */
 
 /*
+ * Definitions for Artemis astronomical USB based cameras
+ * Check it at http://www.artemisccd.co.uk/
+ */
+#define FTDI_ARTEMIS_PID	0xDF28	/* All Artemis Cameras */
+
+/*
+ * Definitions for ATIK Instruments astronomical USB based cameras
+ * Check it at http://www.atik-instruments.com/
+ */
+#define FTDI_ATIK_ATK16_PID	0xDF30	/* ATIK ATK-16 Camera */
+#define FTDI_ATIK_ATK16HR_PID	0xDF31	/* ATIK ATK-16HR Camera */
+
+/*
  * Protego product ids
  */
 #define PROTEGO_SPECIAL_1	0xFC70	/* special/unknown device */
@@ -329,6 +342,9 @@
 #define EVOLUTION_VID		0xDEEE	/* Vendor ID */
 #define EVOLUTION_ER1_PID	0x0300	/* ER1 Control Module */
 
+/* Pyramid Computer GmbH */
+#define FTDI_PYRAMID_PID	0xE6C8	/* Pyramid Appliance Display */
+
 /* Commands */
 #define FTDI_SIO_RESET 		0 /* Reset the port */
 #define FTDI_SIO_MODEM_CTRL 	1 /* Set the modem control register */
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 2ef614d..35820bd 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -1468,16 +1468,13 @@
 }
 
 
-
-
-
-
-
 /* All of the device info needed */
-static struct usb_serial_device_type garmin_device = {
-	.owner               = THIS_MODULE,
-	.name                = "Garmin GPS usb/tty",
-	.short_name          = "garmin_gps",
+static struct usb_serial_driver garmin_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"garmin_gps",
+	},
+	.description =		"Garmin GPS usb/tty",
 	.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 5f7d319..8909208 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -36,10 +36,11 @@
 static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */
 
 /* All of the device info needed for the Generic Serial Converter */
-struct usb_serial_device_type usb_serial_generic_device = {
-	.owner =		THIS_MODULE,
-	.name =			"Generic",
-	.short_name =		"generic",
+struct usb_serial_driver usb_serial_generic_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"generic",
+	},
 	.id_table =		generic_device_ids,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
index 64d55fb..8eadfb7 100644
--- a/drivers/usb/serial/hp4x.c
+++ b/drivers/usb/serial/hp4x.c
@@ -38,15 +38,17 @@
 
 static struct usb_driver hp49gp_driver = {
 	.owner =	THIS_MODULE,
-	.name =		"HP4X",
+	.name =		"hp4X",
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
 };
 
-static struct usb_serial_device_type hp49gp_device = {
-	.owner =		THIS_MODULE,
-	.name =			"HP4X",
+static struct usb_serial_driver hp49gp_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"hp4X",
+	},
 	.id_table =		id_table,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 04bfe27..dc4c498 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -27,225 +27,6 @@
  * Networks technical support, or Peter Berger <pberger@brimson.com>,
  * or Al Borchers <alborchers@steinerpoint.com>.
  *
- * Version history:
- * 
- * 2003_04_03 al borchers
- *  - fixed a bug (that shows up with dosemu) where the tty struct is
- *    used in a callback after it has been freed
- *
- * 2.3 2002_03_08 greg kroah-hartman
- *	- fixed bug when multiple devices were attached at the same time.
- *
- * 2.2 2001_11_14 greg kroah-hartman
- *	- fixed bug in edge_close that kept the port from being used more
- *	  than once.
- *	- fixed memory leak on device removal.
- *	- fixed potential double free of memory when command urb submitting
- *	  failed.
- *	- other small cleanups when the device is removed
- *	
- * 2.1 2001_07_09 greg kroah-hartman
- *	- added support for TIOCMBIS and TIOCMBIC.
- *
- *     (04/08/2001) gb
- *	- Identify version on module load.
- *
- * 2.0 2001_03_05 greg kroah-hartman
- *	- reworked entire driver to fit properly in with the other usb-serial
- *	  drivers.  Occasional oopses still happen, but it's a good start.
- *
- * 1.2.3 (02/23/2001) greg kroah-hartman
- *	- changed device table to work properly for 2.4.x final format.
- *	- fixed problem with dropping data at high data rates.
- *
- * 1.2.2 (11/27/2000) greg kroah-hartman
- *	- cleaned up more NTisms.
- *	- Added device table for 2.4.0-test11
- *
- * 1.2.1 (11/08/2000) greg kroah-hartman
- *	- Started to clean up NTisms.
- *	- Fixed problem with dev field of urb for kernels >= 2.4.0-test9
- *
- * 1.2 (10/17/2000) David Iacovelli
- * 	Remove all EPIC code and GPL source
- *  Fix RELEVANT_IFLAG macro to include flow control 
- *  changes port configuration changes.
- *  Fix redefinition of SERIAL_MAGIC
- *  Change all timeout values to 5 seconds
- *  Tried to fix the UHCI multiple urb submission, but failed miserably.
- *  it seems to work fine with OHCI.
- *  ( Greg take a look at the #if 0 at end of WriteCmdUsb() we must 
- *    find a way to work arount this UHCI bug )
- *
- * 1.1 (10/11/2000) David Iacovelli
- *  Fix XON/XOFF flow control to support both IXON and IXOFF
- *
- * 0.9.27 (06/30/2000) David Iacovelli
- *  Added transmit queue and now allocate urb for command writes.
- *
- * 0.9.26 (06/29/2000) David Iacovelli
- *  Add support for 80251 based edgeport
- *
- * 0.9.25 (06/27/2000) David Iacovelli
- *  Do not close the port if it has multiple opens.
- *
- * 0.9.24 (05/26/2000) David Iacovelli
- *  Add IOCTLs to support RXTX and JAVA POS 
- *  and first cut at running BlackBox Demo
- *
- * 0.9.23 (05/24/2000) David Iacovelli
- *  Add IOCTLs to support RXTX and JAVA POS
- *
- * 0.9.22 (05/23/2000) David Iacovelli
- *  fixed bug in enumeration.  If epconfig turns on mapping by
- *  path after a device is already plugged in, we now update
- *  the mapping correctly
- *
- * 0.9.21 (05/16/2000) David Iacovelli
- *  Added BlockUntilChaseResp() to also wait for txcredits
- *  Updated the way we allocate and handle write URBs 
- *	Add debug code to dump buffers
- *
- * 0.9.20 (05/01/2000) David Iacovelli
- *	change driver to use usb/tts/
- *
- * 0.9.19 (05/01/2000) David Iacovelli
- *  Update code to compile if DEBUG is off
- *
- * 0.9.18 (04/28/2000) David Iacovelli
- *  cleanup and test tty_register with devfs
- *
- * 0.9.17 (04/27/2000) greg kroah-hartman
- * 	changed tty_register around to be like the way it
- * 	was before, but now it works properly with devfs.
- *
- * 0.9.16 (04/26/2000) david iacovelli
- *  Fixed bug in GetProductInfo()
- *
- * 0.9.15 (04/25/2000) david iacovelli
- *	Updated enumeration
- *
- * 0.9.14 (04/24/2000) david iacovelli
- *  Removed all config/status IOCTLS and 
- *  converted to using /proc/edgeport
- *  still playing with devfs
- *
- * 0.9.13 (04/24/2000) david iacovelli
- *  Removed configuration based on ttyUSB0
- *  Added support for configuration using /prod/edgeport
- *  first attempt at using devfs (not working yet!)
- *  Added IOCTL to GetProductInfo()
- *  Added support for custom baud rates
- *	Add support for random port numbers
- *
- * 0.9.12 (04/18/2000) david iacovelli
- *	added additional configuration IOCTLs
- *  use ttyUSB0 for configuration
- *
- * 0.9.11 (04/17/2000) greg kroah-hartman
- *	fixed module initialization race conditions.
- *	made all urbs dynamically allocated.
- *	made driver devfs compatible. now it only registers the tty device
- *	when the device is actually plugged in.
- *
- * 0.9.10 (04/13/2000) greg kroah-hartman
- *	added proc interface framework.
- *
- * 0.9.9 (04/13/2000) david iacovelli
- *	added enumeration code and ioctls to configure the device
- *
- * 0.9.8 (04/12/2000) david iacovelli
- *  Change interrupt read start when device is plugged in
- *  and stop when device is removed
- *	process interrupt reads when all ports are closed 
- *  (keep value of rxBytesAvail consistent with the edgeport)
- *  set the USB_BULK_QUEUE flag so that we can shove a bunch 
- *  of urbs at once down the pipe 
- *
- * 0.9.7 (04/10/2000) david iacovelli
- * 	start to add enumeration code.
- *  generate serial number for epic devices
- *  add support for kdb
- *
- * 0.9.6 (03/30/2000) david iacovelli
- *  add IOCTL to get string, manufacture, and boot descriptors
- *
- * 0.9.5 (03/14/2000) greg kroah-hartman
- *	more error checking added to SerialOpen to try to fix UHCI open problem
- *
- * 0.9.4 (03/09/2000) greg kroah-hartman
- *	added more error checking to handle oops when data is hanging
- *	around and tty is abruptly closed.
- *
- * 0.9.3 (03/09/2000) david iacovelli
- *	Add epic support for xon/xoff chars
- *	play with performance
- *
- * 0.9.2 (03/08/2000) greg kroah-hartman
- *	changed most "info" calls to "dbg"
- *	implemented flow control properly in the termios call
- *
- * 0.9.1 (03/08/2000) david iacovelli
- *	added EPIC support
- *	enabled bootloader update
- *
- * 0.9 (03/08/2000) greg kroah-hartman
- *	Release to IO networks.
- *	Integrated changes that David made
- *  made getting urbs for writing SMP safe
- *
- * 0.8 (03/07/2000) greg kroah-hartman
- *	Release to IO networks.
- *	Fixed problems that were seen in code by David.
- *  Now both Edgeport/4 and Edgeport/2 works properly.
- *  Changed most of the functions to use port instead of serial.
- *
- * 0.7 (02/27/2000) greg kroah-hartman
- *	Milestone 3 release.
- *	Release to IO Networks
- *	ioctl for waiting on line change implemented.
- *	ioctl for getting statistics implemented.
- *	multiport support working.
- *	lsr and msr registers are now handled properly.
- *	change break now hooked up and working.
- *	support for all known Edgeport devices.
- *
- * 0.6 (02/22/2000) greg kroah-hartman
- *	Release to IO networks.
- *	CHASE is implemented correctly when port is closed.
- *	SerialOpen now blocks correctly until port is fully opened.
- *
- * 0.5 (02/20/2000) greg kroah-hartman
- *	Release to IO networks.
- *	Known problems:
- *		modem status register changes are not sent on to the user
- *		CHASE is not implemented when the port is closed.
- *
- * 0.4 (02/16/2000) greg kroah-hartman
- *	Second cut at the CeBit demo.
- *	Doesn't leak memory on every write to the port
- *	Still small leaks on startup.
- *	Added support for Edgeport/2 and Edgeport/8
- *
- * 0.3 (02/15/2000) greg kroah-hartman
- *	CeBit demo release.
- *	Force the line settings to 4800, 8, 1, e for the demo.
- *	Warning! This version leaks memory like crazy!
- *
- * 0.2 (01/30/2000) greg kroah-hartman
- *	Milestone 1 release.
- *	Device is found by USB subsystem, enumerated, fimware is downloaded
- *	and the descriptors are printed to the debug log, config is set, and
- *	green light starts to blink. Open port works, and data can be sent
- *	and received at the default settings of the UART. Loopback connector
- *	and debug log confirms this.
- * 
- * 0.1 (01/23/2000) greg kroah-hartman
- *	Initial release to help IO Networks try to set up their test system. 
- *	Edgeport4 is recognized, firmware is downloaded, config is set so 
- *	device blinks green light every 3 sec. Port is bound, but opening,
- *	closing, and sending data do not work properly.
- * 
  */
 
 #include <linux/config.h>
diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h
index e7ffe02..fad561c 100644
--- a/drivers/usb/serial/io_tables.h
+++ b/drivers/usb/serial/io_tables.h
@@ -75,10 +75,12 @@
 
 MODULE_DEVICE_TABLE (usb, id_table_combined);
 
-static struct usb_serial_device_type edgeport_2port_device = {
-	.owner			= THIS_MODULE,
-	.name			= "Edgeport 2 port adapter",
-	.short_name		= "edgeport_2",
+static struct usb_serial_driver edgeport_2port_device = {
+	.driver = {
+		.owner		= THIS_MODULE,
+		.name		= "edgeport_2",
+	},
+	.description		= "Edgeport 2 port adapter",
 	.id_table		= edgeport_2port_id_table,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 1,
@@ -103,10 +105,12 @@
 	.write_bulk_callback	= edge_bulk_out_data_callback,
 };
 
-static struct usb_serial_device_type edgeport_4port_device = {
-	.owner			= THIS_MODULE,
-	.name			= "Edgeport 4 port adapter",
-	.short_name		= "edgeport_4",
+static struct usb_serial_driver edgeport_4port_device = {
+	.driver = {
+		.owner		= THIS_MODULE,
+		.name		= "edgeport_4",
+	},
+	.description		= "Edgeport 4 port adapter",
 	.id_table		= edgeport_4port_id_table,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 1,
@@ -131,10 +135,12 @@
 	.write_bulk_callback	= edge_bulk_out_data_callback,
 };
 
-static struct usb_serial_device_type edgeport_8port_device = {
-	.owner			= THIS_MODULE,
-	.name			= "Edgeport 8 port adapter",
-	.short_name		= "edgeport_8",
+static struct usb_serial_driver edgeport_8port_device = {
+	.driver = {
+		.owner		= THIS_MODULE,
+		.name		= "edgeport_8",
+	},
+	.description		= "Edgeport 8 port adapter",
 	.id_table		= edgeport_8port_id_table,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 1,
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index ebf9967..832b6d6 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -2982,10 +2982,12 @@
 }
 
 
-static struct usb_serial_device_type edgeport_1port_device = {
-	.owner			= THIS_MODULE,
-	.name			= "Edgeport TI 1 port adapter",
-	.short_name		= "edgeport_ti_1",
+static struct usb_serial_driver edgeport_1port_device = {
+	.driver = {
+		.owner		= THIS_MODULE,
+		.name		= "edgeport_ti_1",
+	},
+	.description		= "Edgeport TI 1 port adapter",
 	.id_table		= edgeport_1port_id_table,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 1,
@@ -3010,10 +3012,12 @@
 	.write_bulk_callback	= edge_bulk_out_callback,
 };
 
-static struct usb_serial_device_type edgeport_2port_device = {
-	.owner			= THIS_MODULE,
-	.name			= "Edgeport TI 2 port adapter",
-	.short_name		= "edgeport_ti_2",
+static struct usb_serial_driver edgeport_2port_device = {
+	.driver = {
+		.owner		= THIS_MODULE,
+		.name		= "edgeport_ti_2",
+	},
+	.description		= "Edgeport TI 2 port adapter",
 	.id_table		= edgeport_2port_id_table,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 2,
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index c05c2a2..d5d0664 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -92,24 +92,7 @@
 static struct usb_device_id ipaq_id_table [] = {
 	/* The first entry is a placeholder for the insmod-specified device */
 	{ USB_DEVICE(0x049F, 0x0003) },
-	{ USB_DEVICE(0x1690, 0x0601) }, /* Askey USB Sync */
-	{ USB_DEVICE(0x0960, 0x0065) }, /* BCOM USB Sync 0065 */
-	{ USB_DEVICE(0x0960, 0x0066) }, /* BCOM USB Sync 0066 */
-	{ USB_DEVICE(0x0960, 0x0067) }, /* BCOM USB Sync 0067 */
-	{ USB_DEVICE(0x07CF, 0x2001) }, /* CASIO USB Sync 2001 */
-	{ USB_DEVICE(0x07CF, 0x2002) }, /* CASIO USB Sync 2002 */
-	{ USB_DEVICE(0x07CF, 0x2003) }, /* CASIO USB Sync 2003 */
-	{ USB_DEVICE(0x049F, 0x0003) }, /* Compaq iPAQ USB Sync */
-	{ USB_DEVICE(0x049F, 0x0032) }, /* Compaq iPAQ USB Sync */
-	{ USB_DEVICE(0x413C, 0x4001) }, /* Dell Axim USB Sync */
-	{ USB_DEVICE(0x413C, 0x4002) }, /* Dell Axim USB Sync */
-	{ USB_DEVICE(0x413C, 0x4003) }, /* Dell Axim USB Sync */
-	{ USB_DEVICE(0x413C, 0x4004) }, /* Dell Axim USB Sync */
-	{ USB_DEVICE(0x413C, 0x4005) }, /* Dell Axim USB Sync */
-	{ USB_DEVICE(0x413C, 0x4006) }, /* Dell Axim USB Sync */
-	{ USB_DEVICE(0x413C, 0x4007) }, /* Dell Axim USB Sync */
-	{ USB_DEVICE(0x413C, 0x4008) }, /* Dell Axim USB Sync */
-	{ USB_DEVICE(0x413C, 0x4009) }, /* Dell Axim USB Sync */
+	{ USB_DEVICE(0x0104, 0x00BE) }, /* Socket USB Sync */
 	{ USB_DEVICE(0x03F0, 0x1016) }, /* HP USB Sync */
 	{ USB_DEVICE(0x03F0, 0x1116) }, /* HP USB Sync 1611 */
 	{ USB_DEVICE(0x03F0, 0x1216) }, /* HP USB Sync 1612 */
@@ -125,7 +108,13 @@
 	{ USB_DEVICE(0x03F0, 0x5016) }, /* HP USB Sync 1650 */
 	{ USB_DEVICE(0x03F0, 0x5116) }, /* HP USB Sync 1651 */
 	{ USB_DEVICE(0x03F0, 0x5216) }, /* HP USB Sync 1652 */
-	{ USB_DEVICE(0x094B, 0x0001) }, /* Linkup Systems USB Sync */
+	{ USB_DEVICE(0x0409, 0x00D5) }, /* NEC USB Sync */
+	{ USB_DEVICE(0x0409, 0x00D6) }, /* NEC USB Sync */
+	{ USB_DEVICE(0x0409, 0x00D7) }, /* NEC USB Sync */
+	{ USB_DEVICE(0x0409, 0x8024) }, /* NEC USB Sync */
+	{ USB_DEVICE(0x0409, 0x8025) }, /* NEC USB Sync */
+	{ USB_DEVICE(0x043E, 0x9C01) }, /* LGE USB Sync */
+	{ USB_DEVICE(0x045E, 0x00CE) }, /* Microsoft USB Sync */
 	{ USB_DEVICE(0x045E, 0x0400) }, /* Windows Powered Pocket PC 2002 */
 	{ USB_DEVICE(0x045E, 0x0401) }, /* Windows Powered Pocket PC 2002 */
 	{ USB_DEVICE(0x045E, 0x0402) }, /* Windows Powered Pocket PC 2002 */
@@ -251,17 +240,81 @@
 	{ USB_DEVICE(0x045E, 0x04E8) }, /* Windows Powered Smartphone 2003 */
 	{ USB_DEVICE(0x045E, 0x04E9) }, /* Windows Powered Smartphone 2003 */
 	{ USB_DEVICE(0x045E, 0x04EA) }, /* Windows Powered Smartphone 2003 */
-	{ USB_DEVICE(0x0961, 0x0010) }, /* Portatec USB Sync */
-	{ USB_DEVICE(0x5E04, 0xCE00) }, /* SAGEM Wireless Assistant */
-	{ USB_DEVICE(0x0104, 0x00BE) }, /* Socket USB Sync */
+	{ USB_DEVICE(0x049F, 0x0003) }, /* Compaq iPAQ USB Sync */
+	{ USB_DEVICE(0x049F, 0x0032) }, /* Compaq iPAQ USB Sync */
+	{ USB_DEVICE(0x04A4, 0x0014) }, /* Hitachi USB Sync */
+	{ USB_DEVICE(0x04AD, 0x0301) }, /* USB Sync 0301 */
+	{ USB_DEVICE(0x04AD, 0x0302) }, /* USB Sync 0302 */
+	{ USB_DEVICE(0x04AD, 0x0303) }, /* USB Sync 0303 */
+	{ USB_DEVICE(0x04C5, 0x1058) }, /* FUJITSU USB Sync */
+	{ USB_DEVICE(0x04C5, 0x1079) }, /* FUJITSU USB Sync */
+	{ USB_DEVICE(0x04DA, 0x2500) }, /* Panasonic USB Sync */
+	{ USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */
+	{ USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */
+	{ USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */
+	{ USB_DEVICE(0x04E8, 0x5F03) }, /* Samsung NEXiO USB Sync */
+	{ USB_DEVICE(0x04E8, 0x5F04) }, /* Samsung NEXiO USB Sync */
+	{ USB_DEVICE(0x04E8, 0x6611) }, /* Samsung MITs USB Sync */
+	{ USB_DEVICE(0x04E8, 0x6613) }, /* Samsung MITs USB Sync */
+	{ USB_DEVICE(0x04E8, 0x6615) }, /* Samsung MITs USB Sync */
+	{ USB_DEVICE(0x04E8, 0x6617) }, /* Samsung MITs USB Sync */
+	{ USB_DEVICE(0x04E8, 0x6619) }, /* Samsung MITs USB Sync */
+	{ USB_DEVICE(0x04E8, 0x661B) }, /* Samsung MITs USB Sync */
+	{ USB_DEVICE(0x04E8, 0x662E) }, /* Samsung MITs USB Sync */
+	{ USB_DEVICE(0x04E8, 0x6630) }, /* Samsung MITs USB Sync */
+	{ USB_DEVICE(0x04E8, 0x6632) }, /* Samsung MITs USB Sync */
+	{ USB_DEVICE(0x04f1, 0x3011) }, /* JVC USB Sync */
+	{ USB_DEVICE(0x04F1, 0x3012) }, /* JVC USB Sync */
+	{ USB_DEVICE(0x0502, 0x1631) }, /* c10 Series */
+	{ USB_DEVICE(0x0502, 0x1632) }, /* c20 Series */
+	{ USB_DEVICE(0x0502, 0x16E1) }, /* Acer n10 Handheld USB Sync */
+	{ USB_DEVICE(0x0502, 0x16E2) }, /* Acer n20 Handheld USB Sync */
+	{ USB_DEVICE(0x0502, 0x16E3) }, /* Acer n30 Handheld USB Sync */
+	{ USB_DEVICE(0x0536, 0x01A0) }, /* HHP PDT */
+	{ USB_DEVICE(0x0543, 0x0ED9) }, /* ViewSonic Color Pocket PC V35 */
+	{ USB_DEVICE(0x0543, 0x1527) }, /* ViewSonic Color Pocket PC V36 */
+	{ USB_DEVICE(0x0543, 0x1529) }, /* ViewSonic Color Pocket PC V37 */
+	{ USB_DEVICE(0x0543, 0x152B) }, /* ViewSonic Color Pocket PC V38 */
+	{ USB_DEVICE(0x0543, 0x152E) }, /* ViewSonic Pocket PC */
+	{ USB_DEVICE(0x0543, 0x1921) }, /* ViewSonic Communicator Pocket PC */
+	{ USB_DEVICE(0x0543, 0x1922) }, /* ViewSonic Smartphone */
+	{ USB_DEVICE(0x0543, 0x1923) }, /* ViewSonic Pocket PC V30 */
+	{ USB_DEVICE(0x05E0, 0x2000) }, /* Symbol USB Sync */
+	{ USB_DEVICE(0x05E0, 0x2001) }, /* Symbol USB Sync 0x2001 */
+	{ USB_DEVICE(0x05E0, 0x2002) }, /* Symbol USB Sync 0x2002 */
+	{ USB_DEVICE(0x05E0, 0x2003) }, /* Symbol USB Sync 0x2003 */
+	{ USB_DEVICE(0x05E0, 0x2004) }, /* Symbol USB Sync 0x2004 */
+	{ USB_DEVICE(0x05E0, 0x2005) }, /* Symbol USB Sync 0x2005 */
+	{ USB_DEVICE(0x05E0, 0x2006) }, /* Symbol USB Sync 0x2006 */
+	{ USB_DEVICE(0x05E0, 0x2007) }, /* Symbol USB Sync 0x2007 */
+	{ USB_DEVICE(0x05E0, 0x2008) }, /* Symbol USB Sync 0x2008 */
+	{ USB_DEVICE(0x05E0, 0x2009) }, /* Symbol USB Sync 0x2009 */
+	{ USB_DEVICE(0x05E0, 0x200A) }, /* Symbol USB Sync 0x200A */
+	{ USB_DEVICE(0x067E, 0x1001) }, /* Intermec Mobile Computer */
+	{ USB_DEVICE(0x07CF, 0x2001) }, /* CASIO USB Sync 2001 */
+	{ USB_DEVICE(0x07CF, 0x2002) }, /* CASIO USB Sync 2002 */
+	{ USB_DEVICE(0x07CF, 0x2003) }, /* CASIO USB Sync 2003 */
 	{ USB_DEVICE(0x0930, 0x0700) }, /* TOSHIBA USB Sync 0700 */
 	{ USB_DEVICE(0x0930, 0x0705) }, /* TOSHIBA Pocket PC e310 */
+	{ USB_DEVICE(0x0930, 0x0706) }, /* TOSHIBA Pocket PC e740 */
 	{ USB_DEVICE(0x0930, 0x0707) }, /* TOSHIBA Pocket PC e330 Series */
 	{ USB_DEVICE(0x0930, 0x0708) }, /* TOSHIBA Pocket PC e350 Series */
-	{ USB_DEVICE(0x0930, 0x0706) }, /* TOSHIBA Pocket PC e740 */
 	{ USB_DEVICE(0x0930, 0x0709) }, /* TOSHIBA Pocket PC e750 Series */
 	{ USB_DEVICE(0x0930, 0x070A) }, /* TOSHIBA Pocket PC e400 Series */
 	{ USB_DEVICE(0x0930, 0x070B) }, /* TOSHIBA Pocket PC e800 Series */
+	{ USB_DEVICE(0x094B, 0x0001) }, /* Linkup Systems USB Sync */
+	{ USB_DEVICE(0x0960, 0x0065) }, /* BCOM USB Sync 0065 */
+	{ USB_DEVICE(0x0960, 0x0066) }, /* BCOM USB Sync 0066 */
+	{ USB_DEVICE(0x0960, 0x0067) }, /* BCOM USB Sync 0067 */
+	{ USB_DEVICE(0x0961, 0x0010) }, /* Portatec USB Sync */
+	{ USB_DEVICE(0x099E, 0x0052) }, /* Trimble GeoExplorer */
+	{ USB_DEVICE(0x099E, 0x4000) }, /* TDS Data Collector */
+	{ USB_DEVICE(0x0B05, 0x4200) }, /* ASUS USB Sync */
+	{ USB_DEVICE(0x0B05, 0x4201) }, /* ASUS USB Sync */
+	{ USB_DEVICE(0x0B05, 0x4202) }, /* ASUS USB Sync */
+	{ USB_DEVICE(0x0B05, 0x420F) }, /* ASUS USB Sync */
+	{ USB_DEVICE(0x0B05, 0x9200) }, /* ASUS USB Sync */
+	{ USB_DEVICE(0x0B05, 0x9202) }, /* ASUS USB Sync */
 	{ USB_DEVICE(0x0BB4, 0x00CE) }, /* HTC USB Sync */
 	{ USB_DEVICE(0x0BB4, 0x0A01) }, /* PocketPC USB Sync */
 	{ USB_DEVICE(0x0BB4, 0x0A02) }, /* PocketPC USB Sync */
@@ -422,116 +475,67 @@
 	{ USB_DEVICE(0x0BB4, 0x0A9D) }, /* SmartPhone USB Sync */
 	{ USB_DEVICE(0x0BB4, 0x0A9E) }, /* SmartPhone USB Sync */
 	{ USB_DEVICE(0x0BB4, 0x0A9F) }, /* SmartPhone USB Sync */
-	{ USB_DEVICE(0x0409, 0x00D5) }, /* NEC USB Sync */
-	{ USB_DEVICE(0x0409, 0x00D6) }, /* NEC USB Sync */
-	{ USB_DEVICE(0x0409, 0x00D7) }, /* NEC USB Sync */
-	{ USB_DEVICE(0x0409, 0x8024) }, /* NEC USB Sync */
-	{ USB_DEVICE(0x0409, 0x8025) }, /* NEC USB Sync */
-	{ USB_DEVICE(0x04A4, 0x0014) }, /* Hitachi USB Sync */
 	{ USB_DEVICE(0x0BF8, 0x1001) }, /* Fujitsu Siemens Computers USB Sync */
-	{ USB_DEVICE(0x0F98, 0x0201) }, /* Cyberbank USB Sync */
-	{ USB_DEVICE(0x0502, 0x16E1) }, /* Acer n10 Handheld USB Sync */
-	{ USB_DEVICE(0x0502, 0x16E3) }, /* Acer n30 Handheld USB Sync */
-	{ USB_DEVICE(0x0502, 0x16E2) }, /* Acer n20 Handheld USB Sync */
-	{ USB_DEVICE(0x0502, 0x1631) }, /* c10 Series */
-	{ USB_DEVICE(0x0502, 0x1632) }, /* c20 Series */
-	{ USB_DEVICE(0x0B05, 0x9202) }, /* ASUS USB Sync */
-	{ USB_DEVICE(0x0B05, 0x420F) }, /* ASUS USB Sync */
-	{ USB_DEVICE(0x0B05, 0x4200) }, /* ASUS USB Sync */
-	{ USB_DEVICE(0x0B05, 0x4201) }, /* ASUS USB Sync */
-	{ USB_DEVICE(0x0B05, 0x4202) }, /* ASUS USB Sync */
-	{ USB_DEVICE(0x0B05, 0x9200) }, /* ASUS USB Sync */
-	{ USB_DEVICE(0x0C8E, 0x6000) }, /* Cesscom Luxian Series */
-	{ USB_DEVICE(0x04AD, 0x0301) }, /* USB Sync 0301 */
-	{ USB_DEVICE(0x04AD, 0x0302) }, /* USB Sync 0302 */
-	{ USB_DEVICE(0x04AD, 0x0303) }, /* USB Sync 0303 */
-	{ USB_DEVICE(0x1066, 0x0300) }, /* E-TEN P3XX Pocket PC */
-	{ USB_DEVICE(0x1066, 0x0500) }, /* E-TEN P5XX Pocket PC */
-	{ USB_DEVICE(0x1066, 0x0600) }, /* E-TEN P6XX Pocket PC */
-	{ USB_DEVICE(0x1066, 0x0700) }, /* E-TEN P7XX Pocket PC */
-	{ USB_DEVICE(0x1066, 0x00CE) }, /* E-TEN USB Sync */
-	{ USB_DEVICE(0x0F4E, 0x0200) }, /* Freedom Scientific USB Sync */
-	{ USB_DEVICE(0x04C5, 0x1058) }, /* FUJITSU USB Sync */
-	{ USB_DEVICE(0x04C5, 0x1079) }, /* FUJITSU USB Sync */
-	{ USB_DEVICE(0x067E, 0x1001) }, /* Intermec Mobile Computer */
-	{ USB_DEVICE(0x04f1, 0x3011) }, /* JVC USB Sync */
-	{ USB_DEVICE(0x04F1, 0x3012) }, /* JVC USB Sync */
-	{ USB_DEVICE(0x3708, 0x20CE) }, /* Legend USB Sync */
-	{ USB_DEVICE(0x3708, 0x21CE) }, /* Lenovo USB Sync */
-	{ USB_DEVICE(0x043E, 0x9C01) }, /* LGE USB Sync */
-	{ USB_DEVICE(0x04DA, 0x2500) }, /* Panasonic USB Sync */
-	{ USB_DEVICE(0x3340, 0x0B1C) }, /* Generic PPC StrongARM */
-	{ USB_DEVICE(0x3340, 0x0E3A) }, /* Generic PPC USB Sync */
-	{ USB_DEVICE(0x3340, 0x0F3A) }, /* Generic SmartPhone USB Sync */
-	{ USB_DEVICE(0x3340, 0x0F1C) }, /* Itautec USB Sync */
-	{ USB_DEVICE(0x3340, 0x1326) }, /* Itautec USB Sync */
-	{ USB_DEVICE(0x3340, 0x3326) }, /* MEDION Winodws Moble USB Sync */
-	{ USB_DEVICE(0x3340, 0x0326) }, /* Mio DigiWalker 338 */
-	{ USB_DEVICE(0x3340, 0x0426) }, /* Mio DigiWalker 338 */
-	{ USB_DEVICE(0x3340, 0x011C) }, /* Mio DigiWalker PPC StrongARM */
-	{ USB_DEVICE(0x3340, 0x053A) }, /* Mio DigiWalker SmartPhone USB Sync */
-	{ USB_DEVICE(0x3340, 0x043A) }, /* Mio DigiWalker USB Sync */
-	{ USB_DEVICE(0x3340, 0x071C) }, /* MiTAC USB Sync */
-	{ USB_DEVICE(0x3340, 0x051C) }, /* MiTAC USB Sync 528 */
-	{ USB_DEVICE(0x3340, 0x2326) }, /* Vobis USB Sync */
-	{ USB_DEVICE(0x3340, 0x191C) }, /* YAKUMO USB Sync */
-	{ USB_DEVICE(0x4113, 0x0210) }, /* Mobile Media Technology USB Sync */
-	{ USB_DEVICE(0x4113, 0x0211) }, /* Mobile Media Technology USB Sync */
-	{ USB_DEVICE(0x4113, 0x0400) }, /* Mobile Media Technology USB Sync */
-	{ USB_DEVICE(0x4113, 0x0410) }, /* Mobile Media Technology USB Sync */
-	{ USB_DEVICE(0x0CAD, 0x9001) }, /* Motorola PowerPad Pocket PC Device */
 	{ USB_DEVICE(0x0C44, 0x03A2) }, /* Motorola iDEN Smartphone */
-	{ USB_DEVICE(0x04E8, 0x6611) }, /* Samsung MITs USB Sync */
-	{ USB_DEVICE(0x04E8, 0x6613) }, /* Samsung MITs USB Sync */
-	{ USB_DEVICE(0x04E8, 0x6615) }, /* Samsung MITs USB Sync */
-	{ USB_DEVICE(0x04E8, 0x6617) }, /* Samsung MITs USB Sync */
-	{ USB_DEVICE(0x04E8, 0x6619) }, /* Samsung MITs USB Sync */
-	{ USB_DEVICE(0x04E8, 0x661B) }, /* Samsung MITs USB Sync */
-	{ USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */
-	{ USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */
-	{ USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */
-	{ USB_DEVICE(0x04E8, 0x5F03) }, /* Samsung NEXiO USB Sync */
-	{ USB_DEVICE(0x04E8, 0x5F04) }, /* Samsung NEXiO USB Sync */
-	{ USB_DEVICE(0x04E8, 0x662E) }, /* Samsung MITs USB Sync */
-	{ USB_DEVICE(0x04E8, 0x6630) }, /* Samsung MITs USB Sync */
-	{ USB_DEVICE(0x04E8, 0x6632) }, /* Samsung MITs USB Sync */
-	{ USB_DEVICE(0x4505, 0x0010) }, /* Smartphone */
-	{ USB_DEVICE(0x05E0, 0x2000) }, /* Symbol USB Sync */
-	{ USB_DEVICE(0x05E0, 0x2001) }, /* Symbol USB Sync 0x2001 */
-	{ USB_DEVICE(0x05E0, 0x2002) }, /* Symbol USB Sync 0x2002 */
-	{ USB_DEVICE(0x05E0, 0x2003) }, /* Symbol USB Sync 0x2003 */
-	{ USB_DEVICE(0x05E0, 0x2004) }, /* Symbol USB Sync 0x2004 */
-	{ USB_DEVICE(0x05E0, 0x2005) }, /* Symbol USB Sync 0x2005 */
-	{ USB_DEVICE(0x05E0, 0x2006) }, /* Symbol USB Sync 0x2006 */
-	{ USB_DEVICE(0x05E0, 0x2007) }, /* Symbol USB Sync 0x2007 */
-	{ USB_DEVICE(0x05E0, 0x2008) }, /* Symbol USB Sync 0x2008 */
-	{ USB_DEVICE(0x05E0, 0x2009) }, /* Symbol USB Sync 0x2009 */
-	{ USB_DEVICE(0x05E0, 0x200A) }, /* Symbol USB Sync 0x200A */
-	{ USB_DEVICE(0x1182, 0x1388) }, /* VES USB Sync */
-	{ USB_DEVICE(0x0543, 0x0ED9) }, /* ViewSonic Color Pocket PC V35 */
-	{ USB_DEVICE(0x0543, 0x1527) }, /* ViewSonic Color Pocket PC V36 */
-	{ USB_DEVICE(0x0543, 0x1529) }, /* ViewSonic Color Pocket PC V37 */
-	{ USB_DEVICE(0x0543, 0x152B) }, /* ViewSonic Color Pocket PC V38 */
-	{ USB_DEVICE(0x0543, 0x152E) }, /* ViewSonic Pocket PC */
-	{ USB_DEVICE(0x0543, 0x1921) }, /* ViewSonic Communicator Pocket PC */
-	{ USB_DEVICE(0x0543, 0x1922) }, /* ViewSonic Smartphone */
-	{ USB_DEVICE(0x0543, 0x1923) }, /* ViewSonic Pocket PC V30 */
-	{ USB_DEVICE(0x0536, 0x01A0) }, /* HHP PDT */
-	{ USB_DEVICE(0x099E, 0x0052) }, /* Trimble GeoExplorer */
-	{ USB_DEVICE(0x099E, 0x4000) }, /* TDS Data Collector */
+	{ USB_DEVICE(0x0C8E, 0x6000) }, /* Cesscom Luxian Series */
+	{ USB_DEVICE(0x0CAD, 0x9001) }, /* Motorola PowerPad Pocket PC Device */
+	{ USB_DEVICE(0x0F4E, 0x0200) }, /* Freedom Scientific USB Sync */
+	{ USB_DEVICE(0x0F98, 0x0201) }, /* Cyberbank USB Sync */
 	{ USB_DEVICE(0x0FB8, 0x3001) }, /* Wistron USB Sync */
 	{ USB_DEVICE(0x0FB8, 0x3002) }, /* Wistron USB Sync */
 	{ USB_DEVICE(0x0FB8, 0x3003) }, /* Wistron USB Sync */
 	{ USB_DEVICE(0x0FB8, 0x4001) }, /* Wistron USB Sync */
-	{ USB_DEVICE(0x11D9, 0x1003) }, /* Rugged Pocket PC 2003 */
+	{ USB_DEVICE(0x1066, 0x00CE) }, /* E-TEN USB Sync */
+	{ USB_DEVICE(0x1066, 0x0300) }, /* E-TEN P3XX Pocket PC */
+	{ USB_DEVICE(0x1066, 0x0500) }, /* E-TEN P5XX Pocket PC */
+	{ USB_DEVICE(0x1066, 0x0600) }, /* E-TEN P6XX Pocket PC */
+	{ USB_DEVICE(0x1066, 0x0700) }, /* E-TEN P7XX Pocket PC */
+	{ USB_DEVICE(0x1114, 0x0001) }, /* Psion Teklogix Sync 753x */
+	{ USB_DEVICE(0x1114, 0x0004) }, /* Psion Teklogix Sync netBookPro */
+	{ USB_DEVICE(0x1114, 0x0006) }, /* Psion Teklogix Sync 7525 */
+	{ USB_DEVICE(0x1182, 0x1388) }, /* VES USB Sync */
 	{ USB_DEVICE(0x11D9, 0x1002) }, /* Rugged Pocket PC 2003 */
+	{ USB_DEVICE(0x11D9, 0x1003) }, /* Rugged Pocket PC 2003 */
+	{ USB_DEVICE(0x1231, 0xCE01) }, /* USB Sync 03 */
+	{ USB_DEVICE(0x1231, 0xCE02) }, /* USB Sync 03 */
+	{ USB_DEVICE(0x1690, 0x0601) }, /* Askey USB Sync */
 	{ USB_DEVICE(0x22B8, 0x4204) }, /* Motorola MPx200 Smartphone */
 	{ USB_DEVICE(0x22B8, 0x4214) }, /* Motorola MPc GSM */
 	{ USB_DEVICE(0x22B8, 0x4224) }, /* Motorola MPx220 Smartphone */
 	{ USB_DEVICE(0x22B8, 0x4234) }, /* Motorola MPc CDMA */
 	{ USB_DEVICE(0x22B8, 0x4244) }, /* Motorola MPx100 Smartphone */
-	{ USB_DEVICE(0x1231, 0xCE01) }, /* USB Sync 03 */
-	{ USB_DEVICE(0x1231, 0xCE02) }, /* USB Sync 03 */
+	{ USB_DEVICE(0x3340, 0x011C) }, /* Mio DigiWalker PPC StrongARM */
+	{ USB_DEVICE(0x3340, 0x0326) }, /* Mio DigiWalker 338 */
+	{ USB_DEVICE(0x3340, 0x0426) }, /* Mio DigiWalker 338 */
+	{ USB_DEVICE(0x3340, 0x043A) }, /* Mio DigiWalker USB Sync */
+	{ USB_DEVICE(0x3340, 0x051C) }, /* MiTAC USB Sync 528 */
+	{ USB_DEVICE(0x3340, 0x053A) }, /* Mio DigiWalker SmartPhone USB Sync */
+	{ USB_DEVICE(0x3340, 0x071C) }, /* MiTAC USB Sync */
+	{ USB_DEVICE(0x3340, 0x0B1C) }, /* Generic PPC StrongARM */
+	{ USB_DEVICE(0x3340, 0x0E3A) }, /* Generic PPC USB Sync */
+	{ USB_DEVICE(0x3340, 0x0F1C) }, /* Itautec USB Sync */
+	{ USB_DEVICE(0x3340, 0x0F3A) }, /* Generic SmartPhone USB Sync */
+	{ USB_DEVICE(0x3340, 0x1326) }, /* Itautec USB Sync */
+	{ USB_DEVICE(0x3340, 0x191C) }, /* YAKUMO USB Sync */
+	{ USB_DEVICE(0x3340, 0x2326) }, /* Vobis USB Sync */
+	{ USB_DEVICE(0x3340, 0x3326) }, /* MEDION Winodws Moble USB Sync */
+	{ USB_DEVICE(0x3708, 0x20CE) }, /* Legend USB Sync */
+	{ USB_DEVICE(0x3708, 0x21CE) }, /* Lenovo USB Sync */
+	{ USB_DEVICE(0x4113, 0x0210) }, /* Mobile Media Technology USB Sync */
+	{ USB_DEVICE(0x4113, 0x0211) }, /* Mobile Media Technology USB Sync */
+	{ USB_DEVICE(0x4113, 0x0400) }, /* Mobile Media Technology USB Sync */
+	{ USB_DEVICE(0x4113, 0x0410) }, /* Mobile Media Technology USB Sync */
+	{ USB_DEVICE(0x413C, 0x4001) }, /* Dell Axim USB Sync */
+	{ USB_DEVICE(0x413C, 0x4002) }, /* Dell Axim USB Sync */
+	{ USB_DEVICE(0x413C, 0x4003) }, /* Dell Axim USB Sync */
+	{ USB_DEVICE(0x413C, 0x4004) }, /* Dell Axim USB Sync */
+	{ USB_DEVICE(0x413C, 0x4005) }, /* Dell Axim USB Sync */
+	{ USB_DEVICE(0x413C, 0x4006) }, /* Dell Axim USB Sync */
+	{ USB_DEVICE(0x413C, 0x4007) }, /* Dell Axim USB Sync */
+	{ USB_DEVICE(0x413C, 0x4008) }, /* Dell Axim USB Sync */
+	{ USB_DEVICE(0x413C, 0x4009) }, /* Dell Axim USB Sync */
+	{ USB_DEVICE(0x4505, 0x0010) }, /* Smartphone */
+	{ USB_DEVICE(0x5E04, 0xCE00) }, /* SAGEM Wireless Assistant */
 	{ }                             /* Terminating entry */
 };
 
@@ -547,9 +551,12 @@
 
 
 /* All of the device info needed for the Compaq iPAQ */
-static struct usb_serial_device_type ipaq_device = {
-	.owner =		THIS_MODULE,
-	.name =			"PocketPC PDA",
+static struct usb_serial_driver ipaq_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"ipaq",
+	},
+	.description =		"PocketPC PDA",
 	.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 85e2424..a02fada 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -443,10 +443,12 @@
 	return 0;
 }
 
-static struct usb_serial_device_type ipw_device = {
-	.owner =		THIS_MODULE,
-	.name =			"IPWireless converter",
-	.short_name =		"ipw",
+static struct usb_serial_driver ipw_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"ipw",
+	},
+	.description =		"IPWireless converter",
 	.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 937b2fd..19f329e 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -133,9 +133,12 @@
 };
 
 
-static struct usb_serial_device_type ir_device = {
-	.owner =		THIS_MODULE,
-	.name =			"IR Dongle",
+static struct usb_serial_driver ir_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"ir-usb",
+	},
+	.description =		"IR Dongle",
 	.id_table =		id_table,
 	.num_interrupt_in =	1,
 	.num_bulk_in =		1,
diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h
index e9b45b7..5cfc13b 100644
--- a/drivers/usb/serial/keyspan.h
+++ b/drivers/usb/serial/keyspan.h
@@ -570,10 +570,12 @@
 };
 
 /* Structs for the devices, pre and post renumeration. */
-static struct usb_serial_device_type keyspan_pre_device = {
-	.owner			= THIS_MODULE,
-	.name			= "Keyspan - (without firmware)",
-	.short_name		= "keyspan_no_firm",
+static struct usb_serial_driver keyspan_pre_device = {
+	.driver = {
+		.owner		= THIS_MODULE,
+		.name		= "keyspan_no_firm",
+	},
+	.description		= "Keyspan - (without firmware)",
 	.id_table		= keyspan_pre_ids,
 	.num_interrupt_in	= NUM_DONT_CARE,
 	.num_bulk_in		= NUM_DONT_CARE,
@@ -582,10 +584,12 @@
 	.attach			= keyspan_fake_startup,
 };
 
-static struct usb_serial_device_type keyspan_1port_device = {
-	.owner			= THIS_MODULE,
-	.name			= "Keyspan 1 port adapter",
-	.short_name		= "keyspan_1",
+static struct usb_serial_driver keyspan_1port_device = {
+	.driver = {
+		.owner		= THIS_MODULE,
+		.name		= "keyspan_1",
+	},
+	.description		= "Keyspan 1 port adapter",
 	.id_table		= keyspan_1port_ids,
 	.num_interrupt_in	= NUM_DONT_CARE,
 	.num_bulk_in		= NUM_DONT_CARE,
@@ -607,10 +611,12 @@
 	.shutdown		= keyspan_shutdown,
 };
 
-static struct usb_serial_device_type keyspan_2port_device = {
-	.owner			= THIS_MODULE,
-	.name			= "Keyspan 2 port adapter",
-	.short_name		= "keyspan_2",
+static struct usb_serial_driver keyspan_2port_device = {
+	.driver = {
+		.owner		= THIS_MODULE,
+		.name		= "keyspan_2",
+	},
+	.description		= "Keyspan 2 port adapter",
 	.id_table		= keyspan_2port_ids,
 	.num_interrupt_in	= NUM_DONT_CARE,
 	.num_bulk_in		= NUM_DONT_CARE,
@@ -632,10 +638,12 @@
 	.shutdown		= keyspan_shutdown,
 };
 
-static struct usb_serial_device_type keyspan_4port_device = {
-	.owner			= THIS_MODULE,
-	.name			= "Keyspan 4 port adapter",
-	.short_name		= "keyspan_4",
+static struct usb_serial_driver keyspan_4port_device = {
+	.driver = {
+		.owner		= THIS_MODULE,
+		.name		= "keyspan_4",
+	},
+	.description		= "Keyspan 4 port adapter",
 	.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 635c384..cd4f48b 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -783,10 +783,12 @@
 }
 
 #ifdef KEYSPAN
-static struct usb_serial_device_type keyspan_pda_fake_device = {
-	.owner =		THIS_MODULE,
-	.name =			"Keyspan PDA - (prerenumeration)",
-	.short_name =		"keyspan_pda_pre",
+static struct usb_serial_driver keyspan_pda_fake_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"keyspan_pda_pre",
+	},
+	.description =		"Keyspan PDA - (prerenumeration)",
 	.id_table =		id_table_fake,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
@@ -797,10 +799,12 @@
 #endif
 
 #ifdef XIRCOM
-static struct usb_serial_device_type xircom_pgs_fake_device = {
-	.owner =		THIS_MODULE,
-	.name =			"Xircom / Entregra PGS - (prerenumeration)",
-	.short_name =		"xircom_no_firm",
+static struct usb_serial_driver xircom_pgs_fake_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"xircom_no_firm",
+	},
+	.description =		"Xircom / Entregra PGS - (prerenumeration)",
 	.id_table =		id_table_fake_xircom,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
@@ -810,10 +814,12 @@
 };
 #endif
 
-static struct usb_serial_device_type keyspan_pda_device = {
-	.owner =		THIS_MODULE,
-	.name =			"Keyspan PDA",
-	.short_name =		"keyspan_pda",
+static struct usb_serial_driver keyspan_pda_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"keyspan_pda",
+	},
+	.description =		"Keyspan PDA",
 	.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 a11e829..a8951c0 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -123,10 +123,12 @@
 	.id_table =	id_table,
 };
 
-static struct usb_serial_device_type kl5kusb105d_device = {
-	.owner =             THIS_MODULE,
-	.name =		     "KL5KUSB105D / PalmConnect",
-	.short_name =	     "kl5kusb105d",
+static struct usb_serial_driver kl5kusb105d_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"kl5kusb105d",
+	},
+	.description =	     "KL5KUSB105D / PalmConnect",
 	.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 fe4c98a..9456dd9 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -105,9 +105,12 @@
 };
 
 
-static struct usb_serial_device_type kobil_device = {
-	.owner =		THIS_MODULE,
-	.name =			"KOBIL USB smart card terminal",
+static struct usb_serial_driver kobil_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"kobil",
+	},
+	.description =		"KOBIL USB smart card terminal",
 	.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 50b63696..ca5dbad 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -132,10 +132,12 @@
 	.id_table =	id_table_combined,
 };
 
-static struct usb_serial_device_type mct_u232_device = {
-	.owner =	     THIS_MODULE,
-	.name =		     "MCT U232",
-	.short_name =	     "mct_u232",
+static struct usb_serial_driver mct_u232_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"mct_u232",
+	},
+	.description =	     "MCT U232",
 	.id_table =	     id_table_combined,
 	.num_interrupt_in =  2,
 	.num_bulk_in =	     0,
diff --git a/drivers/usb/serial/nokia_dku2.c b/drivers/usb/serial/nokia_dku2.c
new file mode 100644
index 0000000..fad01be
--- /dev/null
+++ b/drivers/usb/serial/nokia_dku2.c
@@ -0,0 +1,142 @@
+/*
+ *  Nokia DKU2 USB driver
+ *
+ *  Copyright (C) 2004
+ *  Author: C Kemp
+ *
+ *  This program is largely derived from work by the linux-usb group
+ *  and associated source files.  Please see the usb/serial files for
+ *  individual credits and copyrights.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  20.09.2005 - Matthias Blaesing <matthias.blaesing@rwth-aachen.de>
+ *  Added short name to device structure to make driver load into kernel 2.6.13
+ *
+ *  20.09.2005 - Matthias Blaesing <matthias.blaesing@rwth-aachen.de>
+ *  Added usb_deregister to exit code - to allow remove and reinsert of module
+ */
+
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include "usb-serial.h"
+
+
+#define NOKIA_VENDOR_ID		0x0421
+#define NOKIA7600_PRODUCT_ID	0x0400
+#define NOKIA6230_PRODUCT_ID	0x040f
+#define NOKIA6170_PRODUCT_ID	0x0416
+#define NOKIA6670_PRODUCT_ID	0x041d
+#define NOKIA6680_PRODUCT_ID	0x041e
+#define NOKIA6230i_PRODUCT_ID	0x0428
+
+#define NOKIA_AT_PORT	0x82
+#define NOKIA_FBUS_PORT	0x86
+
+/*
+ * Version Information
+ */
+#define DRIVER_VERSION	"v0.2"
+#define DRIVER_AUTHOR	"C Kemp"
+#define DRIVER_DESC	"Nokia DKU2 Driver"
+
+static struct usb_device_id id_table [] = {
+	{ USB_DEVICE(NOKIA_VENDOR_ID, NOKIA7600_PRODUCT_ID) },
+	{ USB_DEVICE(NOKIA_VENDOR_ID, NOKIA6230_PRODUCT_ID) },
+	{ USB_DEVICE(NOKIA_VENDOR_ID, NOKIA6170_PRODUCT_ID) },
+	{ USB_DEVICE(NOKIA_VENDOR_ID, NOKIA6670_PRODUCT_ID) },
+	{ USB_DEVICE(NOKIA_VENDOR_ID, NOKIA6680_PRODUCT_ID) },
+	{ USB_DEVICE(NOKIA_VENDOR_ID, NOKIA6230i_PRODUCT_ID) },
+	{ }			/* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+/* The only thing which makes this device different from a generic
+ * device is that we have to set an alternative configuration to make
+ * the relevant endpoints available. In 2.6 this is really easy... */
+static int nokia_probe(struct usb_serial *serial,
+		       const struct usb_device_id *id)
+{
+	int retval = -ENODEV;
+
+	if (serial->interface->altsetting[0].endpoint[0].desc.bEndpointAddress == NOKIA_AT_PORT) {
+		/* the AT port */
+		dev_info(&serial->dev->dev, "Nokia AT Port:\n");
+		retval = 0;
+	} else if (serial->interface->num_altsetting == 2 &&
+		   serial->interface->altsetting[1].endpoint[0].desc.bEndpointAddress == NOKIA_FBUS_PORT) {
+		/* the FBUS port */
+		dev_info(&serial->dev->dev, "Nokia FBUS Port:\n");
+		usb_set_interface(serial->dev, 10, 1);
+		retval = 0;
+	}
+
+	return retval;
+}
+
+static struct usb_driver nokia_driver = {
+	.owner =	THIS_MODULE,
+	.name =		"nokia_dku2",
+	.probe =	usb_serial_probe,
+	.disconnect =	usb_serial_disconnect,
+	.id_table =	id_table,
+};
+
+static struct usb_serial_driver nokia_serial_driver = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name = 	"nokia_dku2",
+	},
+	.description =		"Nokia 7600/6230(i)/6170/66x0 DKU2 driver",
+	.id_table =		id_table,
+	.num_interrupt_in =	1,
+	.num_bulk_in =		1,
+	.num_bulk_out =		1,
+	.num_ports =		1,
+	.probe =		nokia_probe,
+};
+
+static int __init nokia_init(void)
+{
+        int retval;
+
+	retval = usb_serial_register(&nokia_serial_driver);
+	if (retval)
+		return retval;
+
+	retval = usb_register(&nokia_driver);
+	if (retval) {
+	        usb_serial_deregister(&nokia_serial_driver);
+		return retval;
+	}
+
+	info(DRIVER_VERSION " " DRIVER_AUTHOR);
+	info(DRIVER_DESC);
+
+	return retval;
+}
+
+static void __exit nokia_exit(void)
+{
+	usb_deregister(&nokia_driver);
+	usb_serial_deregister(&nokia_serial_driver);
+}
+
+module_init(nokia_init);
+module_exit(nokia_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 6a99ae1..3caf970 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -88,10 +88,12 @@
 };
 
 
-static struct usb_serial_device_type zyxel_omninet_device = {
-	.owner =		THIS_MODULE,
-	.name =			"ZyXEL - omni.net lcd plus usb",
-	.short_name =		"omninet",
+static struct usb_serial_driver zyxel_omninet_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"omninet",
+	},
+	.description =		"ZyXEL - omni.net lcd plus usb",
 	.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 4989e57..7716000 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -105,10 +105,12 @@
 /* The card has three separate interfaces, wich the serial driver
  * recognizes separately, thus num_port=1.
  */
-static struct usb_serial_device_type option_3port_device = {
-	.owner             = THIS_MODULE,
-	.name              = "Option 3G data card",
-	.short_name        = "option",
+static struct usb_serial_driver option_3port_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"option",
+	},
+	.description       = "Option 3G data card",
 	.id_table          = option_ids,
 	.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 3cf245b..165c119 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -8,31 +8,10 @@
  *
  *	This program is free software; you can redistribute it and/or modify
  *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2 of the License, or
- *	(at your option) any later version.
+ *	the Free Software Foundation; either version 2 of the License.
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
- * 2002_Mar_26 gkh
- *	allowed driver to work properly if there is no tty assigned to a port
- *	(this happens for serial console devices.)
- *
- * 2001_Oct_06 gkh
- *	Added RTS and DTR line control.  Thanks to joe@bndlg.de for parts of it.
- *
- * 2001_Sep_19 gkh
- *	Added break support.
- *
- * 2001_Aug_30 gkh
- *	fixed oops in write_bulk_callback.
- *
- * 2001_Aug_28 gkh
- *	reworked buffer logic to be like other usb-serial drivers.  Hopefully
- *	removing some reported problems.
- *
- * 2001_Jun_06 gkh
- *	finished porting to 2.4 format.
- * 
  */
 
 #include <linux/config.h>
@@ -55,7 +34,6 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v0.12"
 #define DRIVER_DESC "Prolific PL2303 USB to serial adaptor driver"
 
 static int debug;
@@ -175,9 +153,11 @@
 
 
 /* All of the device info needed for the PL2303 SIO serial converter */
-static struct usb_serial_device_type pl2303_device = {
-	.owner =		THIS_MODULE,
-	.name =			"PL-2303",
+static struct usb_serial_driver pl2303_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"pl2303",
+	},
 	.id_table =		id_table,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		1,
@@ -1195,7 +1175,7 @@
 	retval = usb_register(&pl2303_driver);
 	if (retval)
 		goto failed_usb_register;
-	info(DRIVER_DESC " " DRIVER_VERSION);
+	info(DRIVER_DESC);
 	return 0;
 failed_usb_register:
 	usb_serial_deregister(&pl2303_device);
@@ -1215,7 +1195,6 @@
 module_exit(pl2303_exit);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index 96a1756..c22bdc0 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -92,7 +92,7 @@
 MODULE_LICENSE("GPL");
 
 #if defined(CONFIG_USBD_SAFE_SERIAL_VENDOR) && !defined(CONFIG_USBD_SAFE_SERIAL_PRODUCT)
-#abort "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT"
+#error "SAFE_SERIAL_VENDOR defined without SAFE_SERIAL_PRODUCT"
 #endif
 
 #if ! defined(CONFIG_USBD_SAFE_SERIAL_VENDOR)
@@ -397,9 +397,11 @@
 	return 0;
 }
 
-static struct usb_serial_device_type safe_device = {
-	.owner =		THIS_MODULE,
-	.name =			"Safe",
+static struct usb_serial_driver safe_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"safe_serial",
+	},
 	.id_table =		id_table,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 59c88de..205dbf7 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -255,9 +255,12 @@
 	.id_table		= ti_id_table_combined,
 };
 
-static struct usb_serial_device_type ti_1port_device = {
-	.owner			= THIS_MODULE,
-	.name			= "TI USB 3410 1 port adapter",
+static struct usb_serial_driver ti_1port_device = {
+	.driver = {
+		.owner		= THIS_MODULE,
+		.name		= "ti_usb_3410_5052_1",
+	},
+	.description		= "TI USB 3410 1 port adapter",
 	.id_table		= ti_id_table_3410,
 	.num_interrupt_in	= 1,
 	.num_bulk_in		= 1,
@@ -282,9 +285,12 @@
 	.write_bulk_callback	= ti_bulk_out_callback,
 };
 
-static struct usb_serial_device_type ti_2port_device = {
-	.owner			= THIS_MODULE,
-	.name			= "TI USB 5052 2 port adapter",
+static struct usb_serial_driver ti_2port_device = {
+	.driver = {
+		.owner		= THIS_MODULE,
+		.name		= "ti_usb_3410_5052_2",
+	},
+	.description		= "TI USB 5052 2 port adapter",
 	.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 e77fbdf..0c4881d 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -1,7 +1,7 @@
 /*
  * USB Serial Converter driver
  *
- * Copyright (C) 1999 - 2004 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 1999 - 2005 Greg Kroah-Hartman (greg@kroah.com)
  * Copyright (C) 2000 Peter Berger (pberger@brimson.com)
  * Copyright (C) 2000 Al Borchers (borchers@steinerpoint.com)
  *
@@ -9,316 +9,11 @@
  *	modify it under the terms of the GNU General Public License version
  *	2 as published by the Free Software Foundation.
  *
- * This driver was originally based on the ACM driver by Armin Fuerst (which was 
+ * This driver was originally based on the ACM driver by Armin Fuerst (which was
  * based on a driver by Brad Keryan)
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
- * (12/10/2002) gkh
- *	Split the ports off into their own struct device, and added a
- *	usb-serial bus driver.
- *
- * (11/19/2002) gkh
- *	removed a few #ifdefs for the generic code and cleaned up the failure
- *	logic in initialization.
- *
- * (10/02/2002) gkh
- *	moved the console code to console.c and out of this file.
- *
- * (06/05/2002) gkh
- *	moved location of startup() call in serial_probe() until after all
- *	of the port information and endpoints are initialized.  This makes
- *	things easier for some drivers.
- *
- * (04/10/2002) gkh
- *	added serial_read_proc function which creates a
- *	/proc/tty/driver/usb-serial file.
- *
- * (03/27/2002) gkh
- *	Got USB serial console code working properly and merged into the main
- *	version of the tree.  Thanks to Randy Dunlap for the initial version
- *	of this code, and for pushing me to finish it up.
- *	The USB serial console works with any usb serial driver device.
- *
- * (03/21/2002) gkh
- *	Moved all manipulation of port->open_count into the core.  Now the
- *	individual driver's open and close functions are called only when the
- *	first open() and last close() is called.  Making the drivers a bit
- *	smaller and simpler.
- *	Fixed a bug if a driver didn't have the owner field set.
- *
- * (02/26/2002) gkh
- *	Moved all locking into the main serial_* functions, instead of having 
- *	the individual drivers have to grab the port semaphore.  This should
- *	reduce races.
- *	Reworked the MOD_INC logic a bit to always increment and decrement, even
- *	if the generic driver is being used.
- *
- * (10/10/2001) gkh
- *	usb_serial_disconnect() now sets the serial->dev pointer is to NULL to
- *	help prevent child drivers from accessing the device since it is now
- *	gone.
- *
- * (09/13/2001) gkh
- *	Moved generic driver initialize after we have registered with the USB
- *	core.  Thanks to Randy Dunlap for pointing this problem out.
- *
- * (07/03/2001) gkh
- *	Fixed module paramater size.  Thanks to John Brockmeyer for the pointer.
- *	Fixed vendor and product getting defined through the MODULE_PARM macro
- *	if the Generic driver wasn't compiled in.
- *	Fixed problem with generic_shutdown() not being called for drivers that
- *	don't have a shutdown() function.
- *
- * (06/06/2001) gkh
- *	added evil hack that is needed for the prolific pl2303 device due to the
- *	crazy way its endpoints are set up.
- *
- * (05/30/2001) gkh
- *	switched from using spinlock to a semaphore, which fixes lots of problems.
- *
- * (04/08/2001) gb
- *	Identify version on module load.
- *
- * 2001_02_05 gkh
- *	Fixed buffer overflows bug with the generic serial driver.  Thanks to
- *	Todd Squires <squirest@ct0.com> for fixing this.
- *
- * (01/10/2001) gkh
- *	Fixed bug where the generic serial adaptor grabbed _any_ device that was
- *	offered to it.
- *
- * (12/12/2000) gkh
- *	Removed MOD_INC and MOD_DEC from poll and disconnect functions, and
- *	moved them to the serial_open and serial_close functions.
- *	Also fixed bug with there not being a MOD_DEC for the generic driver
- *	(thanks to Gary Brubaker for finding this.)
- *
- * (11/29/2000) gkh
- *	Small NULL pointer initialization cleanup which saves a bit of disk image
- *
- * (11/01/2000) Adam J. Richter
- *	instead of using idVendor/idProduct pairs, usb serial drivers
- *	now identify their hardware interest with usb_device_id tables,
- *	which they usually have anyhow for use with MODULE_DEVICE_TABLE.
- *
- * (10/05/2000) gkh
- *	Fixed bug with urb->dev not being set properly, now that the usb
- *	core needs it.
- * 
- * (09/11/2000) gkh
- *	Removed DEBUG #ifdefs with call to usb_serial_debug_data
- *
- * (08/28/2000) gkh
- *	Added port_lock to port structure.
- *	Added locks for SMP safeness to generic driver
- *	Fixed the ability to open a generic device's port more than once.
- *
- * (07/23/2000) gkh
- *	Added bulk_out_endpointAddress to port structure.
- *
- * (07/19/2000) gkh, pberger, and borchers
- *	Modifications to allow usb-serial drivers to be modules.
- *
- * (07/03/2000) gkh
- *	Added more debugging to serial_ioctl call
- * 
- * (06/25/2000) gkh
- *	Changed generic_write_bulk_callback to not call wake_up_interruptible
- *	directly, but to have port_softint do it at a safer time.
- *
- * (06/23/2000) gkh
- *	Cleaned up debugging statements in a quest to find UHCI timeout bug.
- *
- * (05/22/2000) gkh
- *	Changed the makefile, enabling the big CONFIG_USB_SERIAL_SOMTHING to be 
- *	removed from the individual device source files.
- *
- * (05/03/2000) gkh
- *	Added the Digi Acceleport driver from Al Borchers and Peter Berger.
- * 
- * (05/02/2000) gkh
- *	Changed devfs and tty register code to work properly now. This was based on
- *	the ACM driver changes by Vojtech Pavlik.
- *
- * (04/27/2000) Ryan VanderBijl
- * 	Put calls to *_paranoia_checks into one function.
- * 
- * (04/23/2000) gkh
- *	Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports.
- *	Moved when the startup code printed out the devices that are supported.
- *
- * (04/19/2000) gkh
- *	Added driver for ZyXEL omni.net lcd plus ISDN TA
- *	Made startup info message specify which drivers were compiled in.
- *
- * (04/03/2000) gkh
- *	Changed the probe process to remove the module unload races.
- *	Changed where the tty layer gets initialized to have devfs work nicer.
- *	Added initial devfs support.
- *
- * (03/26/2000) gkh
- *	Split driver up into device specific pieces.
- * 
- * (03/19/2000) gkh
- *	Fixed oops that could happen when device was removed while a program
- *	was talking to the device.
- *	Removed the static urbs and now all urbs are created and destroyed
- *	dynamically.
- *	Reworked the internal interface. Now everything is based on the 
- *	usb_serial_port structure instead of the larger usb_serial structure.
- *	This fixes the bug that a multiport device could not have more than
- *	one port open at one time.
- *
- * (03/17/2000) gkh
- *	Added config option for debugging messages.
- *	Added patch for keyspan pda from Brian Warner.
- *
- * (03/06/2000) gkh
- *	Added the keyspan pda code from Brian Warner <warner@lothar.com>
- *	Moved a bunch of the port specific stuff into its own structure. This
- *	is in anticipation of the true multiport devices (there's a bug if you
- *	try to access more than one port of any multiport device right now)
- *
- * (02/21/2000) gkh
- *	Made it so that any serial devices only have to specify which functions
- *	they want to overload from the generic function calls (great, 
- *	inheritance in C, in a driver, just what I wanted...)
- *	Added support for set_termios and ioctl function calls. No drivers take
- *	advantage of this yet.
- *	Removed the #ifdef MODULE, now there is no module specific code.
- *	Cleaned up a few comments in usb-serial.h that were wrong (thanks again
- *	to Miles Lott).
- *	Small fix to get_free_serial.
- *
- * (02/14/2000) gkh
- *	Removed the Belkin and Peracom functionality from the driver due to
- *	the lack of support from the vendor, and me not wanting people to 
- *	accidenatly buy the device, expecting it to work with Linux.
- *	Added read_bulk_callback and write_bulk_callback to the type structure
- *	for the needs of the FTDI and WhiteHEAT driver.
- *	Changed all reverences to FTDI to FTDI_SIO at the request of Bill
- *	Ryder.
- *	Changed the output urb size back to the max endpoint size to make
- *	the ftdi_sio driver have it easier, and due to the fact that it didn't
- *	really increase the speed any.
- *
- * (02/11/2000) gkh
- *	Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a
- *	patch from Miles Lott (milos@insync.net).
- *	Fixed bug with not restoring the minor range that a device grabs, if
- *	the startup function fails (thanks Miles for finding this).
- *
- * (02/05/2000) gkh
- *	Added initial framework for the Keyspan PDA serial converter so that
- *	Brian Warner has a place to put his code.
- *	Made the ezusb specific functions generic enough that different
- *	devices can use them (whiteheat and keyspan_pda both need them).
- *	Split out a whole bunch of structure and other stuff to a separate
- *	usb-serial.h file.
- *	Made the Visor connection messages a little more understandable, now
- *	that Miles Lott (milos@insync.net) has gotten the Generic channel to
- *	work. Also made them always show up in the log file.
- * 
- * (01/25/2000) gkh
- *	Added initial framework for FTDI serial converter so that Bill Ryder
- *	has a place to put his code.
- *	Added the vendor specific info from Handspring. Now we can print out
- *	informational debug messages as well as understand what is happening.
- *
- * (01/23/2000) gkh
- *	Fixed problem of crash when trying to open a port that didn't have a
- *	device assigned to it. Made the minor node finding a little smarter,
- *	now it looks to find a continuous space for the new device.
- *
- * (01/21/2000) gkh
- *	Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net)
- *	Fixed get_serial_by_minor which was all messed up for multi port 
- *	devices. Fixed multi port problem for generic devices. Now the number
- *	of ports is determined by the number of bulk out endpoints for the
- *	generic device.
- *
- * (01/19/2000) gkh
- *	Removed lots of cruft that was around from the old (pre urb) driver 
- *	interface.
- *	Made the serial_table dynamic. This should save lots of memory when
- *	the number of minor nodes goes up to 256.
- *	Added initial support for devices that have more than one port. 
- *	Added more debugging comments for the Visor, and added a needed 
- *	set_configuration call.
- *
- * (01/17/2000) gkh
- *	Fixed the WhiteHEAT firmware (my processing tool had a bug)
- *	and added new debug loader firmware for it.
- *	Removed the put_char function as it isn't really needed.
- *	Added visor startup commands as found by the Win98 dump.
- * 
- * (01/13/2000) gkh
- *	Fixed the vendor id for the generic driver to the one I meant it to be.
- *
- * (01/12/2000) gkh
- *	Forget the version numbering...that's pretty useless...
- *	Made the driver able to be compiled so that the user can select which
- *	converter they want to use. This allows people who only want the Visor
- *	support to not pay the memory size price of the WhiteHEAT.
- *	Fixed bug where the generic driver (idVendor=0000 and idProduct=0000)
- *	grabbed the root hub. Not good.
- * 
- * version 0.4.0 (01/10/2000) gkh
- *	Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT
- *	device. Added startup function to allow firmware to be downloaded to
- *	a device if it needs to be.
- *	Added firmware download logic to the WhiteHEAT device.
- *	Started to add #defines to split up the different drivers for potential
- *	configuration option.
- *	
- * version 0.3.1 (12/30/99) gkh
- *      Fixed problems with urb for bulk out.
- *      Added initial support for multiple sets of endpoints. This enables
- *      the Handspring Visor to be attached successfully. Only the first
- *      bulk in / bulk out endpoint pair is being used right now.
- *
- * version 0.3.0 (12/27/99) gkh
- *	Added initial support for the Handspring Visor based on a patch from
- *	Miles Lott (milos@sneety.insync.net)
- *	Cleaned up the code a bunch and converted over to using urbs only.
- *
- * version 0.2.3 (12/21/99) gkh
- *	Added initial support for the Connect Tech WhiteHEAT converter.
- *	Incremented the number of ports in expectation of getting the
- *	WhiteHEAT to work properly (4 ports per connection).
- *	Added notification on insertion and removal of what port the
- *	device is/was connected to (and what kind of device it was).
- *
- * version 0.2.2 (12/16/99) gkh
- *	Changed major number to the new allocated number. We're legal now!
- *
- * version 0.2.1 (12/14/99) gkh
- *	Fixed bug that happens when device node is opened when there isn't a
- *	device attached to it. Thanks to marek@webdesign.no for noticing this.
- *
- * version 0.2.0 (11/10/99) gkh
- *	Split up internals to make it easier to add different types of serial 
- *	converters to the code.
- *	Added a "generic" driver that gets it's vendor and product id
- *	from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net)
- *	for the idea and sample code (from the usb scanner driver.)
- *	Cleared up any licensing questions by releasing it under the GNU GPL.
- *
- * version 0.1.2 (10/25/99) gkh
- * 	Fixed bug in detecting device.
- *
- * version 0.1.1 (10/05/99) gkh
- * 	Changed the major number to not conflict with anything else.
- *
- * version 0.1 (09/28/99) gkh
- * 	Can recognize the two different devices and start up a read from
- *	device when asked to. Writes also work. No control signals yet, this
- *	all is vendor specific data (i.e. no spec), also no control for
- *	different baud rates or other bit settings.
- *	Currently we are using the same devid as the acm driver. This needs
- *	to change.
- * 
  */
 
 #include <linux/config.h>
@@ -342,7 +37,6 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v2.0"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman, greg@kroah.com, http://www.kroah.com/linux/"
 #define DRIVER_DESC "USB Serial Driver core"
 
@@ -427,7 +121,7 @@
 
 	serial = to_usb_serial(kref);
 
-	dbg ("%s - %s", __FUNCTION__, serial->type->name);
+	dbg("%s - %s", __FUNCTION__, serial->type->description);
 
 	serial->type->shutdown(serial);
 
@@ -507,7 +201,7 @@
 		/* lock this module before we call it
 		 * this may fail, which means we must bail out,
 		 * safe because we are called with BKL held */
-		if (!try_module_get(serial->type->owner)) {
+		if (!try_module_get(serial->type->driver.owner)) {
 			retval = -ENODEV;
 			goto bailout_kref_put;
 		}
@@ -522,7 +216,7 @@
 	return 0;
 
 bailout_module_put:
-	module_put(serial->type->owner);
+	module_put(serial->type->driver.owner);
 bailout_kref_put:
 	kref_put(&serial->kref, destroy_serial);
 	port->open_count = 0;
@@ -553,7 +247,7 @@
 			port->tty = NULL;
 		}
 
-		module_put(port->serial->type->owner);
+		module_put(port->serial->type->driver.owner);
 	}
 
 	kref_put(&port->serial->kref, destroy_serial);
@@ -711,16 +405,16 @@
 	char tmp[40];
 
 	dbg("%s", __FUNCTION__);
-	length += sprintf (page, "usbserinfo:1.0 driver:%s\n", DRIVER_VERSION);
+	length += sprintf (page, "usbserinfo:1.0 driver:2.0\n");
 	for (i = 0; i < SERIAL_TTY_MINORS && length < PAGE_SIZE; ++i) {
 		serial = usb_serial_get_by_index(i);
 		if (serial == NULL)
 			continue;
 
 		length += sprintf (page+length, "%d:", i);
-		if (serial->type->owner)
-			length += sprintf (page+length, " module:%s", module_name(serial->type->owner));
-		length += sprintf (page+length, " name:\"%s\"", serial->type->name);
+		if (serial->type->driver.owner)
+			length += sprintf (page+length, " module:%s", module_name(serial->type->driver.owner));
+		length += sprintf (page+length, " name:\"%s\"", serial->type->description);
 		length += sprintf (page+length, " vendor:%04x product:%04x", 
 				   le16_to_cpu(serial->dev->descriptor.idVendor), 
 				   le16_to_cpu(serial->dev->descriptor.idProduct));
@@ -823,7 +517,7 @@
 
 static struct usb_serial * create_serial (struct usb_device *dev, 
 					  struct usb_interface *interface,
-					  struct usb_serial_device_type *type)
+					  struct usb_serial_driver *driver)
 {
 	struct usb_serial *serial;
 
@@ -834,22 +528,22 @@
 	}
 	memset (serial, 0, sizeof(*serial));
 	serial->dev = usb_get_dev(dev);
-	serial->type = type;
+	serial->type = driver;
 	serial->interface = interface;
 	kref_init(&serial->kref);
 
 	return serial;
 }
 
-static struct usb_serial_device_type *search_serial_device(struct usb_interface *iface)
+static struct usb_serial_driver *search_serial_device(struct usb_interface *iface)
 {
 	struct list_head *p;
 	const struct usb_device_id *id;
-	struct usb_serial_device_type *t;
+	struct usb_serial_driver *t;
 
 	/* List trough know devices and see if the usb id matches */
 	list_for_each(p, &usb_serial_driver_list) {
-		t = list_entry(p, struct usb_serial_device_type, 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");
@@ -872,7 +566,7 @@
 	struct usb_endpoint_descriptor *interrupt_out_endpoint[MAX_NUM_PORTS];
 	struct usb_endpoint_descriptor *bulk_in_endpoint[MAX_NUM_PORTS];
 	struct usb_endpoint_descriptor *bulk_out_endpoint[MAX_NUM_PORTS];
-	struct usb_serial_device_type *type = NULL;
+	struct usb_serial_driver *type = NULL;
 	int retval;
 	int minor;
 	int buffer_size;
@@ -900,7 +594,7 @@
 	if (type->probe) {
 		const struct usb_device_id *id;
 
-		if (!try_module_get(type->owner)) {
+		if (!try_module_get(type->driver.owner)) {
 			dev_err(&interface->dev, "module get failed, exiting\n");
 			kfree (serial);
 			return -EIO;
@@ -908,7 +602,7 @@
 
 		id = usb_match_id(interface, type->id_table);
 		retval = type->probe(serial, id);
-		module_put(type->owner);
+		module_put(type->driver.owner);
 
 		if (retval) {
 			dbg ("sub driver rejected device");
@@ -992,7 +686,7 @@
 #endif
 
 	/* found all that we need */
-	dev_info(&interface->dev, "%s converter detected\n", type->name);
+	dev_info(&interface->dev, "%s converter detected\n", type->description);
 
 #ifdef CONFIG_USB_SERIAL_GENERIC
 	if (type == &usb_serial_generic_device) {
@@ -1007,13 +701,13 @@
 	if (!num_ports) {
 		/* if this device type has a calc_num_ports function, call it */
 		if (type->calc_num_ports) {
-			if (!try_module_get(type->owner)) {
+			if (!try_module_get(type->driver.owner)) {
 				dev_err(&interface->dev, "module get failed, exiting\n");
 				kfree (serial);
 				return -EIO;
 			}
 			num_ports = type->calc_num_ports (serial);
-			module_put(type->owner);
+			module_put(type->driver.owner);
 		}
 		if (!num_ports)
 			num_ports = type->num_ports;
@@ -1158,12 +852,12 @@
 	
 	/* if this device type has an attach function, call it */
 	if (type->attach) {
-		if (!try_module_get(type->owner)) {
+		if (!try_module_get(type->driver.owner)) {
 			dev_err(&interface->dev, "module get failed, exiting\n");
 			goto probe_error;
 		}
 		retval = type->attach (serial);
-		module_put(type->owner);
+		module_put(type->driver.owner);
 		if (retval < 0)
 			goto probe_error;
 		if (retval > 0) {
@@ -1330,7 +1024,7 @@
 		goto exit_generic;
 	}
 
-	info(DRIVER_DESC " " DRIVER_VERSION);
+	info(DRIVER_DESC);
 
 	return result;
 
@@ -1375,7 +1069,7 @@
 			}						\
 	} while (0)
 
-static void fixup_generic(struct usb_serial_device_type *device)
+static void fixup_generic(struct usb_serial_driver *device)
 {
 	set_to_generic_if_null(device, open);
 	set_to_generic_if_null(device, write);
@@ -1387,30 +1081,33 @@
 	set_to_generic_if_null(device, shutdown);
 }
 
-int usb_serial_register(struct usb_serial_device_type *new_device)
+int usb_serial_register(struct usb_serial_driver *driver)
 {
 	int retval;
 
-	fixup_generic(new_device);
+	fixup_generic(driver);
+
+	if (!driver->description)
+		driver->description = driver->driver.name;
 
 	/* Add this device to our list of devices */
-	list_add(&new_device->driver_list, &usb_serial_driver_list);
+	list_add(&driver->driver_list, &usb_serial_driver_list);
 
-	retval = usb_serial_bus_register(new_device);
+	retval = usb_serial_bus_register(driver);
 	if (retval) {
-		err("problem %d when registering driver %s", retval, new_device->name);
-		list_del(&new_device->driver_list);
+		err("problem %d when registering driver %s", retval, driver->description);
+		list_del(&driver->driver_list);
 	}
 	else
-		info("USB Serial support registered for %s", new_device->name);
+		info("USB Serial support registered for %s", driver->description);
 
 	return retval;
 }
 
 
-void usb_serial_deregister(struct usb_serial_device_type *device)
+void usb_serial_deregister(struct usb_serial_driver *device)
 {
-	info("USB Serial deregistering driver %s", device->name);
+	info("USB Serial deregistering driver %s", device->description);
 	list_del(&device->driver_list);
 	usb_serial_bus_deregister(device);
 }
@@ -1429,7 +1126,6 @@
 /* Module information */
 MODULE_AUTHOR( DRIVER_AUTHOR );
 MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_VERSION( DRIVER_VERSION );
 MODULE_LICENSE("GPL");
 
 module_param(debug, bool, S_IRUGO | S_IWUSR);
diff --git a/drivers/usb/serial/usb-serial.h b/drivers/usb/serial/usb-serial.h
index 57f92f0..238a5a8 100644
--- a/drivers/usb/serial/usb-serial.h
+++ b/drivers/usb/serial/usb-serial.h
@@ -1,53 +1,13 @@
 /*
  * USB Serial Converter driver
  *
- *	Copyright (C) 1999 - 2004
+ *	Copyright (C) 1999 - 2005
  *	    Greg Kroah-Hartman (greg@kroah.com)
  *
  *	This program is free software; you can redistribute it and/or modify
  *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2 of the License, or
- *	(at your option) any later version.
+ *	the Free Software Foundation; either version 2 of the License.
  *
- * See Documentation/usb/usb-serial.txt for more information on using this driver
- *
- * (03/26/2002) gkh
- *	removed the port->tty check from port_paranoia_check() due to serial
- *	consoles not having a tty device assigned to them.
- *
- * (12/03/2001) gkh
- *	removed active from the port structure.
- *	added documentation to the usb_serial_device_type structure
- *
- * (10/10/2001) gkh
- *	added vendor and product to serial structure.  Needed to determine device
- *	owner when the device is disconnected.
- *
- * (05/30/2001) gkh
- *	added sem to port structure and removed port_lock
- *
- * (10/05/2000) gkh
- *	Added interrupt_in_endpointAddress and bulk_in_endpointAddress to help
- *	fix bug with urb->dev not being set properly, now that the usb core
- *	needs it.
- * 
- * (09/11/2000) gkh
- *	Added usb_serial_debug_data function to help get rid of #DEBUG in the
- *	drivers.
- *
- * (08/28/2000) gkh
- *	Added port_lock to port structure.
- *
- * (08/08/2000) gkh
- *	Added open_count to port structure.
- *
- * (07/23/2000) gkh
- *	Added bulk_out_endpointAddress to port structure.
- *
- * (07/19/2000) gkh, pberger, and borchers
- *	Modifications to allow usb-serial drivers to be modules.
- *
- * 
  */
 
 
@@ -143,7 +103,7 @@
 /**
  * usb_serial - structure used by the usb-serial core for a device
  * @dev: pointer to the struct usb_device for this device
- * @type: pointer to the struct usb_serial_device_type for this device
+ * @type: pointer to the struct usb_serial_driver for this device
  * @interface: pointer to the struct usb_interface for this device
  * @minor: the starting minor number for this device
  * @num_ports: the number of ports this device has
@@ -159,7 +119,7 @@
  */
 struct usb_serial {
 	struct usb_device *		dev;
-	struct usb_serial_device_type *	type;
+	struct usb_serial_driver *	type;
 	struct usb_interface *		interface;
 	unsigned char			minor;
 	unsigned char			num_ports;
@@ -188,13 +148,9 @@
 }
 
 /**
- * usb_serial_device_type - a structure that defines a usb serial device
- * @owner: pointer to the module that owns this device.
- * @name: pointer to a string that describes this device.  This string used
+ * usb_serial_driver - describes a usb serial driver
+ * @description: pointer to a string that describes this driver.  This string used
  *	in the syslog messages when a device is inserted or removed.
- * @short_name: a pointer to a string that describes this device in
- *	KOBJ_NAME_LEN characters or less.  This is used for the sysfs interface
- *	to describe the driver.
  * @id_table: pointer to a list of usb_device_id structures that define all
  *	of the devices this structure can support.
  * @num_interrupt_in: the number of interrupt in endpoints this device will
@@ -221,16 +177,19 @@
  * @shutdown: pointer to the driver's shutdown function.  This will be
  *	called when the device is removed from the system.
  *
- * This structure is defines a USB Serial device.  It provides all of
+ * This structure is defines a USB Serial driver.  It provides all of
  * the information that the USB serial core code needs.  If the function
  * pointers are defined, then the USB serial core code will call them when
  * the corresponding tty port functions are called.  If they are not
  * called, the generic serial function will be used instead.
+ *
+ * The driver.owner field should be set to the module owner of this driver.
+ * The driver.name field should be set to the name of this driver (remember
+ * it will show up in sysfs, so it needs to be short and to the point.
+ * Useing the module name is a good idea.)
  */
-struct usb_serial_device_type {
-	struct module *owner;
-	char	*name;
-	char	*short_name;
+struct usb_serial_driver {
+	const char *description;
 	const struct usb_device_id *id_table;
 	char	num_interrupt_in;
 	char	num_interrupt_out;
@@ -269,10 +228,10 @@
 	void (*read_bulk_callback)(struct urb *urb, struct pt_regs *regs);
 	void (*write_bulk_callback)(struct urb *urb, struct pt_regs *regs);
 };
-#define to_usb_serial_driver(d) container_of(d, struct usb_serial_device_type, driver)
+#define to_usb_serial_driver(d) container_of(d, struct usb_serial_driver, driver)
 
-extern int  usb_serial_register(struct usb_serial_device_type *new_device);
-extern void usb_serial_deregister(struct usb_serial_device_type *device);
+extern int  usb_serial_register(struct usb_serial_driver *driver);
+extern void usb_serial_deregister(struct usb_serial_driver *driver);
 extern void usb_serial_port_softint(void *private);
 
 extern int usb_serial_probe(struct usb_interface *iface, const struct usb_device_id *id);
@@ -303,10 +262,10 @@
 extern int usb_serial_generic_register (int debug);
 extern void usb_serial_generic_deregister (void);
 
-extern int usb_serial_bus_register (struct usb_serial_device_type *device);
-extern void usb_serial_bus_deregister (struct usb_serial_device_type *device);
+extern int usb_serial_bus_register (struct usb_serial_driver *device);
+extern void usb_serial_bus_deregister (struct usb_serial_driver *device);
 
-extern struct usb_serial_device_type usb_serial_generic_device;
+extern struct usb_serial_driver usb_serial_generic_device;
 extern struct bus_type usb_serial_bus_type;
 extern struct tty_driver *usb_serial_tty_driver;
 
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 31c57ad..a473c1c 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -7,139 +7,10 @@
  *
  *	This program is free software; you can redistribute it and/or modify
  *	it under the terms of the GNU General Public License as published by
- *	the Free Software Foundation; either version 2 of the License, or
- *	(at your option) any later version.
+ *	the Free Software Foundation; either version 2 of the License.
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  *
- * (06/03/2003) Judd Montgomery <judd at jpilot.org>
- *     Added support for module parameter options for untested/unknown
- *     devices.
- *
- * (03/09/2003) gkh
- *	Added support for the Sony Clie NZ90V device.  Thanks to Martin Brachtl
- *	<brachtl@redgrep.cz> for the information.
- *
- * (03/05/2003) gkh
- *	Think Treo support is now working.
- *
- * (04/03/2002) gkh
- *	Added support for the Sony OS 4.1 devices.  Thanks to Hiroyuki ARAKI
- *	<hiro@zob.ne.jp> for the information.
- *
- * (03/27/2002) gkh
- *	Removed assumptions that port->tty was always valid (is not true
- *	for usb serial console devices.)
- *
- * (03/23/2002) gkh
- *	Added support for the Palm i705 device, thanks to Thomas Riemer
- *	<tom@netmech.com> for the information.
- *
- * (03/21/2002) gkh
- *	Added support for the Palm m130 device, thanks to Udo Eisenbarth
- *	<udo.eisenbarth@web.de> for the information.
- *
- * (02/27/2002) gkh
- *	Reworked the urb handling logic.  We have no more pool, but dynamically
- *	allocate the urb and the transfer buffer on the fly.  In testing this
- *	does not incure any measurable overhead.  This also relies on the fact
- *	that we have proper reference counting logic for urbs.
- *
- * (02/21/2002) SilaS
- *  Added initial support for the Palm m515 devices.
- *
- * (02/14/2002) gkh
- *	Added support for the Clie S-360 device.
- *
- * (12/18/2001) gkh
- *	Added better Clie support for 3.5 devices.  Thanks to Geoffrey Levand
- *	for the patch.
- *
- * (11/11/2001) gkh
- *	Added support for the m125 devices, and added check to prevent oopses
- *	for Clié devices that lie about the number of ports they have.
- *
- * (08/30/2001) gkh
- *	Added support for the Clie devices, both the 3.5 and 4.0 os versions.
- *	Many thanks to Daniel Burke, and Bryan Payne for helping with this.
- *
- * (08/23/2001) gkh
- *	fixed a few potential bugs pointed out by Oliver Neukum.
- *
- * (05/30/2001) gkh
- *	switched from using spinlock to a semaphore, which fixes lots of problems.
- *
- * (05/28/2000) gkh
- *	Added initial support for the Palm m500 and Palm m505 devices.
- *
- * (04/08/2001) gb
- *	Identify version on module load.
- *
- * (01/21/2000) gkh
- *	Added write_room and chars_in_buffer, as they were previously using the
- *	generic driver versions which is all wrong now that we are using an urb
- *	pool.  Thanks to Wolfgang Grandegger for pointing this out to me.
- *	Removed count assignment in the write function, which was not needed anymore
- *	either.  Thanks to Al Borchers for pointing this out.
- *
- * (12/12/2000) gkh
- *	Moved MOD_DEC to end of visor_close to be nicer, as the final write 
- *	message can sleep.
- * 
- * (11/12/2000) gkh
- *	Fixed bug with data being dropped on the floor by forcing tty->low_latency
- *	to be on.  Hopefully this fixes the OHCI issue!
- *
- * (11/01/2000) Adam J. Richter
- *	usb_device_id table support
- * 
- * (10/05/2000) gkh
- *	Fixed bug with urb->dev not being set properly, now that the usb
- *	core needs it.
- * 
- * (09/11/2000) gkh
- *	Got rid of always calling kmalloc for every urb we wrote out to the
- *	device.
- *	Added visor_read_callback so we can keep track of bytes in and out for
- *	those people who like to know the speed of their device.
- *	Removed DEBUG #ifdefs with call to usb_serial_debug_data
- *
- * (09/06/2000) gkh
- *	Fixed oops in visor_exit.  Need to uncomment usb_unlink_urb call _after_
- *	the host controller drivers set urb->dev = NULL when the urb is finished.
- *
- * (08/28/2000) gkh
- *	Added locks for SMP safeness.
- *
- * (08/08/2000) gkh
- *	Fixed endian problem in visor_startup.
- *	Fixed MOD_INC and MOD_DEC logic and the ability to open a port more 
- *	than once.
- * 
- * (07/23/2000) gkh
- *	Added pool of write urbs to speed up transfers to the visor.
- * 
- * (07/19/2000) gkh
- *	Added module_init and module_exit functions to handle the fact that this
- *	driver is a loadable module now.
- *
- * (07/03/2000) gkh
- *	Added visor_set_ioctl and visor_set_termios functions (they don't do much
- *	of anything, but are good for debugging.)
- * 
- * (06/25/2000) gkh
- *	Fixed bug in visor_unthrottle that should help with the disconnect in PPP
- *	bug that people have been reporting.
- *
- * (06/23/2000) gkh
- *	Cleaned up debugging statements in a quest to find UHCI timeout bug.
- *
- * (04/27/2000) Ryan VanderBijl
- * 	Fixed memory leak in visor_close
- *
- * (03/26/2000) gkh
- *	Split driver up into device specific pieces.
- * 
  */
 
 #include <linux/config.h>
@@ -161,7 +32,6 @@
 /*
  * Version Information
  */
-#define DRIVER_VERSION "v2.1"
 #define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>"
 #define DRIVER_DESC "USB HandSpring Visor / Palm OS driver"
 
@@ -311,10 +181,12 @@
 };
 
 /* All of the device info needed for the Handspring Visor, and Palm 4.0 devices */
-static struct usb_serial_device_type handspring_device = {
-	.owner =		THIS_MODULE,
-	.name =			"Handspring Visor / Palm OS",
-	.short_name =		"visor",
+static struct usb_serial_driver handspring_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"visor",
+	},
+	.description =		"Handspring Visor / Palm OS",
 	.id_table =		id_table,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		2,
@@ -339,10 +211,12 @@
 };
 
 /* All of the device info needed for the Clie UX50, TH55 Palm 5.0 devices */
-static struct usb_serial_device_type clie_5_device = {
-	.owner =		THIS_MODULE,
-	.name =			"Sony Clie 5.0",
-	.short_name =		"clie_5",
+static struct usb_serial_driver clie_5_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"clie_5",
+	},
+	.description =		"Sony Clie 5.0",
 	.id_table =		clie_id_5_table,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		2,
@@ -367,10 +241,12 @@
 };
 
 /* device info for the Sony Clie OS version 3.5 */
-static struct usb_serial_device_type clie_3_5_device = {
-	.owner =		THIS_MODULE,
-	.name =			"Sony Clie 3.5",
-	.short_name =		"clie_3.5",
+static struct usb_serial_driver clie_3_5_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"clie_3.5",
+	},
+	.description =		"Sony Clie 3.5",
 	.id_table =		clie_id_3_5_table,
 	.num_interrupt_in =	0,
 	.num_bulk_in =		1,
@@ -782,7 +658,7 @@
 					break;
 			}
 			dev_info(dev, "%s: port %d, is for %s use\n",
-				serial->type->name,
+				serial->type->description,
 				connection_info->connections[i].port, string);
 		}
 	}
@@ -791,11 +667,11 @@
 	*/
 	if (num_ports == 0 || num_ports > 2) {
 		dev_warn (dev, "%s: No valid connect info available\n",
-			serial->type->name);
+			serial->type->description);
 		num_ports = 2;
 	}
   
-	dev_info(dev, "%s: Number of ports: %d\n", serial->type->name,
+	dev_info(dev, "%s: Number of ports: %d\n", serial->type->description,
 		num_ports);
 
 	/*
@@ -1125,7 +1001,7 @@
 	retval = usb_register(&visor_driver);
 	if (retval) 
 		goto failed_usb_register;
-	info(DRIVER_DESC " " DRIVER_VERSION);
+	info(DRIVER_DESC);
 
 	return 0;
 failed_usb_register:
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index cf3bc30..18c3183 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -156,10 +156,12 @@
 static void whiteheat_read_callback	(struct urb *urb, struct pt_regs *regs);
 static void whiteheat_write_callback	(struct urb *urb, struct pt_regs *regs);
 
-static struct usb_serial_device_type whiteheat_fake_device = {
-	.owner =		THIS_MODULE,
-	.name =			"Connect Tech - WhiteHEAT - (prerenumeration)",
-	.short_name =		"whiteheatnofirm",
+static struct usb_serial_driver whiteheat_fake_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"whiteheatnofirm",
+	},
+	.description =		"Connect Tech - WhiteHEAT - (prerenumeration)",
 	.id_table =		id_table_prerenumeration,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
@@ -169,10 +171,12 @@
 	.attach =		whiteheat_firmware_attach,
 };
 
-static struct usb_serial_device_type whiteheat_device = {
-	.owner =		THIS_MODULE,
-	.name =			"Connect Tech - WhiteHEAT",
-	.short_name =		"whiteheat",
+static struct usb_serial_driver whiteheat_device = {
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"whiteheat",
+	},
+	.description =		"Connect Tech - WhiteHEAT",
 	.id_table =		id_table_std,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
@@ -382,10 +386,10 @@
 	usb_clear_halt(serial->dev, pipe);
 	ret = usb_bulk_msg (serial->dev, pipe, command, 2, &alen, COMMAND_TIMEOUT_MS);
 	if (ret) {
-		err("%s: Couldn't send command [%d]", serial->type->name, ret);
+		err("%s: Couldn't send command [%d]", serial->type->description, ret);
 		goto no_firmware;
 	} else if (alen != sizeof(command)) {
-		err("%s: Send command incomplete [%d]", serial->type->name, alen);
+		err("%s: Send command incomplete [%d]", serial->type->description, alen);
 		goto no_firmware;
 	}
 
@@ -394,19 +398,19 @@
 	usb_clear_halt(serial->dev, pipe);
 	ret = usb_bulk_msg (serial->dev, pipe, result, sizeof(*hw_info) + 1, &alen, COMMAND_TIMEOUT_MS);
 	if (ret) {
-		err("%s: Couldn't get results [%d]", serial->type->name, ret);
+		err("%s: Couldn't get results [%d]", serial->type->description, ret);
 		goto no_firmware;
 	} else if (alen != sizeof(result)) {
-		err("%s: Get results incomplete [%d]", serial->type->name, alen);
+		err("%s: Get results incomplete [%d]", serial->type->description, alen);
 		goto no_firmware;
 	} else if (result[0] != command[0]) {
-		err("%s: Command failed [%d]", serial->type->name, result[0]);
+		err("%s: Command failed [%d]", serial->type->description, result[0]);
 		goto no_firmware;
 	}
 
 	hw_info = (struct whiteheat_hw_info *)&result[1];
 
-	info("%s: Driver %s: Firmware v%d.%02d", serial->type->name,
+	info("%s: Driver %s: Firmware v%d.%02d", serial->type->description,
 	     DRIVER_VERSION, hw_info->sw_major_rev, hw_info->sw_minor_rev);
 
 	for (i = 0; i < serial->num_ports; i++) {
@@ -414,7 +418,7 @@
 
 		info = (struct whiteheat_private *)kmalloc(sizeof(struct whiteheat_private), GFP_KERNEL);
 		if (info == NULL) {
-			err("%s: Out of memory for port structures\n", serial->type->name);
+			err("%s: Out of memory for port structures\n", serial->type->description);
 			goto no_private;
 		}
 
@@ -484,7 +488,7 @@
 
 	command_info = (struct whiteheat_command_private *)kmalloc(sizeof(struct whiteheat_command_private), GFP_KERNEL);
 	if (command_info == NULL) {
-		err("%s: Out of memory for port structures\n", serial->type->name);
+		err("%s: Out of memory for port structures\n", serial->type->description);
 		goto no_command_private;
 	}
 
@@ -501,9 +505,9 @@
 
 no_firmware:
 	/* Firmware likely not running */
-	err("%s: Unable to retrieve firmware version, try replugging\n", serial->type->name);
-	err("%s: If the firmware is not running (status led not blinking)\n", serial->type->name);
-	err("%s: please contact support@connecttech.com\n", serial->type->name);
+	err("%s: Unable to retrieve firmware version, try replugging\n", serial->type->description);
+	err("%s: If the firmware is not running (status led not blinking)\n", serial->type->description);
+	err("%s: please contact support@connecttech.com\n", serial->type->description);
 	return -ENODEV;
 
 no_command_private:
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index bb9819c..1a9679f 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -2,7 +2,8 @@
 # USB Storage driver configuration
 #
 
-comment "NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support' may also be needed; see USB_STORAGE Help for more information"
+comment "NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'"
+comment "may also be needed; see USB_STORAGE Help for more information"
 	depends on USB
 
 config USB_STORAGE
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
index 356342c..33c55a6 100644
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -1,4 +1,4 @@
-/* Driver for SCM Microsystems USB-ATAPI cable
+/* Driver for SCM Microsystems (a.k.a. Shuttle) USB-ATAPI cable
  *
  * $Id: shuttle_usbat.c,v 1.17 2002/04/22 03:39:43 mdharm Exp $
  *
@@ -67,10 +67,10 @@
 static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us);
 
 /*
- * Convenience function to produce an ATAPI read/write sectors command
+ * Convenience function to produce an ATA read/write sectors command
  * Use cmd=0x20 for read, cmd=0x30 for write
  */
-static void usbat_pack_atapi_sector_cmd(unsigned char *buf,
+static void usbat_pack_ata_sector_cmd(unsigned char *buf,
 					unsigned char thistime,
 					u32 sector, unsigned char cmd)
 {
@@ -196,10 +196,12 @@
 	if (rc != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_FAILED;
 
-	if (*reply & 0x01 && *reply != 0x51) // error/check condition (0x51 is ok)
+	/* error/check condition (0x51 is ok) */
+	if (*reply & 0x01 && *reply != 0x51)
 		return USB_STOR_TRANSPORT_FAILED;
 
-	if (*reply & 0x20) // device fault
+	/* device fault */
+	if (*reply & 0x20)
 		return USB_STOR_TRANSPORT_FAILED;
 
 	return USB_STOR_TRANSPORT_GOOD;
@@ -222,29 +224,39 @@
 	command[0] = 0x40;
 	command[1] = USBAT_CMD_SET_FEAT;
 
-	// The only bit relevant to ATA access is bit 6
-	// which defines 8 bit data access (set) or 16 bit (unset)
+	/*
+	 * The only bit relevant to ATA access is bit 6
+	 * which defines 8 bit data access (set) or 16 bit (unset)
+	 */
 	command[2] = epp_control;
 
-	// If FCQ is set in the qualifier (defined in R/W cmd), then bits U0, U1,
-	// ET1 and ET2 define an external event to be checked for on event of a
-	// _read_blocks or _write_blocks operation. The read/write will not take
-	// place unless the defined trigger signal is active.
+	/*
+	 * If FCQ is set in the qualifier (defined in R/W cmd), then bits U0, U1,
+	 * ET1 and ET2 define an external event to be checked for on event of a
+	 * _read_blocks or _write_blocks operation. The read/write will not take
+	 * place unless the defined trigger signal is active.
+	 */
 	command[3] = external_trigger;
 
-	// The resultant byte of the mask operation (see mask_byte) is compared for
-	// equivalence with this test pattern. If equal, the read/write will take
-	// place.
+	/*
+	 * The resultant byte of the mask operation (see mask_byte) is compared for
+	 * equivalence with this test pattern. If equal, the read/write will take
+	 * place.
+	 */
 	command[4] = test_pattern;
 
-	// This value is logically ANDed with the status register field specified
-	// in the read/write command.
+	/*
+	 * This value is logically ANDed with the status register field specified
+	 * in the read/write command.
+	 */
 	command[5] = mask_byte;
 
-	// If ALQ is set in the qualifier, this field contains the address of the
-	// registers where the byte count should be read for transferring the data.
-	// If ALQ is not set, then this field contains the number of bytes to be
-	// transferred.
+	/*
+	 * If ALQ is set in the qualifier, this field contains the address of the
+	 * registers where the byte count should be read for transferring the data.
+	 * If ALQ is not set, then this field contains the number of bytes to be
+	 * transferred.
+	 */
 	command[6] = subcountL;
 	command[7] = subcountH;
 
@@ -273,26 +285,26 @@
 
 		if (result!=USB_STOR_XFER_GOOD)
 			return USB_STOR_TRANSPORT_ERROR;
-		if (*status & 0x01) { // check condition
+		if (*status & 0x01) { /* check condition */
 			result = usbat_read(us, USBAT_ATA, 0x10, status);
 			return USB_STOR_TRANSPORT_FAILED;
 		}
-		if (*status & 0x20) // device fault
+		if (*status & 0x20) /* device fault */
 			return USB_STOR_TRANSPORT_FAILED;
 
-		if ((*status & 0x80)==0x00) { // not busy
+		if ((*status & 0x80)==0x00) { /* not busy */
 			US_DEBUGP("Waited not busy for %d steps\n", i);
 			return USB_STOR_TRANSPORT_GOOD;
 		}
 
 		if (i<500)
-			msleep(10); // 5 seconds
+			msleep(10); /* 5 seconds */
 		else if (i<700)
-			msleep(50); // 10 seconds
+			msleep(50); /* 10 seconds */
 		else if (i<1200)
-			msleep(100); // 50 seconds
+			msleep(100); /* 50 seconds */
 		else
-			msleep(1000); // X minutes
+			msleep(1000); /* X minutes */
 	}
 
 	US_DEBUGP("Waited not busy for %d minutes, timing out.\n",
@@ -412,9 +424,12 @@
 
 		if (i==0) {
 			cmdlen = 16;
-			// Write to multiple registers
-			// Not really sure the 0x07, 0x17, 0xfc, 0xe7 is necessary here,
-			// but that's what came out of the trace every single time.
+			/*
+			 * Write to multiple registers
+			 * Not really sure the 0x07, 0x17, 0xfc, 0xe7 is
+			 * necessary here, but that's what came out of the
+			 * trace every single time.
+			 */
 			command[0] = 0x40;
 			command[1] = access | USBAT_CMD_WRITE_REGS;
 			command[2] = 0x07;
@@ -426,7 +441,7 @@
 		} else
 			cmdlen = 8;
 
-		// Conditionally read or write blocks
+		/* Conditionally read or write blocks */
 		command[cmdlen-8] = (direction==DMA_TO_DEVICE ? 0x40 : 0xC0);
 		command[cmdlen-7] = access |
 				(direction==DMA_TO_DEVICE ?
@@ -456,11 +471,6 @@
 
 		}
 
-
-		//US_DEBUGP("Transfer %s %d bytes, sg buffers %d\n",
-		//	direction == DMA_TO_DEVICE ? "out" : "in",
-		//	len, use_sg);
-
 		result = usb_stor_bulk_transfer_sg(us,
 			pipe, content, len, use_sg, NULL);
 
@@ -508,9 +518,9 @@
 
 			if (result!=USB_STOR_XFER_GOOD)
 				return USB_STOR_TRANSPORT_ERROR;
-			if (*status & 0x01) // check condition
+			if (*status & 0x01) /* check condition */
 				return USB_STOR_TRANSPORT_FAILED;
-			if (*status & 0x20) // device fault
+			if (*status & 0x20) /* device fault */
 				return USB_STOR_TRANSPORT_FAILED;
 
 			US_DEBUGP("Redoing %s\n",
@@ -547,32 +557,32 @@
 
 	BUG_ON(num_registers > US_IOBUF_SIZE/2);
 
-	// Write to multiple registers, ATA access
+	/* Write to multiple registers, ATA access */
 	command[0] = 0x40;
 	command[1] = USBAT_ATA | USBAT_CMD_WRITE_REGS;
 
-	// No relevance
+	/* No relevance */
 	command[2] = 0;
 	command[3] = 0;
 	command[4] = 0;
 	command[5] = 0;
 
-	// Number of bytes to be transferred (incl. addresses and data)
+	/* Number of bytes to be transferred (incl. addresses and data) */
 	command[6] = LSB_of(num_registers*2);
 	command[7] = MSB_of(num_registers*2);
 
-	// The setup command
+	/* The setup command */
 	result = usbat_execute_command(us, command, 8);
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
-	// Create the reg/data, reg/data sequence
+	/* Create the reg/data, reg/data sequence */
 	for (i=0; i<num_registers; i++) {
 		data[i<<1] = registers[i];
 		data[1+(i<<1)] = data_out[i];
 	}
 
-	// Send the data
+	/* Send the data */
 	result = usbat_bulk_write(us, data, num_registers*2);
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
@@ -606,17 +616,17 @@
 	command[1] = USBAT_ATA | USBAT_CMD_COND_READ_BLOCK;
 	command[2] = USBAT_ATA_DATA;
 	command[3] = USBAT_ATA_STATUS;
-	command[4] = 0xFD; // Timeout (ms);
+	command[4] = 0xFD; /* Timeout (ms); */
 	command[5] = USBAT_QUAL_FCQ;
 	command[6] = LSB_of(len);
 	command[7] = MSB_of(len);
 
-	// Multiple block read setup command
+	/* Multiple block read setup command */
 	result = usbat_execute_command(us, command, 8);
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_FAILED;
 	
-	// Read the blocks we just asked for
+	/* Read the blocks we just asked for */
 	result = usbat_bulk_read(us, buffer, len);
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_FAILED;
@@ -647,17 +657,17 @@
 	command[1] = USBAT_ATA | USBAT_CMD_COND_WRITE_BLOCK;
 	command[2] = USBAT_ATA_DATA;
 	command[3] = USBAT_ATA_STATUS;
-	command[4] = 0xFD; // Timeout (ms)
+	command[4] = 0xFD; /* Timeout (ms) */
 	command[5] = USBAT_QUAL_FCQ;
 	command[6] = LSB_of(len);
 	command[7] = MSB_of(len);
 
-	// Multiple block write setup command
+	/* Multiple block write setup command */
 	result = usbat_execute_command(us, command, 8);
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_FAILED;
 	
-	// Write the data
+	/* Write the data */
 	result = usbat_bulk_write(us, buffer, len);
 	if (result != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_FAILED;
@@ -711,16 +721,20 @@
 {
 	int rc;
 
-	// Reset peripheral, enable peripheral control signals
-	// (bring reset signal up)
+	/*
+	 * Reset peripheral, enable peripheral control signals
+	 * (bring reset signal up)
+	 */
 	rc = usbat_write_user_io(us,
 							 USBAT_UIO_DRVRST | USBAT_UIO_OE1 | USBAT_UIO_OE0,
 							 USBAT_UIO_EPAD | USBAT_UIO_1);
 	if (rc != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 			
-	// Enable peripheral control signals
-	// (bring reset signal down)
+	/*
+	 * Enable peripheral control signals
+	 * (bring reset signal down)
+	 */
 	rc = usbat_write_user_io(us,
 							 USBAT_UIO_OE1  | USBAT_UIO_OE0,
 							 USBAT_UIO_EPAD | USBAT_UIO_1);
@@ -737,7 +751,7 @@
 {
 	int rc;
 
-	// Enable peripheral control signals and card detect
+	/* Enable peripheral control signals and card detect */
 	rc = usbat_write_user_io(us,
 							 USBAT_UIO_ACKD | USBAT_UIO_OE1  | USBAT_UIO_OE0,
 							 USBAT_UIO_EPAD | USBAT_UIO_1);
@@ -786,7 +800,7 @@
 	if (rc != USB_STOR_XFER_GOOD)
 		return USB_STOR_TRANSPORT_ERROR;
 
-	// Check for media existence
+	/* Check for media existence */
 	rc = usbat_flash_check_media_present(uio);
 	if (rc == USBAT_FLASH_MEDIA_NONE) {
 		info->sense_key = 0x02;
@@ -795,11 +809,11 @@
 		return USB_STOR_TRANSPORT_FAILED;
 	}
 
-	// Check for media change
+	/* Check for media change */
 	rc = usbat_flash_check_media_changed(uio);
 	if (rc == USBAT_FLASH_MEDIA_CHANGED) {
 
-		// Reset and re-enable card detect
+		/* Reset and re-enable card detect */
 		rc = usbat_device_reset(us);
 		if (rc != USB_STOR_TRANSPORT_GOOD)
 			return rc;
@@ -855,15 +869,15 @@
  	if (rc != USB_STOR_XFER_GOOD)
  		return USB_STOR_TRANSPORT_ERROR;
 
-	// Check for error bit
-	if (status & 0x01) {
-		 // Device is a CompactFlash reader/writer
-		US_DEBUGP("usbat_identify_device: Detected Flash reader/writer\n");
-		info->devicetype = USBAT_DEV_FLASH;
-	} else {
-		// Device is HP 8200
+	/* Check for error bit, or if the command 'fell through' */
+	if (status == 0xA1 || !(status & 0x01)) {
+		/* Device is HP 8200 */
 		US_DEBUGP("usbat_identify_device: Detected HP8200 CDRW\n");
 		info->devicetype = USBAT_DEV_HP8200;
+	} else {
+		/* Device is a CompactFlash reader/writer */
+		US_DEBUGP("usbat_identify_device: Detected Flash reader/writer\n");
+		info->devicetype = USBAT_DEV_FLASH;
 	}
 
 	return USB_STOR_TRANSPORT_GOOD;
@@ -916,7 +930,7 @@
 	if (!reply)
 		return USB_STOR_TRANSPORT_ERROR;
 
-	// ATAPI command : IDENTIFY DEVICE
+	/* ATA command : IDENTIFY DEVICE */
 	rc = usbat_multiple_write(us, registers, command, 3);
 	if (rc != USB_STOR_XFER_GOOD) {
 		US_DEBUGP("usbat_flash_get_sector_count: Gah! identify_device failed\n");
@@ -924,7 +938,7 @@
 		goto leave;
 	}
 
-	// Read device status
+	/* Read device status */
 	if (usbat_get_status(us, &status) != USB_STOR_XFER_GOOD) {
 		rc = USB_STOR_TRANSPORT_ERROR;
 		goto leave;
@@ -932,7 +946,7 @@
 
 	msleep(100);
 
-	// Read the device identification data
+	/* Read the device identification data */
 	rc = usbat_read_block(us, reply, 512);
 	if (rc != USB_STOR_TRANSPORT_GOOD)
 		goto leave;
@@ -977,19 +991,23 @@
 	if (result != USB_STOR_TRANSPORT_GOOD)
 		return result;
 
-	// we're working in LBA mode.  according to the ATA spec,
-	// we can support up to 28-bit addressing.  I don't know if Jumpshot
-	// supports beyond 24-bit addressing.  It's kind of hard to test
-	// since it requires > 8GB CF card.
+	/*
+	 * we're working in LBA mode.  according to the ATA spec,
+	 * we can support up to 28-bit addressing.  I don't know if Jumpshot
+	 * supports beyond 24-bit addressing.  It's kind of hard to test
+	 * since it requires > 8GB CF card.
+	 */
 
 	if (sector > 0x0FFFFFFF)
 		return USB_STOR_TRANSPORT_ERROR;
 
 	totallen = sectors * info->ssize;
 
-	// Since we don't read more than 64 KB at a time, we have to create
-	// a bounce buffer and move the data a piece at a time between the
-	// bounce buffer and the actual transfer buffer.
+	/*
+	 * Since we don't read more than 64 KB at a time, we have to create
+	 * a bounce buffer and move the data a piece at a time between the
+	 * bounce buffer and the actual transfer buffer.
+	 */
 
 	alloclen = min(totallen, 65536u);
 	buffer = kmalloc(alloclen, GFP_NOIO);
@@ -997,27 +1015,29 @@
 		return USB_STOR_TRANSPORT_ERROR;
 
 	do {
-		// loop, never allocate or transfer more than 64k at once
-		// (min(128k, 255*info->ssize) is the real limit)
+		/*
+		 * loop, never allocate or transfer more than 64k at once
+		 * (min(128k, 255*info->ssize) is the real limit)
+		 */
 		len = min(totallen, alloclen);
 		thistime = (len / info->ssize) & 0xff;
  
-		// ATAPI command 0x20 (READ SECTORS)
-		usbat_pack_atapi_sector_cmd(command, thistime, sector, 0x20);
+		/* ATA command 0x20 (READ SECTORS) */
+		usbat_pack_ata_sector_cmd(command, thistime, sector, 0x20);
 
-		// Write/execute ATAPI read command
+		/* Write/execute ATA read command */
 		result = usbat_multiple_write(us, registers, command, 7);
 		if (result != USB_STOR_TRANSPORT_GOOD)
 			goto leave;
 
-		// Read the data we just requested
+		/* Read the data we just requested */
 		result = usbat_read_blocks(us, buffer, len);
 		if (result != USB_STOR_TRANSPORT_GOOD)
 			goto leave;
   	 
 		US_DEBUGP("usbat_flash_read_data:  %d bytes\n", len);
 	
-		// Store the data in the transfer buffer
+		/* Store the data in the transfer buffer */
 		usb_stor_access_xfer_buf(buffer, len, us->srb,
 					 &sg_idx, &sg_offset, TO_XFER_BUF);
 
@@ -1061,19 +1081,23 @@
 	if (result != USB_STOR_TRANSPORT_GOOD)
 		return result;
 
-	// we're working in LBA mode.  according to the ATA spec,
-	// we can support up to 28-bit addressing.  I don't know if Jumpshot
-	// supports beyond 24-bit addressing.  It's kind of hard to test
-	// since it requires > 8GB CF card.
+	/*
+	 * we're working in LBA mode.  according to the ATA spec,
+	 * we can support up to 28-bit addressing.  I don't know if the device
+	 * supports beyond 24-bit addressing.  It's kind of hard to test
+	 * since it requires > 8GB media.
+	 */
 
 	if (sector > 0x0FFFFFFF)
 		return USB_STOR_TRANSPORT_ERROR;
 
 	totallen = sectors * info->ssize;
 
-	// Since we don't write more than 64 KB at a time, we have to create
-	// a bounce buffer and move the data a piece at a time between the
-	// bounce buffer and the actual transfer buffer.
+	/*
+	 * Since we don't write more than 64 KB at a time, we have to create
+	 * a bounce buffer and move the data a piece at a time between the
+	 * bounce buffer and the actual transfer buffer.
+	 */
 
 	alloclen = min(totallen, 65536u);
 	buffer = kmalloc(alloclen, GFP_NOIO);
@@ -1081,24 +1105,26 @@
 		return USB_STOR_TRANSPORT_ERROR;
 
 	do {
-		// loop, never allocate or transfer more than 64k at once
-		// (min(128k, 255*info->ssize) is the real limit)
+		/*
+		 * loop, never allocate or transfer more than 64k at once
+		 * (min(128k, 255*info->ssize) is the real limit)
+		 */
 		len = min(totallen, alloclen);
 		thistime = (len / info->ssize) & 0xff;
 
-		// Get the data from the transfer buffer
+		/* Get the data from the transfer buffer */
 		usb_stor_access_xfer_buf(buffer, len, us->srb,
 					 &sg_idx, &sg_offset, FROM_XFER_BUF);
 
-		// ATAPI command 0x30 (WRITE SECTORS)
-		usbat_pack_atapi_sector_cmd(command, thistime, sector, 0x30);		
+		/* ATA command 0x30 (WRITE SECTORS) */
+		usbat_pack_ata_sector_cmd(command, thistime, sector, 0x30);
 
-		// Write/execute ATAPI write command
+		/* Write/execute ATA write command */
 		result = usbat_multiple_write(us, registers, command, 7);
 		if (result != USB_STOR_TRANSPORT_GOOD)
 			goto leave;
 
-		// Write the data
+		/* Write the data */
 		result = usbat_write_blocks(us, buffer, len);
 		if (result != USB_STOR_TRANSPORT_GOOD)
 			goto leave;
@@ -1169,42 +1195,44 @@
 			srb->transfersize);
 	}
 
-	// Since we only read in one block at a time, we have to create
-	// a bounce buffer and move the data a piece at a time between the
-	// bounce buffer and the actual transfer buffer.
+	/*
+	 * Since we only read in one block at a time, we have to create
+	 * a bounce buffer and move the data a piece at a time between the
+	 * bounce buffer and the actual transfer buffer.
+	 */
 
 	len = (65535/srb->transfersize) * srb->transfersize;
 	US_DEBUGP("Max read is %d bytes\n", len);
 	len = min(len, srb->request_bufflen);
 	buffer = kmalloc(len, GFP_NOIO);
-	if (buffer == NULL) // bloody hell!
+	if (buffer == NULL) /* bloody hell! */
 		return USB_STOR_TRANSPORT_FAILED;
 	sector = short_pack(data[7+3], data[7+2]);
 	sector <<= 16;
 	sector |= short_pack(data[7+5], data[7+4]);
 	transferred = 0;
 
-	sg_segment = 0; // for keeping track of where we are in
-	sg_offset = 0;  // the scatter/gather list
+	sg_segment = 0; /* for keeping track of where we are in */
+	sg_offset = 0;  /* the scatter/gather list */
 
 	while (transferred != srb->request_bufflen) {
 
 		if (len > srb->request_bufflen - transferred)
 			len = srb->request_bufflen - transferred;
 
-		data[3] = len&0xFF; 	  // (cylL) = expected length (L)
-		data[4] = (len>>8)&0xFF;  // (cylH) = expected length (H)
+		data[3] = len&0xFF; 	  /* (cylL) = expected length (L) */
+		data[4] = (len>>8)&0xFF;  /* (cylH) = expected length (H) */
 
-		// Fix up the SCSI command sector and num sectors
+		/* Fix up the SCSI command sector and num sectors */
 
-		data[7+2] = MSB_of(sector>>16); // SCSI command sector
+		data[7+2] = MSB_of(sector>>16); /* SCSI command sector */
 		data[7+3] = LSB_of(sector>>16);
 		data[7+4] = MSB_of(sector&0xFFFF);
 		data[7+5] = LSB_of(sector&0xFFFF);
 		if (data[7+0] == GPCMD_READ_CD)
 			data[7+6] = 0;
-		data[7+7] = MSB_of(len / srb->transfersize); // SCSI command
-		data[7+8] = LSB_of(len / srb->transfersize); // num sectors
+		data[7+7] = MSB_of(len / srb->transfersize); /* SCSI command */
+		data[7+8] = LSB_of(len / srb->transfersize); /* num sectors */
 
 		result = usbat_hp8200e_rw_block_test(us, USBAT_ATA, 
 			registers, data, 19,
@@ -1217,16 +1245,16 @@
 		if (result != USB_STOR_TRANSPORT_GOOD)
 			break;
 
-		// Store the data in the transfer buffer
+		/* Store the data in the transfer buffer */
 		usb_stor_access_xfer_buf(buffer, len, srb,
 				 &sg_segment, &sg_offset, TO_XFER_BUF);
 
-		// Update the amount transferred and the sector number
+		/* Update the amount transferred and the sector number */
 
 		transferred += len;
 		sector += len / srb->transfersize;
 
-	} // while transferred != srb->request_bufflen
+	} /* while transferred != srb->request_bufflen */
 
 	kfree(buffer);
 	return result;
@@ -1237,7 +1265,7 @@
 	int selector;
 	unsigned char *status = us->iobuf;
 
-	// try device = master, then device = slave.
+	/* try device = master, then device = slave. */
 	for (selector = 0xA0; selector <= 0xB0; selector += 0x10) {
 		if (usbat_write(us, USBAT_ATA, USBAT_ATA_DEVICE, selector) !=
 				USB_STOR_XFER_GOOD)
@@ -1298,7 +1326,7 @@
 	memset(us->extra, 0, sizeof(struct usbat_info));
 	info = (struct usbat_info *) (us->extra);
 
-	// Enable peripheral control signals
+	/* Enable peripheral control signals */
 	rc = usbat_write_user_io(us,
 				 USBAT_UIO_OE1 | USBAT_UIO_OE0,
 				 USBAT_UIO_EPAD | USBAT_UIO_1);
@@ -1337,7 +1365,7 @@
 
 	US_DEBUGP("INIT 5\n");
 
-	// Enable peripheral control signals and card detect
+	/* Enable peripheral control signals and card detect */
 	rc = usbat_device_enable_cdt(us);
 	if (rc != USB_STOR_TRANSPORT_GOOD)
 		return rc;
@@ -1364,7 +1392,7 @@
 
 	US_DEBUGP("INIT 9\n");
 
-	// At this point, we need to detect which device we are using
+	/* At this point, we need to detect which device we are using */
 	if (usbat_set_transport(us, info))
 		return USB_STOR_TRANSPORT_ERROR;
 
@@ -1414,10 +1442,10 @@
 	data[0] = 0x00;
 	data[1] = 0x00;
 	data[2] = 0x00;
-	data[3] = len&0xFF; 		// (cylL) = expected length (L)
-	data[4] = (len>>8)&0xFF; 	// (cylH) = expected length (H)
-	data[5] = 0xB0; 		// (device sel) = slave
-	data[6] = 0xA0; 		// (command) = ATA PACKET COMMAND
+	data[3] = len&0xFF; 		/* (cylL) = expected length (L) */
+	data[4] = (len>>8)&0xFF; 	/* (cylH) = expected length (H) */
+	data[5] = 0xB0; 		/* (device sel) = slave */
+	data[6] = 0xA0; 		/* (command) = ATA PACKET COMMAND */
 
 	for (i=7; i<19; i++) {
 		registers[i] = 0x10;
@@ -1466,13 +1494,15 @@
 		return result;
 	}
 
-	// Write the 12-byte command header.
-
-	// If the command is BLANK then set the timer for 75 minutes.
-	// Otherwise set it for 10 minutes.
-
-	// NOTE: THE 8200 DOCUMENTATION STATES THAT BLANKING A CDRW
-	// AT SPEED 4 IS UNRELIABLE!!!
+	/*
+	 * Write the 12-byte command header.
+	 *
+	 * If the command is BLANK then set the timer for 75 minutes.
+	 * Otherwise set it for 10 minutes.
+	 *
+	 * NOTE: THE 8200 DOCUMENTATION STATES THAT BLANKING A CDRW
+	 * AT SPEED 4 IS UNRELIABLE!!!
+	 */
 
 	if ( (result = usbat_write_block(us, 
 			USBAT_ATA, srb->cmnd, 12,
@@ -1481,19 +1511,18 @@
 		return result;
 	}
 
-	// If there is response data to be read in 
-	// then do it here.
+	/* If there is response data to be read in then do it here. */
 
 	if (len != 0 && (srb->sc_data_direction == DMA_FROM_DEVICE)) {
 
-		// How many bytes to read in? Check cylL register
+		/* How many bytes to read in? Check cylL register */
 
 		if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_ME, status) != 
 		    	USB_STOR_XFER_GOOD) {
 			return USB_STOR_TRANSPORT_ERROR;
 		}
 
-		if (len > 0xFF) { // need to read cylH also
+		if (len > 0xFF) { /* need to read cylH also */
 			len = *status;
 			if (usbat_read(us, USBAT_ATA, USBAT_ATA_LBA_HI, status) !=
 				    USB_STOR_XFER_GOOD) {
@@ -1556,13 +1585,16 @@
 		if (rc != USB_STOR_TRANSPORT_GOOD)
 			return rc;
 
-		info->ssize = 0x200;  // hard coded 512 byte sectors as per ATA spec
+		/* hard coded 512 byte sectors as per ATA spec */
+		info->ssize = 0x200;
 		US_DEBUGP("usbat_flash_transport: READ_CAPACITY: %ld sectors, %ld bytes per sector\n",
 			  info->sectors, info->ssize);
 
-		// build the reply
-		// note: must return the sector number of the last sector,
-		// *not* the total number of sectors
+		/*
+		 * build the reply
+		 * note: must return the sector number of the last sector,
+		 * *not* the total number of sectors
+		 */
 		((__be32 *) ptr)[0] = cpu_to_be32(info->sectors - 1);
 		((__be32 *) ptr)[1] = cpu_to_be32(info->ssize);
 		usb_stor_set_xfer_buf(ptr, 8, srb);
@@ -1586,7 +1618,9 @@
 	}
 
 	if (srb->cmnd[0] == READ_12) {
-		// I don't think we'll ever see a READ_12 but support it anyway...
+		/*
+		 * I don't think we'll ever see a READ_12 but support it anyway
+		 */
 		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
 		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
 
@@ -1608,7 +1642,9 @@
 	}
 
 	if (srb->cmnd[0] == WRITE_12) {
-		// I don't think we'll ever see a WRITE_12 but support it anyway...
+		/*
+		 * I don't think we'll ever see a WRITE_12 but support it anyway
+		 */
 		block = ((u32)(srb->cmnd[2]) << 24) | ((u32)(srb->cmnd[3]) << 16) |
 		        ((u32)(srb->cmnd[4]) <<  8) | ((u32)(srb->cmnd[5]));
 
@@ -1645,8 +1681,10 @@
 	}
 
 	if (srb->cmnd[0] == ALLOW_MEDIUM_REMOVAL) {
-		// sure.  whatever.  not like we can stop the user from popping
-		// the media out of the device (no locking doors, etc)
+		/*
+		 * sure.  whatever.  not like we can stop the user from popping
+		 * the media out of the device (no locking doors, etc)
+		 */
 		return USB_STOR_TRANSPORT_GOOD;
 	}
 
diff --git a/drivers/usb/storage/shuttle_usbat.h b/drivers/usb/storage/shuttle_usbat.h
index 5b8e867..25e7d8b 100644
--- a/drivers/usb/storage/shuttle_usbat.h
+++ b/drivers/usb/storage/shuttle_usbat.h
@@ -55,8 +55,8 @@
 #define USBAT_UIO_WRITE	0
 
 /* Qualifier bits */
-#define USBAT_QUAL_FCQ	0x20 // full compare
-#define USBAT_QUAL_ALQ	0x10 // auto load subcount
+#define USBAT_QUAL_FCQ	0x20	/* full compare */
+#define USBAT_QUAL_ALQ	0x10	/* auto load subcount */
 
 /* USBAT Flash Media status types */
 #define USBAT_FLASH_MEDIA_NONE	0
@@ -67,39 +67,39 @@
 #define USBAT_FLASH_MEDIA_CHANGED	1
 
 /* USBAT ATA registers */
-#define USBAT_ATA_DATA      0x10  // read/write data (R/W)
-#define USBAT_ATA_FEATURES  0x11  // set features (W)
-#define USBAT_ATA_ERROR     0x11  // error (R)
-#define USBAT_ATA_SECCNT    0x12  // sector count (R/W)
-#define USBAT_ATA_SECNUM    0x13  // sector number (R/W)
-#define USBAT_ATA_LBA_ME    0x14  // cylinder low (R/W)
-#define USBAT_ATA_LBA_HI    0x15  // cylinder high (R/W)
-#define USBAT_ATA_DEVICE    0x16  // head/device selection (R/W)
-#define USBAT_ATA_STATUS    0x17  // device status (R)
-#define USBAT_ATA_CMD       0x17  // device command (W)
-#define USBAT_ATA_ALTSTATUS 0x0E  // status (no clear IRQ) (R)
+#define USBAT_ATA_DATA      0x10  /* read/write data (R/W) */
+#define USBAT_ATA_FEATURES  0x11  /* set features (W) */
+#define USBAT_ATA_ERROR     0x11  /* error (R) */
+#define USBAT_ATA_SECCNT    0x12  /* sector count (R/W) */
+#define USBAT_ATA_SECNUM    0x13  /* sector number (R/W) */
+#define USBAT_ATA_LBA_ME    0x14  /* cylinder low (R/W) */
+#define USBAT_ATA_LBA_HI    0x15  /* cylinder high (R/W) */
+#define USBAT_ATA_DEVICE    0x16  /* head/device selection (R/W) */
+#define USBAT_ATA_STATUS    0x17  /* device status (R) */
+#define USBAT_ATA_CMD       0x17  /* device command (W) */
+#define USBAT_ATA_ALTSTATUS 0x0E  /* status (no clear IRQ) (R) */
 
 /* USBAT User I/O Data registers */
-#define USBAT_UIO_EPAD		0x80 // Enable Peripheral Control Signals
-#define USBAT_UIO_CDT		0x40 // Card Detect (Read Only)
-				     // CDT = ACKD & !UI1 & !UI0
-#define USBAT_UIO_1		0x20 // I/O 1
-#define USBAT_UIO_0		0x10 // I/O 0
-#define USBAT_UIO_EPP_ATA	0x08 // 1=EPP mode, 0=ATA mode
-#define USBAT_UIO_UI1		0x04 // Input 1
-#define USBAT_UIO_UI0		0x02 // Input 0
-#define USBAT_UIO_INTR_ACK	0x01 // Interrupt (ATA & ISA)/Acknowledge (EPP)
+#define USBAT_UIO_EPAD		0x80 /* Enable Peripheral Control Signals */
+#define USBAT_UIO_CDT		0x40 /* Card Detect (Read Only) */
+				     /* CDT = ACKD & !UI1 & !UI0 */
+#define USBAT_UIO_1		0x20 /* I/O 1 */
+#define USBAT_UIO_0		0x10 /* I/O 0 */
+#define USBAT_UIO_EPP_ATA	0x08 /* 1=EPP mode, 0=ATA mode */
+#define USBAT_UIO_UI1		0x04 /* Input 1 */
+#define USBAT_UIO_UI0		0x02 /* Input 0 */
+#define USBAT_UIO_INTR_ACK	0x01 /* Interrupt (ATA/ISA)/Acknowledge (EPP) */
 
 /* USBAT User I/O Enable registers */
-#define USBAT_UIO_DRVRST	0x80 // Reset Peripheral
-#define USBAT_UIO_ACKD		0x40 // Enable Card Detect
-#define USBAT_UIO_OE1		0x20 // I/O 1 set=output/clr=input
-				     // If ACKD=1, set OE1 to 1 also.
-#define USBAT_UIO_OE0		0x10 // I/O 0 set=output/clr=input
-#define USBAT_UIO_ADPRST	0x01 // Reset SCM chip
+#define USBAT_UIO_DRVRST	0x80 /* Reset Peripheral */
+#define USBAT_UIO_ACKD		0x40 /* Enable Card Detect */
+#define USBAT_UIO_OE1		0x20 /* I/O 1 set=output/clr=input */
+				     /* If ACKD=1, set OE1 to 1 also. */
+#define USBAT_UIO_OE0		0x10 /* I/O 0 set=output/clr=input */
+#define USBAT_UIO_ADPRST	0x01 /* Reset SCM chip */
 
 /* USBAT Features */
-#define USBAT_FEAT_ETEN	0x80 // External trigger enable
+#define USBAT_FEAT_ETEN	0x80	/* External trigger enable */
 #define USBAT_FEAT_U1	0x08
 #define USBAT_FEAT_U0	0x04
 #define USBAT_FEAT_ET1	0x02
@@ -112,12 +112,12 @@
 	int devicetype;
 
 	/* Used for Flash readers only */
-	unsigned long sectors;     // total sector count
-	unsigned long ssize;       // sector size in bytes
+	unsigned long sectors;     /* total sector count */
+	unsigned long ssize;       /* sector size in bytes */
 
 	unsigned char sense_key;
-	unsigned long sense_asc;   // additional sense code
-	unsigned long sense_ascq;  // additional sense code qualifier
+	unsigned long sense_asc;   /* additional sense code */
+	unsigned long sense_ascq;  /* additional sense code qualifier */
 };
 
 #endif
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index c1ba530..7ca896a 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -636,11 +636,11 @@
 
 		/* use the new buffer we have */
 		old_request_buffer = srb->request_buffer;
-		srb->request_buffer = srb->sense_buffer;
+		srb->request_buffer = us->sensebuf;
 
 		/* set the buffer length for transfer */
 		old_request_bufflen = srb->request_bufflen;
-		srb->request_bufflen = 18;
+		srb->request_bufflen = US_SENSE_SIZE;
 
 		/* set up for no scatter-gather use */
 		old_sg = srb->use_sg;
@@ -652,6 +652,7 @@
 		temp_result = us->transport(us->srb, us);
 
 		/* let's clean up right away */
+		memcpy(srb->sense_buffer, us->sensebuf, US_SENSE_SIZE);
 		srb->resid = old_resid;
 		srb->request_buffer = old_request_buffer;
 		srb->request_bufflen = old_request_bufflen;
@@ -923,6 +924,7 @@
 	int result;
 
 	/* issue the command */
+	us->iobuf[0] = 0;
 	result = usb_stor_control_msg(us, us->recv_ctrl_pipe,
 				 US_BULK_GET_MAX_LUN, 
 				 USB_DIR_IN | USB_TYPE_CLASS | 
diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
index 8d9e066..0a362cc 100644
--- a/drivers/usb/storage/transport.h
+++ b/drivers/usb/storage/transport.h
@@ -50,7 +50,7 @@
 #define US_PR_CB	0x01		/* Control/Bulk w/o interrupt */
 #define US_PR_BULK	0x50		/* bulk only */
 #ifdef CONFIG_USB_STORAGE_USBAT
-#define US_PR_SCM_ATAPI	0x80		/* SCM-ATAPI bridge */
+#define US_PR_USBAT	0x80		/* SCM-ATAPI bridge */
 #endif
 #ifdef CONFIG_USB_STORAGE_SDDR09
 #define US_PR_EUSB_SDDR09	0x81	/* SCM-SCSI bridge for SDDR-09 */
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index b79dad1..9e926a8 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -71,12 +71,12 @@
 UNUSUAL_DEV(  0x03f0, 0x0207, 0x0001, 0x0001, 
 		"HP",
 		"CD-Writer+ 8200e",
-		US_SC_8070, US_PR_SCM_ATAPI, init_usbat, 0), 
+		US_SC_8070, US_PR_USBAT, init_usbat, 0),
 
 UNUSUAL_DEV(  0x03f0, 0x0307, 0x0001, 0x0001, 
 		"HP",
 		"CD-Writer+ CD-4e",
-		US_SC_8070, US_PR_SCM_ATAPI, init_usbat, 0), 
+		US_SC_8070, US_PR_USBAT, init_usbat, 0),
 #endif
 
 /* Patch submitted by Mihnea-Costin Grigore <mihnea@zulu.ro> */
@@ -106,6 +106,13 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_INQUIRY ),
 
+/* Reported by Stefan Werner <dustbln@gmx.de> */
+UNUSUAL_DEV(  0x0419, 0xaaf6, 0x0100, 0x0100,
+		"TrekStor",
+		"i.Beat Joy 2.0",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_IGNORE_RESIDUE ),
+
 /* Reported by Olaf Hering <olh@suse.de> from novell bug #105878 */
 UNUSUAL_DEV(  0x0424, 0x0fdc, 0x0210, 0x0210,
 		"SMSC",
@@ -244,6 +251,13 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ),
 
+/* Reported by Simeon Simeonov <simeonov_2000@yahoo.com> */
+UNUSUAL_DEV(  0x04da, 0x2373, 0x0000, 0x9999,
+		"LEICA",
+		"D-LUX Camera",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY | US_FL_NOT_LOCKABLE ),
+
 /* Most of the following entries were developed with the help of
  * Shuttle/SCM directly.
  */
@@ -333,9 +347,9 @@
 
 #ifdef CONFIG_USB_STORAGE_USBAT
 UNUSUAL_DEV(  0x04e6, 0x1010, 0x0000, 0x9999,
-		"SCM",
-		"SCM USBAT-02",
-		US_SC_SCSI, US_PR_SCM_ATAPI, init_usbat,
+		"Shuttle/SCM",
+		"USBAT-02",
+		US_SC_SCSI, US_PR_USBAT, init_usbat,
 		US_FL_SINGLE_LUN),
 #endif
 
@@ -598,6 +612,16 @@
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
 		US_FL_FIX_CAPACITY ),
 
+/*
+ * Reported by Tyson Vinson <lornoss@gmail.com>
+ * This particular productId is the iPod Nano
+ */
+UNUSUAL_DEV( 0x05ac, 0x120a, 0x0000, 0x9999,
+		"Apple",
+		"iPod",
+		US_SC_DEVICE, US_PR_DEVICE, NULL,
+		US_FL_FIX_CAPACITY ),
+
 #ifdef CONFIG_USB_STORAGE_JUMPSHOT
 UNUSUAL_DEV(  0x05dc, 0x0001, 0x0000, 0x0001,
 		"Lexar",
@@ -702,6 +726,14 @@
 		US_SC_SCSI, US_PR_CB, NULL,
 		US_FL_SINGLE_LUN ),
 
+#ifdef CONFIG_USB_STORAGE_USBAT
+UNUSUAL_DEV(  0x0781, 0x0005, 0x0005, 0x0005,
+		"Sandisk",
+		"ImageMate SDDR-05b",
+		US_SC_SCSI, US_PR_USBAT, init_usbat,
+		US_FL_SINGLE_LUN ),
+#endif
+
 UNUSUAL_DEV(  0x0781, 0x0100, 0x0100, 0x0100,
 		"Sandisk",
 		"ImageMate SDDR-12",
@@ -724,7 +756,7 @@
 #endif
 
 /* Reported by Eero Volotinen <eero@ping-viini.org> */
-UNUSUAL_DEV(  0x07ab, 0xfccd, 0x0406, 0x0406,
+UNUSUAL_DEV(  0x07ab, 0xfccd, 0x0000, 0x9999,
 		"Freecom Technologies",
 		"FHD-Classic",
 		US_SC_DEVICE, US_PR_DEVICE, NULL,
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index f9a9bfa..3847ebe 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -54,6 +54,7 @@
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
+#include <linux/kthread.h>
 
 #include <scsi/scsi.h>
 #include <scsi/scsi_cmnd.h>
@@ -111,11 +112,6 @@
 static DECLARE_COMPLETION(threads_gone);
 
 
-static int storage_probe(struct usb_interface *iface,
-			 const struct usb_device_id *id);
-
-static void storage_disconnect(struct usb_interface *iface);
-
 /* The entries in this table, except for final ones here
  * (USB_MASS_STORAGE_CLASS and the empty entry), correspond,
  * line for line with the entries of us_unsuaul_dev_list[].
@@ -233,13 +229,40 @@
 	{ NULL }
 };
 
-static struct usb_driver usb_storage_driver = {
-	.owner =	THIS_MODULE,
-	.name =		"usb-storage",
-	.probe =	storage_probe,
-	.disconnect =	storage_disconnect,
-	.id_table =	storage_usb_ids,
-};
+
+#ifdef CONFIG_PM	/* Minimal support for suspend and resume */
+
+static int storage_suspend(struct usb_interface *iface, pm_message_t message)
+{
+	struct us_data *us = usb_get_intfdata(iface);
+
+	/* Wait until no command is running */
+	down(&us->dev_semaphore);
+
+	US_DEBUGP("%s\n", __FUNCTION__);
+	iface->dev.power.power_state.event = message.event;
+
+	/* When runtime PM is working, we'll set a flag to indicate
+	 * whether we should autoresume when a SCSI request arrives. */
+
+	up(&us->dev_semaphore);
+	return 0;
+}
+
+static int storage_resume(struct usb_interface *iface)
+{
+	struct us_data *us = usb_get_intfdata(iface);
+
+	down(&us->dev_semaphore);
+
+	US_DEBUGP("%s\n", __FUNCTION__);
+	iface->dev.power.power_state.event = PM_EVENT_ON;
+
+	up(&us->dev_semaphore);
+	return 0;
+}
+
+#endif /* CONFIG_PM */
 
 /*
  * fill_inquiry_response takes an unsigned char array (which must
@@ -288,22 +311,7 @@
 	struct us_data *us = (struct us_data *)__us;
 	struct Scsi_Host *host = us_to_host(us);
 
-	lock_kernel();
-
-	/*
-	 * This thread doesn't need any user-level access,
-	 * so get rid of all our resources.
-	 */
-	daemonize("usb-storage");
 	current->flags |= PF_NOFREEZE;
-	unlock_kernel();
-
-	/* acquire a reference to the host, so it won't be deallocated
-	 * until we're ready to exit */
-	scsi_host_get(host);
-
-	/* signal that we've started the thread */
-	complete(&(us->notify));
 
 	for(;;) {
 		US_DEBUGP("*** thread sleeping.\n");
@@ -467,6 +475,12 @@
 		US_DEBUGP("I/O buffer allocation failed\n");
 		return -ENOMEM;
 	}
+
+	us->sensebuf = kmalloc(US_SENSE_SIZE, GFP_KERNEL);
+	if (!us->sensebuf) {
+		US_DEBUGP("Sense buffer allocation failed\n");
+		return -ENOMEM;
+	}
 	return 0;
 }
 
@@ -555,8 +569,8 @@
 		break;
 
 #ifdef CONFIG_USB_STORAGE_USBAT
-	case US_PR_SCM_ATAPI:
-		us->transport_name = "SCM/ATAPI";
+	case US_PR_USBAT:
+		us->transport_name = "Shuttle USBAT";
 		us->transport = usbat_transport;
 		us->transport_reset = usb_stor_CB_reset;
 		us->max_lun = 1;
@@ -740,6 +754,7 @@
 static int usb_stor_acquire_resources(struct us_data *us)
 {
 	int p;
+	struct task_struct *th;
 
 	us->current_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!us->current_urb) {
@@ -747,38 +762,28 @@
 		return -ENOMEM;
 	}
 
-	/* Lock the device while we carry out the next two operations */
-	down(&us->dev_semaphore);
-
-	/* For bulk-only devices, determine the max LUN value */
-	if (us->protocol == US_PR_BULK) {
-		p = usb_stor_Bulk_max_lun(us);
-		if (p < 0) {
-			up(&us->dev_semaphore);
-			return p;
-		}
-		us->max_lun = p;
-	}
-
 	/* Just before we start our control thread, initialize
 	 * the device if it needs initialization */
-	if (us->unusual_dev->initFunction)
-		us->unusual_dev->initFunction(us);
-
-	up(&us->dev_semaphore);
+	if (us->unusual_dev->initFunction) {
+		p = us->unusual_dev->initFunction(us);
+		if (p)
+			return p;
+	}
 
 	/* Start up our control thread */
-	p = kernel_thread(usb_stor_control_thread, us, CLONE_VM);
-	if (p < 0) {
+	th = kthread_create(usb_stor_control_thread, us, "usb-storage");
+	if (IS_ERR(th)) {
 		printk(KERN_WARNING USB_STORAGE 
 		       "Unable to start control thread\n");
-		return p;
+		return PTR_ERR(th);
 	}
-	us->pid = p;
-	atomic_inc(&total_threads);
 
-	/* Wait for the thread to start */
-	wait_for_completion(&(us->notify));
+	/* Take a reference to the host for the control thread and
+	 * count it among all the threads we have launched.  Then
+	 * start it up. */
+	scsi_host_get(us_to_host(us));
+	atomic_inc(&total_threads);
+	wake_up_process(th);
 
 	return 0;
 }
@@ -812,6 +817,8 @@
 {
 	US_DEBUGP("-- %s\n", __FUNCTION__);
 
+	kfree(us->sensebuf);
+
 	/* Free the device-related DMA-mapped buffers */
 	if (us->cr)
 		usb_buffer_free(us->pusb_dev, sizeof(*us->cr), us->cr,
@@ -872,21 +879,6 @@
 {
 	struct us_data *us = (struct us_data *)__us;
 
-	/*
-	 * This thread doesn't need any user-level access,
-	 * so get rid of all our resources.
-	 */
-	lock_kernel();
-	daemonize("usb-stor-scan");
-	unlock_kernel();
-
-	/* Acquire a reference to the host, so it won't be deallocated
-	 * until we're ready to exit */
-	scsi_host_get(us_to_host(us));
-
-	/* Signal that we've started the thread */
-	complete(&(us->notify));
-
 	printk(KERN_DEBUG
 		"usb-storage: device found at %d\n", us->pusb_dev->devnum);
 
@@ -904,6 +896,14 @@
 
 	/* If the device is still connected, perform the scanning */
 	if (!test_bit(US_FLIDX_DISCONNECTING, &us->flags)) {
+
+		/* For bulk-only devices, determine the max LUN value */
+		if (us->protocol == US_PR_BULK &&
+				!(us->flags & US_FL_SINGLE_LUN)) {
+			down(&us->dev_semaphore);
+			us->max_lun = usb_stor_Bulk_max_lun(us);
+			up(&us->dev_semaphore);
+		}
 		scsi_scan_host(us_to_host(us));
 		printk(KERN_DEBUG "usb-storage: device scan complete\n");
 
@@ -923,6 +923,7 @@
 	struct us_data *us;
 	const int id_index = id - storage_usb_ids; 
 	int result;
+	struct task_struct *th;
 
 	US_DEBUGP("USB Mass Storage device detected\n");
 
@@ -1003,17 +1004,21 @@
 	}
 
 	/* Start up the thread for delayed SCSI-device scanning */
-	result = kernel_thread(usb_stor_scan_thread, us, CLONE_VM);
-	if (result < 0) {
+	th = kthread_create(usb_stor_scan_thread, us, "usb-stor-scan");
+	if (IS_ERR(th)) {
 		printk(KERN_WARNING USB_STORAGE 
 		       "Unable to start the device-scanning thread\n");
 		quiesce_and_remove_host(us);
+		result = PTR_ERR(th);
 		goto BadDevice;
 	}
-	atomic_inc(&total_threads);
 
-	/* Wait for the thread to start */
-	wait_for_completion(&(us->notify));
+	/* Take a reference to the host for the scanning thread and
+	 * count it among all the threads we have launched.  Then
+	 * start it up. */
+	scsi_host_get(us_to_host(us));
+	atomic_inc(&total_threads);
+	wake_up_process(th);
 
 	return 0;
 
@@ -1038,6 +1043,18 @@
  * Initialization and registration
  ***********************************************************************/
 
+static struct usb_driver usb_storage_driver = {
+	.owner =	THIS_MODULE,
+	.name =		"usb-storage",
+	.probe =	storage_probe,
+	.disconnect =	storage_disconnect,
+#ifdef CONFIG_PM
+	.suspend =	storage_suspend,
+	.resume =	storage_resume,
+#endif
+	.id_table =	storage_usb_ids,
+};
+
 static int __init usb_stor_init(void)
 {
 	int retval;
diff --git a/drivers/usb/storage/usb.h b/drivers/usb/storage/usb.h
index a195ada..98b0971 100644
--- a/drivers/usb/storage/usb.h
+++ b/drivers/usb/storage/usb.h
@@ -117,6 +117,7 @@
  */
 
 #define US_IOBUF_SIZE		64	/* Size of the DMA-mapped I/O buffer */
+#define US_SENSE_SIZE		18	/* Size of the autosense data buffer */
 
 typedef int (*trans_cmnd)(struct scsi_cmnd *, struct us_data*);
 typedef int (*trans_reset)(struct us_data*);
@@ -160,14 +161,12 @@
 	struct scsi_cmnd	*srb;		 /* current srb		*/
 	unsigned int		tag;		 /* current dCBWTag	*/
 
-	/* thread information */
-	int			pid;		 /* control thread	 */
-
 	/* control and bulk communications data */
 	struct urb		*current_urb;	 /* USB requests	 */
 	struct usb_ctrlrequest	*cr;		 /* control requests	 */
 	struct usb_sg_request	current_sg;	 /* scatter-gather req.  */
 	unsigned char		*iobuf;		 /* I/O buffer		 */
+	unsigned char		*sensebuf;	 /* sense data buffer	 */
 	dma_addr_t		cr_dma;		 /* buffer DMA addresses */
 	dma_addr_t		iobuf_dma;
 
diff --git a/drivers/usb/usb-skeleton.c b/drivers/usb/usb-skeleton.c
index 353f24d..6c3a53f 100644
--- a/drivers/usb/usb-skeleton.c
+++ b/drivers/usb/usb-skeleton.c
@@ -223,9 +223,8 @@
  * and to have the device registered with devfs and the driver core
  */
 static struct usb_class_driver skel_class = {
-	.name =		"usb/skel%d",
+	.name =		"skel%d",
 	.fops =		&skel_fops,
-	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
 	.minor_base =	USB_SKEL_MINOR_BASE,
 };
 
diff --git a/fs/compat_ioctl.c b/fs/compat_ioctl.c
index e28a7420..a327e03 100644
--- a/fs/compat_ioctl.c
+++ b/fs/compat_ioctl.c
@@ -3050,6 +3050,7 @@
 HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control)
 HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk)
 HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal)
+COMPATIBLE_IOCTL(USBDEVFS_IOCTL32)
 /* i2c */
 HANDLE_IOCTL(I2C_FUNCS, w_long)
 HANDLE_IOCTL(I2C_RDWR, do_i2c_rdwr_ioctl)
diff --git a/include/asm-i386/mach-summit/mach_mpparse.h b/include/asm-i386/mach-summit/mach_mpparse.h
index 2b9e6d5..1cce2b9 100644
--- a/include/asm-i386/mach-summit/mach_mpparse.h
+++ b/include/asm-i386/mach-summit/mach_mpparse.h
@@ -22,7 +22,6 @@
 {
 }
 
-extern int usb_early_handoff;
 static inline int mps_oem_check(struct mp_config_table *mpc, char *oem, 
 		char *productid)
 {
@@ -32,7 +31,6 @@
 			 || !strncmp(productid, "RUTHLESS SMP", 12))){
 		use_cyclone = 1; /*enable cyclone-timer*/
 		setup_summit();
-		usb_early_handoff = 1;
 		return 1;
 	}
 	return 0;
@@ -46,7 +44,6 @@
 	     || !strncmp(oem_table_id, "EXA", 3))){
 		use_cyclone = 1; /*enable cyclone-timer*/
 		setup_summit();
-		usb_early_handoff = 1;
 		return 1;
 	}
 	return 0;
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 7d300f7..467a096 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -96,6 +96,9 @@
 #define PCI_CLASS_SERIAL_ACCESS		0x0c01
 #define PCI_CLASS_SERIAL_SSA		0x0c02
 #define PCI_CLASS_SERIAL_USB		0x0c03
+#define PCI_CLASS_SERIAL_USB_UHCI	0x0c0300
+#define PCI_CLASS_SERIAL_USB_OHCI	0x0c0310
+#define PCI_CLASS_SERIAL_USB_EHCI	0x0c0320
 #define PCI_CLASS_SERIAL_FIBER		0x0c04
 #define PCI_CLASS_SERIAL_SMBUS		0x0c05
 
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 7897cf5..c61d5de 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -224,7 +224,6 @@
 	unsigned		should_wakeup:1;
 	pm_message_t		prev_state;
 	void			* saved_state;
-	atomic_t		pm_users;
 	struct device		* pm_parent;
 	struct list_head	entry;
 #endif
@@ -244,6 +243,9 @@
 #define device_may_wakeup(dev) \
 	(device_can_wakeup(dev) && (dev)->power.should_wakeup)
 
+extern int dpm_runtime_suspend(struct device *, pm_message_t);
+extern void dpm_runtime_resume(struct device *);
+
 #else /* !CONFIG_PM */
 
 static inline int device_suspend(pm_message_t state)
@@ -254,6 +256,16 @@
 #define device_set_wakeup_enable(dev,val)	do{}while(0)
 #define device_may_wakeup(dev)			(0)
 
+static inline int dpm_runtime_suspend(struct device * dev, pm_message_t state)
+{
+	return 0;
+}
+
+static inline void dpm_runtime_resume(struct device * dev)
+{
+
+}
+
 #endif
 
 /* changes to device_may_wakeup take effect on the next pm state change.
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 8f731e8..748d043 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -57,6 +57,7 @@
 	struct usb_endpoint_descriptor	desc;
 	struct list_head		urb_list;
 	void				*hcpriv;
+	struct kobject			*kobj;	/* For sysfs info */
 
 	unsigned char *extra;   /* Extra descriptors */
 	int extralen;
@@ -136,7 +137,8 @@
 					 * active alternate setting */
 	unsigned num_altsetting;	/* number of alternate settings */
 
-	int minor;			/* minor number this interface is bound to */
+	int minor;			/* minor number this interface is
+					 * bound to */
 	enum usb_interface_condition condition;		/* state of binding */
 	struct device dev;		/* interface specific device info */
 	struct class_device *class_dev;
@@ -229,7 +231,7 @@
 struct usb_host_config {
 	struct usb_config_descriptor	desc;
 
-	char *string;
+	char *string;		/* iConfiguration string, if present */
 	/* the interfaces associated with this configuration,
 	 * stored in no particular order */
 	struct usb_interface *interface[USB_MAXINTERFACES];
@@ -248,7 +250,7 @@
 	__usb_get_extra_descriptor((ifpoint)->extra,(ifpoint)->extralen,\
 		type,(void**)ptr)
 
-/* -------------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- */
 
 struct usb_operations;
 
@@ -268,7 +270,8 @@
 	unsigned is_b_host:1;		/* true during some HNP roleswitches */
 	unsigned b_hnp_enable:1;	/* OTG: did A-Host enable HNP? */
 
-	int devnum_next;		/* Next open device number in round-robin allocation */
+	int devnum_next;		/* Next open device number in
+					 * round-robin allocation */
 
 	struct usb_devmap devmap;	/* device address allocation map */
 	struct usb_operations *op;	/* Operations (specific to the HC) */
@@ -289,15 +292,16 @@
 	struct dentry *usbfs_dentry;	/* usbfs dentry entry for the bus */
 
 	struct class_device *class_dev;	/* class device for this bus */
-	struct kref kref;		/* handles reference counting this bus */
-	void (*release)(struct usb_bus *bus);	/* function to destroy this bus's memory */
+	struct kref kref;		/* reference counting for this bus */
+	void (*release)(struct usb_bus *bus);
+
 #if defined(CONFIG_USB_MON)
 	struct mon_bus *mon_bus;	/* non-null when associated */
 	int monitored;			/* non-zero when monitored */
 #endif
 };
 
-/* -------------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- */
 
 /* This is arbitrary.
  * From USB 2.0 spec Table 11-13, offset 7, a hub can
@@ -326,7 +330,8 @@
 
 	struct semaphore serialize;
 
-	unsigned int toggle[2];		/* one bit for each endpoint ([0] = IN, [1] = OUT) */
+	unsigned int toggle[2];		/* one bit for each endpoint
+					 * ([0] = IN, [1] = OUT) */
 
 	struct usb_device *parent;	/* our hub, unless we're the root */
 	struct usb_bus *bus;		/* Bus we're part of */
@@ -343,12 +348,14 @@
 
 	char **rawdescriptors;		/* Raw descriptors for each config */
 
-	int have_langid;		/* whether string_langid is valid yet */
+	int have_langid;		/* whether string_langid is valid */
 	int string_langid;		/* language ID for strings */
 
-	char *product;
-	char *manufacturer;
-	char *serial;			/* static strings from the device */
+	/* static strings from the device */
+	char *product;			/* iProduct string, if present */
+	char *manufacturer;		/* iManufacturer string, if present */
+	char *serial;			/* iSerialNumber string, if present */
+
 	struct list_head filelist;
 	struct class_device *class_dev;
 	struct dentry *usbfs_dentry;	/* usbfs dentry entry for the device */
@@ -440,22 +447,31 @@
  * USB 2.0 root hubs (EHCI host controllers) will get one path ID if they are
  * high speed, and a different one if they are full or low speed.
  */
-static inline int usb_make_path (struct usb_device *dev, char *buf, size_t size)
+static inline int usb_make_path (struct usb_device *dev, char *buf,
+		size_t size)
 {
 	int actual;
-	actual = snprintf (buf, size, "usb-%s-%s", dev->bus->bus_name, dev->devpath);
+	actual = snprintf (buf, size, "usb-%s-%s", dev->bus->bus_name,
+			dev->devpath);
 	return (actual >= (int)size) ? -1 : actual;
 }
 
 /*-------------------------------------------------------------------------*/
 
-#define USB_DEVICE_ID_MATCH_DEVICE		(USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT)
-#define USB_DEVICE_ID_MATCH_DEV_RANGE		(USB_DEVICE_ID_MATCH_DEV_LO | USB_DEVICE_ID_MATCH_DEV_HI)
-#define USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION	(USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_RANGE)
+#define USB_DEVICE_ID_MATCH_DEVICE \
+		(USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT)
+#define USB_DEVICE_ID_MATCH_DEV_RANGE \
+		(USB_DEVICE_ID_MATCH_DEV_LO | USB_DEVICE_ID_MATCH_DEV_HI)
+#define USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION \
+		(USB_DEVICE_ID_MATCH_DEVICE | USB_DEVICE_ID_MATCH_DEV_RANGE)
 #define USB_DEVICE_ID_MATCH_DEV_INFO \
-	(USB_DEVICE_ID_MATCH_DEV_CLASS | USB_DEVICE_ID_MATCH_DEV_SUBCLASS | USB_DEVICE_ID_MATCH_DEV_PROTOCOL)
+		(USB_DEVICE_ID_MATCH_DEV_CLASS | \
+		USB_DEVICE_ID_MATCH_DEV_SUBCLASS | \
+		USB_DEVICE_ID_MATCH_DEV_PROTOCOL)
 #define USB_DEVICE_ID_MATCH_INT_INFO \
-	(USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS | USB_DEVICE_ID_MATCH_INT_PROTOCOL)
+		(USB_DEVICE_ID_MATCH_INT_CLASS | \
+		USB_DEVICE_ID_MATCH_INT_SUBCLASS | \
+		USB_DEVICE_ID_MATCH_INT_PROTOCOL)
 
 /**
  * USB_DEVICE - macro used to describe a specific usb device
@@ -466,9 +482,11 @@
  * specific device.
  */
 #define USB_DEVICE(vend,prod) \
-	.match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = (vend), .idProduct = (prod)
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE, .idVendor = (vend), \
+			.idProduct = (prod)
 /**
- * USB_DEVICE_VER - macro used to describe a specific usb device with a version range
+ * USB_DEVICE_VER - macro used to describe a specific usb device with a
+ *		version range
  * @vend: the 16 bit USB Vendor ID
  * @prod: the 16 bit USB Product ID
  * @lo: the bcdDevice_lo value
@@ -478,7 +496,9 @@
  * specific device, with a version range.
  */
 #define USB_DEVICE_VER(vend,prod,lo,hi) \
-	.match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, .idVendor = (vend), .idProduct = (prod), .bcdDevice_lo = (lo), .bcdDevice_hi = (hi)
+	.match_flags = USB_DEVICE_ID_MATCH_DEVICE_AND_VERSION, \
+	.idVendor = (vend), .idProduct = (prod), \
+	.bcdDevice_lo = (lo), .bcdDevice_hi = (hi)
 
 /**
  * USB_DEVICE_INFO - macro used to describe a class of usb devices
@@ -490,7 +510,8 @@
  * specific class of devices.
  */
 #define USB_DEVICE_INFO(cl,sc,pr) \
-	.match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, .bDeviceClass = (cl), .bDeviceSubClass = (sc), .bDeviceProtocol = (pr)
+	.match_flags = USB_DEVICE_ID_MATCH_DEV_INFO, .bDeviceClass = (cl), \
+	.bDeviceSubClass = (sc), .bDeviceProtocol = (pr)
 
 /**
  * USB_INTERFACE_INFO - macro used to describe a class of usb interfaces 
@@ -502,9 +523,10 @@
  * specific class of interfaces.
  */
 #define USB_INTERFACE_INFO(cl,sc,pr) \
-	.match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl), .bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
+	.match_flags = USB_DEVICE_ID_MATCH_INT_INFO, .bInterfaceClass = (cl), \
+	.bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
 
-/* -------------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- */
 
 /**
  * struct usb_driver - identifies USB driver to usbcore
@@ -557,7 +579,8 @@
 
 	void (*disconnect) (struct usb_interface *intf);
 
-	int (*ioctl) (struct usb_interface *intf, unsigned int code, void *buf);
+	int (*ioctl) (struct usb_interface *intf, unsigned int code,
+			void *buf);
 
 	int (*suspend) (struct usb_interface *intf, pm_message_t message);
 	int (*resume) (struct usb_interface *intf);
@@ -572,10 +595,8 @@
 
 /**
  * struct usb_class_driver - identifies a USB driver that wants to use the USB major number
- * @name: devfs name for this driver.  Will also be used by the driver
- *	class code to create a usb class device.
+ * @name: the usb class device name for this driver.  Will show up in sysfs.
  * @fops: pointer to the struct file_operations of this driver.
- * @mode: the mode for the devfs file to be created for this driver.
  * @minor_base: the start of the minor range for this driver.
  *
  * This structure is used for the usb_register_dev() and
@@ -585,8 +606,7 @@
 struct usb_class_driver {
 	char *name;
 	struct file_operations *fops;
-	mode_t mode;
-	int minor_base;	
+	int minor_base;
 };
 
 /*
@@ -603,7 +623,7 @@
 
 extern int usb_disabled(void);
 
-/* -------------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- */
 
 /*
  * URB support, for asynchronous request completions
@@ -613,12 +633,14 @@
  * urb->transfer_flags:
  */
 #define URB_SHORT_NOT_OK	0x0001	/* report short reads as errors */
-#define URB_ISO_ASAP		0x0002	/* iso-only, urb->start_frame ignored */
+#define URB_ISO_ASAP		0x0002	/* iso-only, urb->start_frame
+					 * ignored */
 #define URB_NO_TRANSFER_DMA_MAP	0x0004	/* urb->transfer_dma valid on submit */
 #define URB_NO_SETUP_DMA_MAP	0x0008	/* urb->setup_dma valid on submit */
 #define URB_NO_FSBR		0x0020	/* UHCI-specific */
-#define URB_ZERO_PACKET		0x0040	/* Finish bulk OUTs with short packet */
-#define URB_NO_INTERRUPT	0x0080	/* HINT: no non-error interrupt needed */
+#define URB_ZERO_PACKET		0x0040	/* Finish bulk OUT with short packet */
+#define URB_NO_INTERRUPT	0x0080	/* HINT: no non-error interrupt
+					 * needed */
 
 struct usb_iso_packet_descriptor {
 	unsigned int offset;
@@ -806,7 +828,8 @@
 	u8 reject;			/* submissions will fail */
 
 	/* public, documented fields in the urb that can be used by drivers */
-	struct list_head urb_list;	/* list head for use by the urb owner */
+	struct list_head urb_list;	/* list head for use by the urb's
+					 * current owner */
 	struct usb_device *dev; 	/* (in) pointer to associated device */
 	unsigned int pipe;		/* (in) pipe information */
 	int status;			/* (return) non-ISO status */
@@ -819,14 +842,16 @@
 	dma_addr_t setup_dma;		/* (in) dma addr for setup_packet */
 	int start_frame;		/* (modify) start frame (ISO) */
 	int number_of_packets;		/* (in) number of ISO packets */
-	int interval;			/* (modify) transfer interval (INT/ISO) */
+	int interval;			/* (modify) transfer interval
+					 * (INT/ISO) */
 	int error_count;		/* (return) number of ISO errors */
 	void *context;			/* (in) context for completion */
 	usb_complete_t complete;	/* (in) completion routine */
-	struct usb_iso_packet_descriptor iso_frame_desc[0];	/* (in) ISO ONLY */
+	struct usb_iso_packet_descriptor iso_frame_desc[0];
+					/* (in) ISO ONLY */
 };
 
-/* -------------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- */
 
 /**
  * usb_fill_control_urb - initializes a control urb
@@ -974,11 +999,6 @@
 	void *data, int len, int *actual_length,
 	int timeout);
 
-/* selective suspend/resume */
-extern int usb_suspend_device(struct usb_device *dev, pm_message_t message);
-extern int usb_resume_device(struct usb_device *dev);
-
-
 /* wrappers around usb_control_msg() for the most common standard requests */
 extern int usb_get_descriptor(struct usb_device *dev, unsigned char desctype,
 	unsigned char descindex, void *buf, int size);
@@ -1056,7 +1076,7 @@
 void usb_sg_wait (struct usb_sg_request *io);
 
 
-/* -------------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- */
 
 /*
  * For various legacy reasons, Linux has a small cookie that's paired with
@@ -1097,23 +1117,34 @@
 /* The D0/D1 toggle bits ... USE WITH CAUTION (they're almost hcd-internal) */
 #define usb_gettoggle(dev, ep, out) (((dev)->toggle[out] >> (ep)) & 1)
 #define	usb_dotoggle(dev, ep, out)  ((dev)->toggle[out] ^= (1 << (ep)))
-#define usb_settoggle(dev, ep, out, bit) ((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | ((bit) << (ep)))
+#define usb_settoggle(dev, ep, out, bit) \
+		((dev)->toggle[out] = ((dev)->toggle[out] & ~(1 << (ep))) | \
+		 ((bit) << (ep)))
 
 
-static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint)
+static inline unsigned int __create_pipe(struct usb_device *dev,
+		unsigned int endpoint)
 {
 	return (dev->devnum << 8) | (endpoint << 15);
 }
 
 /* Create various pipes... */
-#define usb_sndctrlpipe(dev,endpoint)	((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint))
-#define usb_rcvctrlpipe(dev,endpoint)	((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
-#define usb_sndisocpipe(dev,endpoint)	((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint))
-#define usb_rcvisocpipe(dev,endpoint)	((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
-#define usb_sndbulkpipe(dev,endpoint)	((PIPE_BULK << 30) | __create_pipe(dev,endpoint))
-#define usb_rcvbulkpipe(dev,endpoint)	((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
-#define usb_sndintpipe(dev,endpoint)	((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint))
-#define usb_rcvintpipe(dev,endpoint)	((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+#define usb_sndctrlpipe(dev,endpoint)	\
+	((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvctrlpipe(dev,endpoint)	\
+	((PIPE_CONTROL << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+#define usb_sndisocpipe(dev,endpoint)	\
+	((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvisocpipe(dev,endpoint)	\
+	((PIPE_ISOCHRONOUS << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+#define usb_sndbulkpipe(dev,endpoint)	\
+	((PIPE_BULK << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvbulkpipe(dev,endpoint)	\
+	((PIPE_BULK << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
+#define usb_sndintpipe(dev,endpoint)	\
+	((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvintpipe(dev,endpoint)	\
+	((PIPE_INTERRUPT << 30) | __create_pipe(dev,endpoint) | USB_DIR_IN)
 
 /*-------------------------------------------------------------------------*/
 
@@ -1137,17 +1168,29 @@
 	return le16_to_cpu(ep->desc.wMaxPacketSize);
 }
 
-/* -------------------------------------------------------------------------- */
+/* ----------------------------------------------------------------------- */
+
+/* Events from the usb core */
+#define USB_DEVICE_ADD		0x0001
+#define USB_DEVICE_REMOVE	0x0002
+#define USB_BUS_ADD		0x0003
+#define USB_BUS_REMOVE		0x0004
+extern void usb_register_notify(struct notifier_block *nb);
+extern void usb_unregister_notify(struct notifier_block *nb);
 
 #ifdef DEBUG
-#define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , ## arg)
+#define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , \
+	__FILE__ , ## arg)
 #else
 #define dbg(format, arg...) do {} while (0)
 #endif
 
-#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , __FILE__ , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format "\n" , __FILE__ , ## arg)
-#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n" , __FILE__ , ## arg)
+#define err(format, arg...) printk(KERN_ERR "%s: " format "\n" , \
+	__FILE__ , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format "\n" , \
+	__FILE__ , ## arg)
+#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n" , \
+	__FILE__ , ## arg)
 
 
 #endif  /* __KERNEL__ */
diff --git a/include/linux/usb_otg.h b/include/linux/usb_otg.h
index c668314..f827f6e 100644
--- a/include/linux/usb_otg.h
+++ b/include/linux/usb_otg.h
@@ -63,6 +63,10 @@
 	int	(*set_power)(struct otg_transceiver *otg,
 				unsigned mA);
 
+	/* for non-OTG B devices: set transceiver into suspend mode */
+	int	(*set_suspend)(struct otg_transceiver *otg,
+				int suspend);
+
 	/* for B devices only:  start session with A-Host */
 	int	(*start_srp)(struct otg_transceiver *otg);
 
@@ -108,6 +112,15 @@
 }
 
 static inline int
+otg_set_suspend(struct otg_transceiver *otg, int suspend)
+{
+	if (otg->set_suspend != NULL)
+		return otg->set_suspend(otg, suspend);
+	else
+		return 0;
+}
+
+static inline int
 otg_start_srp(struct otg_transceiver *otg)
 {
 	return otg->start_srp(otg);
diff --git a/include/linux/usbdevice_fs.h b/include/linux/usbdevice_fs.h
index 9facf73..8859f0b 100644
--- a/include/linux/usbdevice_fs.h
+++ b/include/linux/usbdevice_fs.h
@@ -140,6 +140,12 @@
 	compat_caddr_t usercontext; /* unused */
 	struct usbdevfs_iso_packet_desc iso_frame_desc[0];
 };
+
+struct usbdevfs_ioctl32 {
+	s32 ifno;
+	s32 ioctl_code;
+	compat_caddr_t data;
+};
 #endif
 
 #define USBDEVFS_CONTROL           _IOWR('U', 0, struct usbdevfs_ctrltransfer)
@@ -160,6 +166,7 @@
 #define USBDEVFS_RELEASEINTERFACE  _IOR('U', 16, unsigned int)
 #define USBDEVFS_CONNECTINFO       _IOW('U', 17, struct usbdevfs_connectinfo)
 #define USBDEVFS_IOCTL             _IOWR('U', 18, struct usbdevfs_ioctl)
+#define USBDEVFS_IOCTL32           _IOWR('U', 18, struct usbdevfs_ioctl32)
 #define USBDEVFS_HUB_PORTINFO      _IOR('U', 19, struct usbdevfs_hub_portinfo)
 #define USBDEVFS_RESET             _IO('U', 20)
 #define USBDEVFS_CLEAR_HALT        _IOR('U', 21, unsigned int)