Эх сурвалжийг харах

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

Linus Torvalds 20 жил өмнө
parent
commit
1f419cadff
100 өөрчлөгдсөн 3143 нэмэгдсэн , 3214 устгасан
  1. 1 1
      Documentation/DocBook/usb.tmpl
  2. 16 3
      Documentation/input/yealink.txt
  3. 0 2
      Documentation/kernel-parameters.txt
  4. 6 14
      MAINTAINERS
  5. 1 1
      drivers/Makefile
  6. 3 23
      drivers/base/power/main.c
  7. 0 13
      drivers/base/power/power.h
  8. 1 0
      drivers/base/power/runtime.c
  9. 2 2
      drivers/block/ub.c
  10. 3 250
      drivers/pci/quirks.c
  11. 1 1
      drivers/usb/Makefile
  12. 0 23
      drivers/usb/class/Kconfig
  13. 0 1
      drivers/usb/class/Makefile
  14. 0 1279
      drivers/usb/class/bluetty.c
  15. 2 3
      drivers/usb/class/cdc-acm.c
  16. 1 2
      drivers/usb/class/usblp.c
  17. 7 4
      drivers/usb/core/Kconfig
  18. 1 1
      drivers/usb/core/Makefile
  19. 10 12
      drivers/usb/core/config.c
  20. 145 45
      drivers/usb/core/devio.c
  21. 4 15
      drivers/usb/core/file.c
  22. 50 56
      drivers/usb/core/hcd-pci.c
  23. 102 49
      drivers/usb/core/hcd.c
  24. 32 37
      drivers/usb/core/hcd.h
  25. 182 228
      drivers/usb/core/hub.c
  26. 1 1
      drivers/usb/core/hub.h
  27. 31 13
      drivers/usb/core/inode.c
  28. 61 27
      drivers/usb/core/message.c
  29. 120 0
      drivers/usb/core/notify.c
  30. 268 51
      drivers/usb/core/sysfs.c
  31. 2 1
      drivers/usb/core/urb.c
  32. 105 60
      drivers/usb/core/usb.c
  33. 30 3
      drivers/usb/core/usb.h
  34. 6 18
      drivers/usb/gadget/dummy_hcd.c
  35. 1 0
      drivers/usb/gadget/ether.c
  36. 22 30
      drivers/usb/gadget/file_storage.c
  37. 1 0
      drivers/usb/gadget/goku_udc.c
  38. 1 0
      drivers/usb/gadget/lh7a40x_udc.c
  39. 1 0
      drivers/usb/gadget/net2280.c
  40. 10 3
      drivers/usb/gadget/omap_udc.c
  41. 1 0
      drivers/usb/gadget/pxa2xx_udc.c
  42. 1 0
      drivers/usb/gadget/zero.c
  43. 3 2
      drivers/usb/host/Makefile
  44. 81 462
      drivers/usb/host/ehci-hcd.c
  45. 4 4
      drivers/usb/host/ehci-hub.c
  46. 415 0
      drivers/usb/host/ehci-pci.c
  47. 1 0
      drivers/usb/host/ehci.h
  48. 10 31
      drivers/usb/host/isp116x-hcd.c
  49. 0 1
      drivers/usb/host/isp116x.h
  50. 6 0
      drivers/usb/host/ohci-au1xxx.c
  51. 0 4
      drivers/usb/host/ohci-dbg.c
  52. 2 2
      drivers/usb/host/ohci-hcd.c
  53. 17 35
      drivers/usb/host/ohci-hub.c
  54. 6 0
      drivers/usb/host/ohci-lh7a404.c
  55. 0 1
      drivers/usb/host/ohci-mem.c
  56. 17 28
      drivers/usb/host/ohci-omap.c
  57. 12 35
      drivers/usb/host/ohci-pci.c
  58. 5 4
      drivers/usb/host/ohci-ppc-soc.c
  59. 4 3
      drivers/usb/host/ohci-pxa27x.c
  60. 5 4
      drivers/usb/host/ohci-s3c2410.c
  61. 4 3
      drivers/usb/host/ohci-sa1111.c
  62. 0 1
      drivers/usb/host/ohci.h
  63. 296 0
      drivers/usb/host/pci-quirks.c
  64. 9 8
      drivers/usb/host/sl811-hcd.c
  65. 2 3
      drivers/usb/host/uhci-debug.c
  66. 51 127
      drivers/usb/host/uhci-hcd.c
  67. 53 45
      drivers/usb/host/uhci-hcd.h
  68. 35 27
      drivers/usb/host/uhci-q.c
  69. 22 11
      drivers/usb/image/mdc800.c
  70. 1 2
      drivers/usb/image/microtek.c
  71. 1 1
      drivers/usb/input/aiptek.c
  72. 3 2
      drivers/usb/input/hid-core.c
  73. 1 2
      drivers/usb/input/hiddev.c
  74. 1 1
      drivers/usb/input/map_to_7segment.h
  75. 2 0
      drivers/usb/input/touchkitusb.c
  76. 1 2
      drivers/usb/media/dabusb.c
  77. 1 2
      drivers/usb/misc/auerswald.c
  78. 2 3
      drivers/usb/misc/idmouse.c
  79. 2 3
      drivers/usb/misc/legousbtower.c
  80. 1 2
      drivers/usb/misc/rio500.c
  81. 1 6
      drivers/usb/misc/sisusbvga/sisusb.c
  82. 4 5
      drivers/usb/misc/usblcd.c
  83. 1 10
      drivers/usb/misc/usbtest.c
  84. 21 2
      drivers/usb/mon/mon_main.c
  85. 1 1
      drivers/usb/net/Kconfig
  86. 1 1
      drivers/usb/net/kaweth.c
  87. 0 2
      drivers/usb/net/pegasus.c
  88. 2 0
      drivers/usb/net/pegasus.h
  89. 1 0
      drivers/usb/net/rtl8150.c
  90. 0 2
      drivers/usb/net/usbnet.c
  91. 730 0
      drivers/usb/serial/ChangeLog.old
  92. 9 0
      drivers/usb/serial/Kconfig
  93. 1 0
      drivers/usb/serial/Makefile
  94. 5 3
      drivers/usb/serial/airprime.c
  95. 6 4
      drivers/usb/serial/belkin_sa.c
  96. 16 21
      drivers/usb/serial/bus.c
  97. 6 4
      drivers/usb/serial/cp2101.c
  98. 6 4
      drivers/usb/serial/cyberjack.c
  99. 12 8
      drivers/usb/serial/cypress_m8.c
  100. 12 8
      drivers/usb/serial/digi_acceleport.c

+ 1 - 1
Documentation/DocBook/usb.tmpl

@@ -291,7 +291,7 @@
 
 
 !Edrivers/usb/core/hcd.c
 !Edrivers/usb/core/hcd.c
 !Edrivers/usb/core/hcd-pci.c
 !Edrivers/usb/core/hcd-pci.c
-!Edrivers/usb/core/buffer.c
+!Idrivers/usb/core/buffer.c
     </chapter>
     </chapter>
 
 
     <chapter>
     <chapter>

+ 16 - 3
Documentation/input/yealink.txt

@@ -2,7 +2,6 @@ Driver documentation for yealink usb-p1k phones
 
 
 0. Status
 0. Status
 ~~~~~~~~~
 ~~~~~~~~~
-
 The p1k is a relatively cheap usb 1.1 phone with:
 The p1k is a relatively cheap usb 1.1 phone with:
   - keyboard		full support, yealink.ko / input event API
   - keyboard		full support, yealink.ko / input event API
   - LCD			full support, yealink.ko / sysfs API
   - LCD			full support, yealink.ko / sysfs API
@@ -17,9 +16,8 @@ For vendor documentation see http://www.yealink.com
 
 
 1. Compilation (stand alone version)
 1. Compilation (stand alone version)
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
 Currently only kernel 2.6.x.y versions are supported.
 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
   make
 
 
@@ -28,6 +26,21 @@ the Makefile is pointing to the location where your kernel sources
 are located, default /usr/src/linux.
 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
 2. keyboard features
 ~~~~~~~~~~~~~~~~~~~~
 ~~~~~~~~~~~~~~~~~~~~

+ 0 - 2
Documentation/kernel-parameters.txt

@@ -1517,8 +1517,6 @@ running once the system is up.
 	uart6850=	[HW,OSS]
 	uart6850=	[HW,OSS]
 			Format: <io>,<irq>
 			Format: <io>,<irq>
 
 
-	usb-handoff	[HW] Enable early USB BIOS -> OS handoff
-
 	usbhid.mousepoll=
 	usbhid.mousepoll=
 			[USBHID] The interval which mice are to be polled at.
 			[USBHID] The interval which mice are to be polled at.
 
 

+ 6 - 14
MAINTAINERS

@@ -116,12 +116,6 @@ M:	ajk@iehk.rwth-aachen.de
 L:	linux-hams@vger.kernel.org
 L:	linux-hams@vger.kernel.org
 S:	Maintained
 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
 8139CP 10/100 FAST ETHERNET DRIVER
 P:	Jeff Garzik
 P:	Jeff Garzik
 M:	jgarzik@pobox.com
 M:	jgarzik@pobox.com
@@ -2495,14 +2489,6 @@ L:	linux-kernel@vger.kernel.org
 L:	linux-usb-devel@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
 S:	Supported
 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
 USB CDC ETHERNET DRIVER
 P:	Greg Kroah-Hartman
 P:	Greg Kroah-Hartman
 M:	greg@kroah.com
 M:	greg@kroah.com
@@ -2863,6 +2849,12 @@ M:	jpr@f6fbb.org
 L:	linux-hams@vger.kernel.org
 L:	linux-hams@vger.kernel.org
 S:	Maintained
 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)
 YMFPCI YAMAHA PCI SOUND (Use ALSA instead)
 P:	Pete Zaitcev
 P:	Pete Zaitcev
 M:	zaitcev@yahoo.com
 M:	zaitcev@yahoo.com

+ 1 - 1
drivers/Makefile

@@ -5,7 +5,7 @@
 # Rewritten to use lists instead of if-statements.
 # Rewritten to use lists instead of if-statements.
 #
 #
 
 
-obj-$(CONFIG_PCI)		+= pci/
+obj-$(CONFIG_PCI)		+= pci/ usb/
 obj-$(CONFIG_PARISC)		+= parisc/
 obj-$(CONFIG_PARISC)		+= parisc/
 obj-y				+= video/
 obj-y				+= video/
 obj-$(CONFIG_ACPI)		+= acpi/
 obj-$(CONFIG_ACPI)		+= acpi/

+ 3 - 23
drivers/base/power/main.c

@@ -30,23 +30,6 @@ LIST_HEAD(dpm_off_irq);
 DECLARE_MUTEX(dpm_sem);
 DECLARE_MUTEX(dpm_sem);
 DECLARE_MUTEX(dpm_list_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.
  *	device_pm_set_parent - Specify power dependency.
  *	@dev:		Device who needs power.
  *	@dev:		Device who needs power.
@@ -62,10 +45,8 @@ static inline void device_pm_release(struct device * dev)
 
 
 void device_pm_set_parent(struct device * dev, struct device * parent)
 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);
 EXPORT_SYMBOL_GPL(device_pm_set_parent);
 
 
@@ -75,7 +56,6 @@ int device_pm_add(struct device * dev)
 
 
 	pr_debug("PM: Adding info for %s:%s\n",
 	pr_debug("PM: Adding info for %s:%s\n",
 		 dev->bus ? dev->bus->name : "No Bus", dev->kobj.name);
 		 dev->bus ? dev->bus->name : "No Bus", dev->kobj.name);
-	atomic_set(&dev->power.pm_users, 0);
 	down(&dpm_list_sem);
 	down(&dpm_list_sem);
 	list_add_tail(&dev->power.entry, &dpm_active);
 	list_add_tail(&dev->power.entry, &dpm_active);
 	device_pm_set_parent(dev, dev->parent);
 	device_pm_set_parent(dev, dev->parent);
@@ -91,7 +71,7 @@ void device_pm_remove(struct device * dev)
 		 dev->bus ? dev->bus->name : "No Bus", dev->kobj.name);
 		 dev->bus ? dev->bus->name : "No Bus", dev->kobj.name);
 	down(&dpm_list_sem);
 	down(&dpm_list_sem);
 	dpm_sysfs_remove(dev);
 	dpm_sysfs_remove(dev);
-	device_pm_release(dev->power.pm_parent);
+	put_device(dev->power.pm_parent);
 	list_del_init(&dev->power.entry);
 	list_del_init(&dev->power.entry);
 	up(&dpm_list_sem);
 	up(&dpm_list_sem);
 }
 }

+ 0 - 13
drivers/base/power/power.h

@@ -67,9 +67,6 @@ extern int suspend_device(struct device *, pm_message_t);
  * runtime.c
  * runtime.c
  */
  */
 
 
-extern int dpm_runtime_suspend(struct device *, pm_message_t);
-extern void dpm_runtime_resume(struct device *);
-
 #else /* CONFIG_PM */
 #else /* CONFIG_PM */
 
 
 
 
@@ -82,14 +79,4 @@ static inline void device_pm_remove(struct device * dev)
 
 
 }
 }
 
 
-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
 #endif

+ 1 - 0
drivers/base/power/runtime.c

@@ -36,6 +36,7 @@ void dpm_runtime_resume(struct device * dev)
 	runtime_resume(dev);
 	runtime_resume(dev);
 	up(&dpm_sem);
 	up(&dpm_sem);
 }
 }
+EXPORT_SYMBOL(dpm_runtime_resume);
 
 
 
 
 /**
 /**

+ 2 - 2
drivers/block/ub.c

@@ -1512,7 +1512,7 @@ static void ub_state_sense(struct ub_dev *sc, struct ub_scsi_cmd *cmd)
 	scmd->nsg = 1;
 	scmd->nsg = 1;
 	sg = &scmd->sgv[0];
 	sg = &scmd->sgv[0];
 	sg->page = virt_to_page(sc->top_sense);
 	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;
 	sg->length = UB_SENSE_SIZE;
 	scmd->len = UB_SENSE_SIZE;
 	scmd->len = UB_SENSE_SIZE;
 	scmd->lun = cmd->lun;
 	scmd->lun = cmd->lun;
@@ -1891,7 +1891,7 @@ static int ub_sync_read_cap(struct ub_dev *sc, struct ub_lun *lun,
 	cmd->nsg = 1;
 	cmd->nsg = 1;
 	sg = &cmd->sgv[0];
 	sg = &cmd->sgv[0];
 	sg->page = virt_to_page(p);
 	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;
 	sg->length = 8;
 	cmd->len = 8;
 	cmd->len = 8;
 	cmd->lun = lun;
 	cmd->lun = lun;

+ 3 - 250
drivers/pci/quirks.c

@@ -7,6 +7,9 @@
  *
  *
  *  Copyright (c) 1999 Martin Mares <mj@ucw.cz>
  *  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
  *  The bridge optimization stuff has been removed. If you really
  *  have a silly BIOS which is unable to set your host bridge right,
  *  have a silly BIOS which is unable to set your host bridge right,
  *  use the PowerTweak utility (see http://powertweak.sourceforge.net).
  *  use the PowerTweak utility (see http://powertweak.sourceforge.net).
@@ -644,28 +647,6 @@ static void quirk_via_irq(struct pci_dev *dev)
 }
 }
 DECLARE_PCI_FIXUP_ENABLE(PCI_VENDOR_ID_VIA, PCI_ANY_ID, quirk_via_irq);
 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
  * VIA VT82C598 has its device ID settable and many BIOSes
  * set it to the ID of VT82C597 for backward compatibility.
  * set it to the ID of VT82C597 for backward compatibility.
@@ -1039,234 +1020,6 @@ static void __init quirk_sis_96x_smbus(struct pci_dev *dev)
 	pci_read_config_byte(dev, 0x77, &val);
 	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
  * ... This is further complicated by the fact that some SiS96x south
  * bridges pretend to be 85C503/5513 instead.  In that case see if we
  * bridges pretend to be 85C503/5513 instead.  In that case see if we

+ 1 - 1
drivers/usb/Makefile

@@ -8,6 +8,7 @@ obj-$(CONFIG_USB)		+= core/
 
 
 obj-$(CONFIG_USB_MON)		+= mon/
 obj-$(CONFIG_USB_MON)		+= mon/
 
 
+obj-$(CONFIG_PCI)		+= host/
 obj-$(CONFIG_USB_EHCI_HCD)	+= host/
 obj-$(CONFIG_USB_EHCI_HCD)	+= host/
 obj-$(CONFIG_USB_ISP116X_HCD)	+= host/
 obj-$(CONFIG_USB_ISP116X_HCD)	+= host/
 obj-$(CONFIG_USB_OHCI_HCD)	+= host/
 obj-$(CONFIG_USB_OHCI_HCD)	+= host/
@@ -17,7 +18,6 @@ obj-$(CONFIG_ETRAX_USB_HOST)	+= host/
 
 
 obj-$(CONFIG_USB_ACM)		+= class/
 obj-$(CONFIG_USB_ACM)		+= class/
 obj-$(CONFIG_USB_AUDIO)		+= class/
 obj-$(CONFIG_USB_AUDIO)		+= class/
-obj-$(CONFIG_USB_BLUETOOTH_TTY)	+= class/
 obj-$(CONFIG_USB_MIDI)		+= class/
 obj-$(CONFIG_USB_MIDI)		+= class/
 obj-$(CONFIG_USB_PRINTER)	+= class/
 obj-$(CONFIG_USB_PRINTER)	+= class/
 
 

+ 0 - 23
drivers/usb/class/Kconfig

@@ -28,29 +28,6 @@ config USB_AUDIO
 	  To compile this driver as a module, choose M here: the
 	  To compile this driver as a module, choose M here: the
 	  module will be called audio.
 	  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
 config USB_MIDI
 	tristate "USB MIDI support"
 	tristate "USB MIDI support"
 	depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER
 	depends on USB && SOUND && OBSOLETE_OSS_USB_DRIVER

+ 0 - 1
drivers/usb/class/Makefile

@@ -5,6 +5,5 @@
 
 
 obj-$(CONFIG_USB_ACM)		+= cdc-acm.o
 obj-$(CONFIG_USB_ACM)		+= cdc-acm.o
 obj-$(CONFIG_USB_AUDIO)		+= audio.o
 obj-$(CONFIG_USB_AUDIO)		+= audio.o
-obj-$(CONFIG_USB_BLUETOOTH_TTY)	+= bluetty.o
 obj-$(CONFIG_USB_MIDI)		+= usb-midi.o
 obj-$(CONFIG_USB_MIDI)		+= usb-midi.o
 obj-$(CONFIG_USB_PRINTER)	+= usblp.o
 obj-$(CONFIG_USB_PRINTER)	+= usblp.o

+ 0 - 1279
drivers/usb/class/bluetty.c

@@ -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");
-

+ 2 - 3
drivers/usb/class/cdc-acm.c

@@ -827,11 +827,10 @@ skip_normal_probe:
 		return -ENODEV;
 		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;
 		goto alloc_fail;
 	}
 	}
-	memset(acm, 0, sizeof(struct acm));
 
 
 	ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
 	ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
 	readsize = le16_to_cpu(epread->wMaxPacketSize);
 	readsize = le16_to_cpu(epread->wMaxPacketSize);

+ 1 - 2
drivers/usb/class/usblp.c

@@ -844,9 +844,8 @@ static struct file_operations usblp_fops = {
 };
 };
 
 
 static struct usb_class_driver usblp_class = {
 static struct usb_class_driver usblp_class = {
-	.name =		"usb/lp%d",
+	.name =		"lp%d",
 	.fops =		&usblp_fops,
 	.fops =		&usblp_fops,
-	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
 	.minor_base =	USBLP_MINOR_BASE,
 	.minor_base =	USBLP_MINOR_BASE,
 };
 };
 
 

+ 7 - 4
drivers/usb/core/Kconfig

@@ -61,14 +61,17 @@ config USB_DYNAMIC_MINORS
 	  If you are unsure about this, say N here.
 	  If you are unsure about this, say N here.
 
 
 config USB_SUSPEND
 config USB_SUSPEND
-	bool "USB suspend/resume (EXPERIMENTAL)"
+	bool "USB selective suspend/resume and wakeup (EXPERIMENTAL)"
 	depends on USB && PM && EXPERIMENTAL
 	depends on USB && PM && EXPERIMENTAL
 	help
 	help
 	  If you say Y here, you can use driver calls or the sysfs
 	  If you say Y here, you can use driver calls or the sysfs
 	  "power/state" file to suspend or resume individual USB
 	  "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.
 	  If you are unsure about this, say N here.
 
 

+ 1 - 1
drivers/usb/core/Makefile

@@ -3,7 +3,7 @@
 #
 #
 
 
 usbcore-objs	:= usb.o hub.o hcd.o urb.o message.o \
 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)
 ifeq ($(CONFIG_PCI),y)
 	usbcore-objs	+= hcd-pci.o
 	usbcore-objs	+= hcd-pci.o

+ 10 - 12
drivers/usb/core/config.c

@@ -112,8 +112,12 @@ void usb_release_interface_cache(struct kref *ref)
 	struct usb_interface_cache *intfc = ref_to_usb_interface_cache(ref);
 	struct usb_interface_cache *intfc = ref_to_usb_interface_cache(ref);
 	int j;
 	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);
 	kfree(intfc);
 }
 }
 
 
@@ -188,10 +192,9 @@ static int usb_parse_interface(struct device *ddev, int cfgno,
 	}
 	}
 
 
 	len = sizeof(struct usb_host_endpoint) * num_ep;
 	len = sizeof(struct usb_host_endpoint) * num_ep;
-	alt->endpoint = kmalloc(len, GFP_KERNEL);
+	alt->endpoint = kzalloc(len, GFP_KERNEL);
 	if (!alt->endpoint)
 	if (!alt->endpoint)
 		return -ENOMEM;
 		return -ENOMEM;
-	memset(alt->endpoint, 0, len);
 
 
 	/* Parse all the endpoint descriptors */
 	/* Parse all the endpoint descriptors */
 	n = 0;
 	n = 0;
@@ -353,10 +356,9 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx,
 		}
 		}
 
 
 		len = sizeof(*intfc) + sizeof(struct usb_host_interface) * j;
 		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)
 		if (!intfc)
 			return -ENOMEM;
 			return -ENOMEM;
-		memset(intfc, 0, len);
 		kref_init(&intfc->ref);
 		kref_init(&intfc->ref);
 	}
 	}
 
 
@@ -422,8 +424,6 @@ void usb_destroy_configuration(struct usb_device *dev)
 		struct usb_host_config *cf = &dev->config[c];
 		struct usb_host_config *cf = &dev->config[c];
 
 
 		kfree(cf->string);
 		kfree(cf->string);
-		cf->string = NULL;
-
 		for (i = 0; i < cf->desc.bNumInterfaces; i++) {
 		for (i = 0; i < cf->desc.bNumInterfaces; i++) {
 			if (cf->intf_cache[i])
 			if (cf->intf_cache[i])
 				kref_put(&cf->intf_cache[i]->ref, 
 				kref_put(&cf->intf_cache[i]->ref, 
@@ -459,16 +459,14 @@ int usb_get_configuration(struct usb_device *dev)
 	}
 	}
 
 
 	length = ncfg * sizeof(struct usb_host_config);
 	length = ncfg * sizeof(struct usb_host_config);
-	dev->config = kmalloc(length, GFP_KERNEL);
+	dev->config = kzalloc(length, GFP_KERNEL);
 	if (!dev->config)
 	if (!dev->config)
 		goto err2;
 		goto err2;
-	memset(dev->config, 0, length);
 
 
 	length = ncfg * sizeof(char *);
 	length = ncfg * sizeof(char *);
-	dev->rawdescriptors = kmalloc(length, GFP_KERNEL);
+	dev->rawdescriptors = kzalloc(length, GFP_KERNEL);
 	if (!dev->rawdescriptors)
 	if (!dev->rawdescriptors)
 		goto err2;
 		goto err2;
-	memset(dev->rawdescriptors, 0, length);
 
 
 	buffer = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
 	buffer = kmalloc(USB_DT_CONFIG_SIZE, GFP_KERNEL);
 	if (!buffer)
 	if (!buffer)

+ 145 - 45
drivers/usb/core/devio.c

@@ -46,6 +46,7 @@
 #include <linux/usb.h>
 #include <linux/usb.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/cdev.h>
 #include <linux/cdev.h>
+#include <linux/notifier.h>
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 #include <asm/byteorder.h>
 #include <linux/moduleparam.h>
 #include <linux/moduleparam.h>
@@ -209,10 +210,10 @@ err:
 static struct async *alloc_async(unsigned int numisoframes)
 static struct async *alloc_async(unsigned int numisoframes)
 {
 {
         unsigned int assize = sizeof(struct async) + numisoframes * sizeof(struct usb_iso_packet_descriptor);
         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)
         if (!as)
                 return NULL;
                 return NULL;
-        memset(as, 0, assize);
 	as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL);
 	as->urb = usb_alloc_urb(numisoframes, GFP_KERNEL);
 	if (!as->urb) {
 	if (!as->urb) {
 		kfree(as);
 		kfree(as);
@@ -279,6 +280,28 @@ static inline struct async *async_getpending(struct dev_state *ps, void __user *
         return NULL;
         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)
 static void async_completed(struct urb *urb, struct pt_regs *regs)
 {
 {
         struct async *as = (struct async *)urb->context;
         struct async *as = (struct async *)urb->context;
@@ -296,7 +319,9 @@ static void async_completed(struct urb *urb, struct pt_regs *regs)
 		kill_proc_info_as_uid(as->signr, &sinfo, as->pid, as->uid, 
 		kill_proc_info_as_uid(as->signr, &sinfo, as->pid, as->uid, 
 				      as->euid);
 				      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)
 static void destroy_async (struct dev_state *ps, struct list_head *list)
@@ -493,6 +518,23 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
 	return ret;
 	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
  * file operations
  */
  */
@@ -601,7 +643,7 @@ static int proc_control(struct dev_state *ps, void __user *arg)
 			if (usbfs_snoop) {
 			if (usbfs_snoop) {
 				dev_info(&dev->dev, "control read: data ");
 				dev_info(&dev->dev, "control read: data ");
 				for (j = 0; j < i; ++j)
 				for (j = 0; j < i; ++j)
-					printk ("%02x ", (unsigned char)(tbuf)[j]);
+					printk("%02x ", (unsigned char)(tbuf)[j]);
 				printk("\n");
 				printk("\n");
 			}
 			}
 			if (copy_to_user(ctrl.data, tbuf, i)) {
 			if (copy_to_user(ctrl.data, tbuf, i)) {
@@ -624,7 +666,7 @@ static int proc_control(struct dev_state *ps, void __user *arg)
 		if (usbfs_snoop) {
 		if (usbfs_snoop) {
 			dev_info(&dev->dev, "control write: data: ");
 			dev_info(&dev->dev, "control write: data: ");
 			for (j = 0; j < ctrl.wLength; ++j)
 			for (j = 0; j < ctrl.wLength; ++j)
-				printk ("%02x ", (unsigned char)(tbuf)[j]);
+				printk("%02x ", (unsigned char)(tbuf)[j]);
 			printk("\n");
 			printk("\n");
 		}
 		}
 		usb_unlock_device(dev);
 		usb_unlock_device(dev);
@@ -649,7 +691,7 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
 	unsigned int tmo, len1, pipe;
 	unsigned int tmo, len1, pipe;
 	int len2;
 	int len2;
 	unsigned char *tbuf;
 	unsigned char *tbuf;
-	int i, ret;
+	int i, j, ret;
 
 
 	if (copy_from_user(&bulk, arg, sizeof(bulk)))
 	if (copy_from_user(&bulk, arg, sizeof(bulk)))
 		return -EFAULT;
 		return -EFAULT;
@@ -674,10 +716,18 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
 			kfree(tbuf);
 			kfree(tbuf);
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
+		snoop(&dev->dev, "bulk read: len=0x%02x timeout=%04d\n",
+			bulk.len, bulk.timeout);
 		usb_unlock_device(dev);
 		usb_unlock_device(dev);
 		i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
 		i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
 		usb_lock_device(dev);
 		usb_lock_device(dev);
 		if (!i && len2) {
 		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)) {
 			if (copy_to_user(bulk.data, tbuf, len2)) {
 				kfree(tbuf);
 				kfree(tbuf);
 				return -EFAULT;
 				return -EFAULT;
@@ -690,6 +740,14 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
 				return -EFAULT;
 				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);
 		usb_unlock_device(dev);
 		i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
 		i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
 		usb_lock_device(dev);
 		usb_lock_device(dev);
@@ -835,7 +893,6 @@ static int proc_setconfig(struct dev_state *ps, void __user *arg)
 	return status;
 	return status;
 }
 }
 
 
-
 static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 			     struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
 			     struct usbdevfs_iso_packet_desc __user *iso_frame_desc,
 			     void __user *arg)
 			     void __user *arg)
@@ -896,6 +953,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 			kfree(dr);
 			kfree(dr);
 			return -EFAULT;
 			return -EFAULT;
 		}
 		}
+		snoop(&ps->dev->dev, "control urb\n");
 		break;
 		break;
 
 
 	case USBDEVFS_URB_TYPE_BULK:
 	case USBDEVFS_URB_TYPE_BULK:
@@ -910,6 +968,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 			return -EINVAL;
 			return -EINVAL;
 		if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
 		if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
 			return -EFAULT;
 			return -EFAULT;
+		snoop(&ps->dev->dev, "bulk urb\n");
 		break;
 		break;
 
 
 	case USBDEVFS_URB_TYPE_ISO:
 	case USBDEVFS_URB_TYPE_ISO:
@@ -939,6 +998,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
 		uurb->buffer_length = totlen;
 		uurb->buffer_length = totlen;
+		snoop(&ps->dev->dev, "iso urb\n");
 		break;
 		break;
 
 
 	case USBDEVFS_URB_TYPE_INTERRUPT:
 	case USBDEVFS_URB_TYPE_INTERRUPT:
@@ -954,6 +1014,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 			return -EINVAL;
 			return -EINVAL;
 		if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
 		if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
 			return -EFAULT;
 			return -EFAULT;
+		snoop(&ps->dev->dev, "interrupt urb\n");
 		break;
 		break;
 
 
 	default:
 	default:
@@ -1003,6 +1064,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 			return -EFAULT;
 			return -EFAULT;
 		}
 		}
 	}
 	}
+	snoop(&as->urb->dev->dev, "submit urb\n");
+	snoop_urb(as->urb, as->userurb);
         async_newpending(as);
         async_newpending(as);
         if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
         if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
 		dev_printk(KERN_DEBUG, &ps->dev->dev, "usbfs: usb_submit_urb returned %d\n", ret);
 		dev_printk(KERN_DEBUG, &ps->dev->dev, "usbfs: usb_submit_urb returned %d\n", ret);
@@ -1238,23 +1301,20 @@ static int proc_releaseinterface(struct dev_state *ps, void __user *arg)
 	return 0;
 	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;
 	int			size;
 	void			*buf = NULL;
 	void			*buf = NULL;
 	int			retval = 0;
 	int			retval = 0;
 	struct usb_interface    *intf = NULL;
 	struct usb_interface    *intf = NULL;
 	struct usb_driver       *driver = 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)
 		if ((buf = kmalloc (size, GFP_KERNEL)) == NULL)
 			return -ENOMEM;
 			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);
 				kfree(buf);
 				return -EFAULT;
 				return -EFAULT;
 			}
 			}
@@ -1270,9 +1330,9 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
 
 
 	if (ps->dev->state != USB_STATE_CONFIGURED)
 	if (ps->dev->state != USB_STATE_CONFIGURED)
 		retval = -EHOSTUNREACH;
 		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;
                retval = -EINVAL;
-	else switch (ctrl.ioctl_code) {
+	else switch (ctl->ioctl_code) {
 
 
 	/* disconnect kernel driver from interface */
 	/* disconnect kernel driver from interface */
 	case USBDEVFS_DISCONNECT:
 	case USBDEVFS_DISCONNECT:
@@ -1304,7 +1364,7 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
 		if (driver == NULL || driver->ioctl == NULL) {
 		if (driver == NULL || driver->ioctl == NULL) {
 			retval = -ENOTTY;
 			retval = -ENOTTY;
 		} else {
 		} else {
-			retval = driver->ioctl (intf, ctrl.ioctl_code, buf);
+			retval = driver->ioctl (intf, ctl->ioctl_code, buf);
 			if (retval == -ENOIOCTLCMD)
 			if (retval == -ENOIOCTLCMD)
 				retval = -ENOTTY;
 				retval = -ENOTTY;
 		}
 		}
@@ -1313,15 +1373,42 @@ static int proc_ioctl (struct dev_state *ps, void __user *arg)
 
 
 	/* cleanup and return */
 	/* cleanup and return */
 	if (retval >= 0
 	if (retval >= 0
-			&& (_IOC_DIR (ctrl.ioctl_code) & _IOC_READ) != 0
+			&& (_IOC_DIR (ctl->ioctl_code) & _IOC_READ) != 0
 			&& size > 0
 			&& size > 0
-			&& copy_to_user (ctrl.data, buf, size) != 0)
+			&& copy_to_user (ctl->data, buf, size) != 0)
 		retval = -EFAULT;
 		retval = -EFAULT;
 
 
 	kfree(buf);
 	kfree(buf);
 	return retval;
 	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
  * NOTE:  All requests here that have interface numbers as parameters
  * are assuming that somehow the configuration has been prevented from
  * are assuming that somehow the configuration has been prevented from
@@ -1422,6 +1509,10 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
 		ret = proc_reapurbnonblock_compat(ps, p);
 		ret = proc_reapurbnonblock_compat(ps, p);
 		break;
 		break;
 
 
+	case USBDEVFS_IOCTL32:
+		snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__);
+		ret = proc_ioctl_compat(ps, p);
+		break;
 #endif
 #endif
 
 
 	case USBDEVFS_DISCARDURB:
 	case USBDEVFS_DISCARDURB:
@@ -1456,7 +1547,7 @@ static int usbdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd
 
 
 	case USBDEVFS_IOCTL:
 	case USBDEVFS_IOCTL:
 		snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__);
 		snoop(&dev->dev, "%s: IOCTL\n", __FUNCTION__);
-		ret = proc_ioctl(ps, p);
+		ret = proc_ioctl_default(ps, p);
 		break;
 		break;
 	}
 	}
 	usb_unlock_device(dev);
 	usb_unlock_device(dev);
@@ -1488,24 +1579,7 @@ struct file_operations usbfs_device_file_operations = {
 	.release =	usbdev_release,
 	.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);
 	int minor = ((dev->bus->busnum-1) * 128) + (dev->devnum-1);
 
 
@@ -1516,11 +1590,29 @@ void usbdev_add(struct usb_device *dev)
 	dev->class_dev->class_data = dev;
 	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);
 	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 = {
 static struct cdev usb_device_cdev = {
 	.kobj   = {.name = "usb_device", },
 	.kobj   = {.name = "usb_device", },
 	.owner  = THIS_MODULE,
 	.owner  = THIS_MODULE,
@@ -1540,24 +1632,32 @@ int __init usbdev_init(void)
 	retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);
 	retval = cdev_add(&usb_device_cdev, USB_DEVICE_DEV, USB_DEVICE_MAX);
 	if (retval) {
 	if (retval) {
 		err("unable to get usb_device major %d", USB_DEVICE_MAJOR);
 		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");
 	usb_device_class = class_create(THIS_MODULE, "usb_device");
 	if (IS_ERR(usb_device_class)) {
 	if (IS_ERR(usb_device_class)) {
 		err("unable to register usb_device class");
 		err("unable to register usb_device class");
 		retval = PTR_ERR(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:
 out:
 	return retval;
 	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)
 void usbdev_cleanup(void)
 {
 {
+	usb_unregister_notify(&usbdev_nb);
 	class_destroy(usb_device_class);
 	class_destroy(usb_device_class);
 	cdev_del(&usb_device_cdev);
 	cdev_del(&usb_device_cdev);
 	unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);
 	unregister_chrdev_region(USB_DEVICE_DEV, USB_DEVICE_MAX);

+ 4 - 15
drivers/usb/core/file.c

@@ -17,7 +17,6 @@
 
 
 #include <linux/config.h>
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/module.h>
-#include <linux/devfs_fs_kernel.h>
 #include <linux/spinlock.h>
 #include <linux/spinlock.h>
 #include <linux/errno.h>
 #include <linux/errno.h>
 
 
@@ -88,8 +87,6 @@ int usb_major_init(void)
 		goto out;
 		goto out;
 	}
 	}
 
 
-	devfs_mk_dir("usb");
-
 out:
 out:
 	return error;
 	return error;
 }
 }
@@ -97,7 +94,6 @@ out:
 void usb_major_cleanup(void)
 void usb_major_cleanup(void)
 {
 {
 	class_destroy(usb_class);
 	class_destroy(usb_class);
-	devfs_remove("usb");
 	unregister_chrdev(USB_MAJOR, "usb");
 	unregister_chrdev(USB_MAJOR, "usb");
 }
 }
 
 
@@ -112,8 +108,7 @@ void usb_major_cleanup(void)
  * enabled, the minor number will be based on the next available free minor,
  * enabled, the minor number will be based on the next available free minor,
  * starting at the class_driver->minor_base.
  * 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
  * usb_deregister_dev() must be called when the driver is done with
  * the minor numbers given out by this function.
  * the minor numbers given out by this function.
@@ -162,11 +157,8 @@ int usb_register_dev(struct usb_interface *intf,
 
 
 	intf->minor = minor;
 	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 */
 	/* create a usb class device for this usb interface */
+	snprintf(name, BUS_ID_SIZE, class_driver->name, minor - minor_base);
 	temp = strrchr(name, '/');
 	temp = strrchr(name, '/');
 	if (temp && (temp[1] != 0x00))
 	if (temp && (temp[1] != 0x00))
 		++temp;
 		++temp;
@@ -179,7 +171,6 @@ int usb_register_dev(struct usb_interface *intf,
 		spin_lock (&minor_lock);
 		spin_lock (&minor_lock);
 		usb_minors[intf->minor] = NULL;
 		usb_minors[intf->minor] = NULL;
 		spin_unlock (&minor_lock);
 		spin_unlock (&minor_lock);
-		devfs_remove (name);
 		retval = PTR_ERR(intf->class_dev);
 		retval = PTR_ERR(intf->class_dev);
 	}
 	}
 exit:
 exit:
@@ -197,9 +188,8 @@ EXPORT_SYMBOL(usb_register_dev);
  * call to usb_register_dev() (usually when the device is disconnected
  * call to usb_register_dev() (usually when the device is disconnected
  * from the system.)
  * 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.
  * This should be called by all drivers that use the USB major number.
  */
  */
 void usb_deregister_dev(struct usb_interface *intf,
 void usb_deregister_dev(struct usb_interface *intf,
@@ -222,7 +212,6 @@ void usb_deregister_dev(struct usb_interface *intf,
 	spin_unlock (&minor_lock);
 	spin_unlock (&minor_lock);
 
 
 	snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
 	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));
 	class_device_destroy(usb_class, MKDEV(USB_MAJOR, intf->minor));
 	intf->class_dev = NULL;
 	intf->class_dev = NULL;
 	intf->minor = -1;
 	intf->minor = -1;

+ 50 - 56
drivers/usb/core/hcd-pci.c

@@ -30,6 +30,8 @@
 #include <asm/io.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/irq.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
+
+#include "usb.h"
 #include "hcd.h"
 #include "hcd.h"
 
 
 
 
@@ -197,6 +199,26 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
 
 
 	hcd = pci_get_drvdata(dev);
 	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
 	/* FIXME until the generic PM interfaces change a lot more, this
 	 * can't use PCI D1 and D2 states.  For example, the confusion
 	 * can't use PCI D1 and D2 states.  For example, the confusion
 	 * between messages and states will need to vanish, and messages
 	 * between messages and states will need to vanish, and messages
@@ -215,31 +237,13 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
 	 */
 	 */
 	has_pci_pm = pci_find_capability(dev, PCI_CAP_ID_PM);
 	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 */
 		/* no DMA or IRQs except when HC is active */
 		if (dev->current_state == PCI_D0) {
 		if (dev->current_state == PCI_D0) {
 			pci_save_state (dev);
 			pci_save_state (dev);
@@ -248,7 +252,7 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
 
 
 		if (!has_pci_pm) {
 		if (!has_pci_pm) {
 			dev_dbg (hcd->self.controller, "--> PCI D0/legacy\n");
 			dev_dbg (hcd->self.controller, "--> PCI D0/legacy\n");
-			break;
+			goto done;
 		}
 		}
 
 
 		/* NOTE:  dev->current_state becomes nonzero only here, and
 		/* NOTE:  dev->current_state becomes nonzero only here, and
@@ -259,28 +263,29 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
 		retval = pci_set_power_state (dev, PCI_D3hot);
 		retval = pci_set_power_state (dev, PCI_D3hot);
 		if (retval == 0) {
 		if (retval == 0) {
 			dev_dbg (hcd->self.controller, "--> PCI D3\n");
 			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",
 			dev_dbg (&dev->dev, "PCI D3 suspend fail, %d\n",
 					retval);
 					retval);
 			(void) usb_hcd_pci_resume (dev);
 			(void) usb_hcd_pci_resume (dev);
-			break;
 		}
 		}
-		break;
-	default:
+
+	} else {
 		dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n",
 		dev_dbg (hcd->self.controller, "hcd state %d; not suspended\n",
 			hcd->state);
 			hcd->state);
 		WARN_ON(1);
 		WARN_ON(1);
 		retval = -EINVAL;
 		retval = -EINVAL;
-		break;
 	}
 	}
 
 
-	/* update power_state **ONLY** to make sysfs happier */
+done:
 	if (retval == 0)
 	if (retval == 0)
-		dev->dev.power.power_state = message;
+		dev->dev.power.power_state = PMSG_SUSPEND;
 	return retval;
 	return retval;
 }
 }
 EXPORT_SYMBOL (usb_hcd_pci_suspend);
 EXPORT_SYMBOL (usb_hcd_pci_suspend);
@@ -336,20 +341,9 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
 				dev->current_state);
 				dev->current_state);
 		}
 		}
 #endif
 #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 {
 	} else {
 		/* Same basic cases: clean (powered/not), dirty */
 		/* Same basic cases: clean (powered/not), dirty */
 		dev_dbg(hcd->self.controller, "PCI legacy resume\n");
 		dev_dbg(hcd->self.controller, "PCI legacy resume\n");
@@ -371,17 +365,17 @@ int usb_hcd_pci_resume (struct pci_dev *dev)
 
 
 	dev->dev.power.power_state = PMSG_ON;
 	dev->dev.power.power_state = PMSG_ON;
 
 
-	hcd->state = HC_STATE_RESUMING;
 	hcd->saw_irq = 0;
 	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;
 	return retval;
 }
 }
 EXPORT_SYMBOL (usb_hcd_pci_resume);
 EXPORT_SYMBOL (usb_hcd_pci_resume);

+ 102 - 49
drivers/usb/core/hcd.c

@@ -130,7 +130,7 @@ static const u8 usb2_rh_dev_descriptor [18] = {
 	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
 	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
 	0x00,	    /*  __u8  bDeviceSubClass; */
 	0x00,	    /*  __u8  bDeviceSubClass; */
 	0x01,       /*  __u8  bDeviceProtocol; [ usb 2.0 single TT ]*/
 	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 idVendor; */
  	0x00, 0x00, /*  __le16 idProduct; */
  	0x00, 0x00, /*  __le16 idProduct; */
@@ -153,7 +153,7 @@ static const u8 usb11_rh_dev_descriptor [18] = {
 	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
 	0x09,	    /*  __u8  bDeviceClass; HUB_CLASSCODE */
 	0x00,	    /*  __u8  bDeviceSubClass; */
 	0x00,	    /*  __u8  bDeviceSubClass; */
 	0x00,       /*  __u8  bDeviceProtocol; [ low/full speeds only ] */
 	0x00,       /*  __u8  bDeviceProtocol; [ low/full speeds only ] */
-	0x08,       /*  __u8  bMaxPacketSize0; 8 Bytes */
+	0x40,       /*  __u8  bMaxPacketSize0; 64 Bytes */
 
 
 	0x00, 0x00, /*  __le16 idVendor; */
 	0x00, 0x00, /*  __le16 idVendor; */
  	0x00, 0x00, /*  __le16 idProduct; */
  	0x00, 0x00, /*  __le16 idProduct; */
@@ -458,22 +458,18 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
 
 
 	default:
 	default:
 		/* non-generic request */
 		/* 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;
 		break;
 error:
 error:
 		/* "protocol stall" on error */
 		/* "protocol stall" on error */
@@ -487,7 +483,7 @@ error:
 				"CTRL: TypeReq=0x%x val=0x%x "
 				"CTRL: TypeReq=0x%x val=0x%x "
 				"idx=0x%x len=%d ==> %d\n",
 				"idx=0x%x len=%d ==> %d\n",
 				typeReq, wValue, wIndex,
 				typeReq, wValue, wIndex,
-				wLength, urb->status);
+				wLength, status);
 		}
 		}
 	}
 	}
 	if (len) {
 	if (len) {
@@ -748,10 +744,9 @@ struct usb_bus *usb_alloc_bus (struct usb_operations *op)
 {
 {
 	struct usb_bus *bus;
 	struct usb_bus *bus;
 
 
-	bus = kmalloc (sizeof *bus, GFP_KERNEL);
+	bus = kzalloc (sizeof *bus, GFP_KERNEL);
 	if (!bus)
 	if (!bus)
 		return NULL;
 		return NULL;
-	memset(bus, 0, sizeof(struct usb_bus));
 	usb_bus_init (bus);
 	usb_bus_init (bus);
 	bus->op = op;
 	bus->op = op;
 	return bus;
 	return bus;
@@ -796,8 +791,7 @@ static int usb_register_bus(struct usb_bus *bus)
 	list_add (&bus->bus_list, &usb_bus_list);
 	list_add (&bus->bus_list, &usb_bus_list);
 	up (&usb_bus_list_lock);
 	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);
 	dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum);
 	return 0;
 	return 0;
@@ -824,8 +818,7 @@ static void usb_deregister_bus (struct usb_bus *bus)
 	list_del (&bus->bus_list);
 	list_del (&bus->bus_list);
 	up (&usb_bus_list_lock);
 	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);
 	clear_bit (bus->busnum, busmap.busmap);
 
 
@@ -1143,10 +1136,20 @@ static int hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
 	else switch (hcd->state) {
 	else switch (hcd->state) {
 	case HC_STATE_RUNNING:
 	case HC_STATE_RUNNING:
 	case HC_STATE_RESUMING:
 	case HC_STATE_RESUMING:
+doit:
 		usb_get_dev (urb->dev);
 		usb_get_dev (urb->dev);
 		list_add_tail (&urb->urb_list, &ep->urb_list);
 		list_add_tail (&urb->urb_list, &ep->urb_list);
 		status = 0;
 		status = 0;
 		break;
 		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:
 	default:
 		status = -ESHUTDOWN;
 		status = -ESHUTDOWN;
 		break;
 		break;
@@ -1294,12 +1297,6 @@ static int hcd_unlink_urb (struct urb *urb, int status)
 		goto done;
 		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 */
 	/* insist the urb is still queued */
 	list_for_each(tmp, &ep->urb_list) {
 	list_for_each(tmp, &ep->urb_list) {
 		if (tmp == &urb->urb_list)
 		if (tmp == &urb->urb_list)
@@ -1431,28 +1428,92 @@ rescan:
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-#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;
 	struct usb_hcd		*hcd;
+	int			status;
 
 
 	hcd = container_of (bus, struct usb_hcd, self);
 	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;
 	struct usb_hcd		*hcd;
+	int			status;
 
 
 	hcd = container_of (bus, struct usb_hcd, self);
 	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 
  * usb_hcd_resume_root_hub - called by HCD to resume its root hub 
  * @hcd: host controller for this root hub
  * @hcd: host controller for this root hub
@@ -1460,7 +1521,7 @@ static int hcd_hub_resume (struct usb_bus *bus)
  * The USB host controller calls this function when its root hub is
  * The USB host controller calls this function when its root hub is
  * suspended (with the remote wakeup feature enabled) and a remote
  * suspended (with the remote wakeup feature enabled) and a remote
  * wakeup request is received.  It queues a request for khubd to
  * 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)
 void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
 {
 {
@@ -1471,13 +1532,9 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
 		usb_resume_root_hub (hcd->self.root_hub);
 		usb_resume_root_hub (hcd->self.root_hub);
 	spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
 	spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
 }
 }
+EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
 
 
-#else
-void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
-{
-}
 #endif
 #endif
-EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
@@ -1530,10 +1587,6 @@ static struct usb_operations usb_hcd_operations = {
 	.buffer_alloc =		hcd_buffer_alloc,
 	.buffer_alloc =		hcd_buffer_alloc,
 	.buffer_free =		hcd_buffer_free,
 	.buffer_free =		hcd_buffer_free,
 	.disable =		hcd_endpoint_disable,
 	.disable =		hcd_endpoint_disable,
-#ifdef	CONFIG_USB_SUSPEND
-	.hub_suspend =		hcd_hub_suspend,
-	.hub_resume =		hcd_hub_resume,
-#endif
 };
 };
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/

+ 32 - 37
drivers/usb/core/hcd.h

@@ -154,10 +154,6 @@ struct usb_operations {
 
 
 	void (*disable)(struct usb_device *udev,
 	void (*disable)(struct usb_device *udev,
 			struct usb_host_endpoint *ep);
 			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 */
 /* each driver provides one of these, and hardware init support */
@@ -182,12 +178,12 @@ struct hc_driver {
 	int	(*start) (struct usb_hcd *hcd);
 	int	(*start) (struct usb_hcd *hcd);
 
 
 	/* NOTE:  these suspend/resume calls relate to the HC as
 	/* 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);
 	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);
 	int	(*resume) (struct usb_hcd *hcd);
 
 
 	/* cleanly make HCD stop writing memory and doing I/O */
 	/* cleanly make HCD stop writing memory and doing I/O */
@@ -212,8 +208,8 @@ struct hc_driver {
 	int		(*hub_control) (struct usb_hcd *hcd,
 	int		(*hub_control) (struct usb_hcd *hcd,
 				u16 typeReq, u16 wValue, u16 wIndex,
 				u16 typeReq, u16 wValue, u16 wIndex,
 				char *buf, u16 wLength);
 				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);
 	int		(*start_port_reset)(struct usb_hcd *, unsigned port_num);
 	void		(*hub_irq_enable)(struct usb_hcd *);
 	void		(*hub_irq_enable)(struct usb_hcd *);
 		/* Needed only if port-change IRQs are level-triggered */
 		/* Needed only if port-change IRQs are level-triggered */
@@ -355,8 +351,6 @@ extern long usb_calc_bus_time (int speed, int is_input,
 
 
 extern struct usb_bus *usb_alloc_bus (struct usb_operations *);
 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,
 extern void usb_set_device_state(struct usb_device *udev,
 		enum usb_device_state new_state);
 		enum usb_device_state new_state);
 
 
@@ -378,6 +372,33 @@ extern int usb_find_interface_driver (struct usb_device *dev,
 
 
 #define usb_endpoint_out(ep_dir)	(!((ep_dir) & USB_DIR_IN))
 #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
  * USB device fs stuff
  */
  */
@@ -388,23 +409,13 @@ extern int usb_find_interface_driver (struct usb_device *dev,
  * these are expected to be called from the USB core/hub thread
  * these are expected to be called from the USB core/hub thread
  * with the kernel lock held
  * 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 void usbfs_update_special (void);
-
 extern int usbfs_init(void);
 extern int usbfs_init(void);
 extern void usbfs_cleanup(void);
 extern void usbfs_cleanup(void);
 
 
 #else /* CONFIG_USB_DEVICEFS */
 #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 void usbfs_update_special (void) {}
-
 static inline int usbfs_init(void) { return 0; }
 static inline int usbfs_init(void) { return 0; }
 static inline void usbfs_cleanup(void) { }
 static inline void usbfs_cleanup(void) { }
 
 
@@ -419,8 +430,6 @@ struct usb_mon_operations {
 	void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err);
 	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_complete)(struct usb_bus *bus, struct urb *urb);
 	/* void (*urb_unlink)(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;
 extern struct usb_mon_operations *mon_ops;
@@ -443,18 +452,6 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb)
 	if (bus->monitored)
 	if (bus->monitored)
 		(*mon_ops->urb_complete)(bus, urb);
 		(*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);
 int usb_mon_register(struct usb_mon_operations *ops);
 void usb_mon_deregister(void);
 void usb_mon_deregister(void);
@@ -465,8 +462,6 @@ static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {}
 static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
 static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
     int error) {}
     int error) {}
 static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
 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 */
 #endif /* CONFIG_USB_MON */
 
 

+ 182 - 228
drivers/usb/core/hub.c

@@ -436,9 +436,10 @@ static void hub_power_on(struct usb_hub *hub)
 {
 {
 	int port1;
 	int port1;
 	unsigned pgood_delay = hub->descriptor->bPwrOn2PwrGood * 2;
 	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 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");
 		dev_dbg(hub->intfdev, "enabling power on all ports\n");
 		for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++)
 		for (port1 = 1; port1 <= hub->descriptor->bNbrPorts; port1++)
 			set_port_feature(hub->hdev, port1,
 			set_port_feature(hub->hdev, port1,
@@ -449,10 +450,18 @@ static void hub_power_on(struct usb_hub *hub)
 	msleep(max(pgood_delay, (unsigned) 100));
 	msleep(max(pgood_delay, (unsigned) 100));
 }
 }
 
 
-static void hub_quiesce(struct usb_hub *hub)
+static inline void __hub_quiesce(struct usb_hub *hub)
 {
 {
-	/* stop khubd and related activity */
+	/* (nonblocking) khubd and related activity won't re-trigger */
 	hub->quiescing = 1;
 	hub->quiescing = 1;
+	hub->activating = 0;
+	hub->resume_root_hub = 0;
+}
+
+static void hub_quiesce(struct usb_hub *hub)
+{
+	/* (blocking) stop khubd and related activity */
+	__hub_quiesce(hub);
 	usb_kill_urb(hub->urb);
 	usb_kill_urb(hub->urb);
 	if (hub->has_indicators)
 	if (hub->has_indicators)
 		cancel_delayed_work(&hub->leds);
 		cancel_delayed_work(&hub->leds);
@@ -466,6 +475,7 @@ static void hub_activate(struct usb_hub *hub)
 
 
 	hub->quiescing = 0;
 	hub->quiescing = 0;
 	hub->activating = 1;
 	hub->activating = 1;
+	hub->resume_root_hub = 0;
 	status = usb_submit_urb(hub->urb, GFP_NOIO);
 	status = usb_submit_urb(hub->urb, GFP_NOIO);
 	if (status < 0)
 	if (status < 0)
 		dev_err(hub->intfdev, "activate --> %d\n", status);
 		dev_err(hub->intfdev, "activate --> %d\n", status);
@@ -516,6 +526,7 @@ static int hub_configure(struct usb_hub *hub,
 	struct usb_device *hdev = hub->hdev;
 	struct usb_device *hdev = hub->hdev;
 	struct device *hub_dev = hub->intfdev;
 	struct device *hub_dev = hub->intfdev;
 	u16 hubstatus, hubchange;
 	u16 hubstatus, hubchange;
+	u16 wHubCharacteristics;
 	unsigned int pipe;
 	unsigned int pipe;
 	int maxp, ret;
 	int maxp, ret;
 	char *message;
 	char *message;
@@ -561,9 +572,9 @@ static int hub_configure(struct usb_hub *hub,
 	dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
 	dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
 		(hdev->maxchild == 1) ? "" : "s");
 		(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;
 		int	i;
 		char	portstr [USB_MAXCHILDREN + 1];
 		char	portstr [USB_MAXCHILDREN + 1];
 
 
@@ -576,7 +587,7 @@ static int hub_configure(struct usb_hub *hub,
 	} else
 	} else
 		dev_dbg(hub_dev, "standalone hub\n");
 		dev_dbg(hub_dev, "standalone hub\n");
 
 
-	switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_LPSM) {
+	switch (wHubCharacteristics & HUB_CHAR_LPSM) {
 		case 0x00:
 		case 0x00:
 			dev_dbg(hub_dev, "ganged power switching\n");
 			dev_dbg(hub_dev, "ganged power switching\n");
 			break;
 			break;
@@ -589,7 +600,7 @@ static int hub_configure(struct usb_hub *hub,
 			break;
 			break;
 	}
 	}
 
 
-	switch (hub->descriptor->wHubCharacteristics & HUB_CHAR_OCPM) {
+	switch (wHubCharacteristics & HUB_CHAR_OCPM) {
 		case 0x00:
 		case 0x00:
 			dev_dbg(hub_dev, "global over-current protection\n");
 			dev_dbg(hub_dev, "global over-current protection\n");
 			break;
 			break;
@@ -629,7 +640,7 @@ static int hub_configure(struct usb_hub *hub,
 	}
 	}
 
 
 	/* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */
 	/* 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:
 		case HUB_TTTT_8_BITS:
 			if (hdev->descriptor.bDeviceProtocol != 0) {
 			if (hdev->descriptor.bDeviceProtocol != 0) {
 				hub->tt.think_time = 666;
 				hub->tt.think_time = 666;
@@ -659,7 +670,7 @@ static int hub_configure(struct usb_hub *hub,
 	}
 	}
 
 
 	/* probe() zeroes hub->indicator[] */
 	/* probe() zeroes hub->indicator[] */
-	if (hub->descriptor->wHubCharacteristics & HUB_CHAR_PORTIND) {
+	if (wHubCharacteristics & HUB_CHAR_PORTIND) {
 		hub->has_indicators = 1;
 		hub->has_indicators = 1;
 		dev_dbg(hub_dev, "Port indicators are supported\n");
 		dev_dbg(hub_dev, "Port indicators are supported\n");
 	}
 	}
@@ -704,7 +715,7 @@ static int hub_configure(struct usb_hub *hub,
 			(hubstatus & HUB_STATUS_LOCAL_POWER)
 			(hubstatus & HUB_STATUS_LOCAL_POWER)
 			? "lost (inactive)" : "good");
 			? "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",
 		dev_dbg(hub_dev, "%sover-current condition exists\n",
 			(hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
 			(hubstatus & HUB_STATUS_OVERCURRENT) ? "" : "no ");
 
 
@@ -854,14 +865,12 @@ descriptor_error:
 	/* We found a hub */
 	/* We found a hub */
 	dev_info (&intf->dev, "USB hub found\n");
 	dev_info (&intf->dev, "USB hub found\n");
 
 
-	hub = kmalloc(sizeof(*hub), GFP_KERNEL);
+	hub = kzalloc(sizeof(*hub), GFP_KERNEL);
 	if (!hub) {
 	if (!hub) {
 		dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n");
 		dev_dbg (&intf->dev, "couldn't kmalloc hub struct\n");
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 
 
-	memset(hub, 0, sizeof(*hub));
-
 	INIT_LIST_HEAD(&hub->event_list);
 	INIT_LIST_HEAD(&hub->event_list);
 	hub->intfdev = &intf->dev;
 	hub->intfdev = &intf->dev;
 	hub->hdev = hdev;
 	hub->hdev = hdev;
@@ -1117,14 +1126,14 @@ void usb_disconnect(struct usb_device **pdev)
 	 */
 	 */
 	usb_disable_device(udev, 0);
 	usb_disable_device(udev, 0);
 
 
+	usb_notify_remove_device(udev);
+
 	/* Free the device number, remove the /proc/bus/usb entry and
 	/* Free the device number, remove the /proc/bus/usb entry and
 	 * the sysfs attributes, and delete the parent's children[]
 	 * the sysfs attributes, and delete the parent's children[]
 	 * (or root_hub) pointer.
 	 * (or root_hub) pointer.
 	 */
 	 */
 	dev_dbg (&udev->dev, "unregistering device\n");
 	dev_dbg (&udev->dev, "unregistering device\n");
 	release_address(udev);
 	release_address(udev);
-	usbfs_remove_device(udev);
-	usbdev_remove(udev);
 	usb_remove_sysfs_dev_files(udev);
 	usb_remove_sysfs_dev_files(udev);
 
 
 	/* Avoid races with recursively_mark_NOTATTACHED() */
 	/* Avoid races with recursively_mark_NOTATTACHED() */
@@ -1195,21 +1204,6 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
 {}
 {}
 #endif
 #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
 #ifdef	CONFIG_USB_OTG
 #include "otg_whitelist.h"
 #include "otg_whitelist.h"
@@ -1248,9 +1242,10 @@ int usb_new_device(struct usb_device *udev)
 	}
 	}
 
 
 	/* read the standard strings and cache them if present */
 	/* 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! */
 	/* Tell the world! */
 	dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
 	dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
@@ -1322,11 +1317,9 @@ int usb_new_device(struct usb_device *udev)
 		 * (Includes HNP test device.)
 		 * (Includes HNP test device.)
 		 */
 		 */
 		if (udev->bus->b_hnp_enable || udev->bus->is_b_host) {
 		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)
 			if (err < 0)
 				dev_dbg(&udev->dev, "HNP fail, %d\n", err);
 				dev_dbg(&udev->dev, "HNP fail, %d\n", err);
 		}
 		}
@@ -1362,10 +1355,8 @@ int usb_new_device(struct usb_device *udev)
 	}
 	}
 
 
 	/* USB device state == configured ... usable */
 	/* 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;
 	return 0;
 
 
 fail:
 fail:
@@ -1516,7 +1507,7 @@ static void hub_port_logical_disconnect(struct usb_hub *hub, int port1)
 	/* FIXME let caller ask to power down the port:
 	/* FIXME let caller ask to power down the port:
 	 *  - some devices won't enumerate without a VBUS power cycle
 	 *  - some devices won't enumerate without a VBUS power cycle
 	 *  - SRP saves power that way
 	 *  - 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
 	 * That's easy if this hub can switch power per-port, and
 	 * khubd reactivates the port later (timer, SRP, etc).
 	 * khubd reactivates the port later (timer, SRP, etc).
 	 * Powerdown must be optional, because of reset/DFU.
 	 * Powerdown must be optional, because of reset/DFU.
@@ -1598,11 +1589,14 @@ static int hub_port_suspend(struct usb_hub *hub, int port1,
  * Other than re-initializing the hub (plug/unplug, except for root hubs),
  * Other than re-initializing the hub (plug/unplug, except for root hubs),
  * Linux (2.6) currently has NO mechanisms to initiate that:  no khubd
  * Linux (2.6) currently has NO mechanisms to initiate that:  no khubd
  * timer, no SRP, no requests through sysfs.
  * 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 */
 	/* caller owns the udev device lock */
 	if (port1 < 0)
 	if (port1 < 0)
@@ -1613,95 +1607,39 @@ static int __usb_suspend_device (struct usb_device *udev, int port1,
 		return 0;
 		return 0;
 	}
 	}
 
 
-	/* suspend interface drivers; if this is a hub, it
-	 * suspends the child devices
-	 */
+	/* all interfaces must already be suspended */
 	if (udev->actconfig) {
 	if (udev->actconfig) {
 		int	i;
 		int	i;
 
 
 		for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
 		for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
 			struct usb_interface	*intf;
 			struct usb_interface	*intf;
-			struct usb_driver	*driver;
 
 
 			intf = udev->actconfig->interface[i];
 			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,
 		status = hub_port_suspend(hdev_to_hub(udev->parent), port1,
 				udev);
 				udev);
 
 
 	if (status == 0)
 	if (status == 0)
-		udev->dev.power.power_state = state;
+		udev->dev.power.power_state = PMSG_SUSPEND;
 	return status;
 	return status;
 }
 }
 
 
-/**
+#endif
+
+/*
  * usb_suspend_device - suspend a usb device
  * usb_suspend_device - suspend a usb device
  * @udev: device that's no longer in active use
  * @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.
  * Suspends a USB device that isn't in active use, conserving power.
  * Devices may wake out of a suspend, if anything important happens,
  * Devices may wake out of a suspend, if anything important happens,
@@ -1709,37 +1647,50 @@ static int __usb_suspend_device (struct usb_device *udev, int port1,
  * suspend by the host, using usb_resume_device().  It's also routine
  * suspend by the host, using usb_resume_device().  It's also routine
  * to disconnect devices while they are suspended.
  * 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
  * Suspending OTG devices may trigger HNP, if that's been enabled
  * between a pair of dual-role devices.  That will change roles, such
  * 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.
  * as from A-Host to A-Peripheral or from B-Host back to B-Peripheral.
  *
  *
  * Returns 0 on success, else negative errno.
  * 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;
 	int	port1, status;
 
 
 	port1 = locktree(udev);
 	port1 = locktree(udev);
 	if (port1 < 0)
 	if (port1 < 0)
 		return port1;
 		return port1;
 
 
-	status = __usb_suspend_device(udev, port1, state);
+	status = __usb_suspend_device(udev, port1);
 	usb_unlock_device(udev);
 	usb_unlock_device(udev);
 	return status;
 	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
  * hardware resume signaling is finished, either because of selective
  * resume (by host) or remote wakeup (by device) ... now see what changed
  * resume (by host) or remote wakeup (by device) ... now see what changed
  * in the tree that's rooted at this device.
  * 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;
 	int	status;
 	u16	devstatus;
 	u16	devstatus;
 
 
 	/* caller owns the udev device lock */
 	/* 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
 	/* usb ch9 identifies four variants of SUSPENDED, based on what
 	 * state the device resumes to.  Linux currently won't see the
 	 * state the device resumes to.  Linux currently won't see the
@@ -1749,7 +1700,6 @@ static int finish_port_resume(struct usb_device *udev)
 	usb_set_device_state(udev, udev->actconfig
 	usb_set_device_state(udev, udev->actconfig
 			? USB_STATE_CONFIGURED
 			? USB_STATE_CONFIGURED
 			: USB_STATE_ADDRESS);
 			: USB_STATE_ADDRESS);
-	udev->dev.power.power_state = PMSG_ON;
 
 
  	/* 10.5.4.5 says be sure devices in the tree are still there.
  	/* 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,
  	 * For now let's assume the device didn't go crazy on resume,
@@ -1762,9 +1712,11 @@ static int finish_port_resume(struct usb_device *udev)
 			status);
 			status);
 	else if (udev->actconfig) {
 	else if (udev->actconfig) {
 		unsigned	i;
 		unsigned	i;
+		int		(*resume)(struct device *);
 
 
 		le16_to_cpus(&devstatus);
 		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,
 			status = usb_control_msg(udev,
 					usb_sndctrlpipe(udev, 0),
 					usb_sndctrlpipe(udev, 0),
 					USB_REQ_CLEAR_FEATURE,
 					USB_REQ_CLEAR_FEATURE,
@@ -1780,33 +1732,11 @@ static int finish_port_resume(struct usb_device *udev)
 		}
 		}
 
 
 		/* resume interface drivers; if this is a hub, it
 		/* 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;
 		status = 0;
 
 
 	} else if (udev->devnum <= 0) {
 	} else if (udev->devnum <= 0) {
@@ -1816,6 +1746,8 @@ static int finish_port_resume(struct usb_device *udev)
 	return status;
 	return status;
 }
 }
 
 
+#ifdef	CONFIG_USB_SUSPEND
+
 static int
 static int
 hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
 hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
 {
 {
@@ -1861,7 +1793,7 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
 			/* TRSMRCY = 10 msec */
 			/* TRSMRCY = 10 msec */
 			msleep(10);
 			msleep(10);
 			if (udev)
 			if (udev)
-				status = finish_port_resume(udev);
+				status = finish_device_resume(udev);
 		}
 		}
 	}
 	}
 	if (status < 0)
 	if (status < 0)
@@ -1870,12 +1802,12 @@ hub_port_resume(struct usb_hub *hub, int port1, struct usb_device *udev)
 	return status;
 	return status;
 }
 }
 
 
-static int hub_resume (struct usb_interface *intf);
+#endif
 
 
-/**
+/*
  * usb_resume_device - re-activate a suspended usb device
  * usb_resume_device - re-activate a suspended usb device
  * @udev: device to re-activate
  * @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
  * This will re-activate the suspended device, increasing power usage
  * while letting drivers communicate again with its endpoints.
  * while letting drivers communicate again with its endpoints.
@@ -1893,35 +1825,22 @@ int usb_resume_device(struct usb_device *udev)
 	if (port1 < 0)
 	if (port1 < 0)
 		return port1;
 		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
 		} 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",
 		dev_dbg(&udev->dev, "can't resume, status %d\n",
 			status);
 			status);
-	}
 
 
 	usb_unlock_device(udev);
 	usb_unlock_device(udev);
 
 
@@ -1938,6 +1857,8 @@ static int remote_wakeup(struct usb_device *udev)
 {
 {
 	int	status = 0;
 	int	status = 0;
 
 
+#ifdef	CONFIG_USB_SUSPEND
+
 	/* don't repeat RESUME sequence if this device
 	/* don't repeat RESUME sequence if this device
 	 * was already woken up by some other task
 	 * was already woken up by some other task
 	 */
 	 */
@@ -1946,38 +1867,52 @@ static int remote_wakeup(struct usb_device *udev)
 		dev_dbg(&udev->dev, "RESUME (wakeup)\n");
 		dev_dbg(&udev->dev, "RESUME (wakeup)\n");
 		/* TRSMRCY = 10 msec */
 		/* TRSMRCY = 10 msec */
 		msleep(10);
 		msleep(10);
-		status = finish_port_resume(udev);
+		status = finish_device_resume(udev);
 	}
 	}
 	up(&udev->serialize);
 	up(&udev->serialize);
+#endif
 	return status;
 	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_hub		*hub = usb_get_intfdata (intf);
 	struct usb_device	*hdev = hub->hdev;
 	struct usb_device	*hdev = hub->hdev;
 	unsigned		port1;
 	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++) {
 	for (port1 = 1; port1 <= hdev->maxchild; port1++) {
 		struct usb_device	*udev;
 		struct usb_device	*udev;
 
 
 		udev = hdev->children [port1-1];
 		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;
 	return 0;
 }
 }
 
 
@@ -1985,11 +1920,35 @@ static int hub_resume(struct usb_interface *intf)
 {
 {
 	struct usb_device	*hdev = interface_to_usbdev(intf);
 	struct usb_device	*hdev = interface_to_usbdev(intf);
 	struct usb_hub		*hub = usb_get_intfdata (intf);
 	struct usb_hub		*hub = usb_get_intfdata (intf);
-	unsigned		port1;
 	int			status;
 	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++) {
 	for (port1 = 1; port1 <= hdev->maxchild; port1++) {
 		struct usb_device	*udev;
 		struct usb_device	*udev;
@@ -2015,7 +1974,7 @@ static int hub_resume(struct usb_interface *intf)
 		if (portstat & USB_PORT_STAT_SUSPEND)
 		if (portstat & USB_PORT_STAT_SUSPEND)
 			status = hub_port_resume(hub, port1, udev);
 			status = hub_port_resume(hub, port1, udev);
 		else {
 		else {
-			status = finish_port_resume(udev);
+			status = finish_device_resume(udev);
 			if (status < 0) {
 			if (status < 0) {
 				dev_dbg(&intf->dev, "resume port %d --> %d\n",
 				dev_dbg(&intf->dev, "resume port %d --> %d\n",
 					port1, status);
 					port1, status);
@@ -2024,43 +1983,31 @@ static int hub_resume(struct usb_interface *intf)
 		}
 		}
 		up(&udev->serialize);
 		up(&udev->serialize);
 	}
 	}
-	intf->dev.power.power_state = PMSG_ON;
-
-	hub->resume_root_hub = 0;
-	hub_activate(hub);
+	}
+#endif
 	return 0;
 	return 0;
 }
 }
 
 
-void usb_resume_root_hub(struct usb_device *hdev)
+void usb_suspend_root_hub(struct usb_device *hdev)
 {
 {
 	struct usb_hub *hub = hdev_to_hub(hdev);
 	struct usb_hub *hub = hdev_to_hub(hdev);
 
 
-	hub->resume_root_hub = 1;
-	kick_khubd(hub);
+	/* 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));
 }
 }
 
 
-#else	/* !CONFIG_USB_SUSPEND */
-
-int usb_suspend_device(struct usb_device *udev, pm_message_t state)
+void usb_resume_root_hub(struct usb_device *hdev)
 {
 {
-	return 0;
-}
+	struct usb_hub *hub = hdev_to_hub(hdev);
 
 
-int usb_resume_device(struct usb_device *udev)
-{
-	return 0;
+	hub->resume_root_hub = 1;
+	kick_khubd(hub);
 }
 }
 
 
-#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:
 /* USB 2.0 spec, 7.1.7.3 / fig 7-29:
  *
  *
@@ -2469,6 +2416,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
 {
 {
 	struct usb_device *hdev = hub->hdev;
 	struct usb_device *hdev = hub->hdev;
 	struct device *hub_dev = hub->intfdev;
 	struct device *hub_dev = hub->intfdev;
+	u16 wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
 	int status, i;
 	int status, i;
  
  
 	dev_dbg (hub_dev,
 	dev_dbg (hub_dev,
@@ -2506,8 +2454,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
 	if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
 	if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
 
 
 		/* maybe switch power back on (e.g. root hub was reset) */
 		/* 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)))
 				&& !(portstatus & (1 << USB_PORT_FEAT_POWER)))
 			set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
 			set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
  
  
@@ -2686,21 +2633,28 @@ static void hub_events(void)
 		intf = to_usb_interface(hub->intfdev);
 		intf = to_usb_interface(hub->intfdev);
 		hub_dev = &intf->dev;
 		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
 				hdev->state, hub->descriptor
 					? hub->descriptor->bNbrPorts
 					? hub->descriptor->bNbrPorts
 					: 0,
 					: 0,
 				/* NOTE: expects max 15 ports... */
 				/* NOTE: expects max 15 ports... */
 				(u16) hub->change_bits[0],
 				(u16) hub->change_bits[0],
-				(u16) hub->event_bits[0]);
+				(u16) hub->event_bits[0],
+				i ? ", resume root" : "");
 
 
 		usb_get_intf(intf);
 		usb_get_intf(intf);
-		i = hub->resume_root_hub;
 		spin_unlock_irq(&hub_event_lock);
 		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
 		/* Lock the device, then check to see if we were
 		 * disconnected while waiting for the lock to succeed. */
 		 * disconnected while waiting for the lock to succeed. */

+ 1 - 1
drivers/usb/core/hub.h

@@ -131,7 +131,7 @@ struct usb_hub_descriptor {
 	__u8  bDescLength;
 	__u8  bDescLength;
 	__u8  bDescriptorType;
 	__u8  bDescriptorType;
 	__u8  bNbrPorts;
 	__u8  bNbrPorts;
-	__u16 wHubCharacteristics;
+	__le16 wHubCharacteristics;
 	__u8  bPwrOn2PwrGood;
 	__u8  bPwrOn2PwrGood;
 	__u8  bHubContrCurrent;
 	__u8  bHubContrCurrent;
 	    	/* add 1 bit for hub status change; round to bytes */
 	    	/* add 1 bit for hub status change; round to bytes */

+ 31 - 13
drivers/usb/core/inode.c

@@ -39,6 +39,7 @@
 #include <linux/usbdevice_fs.h>
 #include <linux/usbdevice_fs.h>
 #include <linux/smp_lock.h>
 #include <linux/smp_lock.h>
 #include <linux/parser.h>
 #include <linux/parser.h>
+#include <linux/notifier.h>
 #include <asm/byteorder.h>
 #include <asm/byteorder.h>
 #include "usb.h"
 #include "usb.h"
 #include "hcd.h"
 #include "hcd.h"
@@ -619,7 +620,7 @@ void usbfs_update_special (void)
 	}
 	}
 }
 }
 
 
-void usbfs_add_bus(struct usb_bus *bus)
+static void usbfs_add_bus(struct usb_bus *bus)
 {
 {
 	struct dentry *parent;
 	struct dentry *parent;
 	char name[8];
 	char name[8];
@@ -642,12 +643,9 @@ void usbfs_add_bus(struct usb_bus *bus)
 		err ("error creating usbfs bus entry");
 		err ("error creating usbfs bus entry");
 		return;
 		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) {
 	if (bus->usbfs_dentry) {
 		fs_remove_file (bus->usbfs_dentry);
 		fs_remove_file (bus->usbfs_dentry);
@@ -659,12 +657,9 @@ void usbfs_remove_bus(struct usb_bus *bus)
 		remove_special_files();
 		remove_special_files();
 		num_buses = 0;
 		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];
 	char name[8];
 	int i;
 	int i;
@@ -690,12 +685,9 @@ void usbfs_add_device(struct usb_device *dev)
 	}
 	}
 	if (dev->usbfs_dentry->d_inode)
 	if (dev->usbfs_dentry->d_inode)
 		dev->usbfs_dentry->d_inode->i_size = i_size;
 		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 dev_state *ds;
 	struct siginfo sinfo;
 	struct siginfo sinfo;
@@ -716,10 +708,33 @@ void usbfs_remove_device(struct usb_device *dev)
 			kill_proc_info_as_uid(ds->discsignr, &sinfo, ds->disc_pid, ds->disc_uid, ds->disc_euid);
 			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_update_special();
 	usbfs_conn_disc_event();
 	usbfs_conn_disc_event();
+	return NOTIFY_OK;
 }
 }
 
 
+static struct notifier_block usbfs_nb = {
+	.notifier_call = 	usbfs_notify,
+};
+
 /* --------------------------------------------------------------------- */
 /* --------------------------------------------------------------------- */
 
 
 static struct proc_dir_entry *usbdir = NULL;
 static struct proc_dir_entry *usbdir = NULL;
@@ -732,6 +747,8 @@ int __init usbfs_init(void)
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
 
 
+	usb_register_notify(&usbfs_nb);
+
 	/* create mount point for usbfs */
 	/* create mount point for usbfs */
 	usbdir = proc_mkdir("usb", proc_bus);
 	usbdir = proc_mkdir("usb", proc_bus);
 
 
@@ -740,6 +757,7 @@ int __init usbfs_init(void)
 
 
 void usbfs_cleanup(void)
 void usbfs_cleanup(void)
 {
 {
+	usb_unregister_notify(&usbfs_nb);
 	unregister_filesystem(&usb_fs_type);
 	unregister_filesystem(&usb_fs_type);
 	if (usbdir)
 	if (usbdir)
 		remove_proc_entry("usb", proc_bus);
 		remove_proc_entry("usb", proc_bus);

+ 61 - 27
drivers/usb/core/message.c

@@ -187,21 +187,37 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u
  *      If a thread in your driver uses this call, make sure your disconnect()
  *      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
  *      method can wait for it to complete.  Since you don't have a handle on
  *      the URB used, you can't cancel the request.
  *      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, 
 int usb_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, 
 			void *data, int len, int *actual_length, int timeout)
 			void *data, int len, int *actual_length, int timeout)
 {
 {
 	struct urb *urb;
 	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;
 		return -EINVAL;
 
 
-	urb=usb_alloc_urb(0, GFP_KERNEL);
+	urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!urb)
 	if (!urb)
 		return -ENOMEM;
 		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);
 	return usb_start_wait_urb(urb, timeout, actual_length);
 }
 }
@@ -771,6 +787,31 @@ int usb_string(struct usb_device *dev, int index, char *buf, size_t size)
 	return err;
 	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)
  * usb_get_device_descriptor - (re)reads the device descriptor (usbcore)
  * @dev: the device whose device descriptor is being updated
  * @dev: the device whose device descriptor is being updated
@@ -992,8 +1033,6 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
 			dev_dbg (&dev->dev, "unregistering interface %s\n",
 			dev_dbg (&dev->dev, "unregistering interface %s\n",
 				interface->dev.bus_id);
 				interface->dev.bus_id);
 			usb_remove_sysfs_intf_files(interface);
 			usb_remove_sysfs_intf_files(interface);
-			kfree(interface->cur_altsetting->string);
-			interface->cur_altsetting->string = NULL;
 			device_del (&interface->dev);
 			device_del (&interface->dev);
 		}
 		}
 
 
@@ -1133,6 +1172,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
 	 */
 	 */
 
 
 	/* prevent submissions using previous endpoint settings */
 	/* prevent submissions using previous endpoint settings */
+	if (device_is_registered(&iface->dev))
+		usb_remove_sysfs_intf_files(iface);
 	usb_disable_interface(dev, iface);
 	usb_disable_interface(dev, iface);
 
 
 	iface->cur_altsetting = alt;
 	iface->cur_altsetting = alt;
@@ -1168,6 +1209,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
 	 * (Likewise, EP0 never "halts" on well designed devices.)
 	 * (Likewise, EP0 never "halts" on well designed devices.)
 	 */
 	 */
 	usb_enable_interface(dev, iface);
 	usb_enable_interface(dev, iface);
+	if (device_is_registered(&iface->dev))
+		usb_create_sysfs_intf_files(iface);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1217,10 +1260,8 @@ int usb_reset_configuration(struct usb_device *dev)
 			USB_REQ_SET_CONFIGURATION, 0,
 			USB_REQ_SET_CONFIGURATION, 0,
 			config->desc.bConfigurationValue, 0,
 			config->desc.bConfigurationValue, 0,
 			NULL, 0, USB_CTRL_SET_TIMEOUT);
 			NULL, 0, USB_CTRL_SET_TIMEOUT);
-	if (retval < 0) {
-		usb_set_device_state(dev, USB_STATE_ADDRESS);
+	if (retval < 0)
 		return retval;
 		return retval;
-	}
 
 
 	dev->toggle[0] = dev->toggle[1] = 0;
 	dev->toggle[0] = dev->toggle[1] = 0;
 
 
@@ -1229,6 +1270,8 @@ int usb_reset_configuration(struct usb_device *dev)
 		struct usb_interface *intf = config->interface[i];
 		struct usb_interface *intf = config->interface[i];
 		struct usb_host_interface *alt;
 		struct usb_host_interface *alt;
 
 
+		if (device_is_registered(&intf->dev))
+			usb_remove_sysfs_intf_files(intf);
 		alt = usb_altnum_to_altsetting(intf, 0);
 		alt = usb_altnum_to_altsetting(intf, 0);
 
 
 		/* No altsetting 0?  We'll assume the first altsetting.
 		/* No altsetting 0?  We'll assume the first altsetting.
@@ -1241,6 +1284,8 @@ int usb_reset_configuration(struct usb_device *dev)
 
 
 		intf->cur_altsetting = alt;
 		intf->cur_altsetting = alt;
 		usb_enable_interface(dev, intf);
 		usb_enable_interface(dev, intf);
+		if (device_is_registered(&intf->dev))
+			usb_create_sysfs_intf_files(intf);
 	}
 	}
 	return 0;
 	return 0;
 }
 }
@@ -1328,7 +1373,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
 		}
 		}
 
 
 		for (; n < nintf; ++n) {
 		for (; n < nintf; ++n) {
-			new_interfaces[n] = kmalloc(
+			new_interfaces[n] = kzalloc(
 					sizeof(struct usb_interface),
 					sizeof(struct usb_interface),
 					GFP_KERNEL);
 					GFP_KERNEL);
 			if (!new_interfaces[n]) {
 			if (!new_interfaces[n]) {
@@ -1369,7 +1414,6 @@ free_interfaces:
 			struct usb_host_interface *alt;
 			struct usb_host_interface *alt;
 
 
 			cp->interface[i] = intf = new_interfaces[i];
 			cp->interface[i] = intf = new_interfaces[i];
-			memset(intf, 0, sizeof(*intf));
 			intfc = cp->intf_cache[i];
 			intfc = cp->intf_cache[i];
 			intf->altsetting = intfc->altsetting;
 			intf->altsetting = intfc->altsetting;
 			intf->num_altsetting = intfc->num_altsetting;
 			intf->num_altsetting = intfc->num_altsetting;
@@ -1393,6 +1437,7 @@ free_interfaces:
 			intf->dev.dma_mask = dev->dev.dma_mask;
 			intf->dev.dma_mask = dev->dev.dma_mask;
 			intf->dev.release = release_interface;
 			intf->dev.release = release_interface;
 			device_initialize (&intf->dev);
 			device_initialize (&intf->dev);
+			mark_quiesced(intf);
 			sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
 			sprintf (&intf->dev.bus_id[0], "%d-%s:%d.%d",
 				 dev->bus->busnum, dev->devpath,
 				 dev->bus->busnum, dev->devpath,
 				 configuration,
 				 configuration,
@@ -1400,12 +1445,9 @@ free_interfaces:
 		}
 		}
 		kfree(new_interfaces);
 		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
 		/* Now that all the interfaces are set up, register them
 		 * to trigger binding of drivers to interfaces.  probe()
 		 * to trigger binding of drivers to interfaces.  probe()
@@ -1415,13 +1457,12 @@ free_interfaces:
 		 */
 		 */
 		for (i = 0; i < nintf; ++i) {
 		for (i = 0; i < nintf; ++i) {
 			struct usb_interface *intf = cp->interface[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,
 			dev_dbg (&dev->dev,
 				"adding %s (config #%d, interface %d)\n",
 				"adding %s (config #%d, interface %d)\n",
 				intf->dev.bus_id, configuration,
 				intf->dev.bus_id, configuration,
-				desc->bInterfaceNumber);
+				alt->desc.bInterfaceNumber);
 			ret = device_add (&intf->dev);
 			ret = device_add (&intf->dev);
 			if (ret != 0) {
 			if (ret != 0) {
 				dev_err(&dev->dev,
 				dev_err(&dev->dev,
@@ -1430,13 +1471,6 @@ free_interfaces:
 					ret);
 					ret);
 				continue;
 				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);
 			usb_create_sysfs_intf_files (intf);
 		}
 		}
 	}
 	}

+ 120 - 0
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);
+}

+ 268 - 51
drivers/usb/core/sysfs.c

@@ -22,9 +22,207 @@
 
 
 #include "usb.h"
 #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 */
 /* Active configuration fields */
 #define usb_actconfig_show(field, multiplier, format_string)		\
 #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_device *udev;					\
 	struct usb_host_config *actconfig;				\
 	struct usb_host_config *actconfig;				\
@@ -46,22 +244,17 @@ usb_actconfig_attr (bNumInterfaces, 1, "%2d\n")
 usb_actconfig_attr (bmAttributes, 1, "%2x\n")
 usb_actconfig_attr (bmAttributes, 1, "%2x\n")
 usb_actconfig_attr (bMaxPower, 2, "%3dmA\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_device *udev;
 	struct usb_host_config *actconfig;
 	struct usb_host_config *actconfig;
-	int len;
 
 
 	udev = to_usb_device (dev);
 	udev = to_usb_device (dev);
 	actconfig = udev->actconfig;
 	actconfig = udev->actconfig;
 	if ((!actconfig) || (!actconfig->string))
 	if ((!actconfig) || (!actconfig->string))
 		return 0;
 		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);
 static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
 
 
@@ -69,7 +262,8 @@ static DEVICE_ATTR(configuration, S_IRUGO, show_configuration_string, NULL);
 usb_actconfig_show(bConfigurationValue, 1, "%u\n");
 usb_actconfig_show(bConfigurationValue, 1, "%u\n");
 
 
 static ssize_t
 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);
 	struct usb_device	*udev = udev = to_usb_device (dev);
 	int			config, value;
 	int			config, value;
@@ -87,18 +281,13 @@ static DEVICE_ATTR(bConfigurationValue, S_IRUGO | S_IWUSR,
 
 
 /* String fields */
 /* String fields */
 #define usb_string_attr(name)						\
 #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;					\
 	struct usb_device *udev;					\
-	int len;							\
 									\
 									\
 	udev = to_usb_device (dev);					\
 	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);
 static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
 
 
@@ -167,7 +356,8 @@ static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL);
 /* Descriptor fields */
 /* Descriptor fields */
 #define usb_descriptor_attr_le16(field, format_string)			\
 #define usb_descriptor_attr_le16(field, format_string)			\
 static ssize_t								\
 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;					\
 	struct usb_device *udev;					\
 									\
 									\
@@ -183,7 +373,8 @@ usb_descriptor_attr_le16(bcdDevice, "%04x\n")
 
 
 #define usb_descriptor_attr(field, format_string)			\
 #define usb_descriptor_attr(field, format_string)			\
 static ssize_t								\
 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;					\
 	struct usb_device *udev;					\
 									\
 									\
@@ -236,19 +427,21 @@ void usb_create_sysfs_dev_files (struct usb_device *udev)
 	if (udev->serial)
 	if (udev->serial)
 		device_create_file (dev, &dev_attr_serial);
 		device_create_file (dev, &dev_attr_serial);
 	device_create_file (dev, &dev_attr_configuration);
 	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)
 void usb_remove_sysfs_dev_files (struct usb_device *udev)
 {
 {
 	struct device *dev = &udev->dev;
 	struct device *dev = &udev->dev;
 
 
+	usb_remove_ep_files(&udev->ep0);
 	sysfs_remove_group(&dev->kobj, &dev_attr_grp);
 	sysfs_remove_group(&dev->kobj, &dev_attr_grp);
 
 
-	if (udev->descriptor.iManufacturer)
+	if (udev->manufacturer)
 		device_remove_file(dev, &dev_attr_manufacturer);
 		device_remove_file(dev, &dev_attr_manufacturer);
-	if (udev->descriptor.iProduct)
+	if (udev->product)
 		device_remove_file(dev, &dev_attr_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_serial);
 	device_remove_file (dev, &dev_attr_configuration);
 	device_remove_file (dev, &dev_attr_configuration);
 }
 }
@@ -256,11 +449,13 @@ void usb_remove_sysfs_dev_files (struct usb_device *udev)
 /* Interface fields */
 /* Interface fields */
 #define usb_intf_attr(field, format_string)				\
 #define usb_intf_attr(field, format_string)				\
 static ssize_t								\
 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);		\
 	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);
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
 
 
@@ -271,7 +466,8 @@ usb_intf_attr (bInterfaceClass, "%02x\n")
 usb_intf_attr (bInterfaceSubClass, "%02x\n")
 usb_intf_attr (bInterfaceSubClass, "%02x\n")
 usb_intf_attr (bInterfaceProtocol, "%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_interface *intf;
 	struct usb_device *udev;
 	struct usb_device *udev;
@@ -288,34 +484,28 @@ static ssize_t show_interface_string(struct device *dev, struct device_attribute
 }
 }
 static DEVICE_ATTR(interface, S_IRUGO, show_interface_string, NULL);
 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_interface *intf;
 	struct usb_device *udev;
 	struct usb_device *udev;
-	int len;
+	struct usb_host_interface *alt;
 
 
 	intf = to_usb_interface(dev);
 	intf = to_usb_interface(dev);
 	udev = interface_to_usbdev(intf);
 	udev = interface_to_usbdev(intf);
-
-	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");
-	}
+	alt = intf->cur_altsetting;
+
+	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);
 static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
 
 
@@ -333,20 +523,47 @@ static struct attribute_group intf_attr_grp = {
 	.attrs = intf_attrs,
 	.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)
 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);
 	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);
 		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)
 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);
 	sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
 
 
 	if (intf->cur_altsetting->string)
 	if (intf->cur_altsetting->string)
 		device_remove_file(&intf->dev, &dev_attr_interface);
 		device_remove_file(&intf->dev, &dev_attr_interface);
-
 }
 }

+ 2 - 1
drivers/usb/core/urb.c

@@ -237,7 +237,8 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 	    (dev->state < USB_STATE_DEFAULT) ||
 	    (dev->state < USB_STATE_DEFAULT) ||
 	    (!dev->bus) || (dev->devnum <= 0))
 	    (!dev->bus) || (dev->devnum <= 0))
 		return -ENODEV;
 		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;
 		return -EHOSTUNREACH;
 	if (!(op = dev->bus->op) || !op->submit_urb)
 	if (!(op = dev->bus->op) || !op->submit_urb)
 		return -ENODEV;
 		return -ENODEV;

+ 105 - 60
drivers/usb/core/usb.c

@@ -107,10 +107,19 @@ static int usb_probe_interface(struct device *dev)
 	id = usb_match_id (intf, driver->id_table);
 	id = usb_match_id (intf, driver->id_table);
 	if (id) {
 	if (id) {
 		dev_dbg (dev, "%s - got id\n", __FUNCTION__);
 		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;
 		intf->condition = USB_INTERFACE_BINDING;
 		error = driver->probe (intf, id);
 		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;
 	return error;
@@ -136,6 +145,7 @@ static int usb_unbind_interface(struct device *dev)
 			0);
 			0);
 	usb_set_intfdata(intf, NULL);
 	usb_set_intfdata(intf, NULL);
 	intf->condition = USB_INTERFACE_UNBOUND;
 	intf->condition = USB_INTERFACE_UNBOUND;
+	mark_quiesced(intf);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -299,6 +309,7 @@ int usb_driver_claim_interface(struct usb_driver *driver,
 	dev->driver = &driver->driver;
 	dev->driver = &driver->driver;
 	usb_set_intfdata(iface, priv);
 	usb_set_intfdata(iface, priv);
 	iface->condition = USB_INTERFACE_BOUND;
 	iface->condition = USB_INTERFACE_BOUND;
+	mark_active(iface);
 
 
 	/* if interface was already added, bind now; else let
 	/* if interface was already added, bind now; else let
 	 * the future device_add() bind it, bypassing probe()
 	 * the future device_add() bind it, bypassing probe()
@@ -345,6 +356,7 @@ void usb_driver_release_interface(struct usb_driver *driver,
 	dev->driver = NULL;
 	dev->driver = NULL;
 	usb_set_intfdata(iface, NULL);
 	usb_set_intfdata(iface, NULL);
 	iface->condition = USB_INTERFACE_UNBOUND;
 	iface->condition = USB_INTERFACE_UNBOUND;
+	mark_quiesced(iface);
 }
 }
 
 
 /**
 /**
@@ -557,6 +569,7 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp,
 {
 {
 	struct usb_interface *intf;
 	struct usb_interface *intf;
 	struct usb_device *usb_dev;
 	struct usb_device *usb_dev;
+	struct usb_host_interface *alt;
 	int i = 0;
 	int i = 0;
 	int length = 0;
 	int length = 0;
 
 
@@ -573,7 +586,8 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp,
 
 
 	intf = to_usb_interface(dev);
 	intf = to_usb_interface(dev);
 	usb_dev = interface_to_usbdev (intf);
 	usb_dev = interface_to_usbdev (intf);
-	
+	alt = intf->cur_altsetting;
+
 	if (usb_dev->devnum < 0) {
 	if (usb_dev->devnum < 0) {
 		pr_debug ("usb %s: already deleted?\n", dev->bus_id);
 		pr_debug ("usb %s: already deleted?\n", dev->bus_id);
 		return -ENODEV;
 		return -ENODEV;
@@ -615,46 +629,27 @@ static int usb_hotplug (struct device *dev, char **envp, int num_envp,
 				usb_dev->descriptor.bDeviceProtocol))
 				usb_dev->descriptor.bDeviceProtocol))
 		return -ENOMEM;
 		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;
 	envp[i] = NULL;
 
 
@@ -709,12 +704,10 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
 {
 {
 	struct usb_device *dev;
 	struct usb_device *dev;
 
 
-	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev)
 	if (!dev)
 		return NULL;
 		return NULL;
 
 
-	memset(dev, 0, sizeof(*dev));
-
 	bus = usb_bus_get(bus);
 	bus = usb_bus_get(bus);
 	if (!bus) {
 	if (!bus) {
 		kfree(dev);
 		kfree(dev);
@@ -1402,13 +1395,30 @@ void usb_buffer_unmap_sg (struct usb_device *dev, unsigned pipe,
 			usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 			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)
 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) ||
 	if ((dev->driver == NULL) ||
 	    (dev->driver_data == &usb_generic_driver_data))
 	    (dev->driver_data == &usb_generic_driver_data))
@@ -1417,23 +1427,44 @@ static int usb_generic_suspend(struct device *dev, pm_message_t message)
 	intf = to_usb_interface(dev);
 	intf = to_usb_interface(dev);
 	driver = to_usb_driver(dev->driver);
 	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;
 		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)
 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));
 		return usb_resume_device (to_usb_device(dev));
+	}
 
 
 	if ((dev->driver == NULL) ||
 	if ((dev->driver == NULL) ||
 	    (dev->driver_data == &usb_generic_driver_data))
 	    (dev->driver_data == &usb_generic_driver_data))
@@ -1442,8 +1473,22 @@ static int usb_generic_resume(struct device *dev)
 	intf = to_usb_interface(dev);
 	intf = to_usb_interface(dev);
 	driver = to_usb_driver(dev->driver);
 	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;
 	return 0;
 }
 }
 
 

+ 30 - 3
drivers/usb/core/usb.h

@@ -13,12 +13,14 @@ extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
 
 
 extern int usb_get_device_descriptor(struct usb_device *dev,
 extern int usb_get_device_descriptor(struct usb_device *dev,
 		unsigned int size);
 		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 int usb_set_configuration(struct usb_device *dev, int configuration);
 
 
 extern void usb_lock_all_devices(void);
 extern void usb_lock_all_devices(void);
 extern void usb_unlock_all_devices(void);
 extern void usb_unlock_all_devices(void);
 
 
 extern void usb_kick_khubd(struct usb_device *dev);
 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 void usb_resume_root_hub(struct usb_device *dev);
 
 
 extern int  usb_hub_init(void);
 extern int  usb_hub_init(void);
@@ -28,6 +30,28 @@ extern void usb_major_cleanup(void);
 extern int usb_host_init(void);
 extern int usb_host_init(void);
 extern void usb_host_cleanup(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 */
 /* for labeling diagnostics */
 extern const char *usbcore_name;
 extern const char *usbcore_name;
 
 
@@ -39,9 +63,6 @@ extern void usbfs_conn_disc_event(void);
 
 
 extern int usbdev_init(void);
 extern int usbdev_init(void);
 extern void usbdev_cleanup(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 dev_state {
 	struct list_head list;      /* state list */
 	struct list_head list;      /* state list */
@@ -58,3 +79,9 @@ struct dev_state {
 	unsigned long ifclaimed;
 	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);
+

+ 6 - 18
drivers/usb/gadget/dummy_hcd.c

@@ -967,6 +967,7 @@ static int dummy_udc_resume (struct device *dev)
 
 
 static struct device_driver dummy_udc_driver = {
 static struct device_driver dummy_udc_driver = {
 	.name		= (char *) gadget_name,
 	.name		= (char *) gadget_name,
+	.owner		= THIS_MODULE,
 	.bus		= &platform_bus_type,
 	.bus		= &platform_bus_type,
 	.probe		= dummy_udc_probe,
 	.probe		= dummy_udc_probe,
 	.remove		= dummy_udc_remove,
 	.remove		= dummy_udc_remove,
@@ -1751,7 +1752,7 @@ static int dummy_hub_control (
 	return retval;
 	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);
 	struct dummy *dum = hcd_to_dummy (hcd);
 
 
@@ -1762,7 +1763,7 @@ static int dummy_hub_suspend (struct usb_hcd *hcd)
 	return 0;
 	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);
 	struct dummy *dum = hcd_to_dummy (hcd);
 
 
@@ -1894,8 +1895,8 @@ static const struct hc_driver dummy_hcd = {
 
 
 	.hub_status_data = 	dummy_hub_status,
 	.hub_status_data = 	dummy_hub_status,
 	.hub_control = 		dummy_hub_control,
 	.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)
 static int dummy_hcd_probe (struct device *dev)
@@ -1936,13 +1937,6 @@ static int dummy_hcd_suspend (struct device *dev, pm_message_t state)
 	dev_dbg (dev, "%s\n", __FUNCTION__);
 	dev_dbg (dev, "%s\n", __FUNCTION__);
 	hcd = dev_get_drvdata (dev);
 	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;
 	hcd->state = HC_STATE_SUSPENDED;
 	return 0;
 	return 0;
 }
 }
@@ -1955,19 +1949,13 @@ static int dummy_hcd_resume (struct device *dev)
 	hcd = dev_get_drvdata (dev);
 	hcd = dev_get_drvdata (dev);
 	hcd->state = HC_STATE_RUNNING;
 	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);
 	usb_hcd_poll_rh_status (hcd);
 	return 0;
 	return 0;
 }
 }
 
 
 static struct device_driver dummy_hcd_driver = {
 static struct device_driver dummy_hcd_driver = {
 	.name		= (char *) driver_name,
 	.name		= (char *) driver_name,
+	.owner		= THIS_MODULE,
 	.bus		= &platform_bus_type,
 	.bus		= &platform_bus_type,
 	.probe		= dummy_hcd_probe,
 	.probe		= dummy_hcd_probe,
 	.remove		= dummy_hcd_remove,
 	.remove		= dummy_hcd_remove,

+ 1 - 0
drivers/usb/gadget/ether.c

@@ -2533,6 +2533,7 @@ static struct usb_gadget_driver eth_driver = {
 
 
 	.driver 	= {
 	.driver 	= {
 		.name		= (char *) shortname,
 		.name		= (char *) shortname,
+		.owner		= THIS_MODULE,
 		// .shutdown = ...
 		// .shutdown = ...
 		// .suspend = ...
 		// .suspend = ...
 		// .resume = ...
 		// .resume = ...

+ 22 - 30
drivers/usb/gadget/file_storage.c

@@ -224,6 +224,7 @@
 #include <linux/fs.h>
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
+#include <linux/kthread.h>
 #include <linux/limits.h>
 #include <linux/limits.h>
 #include <linux/list.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/module.h>
@@ -669,7 +670,6 @@ struct fsg_dev {
 	wait_queue_head_t	thread_wqh;
 	wait_queue_head_t	thread_wqh;
 	int			thread_wakeup_needed;
 	int			thread_wakeup_needed;
 	struct completion	thread_notifier;
 	struct completion	thread_notifier;
-	int			thread_pid;
 	struct task_struct	*thread_task;
 	struct task_struct	*thread_task;
 	sigset_t		thread_signal_mask;
 	sigset_t		thread_signal_mask;
 
 
@@ -1084,7 +1084,6 @@ static void wakeup_thread(struct fsg_dev *fsg)
 static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state)
 static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state)
 {
 {
 	unsigned long		flags;
 	unsigned long		flags;
-	struct task_struct	*thread_task;
 
 
 	/* Do nothing if a higher-priority exception is already in progress.
 	/* Do nothing if a higher-priority exception is already in progress.
 	 * If a lower-or-equal priority exception is in progress, preempt it
 	 * If a lower-or-equal priority exception is in progress, preempt it
@@ -1093,9 +1092,9 @@ static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state)
 	if (fsg->state <= new_state) {
 	if (fsg->state <= new_state) {
 		fsg->exception_req_tag = fsg->ep0_req_tag;
 		fsg->exception_req_tag = fsg->ep0_req_tag;
 		fsg->state = new_state;
 		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);
 	spin_unlock_irqrestore(&fsg->lock, flags);
 }
 }
@@ -3383,11 +3382,6 @@ static int fsg_main_thread(void *fsg_)
 {
 {
 	struct fsg_dev		*fsg = (struct fsg_dev *) fsg_;
 	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
 	/* Allow the thread to be killed by a signal, but set the signal mask
 	 * to block everything but INT, TERM, KILL, and USR1. */
 	 * to block everything but INT, TERM, KILL, and USR1. */
 	siginitsetinv(&fsg->thread_signal_mask, sigmask(SIGINT) |
 	siginitsetinv(&fsg->thread_signal_mask, sigmask(SIGINT) |
@@ -3400,9 +3394,6 @@ static int fsg_main_thread(void *fsg_)
 	 * that expects a __user pointer and it will work okay. */
 	 * that expects a __user pointer and it will work okay. */
 	set_fs(get_ds());
 	set_fs(get_ds());
 
 
-	/* Wait for the gadget registration to finish up */
-	wait_for_completion(&fsg->thread_notifier);
-
 	/* The main loop */
 	/* The main loop */
 	while (fsg->state != FSG_STATE_TERMINATED) {
 	while (fsg->state != FSG_STATE_TERMINATED) {
 		if (exception_in_progress(fsg) || signal_pending(current)) {
 		if (exception_in_progress(fsg) || signal_pending(current)) {
@@ -3440,8 +3431,9 @@ static int fsg_main_thread(void *fsg_)
 		spin_unlock_irq(&fsg->lock);
 		spin_unlock_irq(&fsg->lock);
 		}
 		}
 
 
+	spin_lock_irq(&fsg->lock);
 	fsg->thread_task = NULL;
 	fsg->thread_task = NULL;
-	flush_signals(current);
+	spin_unlock_irq(&fsg->lock);
 
 
 	/* In case we are exiting because of a signal, unregister the
 	/* In case we are exiting because of a signal, unregister the
 	 * gadget driver and close the backing file. */
 	 * gadget driver and close the backing file. */
@@ -3831,12 +3823,11 @@ static int __init fsg_bind(struct usb_gadget *gadget)
 
 
 	/* Create the LUNs, open their backing files, and register the
 	/* Create the LUNs, open their backing files, and register the
 	 * LUN devices in sysfs. */
 	 * 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) {
 	if (!fsg->luns) {
 		rc = -ENOMEM;
 		rc = -ENOMEM;
 		goto out;
 		goto out;
 	}
 	}
-	memset(fsg->luns, 0, i * sizeof(struct lun));
 	fsg->nluns = i;
 	fsg->nluns = i;
 
 
 	for (i = 0; i < fsg->nluns; ++i) {
 	for (i = 0; i < fsg->nluns; ++i) {
@@ -3959,10 +3950,12 @@ static int __init fsg_bind(struct usb_gadget *gadget)
 		sprintf(&serial[i], "%02X", c);
 		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;
 		goto out;
-	fsg->thread_pid = rc;
+	}
 
 
 	INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
 	INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
 	INFO(fsg, "Number of LUNs=%d\n", fsg->nluns);
 	INFO(fsg, "Number of LUNs=%d\n", fsg->nluns);
@@ -3994,7 +3987,12 @@ static int __init fsg_bind(struct usb_gadget *gadget)
 	DBG(fsg, "removable=%d, stall=%d, buflen=%u\n",
 	DBG(fsg, "removable=%d, stall=%d, buflen=%u\n",
 			mod_data.removable, mod_data.can_stall,
 			mod_data.removable, mod_data.can_stall,
 			mod_data.buflen);
 			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;
 	return 0;
 
 
 autoconf_fail:
 autoconf_fail:
@@ -4046,6 +4044,7 @@ static struct usb_gadget_driver		fsg_driver = {
 
 
 	.driver		= {
 	.driver		= {
 		.name		= (char *) shortname,
 		.name		= (char *) shortname,
+		.owner		= THIS_MODULE,
 		// .release = ...
 		// .release = ...
 		// .suspend = ...
 		// .suspend = ...
 		// .resume = ...
 		// .resume = ...
@@ -4057,10 +4056,9 @@ static int __init fsg_alloc(void)
 {
 {
 	struct fsg_dev		*fsg;
 	struct fsg_dev		*fsg;
 
 
-	fsg = kmalloc(sizeof *fsg, GFP_KERNEL);
+	fsg = kzalloc(sizeof *fsg, GFP_KERNEL);
 	if (!fsg)
 	if (!fsg)
 		return -ENOMEM;
 		return -ENOMEM;
-	memset(fsg, 0, sizeof *fsg);
 	spin_lock_init(&fsg->lock);
 	spin_lock_init(&fsg->lock);
 	init_rwsem(&fsg->filesem);
 	init_rwsem(&fsg->filesem);
 	init_waitqueue_head(&fsg->thread_wqh);
 	init_waitqueue_head(&fsg->thread_wqh);
@@ -4086,15 +4084,9 @@ static int __init fsg_init(void)
 	if ((rc = fsg_alloc()) != 0)
 	if ((rc = fsg_alloc()) != 0)
 		return rc;
 		return rc;
 	fsg = the_fsg;
 	fsg = the_fsg;
-	if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0) {
+	if ((rc = usb_gadget_register_driver(&fsg_driver)) != 0)
 		fsg_free(fsg);
 		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);
 module_init(fsg_init);
 
 

+ 1 - 0
drivers/usb/gadget/goku_udc.c

@@ -1970,6 +1970,7 @@ MODULE_DEVICE_TABLE (pci, pci_ids);
 static struct pci_driver goku_pci_driver = {
 static struct pci_driver goku_pci_driver = {
 	.name =		(char *) driver_name,
 	.name =		(char *) driver_name,
 	.id_table =	pci_ids,
 	.id_table =	pci_ids,
+	.owner =	THIS_MODULE,
 
 
 	.probe =	goku_probe,
 	.probe =	goku_probe,
 	.remove =	goku_remove,
 	.remove =	goku_remove,

+ 1 - 0
drivers/usb/gadget/lh7a40x_udc.c

@@ -2140,6 +2140,7 @@ static int lh7a40x_udc_remove(struct device *_dev)
 
 
 static struct device_driver udc_driver = {
 static struct device_driver udc_driver = {
 	.name = (char *)driver_name,
 	.name = (char *)driver_name,
+	.owner = THIS_MODULE,
 	.bus = &platform_bus_type,
 	.bus = &platform_bus_type,
 	.probe = lh7a40x_udc_probe,
 	.probe = lh7a40x_udc_probe,
 	.remove = lh7a40x_udc_remove
 	.remove = lh7a40x_udc_remove

+ 1 - 0
drivers/usb/gadget/net2280.c

@@ -2948,6 +2948,7 @@ MODULE_DEVICE_TABLE (pci, pci_ids);
 static struct pci_driver net2280_pci_driver = {
 static struct pci_driver net2280_pci_driver = {
 	.name =		(char *) driver_name,
 	.name =		(char *) driver_name,
 	.id_table =	pci_ids,
 	.id_table =	pci_ids,
+	.owner =	THIS_MODULE,
 
 
 	.probe =	net2280_probe,
 	.probe =	net2280_probe,
 	.remove =	net2280_remove,
 	.remove =	net2280_remove,

+ 10 - 3
drivers/usb/gadget/omap_udc.c

@@ -691,7 +691,7 @@ static void next_out_dma(struct omap_ep *ep, struct omap_req *req)
 }
 }
 
 
 static void
 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;
 	u16	count;
 
 
@@ -699,6 +699,8 @@ finish_out_dma(struct omap_ep *ep, struct omap_req *req, int status)
 		ep->dma_counter = (u16) (req->req.dma + req->req.actual);
 		ep->dma_counter = (u16) (req->req.dma + req->req.actual);
 	count = dma_dest_len(ep, req->req.dma + req->req.actual);
 	count = dma_dest_len(ep, req->req.dma + req->req.actual);
 	count += req->req.actual;
 	count += req->req.actual;
+	if (one)
+		count--;
 	if (count <= req->req.length)
 	if (count <= req->req.length)
 		req->req.actual = count;
 		req->req.actual = count;
 
 
@@ -747,7 +749,7 @@ static void dma_irq(struct omap_udc *udc, u16 irq_src)
 		if (!list_empty(&ep->queue)) {
 		if (!list_empty(&ep->queue)) {
 			req = container_of(ep->queue.next,
 			req = container_of(ep->queue.next,
 					struct omap_req, queue);
 					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;
 		UDC_IRQ_SRC_REG = UDC_RXN_EOT;
 
 
@@ -925,7 +927,7 @@ static void dma_channel_release(struct omap_ep *ep)
 		while (UDC_RXDMA_CFG_REG & mask)
 		while (UDC_RXDMA_CFG_REG & mask)
 			udelay(10);
 			udelay(10);
 		if (req)
 		if (req)
-			finish_out_dma(ep, req, -ECONNRESET);
+			finish_out_dma(ep, req, -ECONNRESET, 0);
 	}
 	}
 	omap_free_dma(ep->lch);
 	omap_free_dma(ep->lch);
 	ep->dma_channel = 0;
 	ep->dma_channel = 0;
@@ -1786,8 +1788,12 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src)
 					udc->driver->suspend(&udc->gadget);
 					udc->driver->suspend(&udc->gadget);
 					spin_lock(&udc->lock);
 					spin_lock(&udc->lock);
 				}
 				}
+				if (udc->transceiver)
+					otg_set_suspend(udc->transceiver, 1);
 			} else {
 			} else {
 				VDBG("resume\n");
 				VDBG("resume\n");
+				if (udc->transceiver)
+					otg_set_suspend(udc->transceiver, 0);
 				if (udc->gadget.speed == USB_SPEED_FULL
 				if (udc->gadget.speed == USB_SPEED_FULL
 						&& udc->driver->resume) {
 						&& udc->driver->resume) {
 					spin_unlock(&udc->lock);
 					spin_unlock(&udc->lock);
@@ -2943,6 +2949,7 @@ static int omap_udc_resume(struct device *dev)
 
 
 static struct device_driver udc_driver = {
 static struct device_driver udc_driver = {
 	.name		= (char *) driver_name,
 	.name		= (char *) driver_name,
+	.owner		= THIS_MODULE,
 	.bus		= &platform_bus_type,
 	.bus		= &platform_bus_type,
 	.probe		= omap_udc_probe,
 	.probe		= omap_udc_probe,
 	.remove		= __exit_p(omap_udc_remove),
 	.remove		= __exit_p(omap_udc_remove),

+ 1 - 0
drivers/usb/gadget/pxa2xx_udc.c

@@ -2631,6 +2631,7 @@ static int pxa2xx_udc_resume(struct device *dev)
 
 
 static struct device_driver udc_driver = {
 static struct device_driver udc_driver = {
 	.name		= "pxa2xx-udc",
 	.name		= "pxa2xx-udc",
+	.owner		= THIS_MODULE,
 	.bus		= &platform_bus_type,
 	.bus		= &platform_bus_type,
 	.probe		= pxa2xx_udc_probe,
 	.probe		= pxa2xx_udc_probe,
 	.shutdown	= pxa2xx_udc_shutdown,
 	.shutdown	= pxa2xx_udc_shutdown,

+ 1 - 0
drivers/usb/gadget/zero.c

@@ -1302,6 +1302,7 @@ static struct usb_gadget_driver zero_driver = {
 
 
 	.driver 	= {
 	.driver 	= {
 		.name		= (char *) shortname,
 		.name		= (char *) shortname,
+		.owner		= THIS_MODULE,
 		// .shutdown = ...
 		// .shutdown = ...
 		// .suspend = ...
 		// .suspend = ...
 		// .resume = ...
 		// .resume = ...

+ 3 - 2
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_EHCI_HCD)	+= ehci-hcd.o
 obj-$(CONFIG_USB_ISP116X_HCD)	+= isp116x-hcd.o
 obj-$(CONFIG_USB_ISP116X_HCD)	+= isp116x-hcd.o
 obj-$(CONFIG_USB_OHCI_HCD)	+= ohci-hcd.o
 obj-$(CONFIG_USB_OHCI_HCD)	+= ohci-hcd.o

+ 81 - 462
drivers/usb/host/ehci-hcd.c

@@ -182,6 +182,9 @@ static int ehci_halt (struct ehci_hcd *ehci)
 {
 {
 	u32	temp = readl (&ehci->regs->status);
 	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)
 	if ((temp & STS_HALT) != 0)
 		return 0;
 		return 0;
 
 
@@ -297,50 +300,17 @@ static void ehci_watchdog (unsigned long param)
 	spin_unlock_irqrestore (&ehci->lock, flags);
 	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
 static int
 ehci_reboot (struct notifier_block *self, unsigned long code, void *null)
 ehci_reboot (struct notifier_block *self, unsigned long code, void *null)
 {
 {
 	struct ehci_hcd		*ehci;
 	struct ehci_hcd		*ehci;
 
 
 	ehci = container_of (self, struct ehci_hcd, reboot_notifier);
 	ehci = container_of (self, struct ehci_hcd, reboot_notifier);
+	(void) ehci_halt (ehci);
 
 
 	/* make BIOS/etc use companion controller during reboot */
 	/* make BIOS/etc use companion controller during reboot */
 	writel (0, &ehci->regs->configured_flag);
 	writel (0, &ehci->regs->configured_flag);
@@ -363,156 +333,90 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
 	msleep(20);
 	msleep(20);
 }
 }
 
 
+/*-------------------------------------------------------------------------*/
+
+/*
+ * 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;
 
 
-/* called by khubd or root hub init threads */
+	/* 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_hc_reset (struct usb_hcd *hcd)
+static void ehci_stop (struct usb_hcd *hcd)
 {
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	u32			temp;
-	unsigned		count = 256/4;
 
 
-	spin_lock_init (&ehci->lock);
+	ehci_dbg (ehci, "stop\n");
 
 
-	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");
+	/* Turn off port power on all root hub ports. */
+	ehci_port_power (ehci, 0);
 
 
-	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = readl (&ehci->caps->hcs_params);
+	/* no more interrupts ... */
+	del_timer_sync (&ehci->watchdog);
 
 
-#ifdef	CONFIG_PCI
-	if (hcd->self.controller->bus == &pci_bus_type) {
-		struct pci_dev	*pdev = to_pci_dev(hcd->self.controller);
+	spin_lock_irq(&ehci->lock);
+	if (HC_IS_RUNNING (hcd->state))
+		ehci_quiesce (ehci);
 
 
-		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;
-		}
+	ehci_reset (ehci);
+	writel (0, &ehci->regs->intr_enable);
+	spin_unlock_irq(&ehci->lock);
 
 
-		/* 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;
-			}
-		}
+	/* let companion controllers work when we aren't */
+	writel (0, &ehci->regs->configured_flag);
+	unregister_reboot_notifier (&ehci->reboot_notifier);
 
 
-		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
+	remove_debug_files (ehci);
 
 
-	ehci_port_power (ehci, 0);
+	/* 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);
 
 
-	/* 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;
-			}
-		}
+#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
 #endif
-	}
 
 
-	/* force HC to halt state */
-	return ehci_halt (ehci);
+	dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
 }
 }
 
 
-static int ehci_start (struct usb_hcd *hcd)
+static int ehci_run (struct usb_hcd *hcd)
 {
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	u32			temp;
 	u32			temp;
 	int			retval;
 	int			retval;
 	u32			hcc_params;
 	u32			hcc_params;
-	u8                      sbrn = 0;
 	int			first;
 	int			first;
 
 
 	/* skip some things on restart paths */
 	/* skip some things on restart paths */
@@ -551,27 +455,6 @@ static int ehci_start (struct usb_hcd *hcd)
 	}
 	}
 	writel (ehci->periodic_dma, &ehci->regs->frame_list);
 	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
 	 * 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
 	 * a 'real' qh without stopping the async schedule [4.8].  use it
@@ -667,7 +550,7 @@ static int ehci_start (struct usb_hcd *hcd)
 	temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
 	temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
 	ehci_info (ehci,
 	ehci_info (ehci,
 		"USB %x.%x %s, EHCI %x.%02x, driver %s\n",
 		"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",
 		first ? "initialized" : "restarted",
 		temp >> 8, temp & 0xff, DRIVER_VERSION);
 		temp >> 8, temp & 0xff, DRIVER_VERSION);
 
 
@@ -679,188 +562,6 @@ static int ehci_start (struct usb_hcd *hcd)
 	return 0;
 	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)
 static irqreturn_t ehci_irq (struct usb_hcd *hcd, struct pt_regs *regs)
@@ -1171,106 +872,24 @@ done:
 	return;
 	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
 #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
 
 
 MODULE_DESCRIPTION (DRIVER_INFO);
 MODULE_DESCRIPTION (DRIVER_INFO);
 MODULE_AUTHOR (DRIVER_AUTHOR);
 MODULE_AUTHOR (DRIVER_AUTHOR);
 MODULE_LICENSE ("GPL");
 MODULE_LICENSE ("GPL");
 
 
-static int __init 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 (init);
+#ifdef CONFIG_PCI
+#include "ehci-pci.c"
+#endif
 
 
-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

+ 4 - 4
drivers/usb/host/ehci-hub.c

@@ -30,7 +30,7 @@
 
 
 #ifdef	CONFIG_PM
 #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);
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	int			port;
 	int			port;
@@ -83,7 +83,7 @@ static int ehci_hub_suspend (struct usb_hcd *hcd)
 
 
 
 
 /* caller has locked the root hub, and should reset/reinit on error */
 /* 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);
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	u32			temp;
 	u32			temp;
@@ -159,8 +159,8 @@ static int ehci_hub_resume (struct usb_hcd *hcd)
 
 
 #else
 #else
 
 
-#define ehci_hub_suspend	NULL
-#define ehci_hub_resume		NULL
+#define ehci_bus_suspend	NULL
+#define ehci_bus_resume		NULL
 
 
 #endif	/* CONFIG_PM */
 #endif	/* CONFIG_PM */
 
 

+ 415 - 0
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);

+ 1 - 0
drivers/usb/host/ehci.h

@@ -97,6 +97,7 @@ struct ehci_hcd {			/* one per controller */
 #else
 #else
 #	define COUNT(x) do {} while (0)
 #	define COUNT(x) do {} while (0)
 #endif
 #endif
+	u8			sbrn;		/* packed release number */
 };
 };
 
 
 /* convert between an HCD pointer and the corresponding EHCI_HCD */ 
 /* convert between an HCD pointer and the corresponding EHCI_HCD */ 

+ 10 - 31
drivers/usb/host/isp116x-hcd.c

@@ -638,7 +638,7 @@ static irqreturn_t isp116x_irq(struct usb_hcd *hcd, struct pt_regs *regs)
 				  + msecs_to_jiffies(20) + 1);
 				  + msecs_to_jiffies(20) + 1);
 		if (intstat & HCINT_RD) {
 		if (intstat & HCINT_RD) {
 			DBG("---- remote wakeup\n");
 			DBG("---- remote wakeup\n");
-			schedule_work(&isp116x->rh_resume);
+			usb_hcd_resume_root_hub(hcd);
 			ret = IRQ_HANDLED;
 			ret = IRQ_HANDLED;
 		}
 		}
 		irqstat &= ~HCuPINT_OPR;
 		irqstat &= ~HCuPINT_OPR;
@@ -1160,7 +1160,7 @@ static int isp116x_hub_control(struct usb_hcd *hcd,
 
 
 #ifdef	CONFIG_PM
 #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);
 	struct isp116x *isp116x = hcd_to_isp116x(hcd);
 	unsigned long flags;
 	unsigned long flags;
@@ -1200,7 +1200,7 @@ static int isp116x_hub_suspend(struct usb_hcd *hcd)
 	return ret;
 	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);
 	struct isp116x *isp116x = hcd_to_isp116x(hcd);
 	u32 val;
 	u32 val;
@@ -1263,21 +1263,11 @@ static int isp116x_hub_resume(struct usb_hcd *hcd)
 	return 0;
 	return 0;
 }
 }
 
 
-static void isp116x_rh_resume(void *_hcd)
-{
-	struct usb_hcd *hcd = _hcd;
-
-	usb_resume_device(hcd->self.root_hub);
-}
 
 
 #else
 #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
 #endif
 
 
@@ -1636,8 +1626,8 @@ static struct hc_driver isp116x_hc_driver = {
 
 
 	.hub_status_data = isp116x_hub_status_data,
 	.hub_status_data = isp116x_hub_status_data,
 	.hub_control = isp116x_hub_control,
 	.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 @@ static int __init isp116x_probe(struct device *dev)
 	isp116x->addr_reg = addr_reg;
 	isp116x->addr_reg = addr_reg;
 	spin_lock_init(&isp116x->lock);
 	spin_lock_init(&isp116x->lock);
 	INIT_LIST_HEAD(&isp116x->async);
 	INIT_LIST_HEAD(&isp116x->async);
-	INIT_WORK(&isp116x->rh_resume, isp116x_rh_resume, hcd);
 	isp116x->board = dev->platform_data;
 	isp116x->board = dev->platform_data;
 
 
 	if (!isp116x->board) {
 	if (!isp116x->board) {
@@ -1777,16 +1766,10 @@ static int __init isp116x_probe(struct device *dev)
 static int isp116x_suspend(struct device *dev, pm_message_t state)
 static int isp116x_suspend(struct device *dev, pm_message_t state)
 {
 {
 	int ret = 0;
 	int ret = 0;
-	struct usb_hcd *hcd = dev_get_drvdata(dev);
 
 
 	VDBG("%s: state %x\n", __func__, state);
 	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;
 	return ret;
 }
 }
@@ -1797,15 +1780,11 @@ static int isp116x_suspend(struct device *dev, pm_message_t state)
 static int isp116x_resume(struct device *dev)
 static int isp116x_resume(struct device *dev)
 {
 {
 	int ret = 0;
 	int ret = 0;
-	struct usb_hcd *hcd = dev_get_drvdata(dev);
 
 
 	VDBG("%s:  state %x\n", __func__, dev->power.power_state);
 	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;
 	return ret;
 }
 }
 
 

+ 0 - 1
drivers/usb/host/isp116x.h

@@ -253,7 +253,6 @@ static const int cc_to_error[16] = {
 
 
 struct isp116x {
 struct isp116x {
 	spinlock_t lock;
 	spinlock_t lock;
-	struct work_struct rh_resume;
 
 
 	void __iomem *addr_reg;
 	void __iomem *addr_reg;
 	void __iomem *data_reg;
 	void __iomem *data_reg;

+ 6 - 0
drivers/usb/host/ohci-au1xxx.c

@@ -214,6 +214,11 @@ static const struct hc_driver ohci_au1xxx_hc_driver = {
 	 */
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
 	.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 int ohci_hcd_au1xxx_drv_resume(struct device *dev)
 
 
 static struct device_driver ohci_hcd_au1xxx_driver = {
 static struct device_driver ohci_hcd_au1xxx_driver = {
 	.name		= "au1xxx-ohci",
 	.name		= "au1xxx-ohci",
+	.owner		= THIS_MODULE,
 	.bus		= &platform_bus_type,
 	.bus		= &platform_bus_type,
 	.probe		= ohci_hcd_au1xxx_drv_probe,
 	.probe		= ohci_hcd_au1xxx_drv_probe,
 	.remove		= ohci_hcd_au1xxx_drv_remove,
 	.remove		= ohci_hcd_au1xxx_drv_remove,

+ 0 - 4
drivers/usb/host/ohci-dbg.c

@@ -193,10 +193,6 @@ ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size)
 
 
 	maybe_print_eds (controller, "donehead",
 	maybe_print_eds (controller, "donehead",
 			ohci_readl (controller, &regs->donehead), next, size);
 			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) \
 #define dbg_port_sw(hc,num,value,next,size) \

+ 2 - 2
drivers/usb/host/ohci-hcd.c

@@ -723,7 +723,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd, struct pt_regs *ptregs)
 		ohci_vdbg (ohci, "resume detect\n");
 		ohci_vdbg (ohci, "resume detect\n");
 		ohci_writel (ohci, OHCI_INTR_RD, &regs->intrstatus);
 		ohci_writel (ohci, OHCI_INTR_RD, &regs->intrstatus);
 		if (hcd->state != HC_STATE_QUIESCING)
 		if (hcd->state != HC_STATE_QUIESCING)
-			schedule_work(&ohci->rh_resume);
+			usb_hcd_resume_root_hub(hcd);
 	}
 	}
 
 
 	if (ints & OHCI_INTR_WDH) {
 	if (ints & OHCI_INTR_WDH) {
@@ -791,7 +791,7 @@ static void ohci_stop (struct usb_hcd *hcd)
 
 
 /* must not be called from interrupt context */
 /* 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)
 static int ohci_restart (struct ohci_hcd *ohci)
 {
 {

+ 17 - 35
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 \
 #define OHCI_SCHED_ENABLES \
 	(OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
 	(OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_PLE|OHCI_CTRL_IE)
@@ -45,7 +45,7 @@ static void dl_done_list (struct ohci_hcd *, struct pt_regs *);
 static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *);
 static void finish_unlinks (struct ohci_hcd *, u16 , struct pt_regs *);
 static int ohci_restart (struct ohci_hcd *ohci);
 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);
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 	int			status = 0;
 	int			status = 0;
@@ -73,7 +73,6 @@ static int ohci_hub_suspend (struct usb_hcd *hcd)
 	ohci_dbg (ohci, "suspend root hub\n");
 	ohci_dbg (ohci, "suspend root hub\n");
 
 
 	/* First stop any processing */
 	/* First stop any processing */
-	hcd->state = HC_STATE_QUIESCING;
 	if (ohci->hc_control & OHCI_SCHED_ENABLES) {
 	if (ohci->hc_control & OHCI_SCHED_ENABLES) {
 		int		limit;
 		int		limit;
 
 
@@ -108,7 +107,9 @@ static int ohci_hub_suspend (struct usb_hcd *hcd)
 	else
 	else
 		ohci->hc_control &= ~OHCI_CTRL_RWE;
 		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_CTRL_HCFS;
 	ohci->hc_control |= OHCI_USB_SUSPEND;
 	ohci->hc_control |= OHCI_USB_SUSPEND;
 	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
 	ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
@@ -118,8 +119,9 @@ static int ohci_hub_suspend (struct usb_hcd *hcd)
 	ohci->next_statechange = jiffies + msecs_to_jiffies (5);
 	ohci->next_statechange = jiffies + msecs_to_jiffies (5);
 
 
 done:
 done:
+	/* external suspend vs self autosuspend ... same effect */
 	if (status == 0)
 	if (status == 0)
-		hcd->state = HC_STATE_SUSPENDED;
+		usb_hcd_suspend_root_hub(hcd);
 	spin_unlock_irqrestore (&ohci->lock, flags);
 	spin_unlock_irqrestore (&ohci->lock, flags);
 	return status;
 	return status;
 }
 }
@@ -133,7 +135,7 @@ static inline struct ed *find_head (struct ed *ed)
 }
 }
 
 
 /* caller has locked the root hub */
 /* 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);
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 	u32			temp, enables;
 	u32			temp, enables;
@@ -146,7 +148,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
 	ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
 	ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
 
 
 	if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
 	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) {
 		if (hcd->state == HC_STATE_RESUMING) {
 			ohci_dbg (ohci, "BIOS/SMM active, control %03x\n",
 			ohci_dbg (ohci, "BIOS/SMM active, control %03x\n",
 					ohci->hc_control);
 					ohci->hc_control);
@@ -169,11 +171,12 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
 		ohci_info (ohci, "wakeup\n");
 		ohci_info (ohci, "wakeup\n");
 		break;
 		break;
 	case OHCI_USB_OPER:
 	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;
 		break;
 	default:		/* RESET, we lost power */
 	default:		/* RESET, we lost power */
-		ohci_dbg (ohci, "root hub hardware reset\n");
+		ohci_dbg (ohci, "lost power\n");
 		status = -EBUSY;
 		status = -EBUSY;
 	}
 	}
 	spin_unlock_irq (&ohci->lock);
 	spin_unlock_irq (&ohci->lock);
@@ -198,8 +201,7 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
 	}
 	}
 
 
 	/* Some controllers (lucent erratum) need extra-long delays */
 	/* 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_readl (ohci, &ohci->regs->control);
 	temp &= OHCI_CTRL_HCFS;
 	temp &= OHCI_CTRL_HCFS;
@@ -273,28 +275,10 @@ static int ohci_hub_resume (struct usb_hcd *hcd)
 		(void) ohci_readl (ohci, &ohci->regs->control);
 		(void) ohci_readl (ohci, &ohci->regs->control);
 	}
 	}
 
 
-	hcd->state = HC_STATE_RUNNING;
 	return 0;
 	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 @@ done:
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 	/* save power by suspending idle root hubs;
 	/* save power by suspending idle root hubs;
 	 * INTR_RD wakes us when there's work
 	 * 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
 	if (can_suspend
 			&& !changed
 			&& !changed
@@ -379,8 +362,7 @@ done:
 			&& usb_trylock_device (hcd->self.root_hub)
 			&& usb_trylock_device (hcd->self.root_hub)
 			) {
 			) {
 		ohci_vdbg (ohci, "autosuspend\n");
 		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);
 		usb_unlock_device (hcd->self.root_hub);
 	}
 	}
 #endif
 #endif
@@ -554,7 +536,7 @@ static int ohci_hub_control (
 			temp = RH_PS_POCI;
 			temp = RH_PS_POCI;
 			if ((ohci->hc_control & OHCI_CTRL_HCFS)
 			if ((ohci->hc_control & OHCI_CTRL_HCFS)
 					!= OHCI_USB_OPER)
 					!= OHCI_USB_OPER)
-				schedule_work (&ohci->rh_resume);
+				usb_hcd_resume_root_hub(hcd);
 			break;
 			break;
 		case USB_PORT_FEAT_C_SUSPEND:
 		case USB_PORT_FEAT_C_SUSPEND:
 			temp = RH_PS_PSSC;
 			temp = RH_PS_PSSC;

+ 6 - 0
drivers/usb/host/ohci-lh7a404.c

@@ -193,6 +193,11 @@ static const struct hc_driver ohci_lh7a404_hc_driver = {
 	 */
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
 	.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 int ohci_hcd_lh7a404_drv_resume(struct device *dev)
 
 
 static struct device_driver ohci_hcd_lh7a404_driver = {
 static struct device_driver ohci_hcd_lh7a404_driver = {
 	.name		= "lh7a404-ohci",
 	.name		= "lh7a404-ohci",
+	.owner		= THIS_MODULE,
 	.bus		= &platform_bus_type,
 	.bus		= &platform_bus_type,
 	.probe		= ohci_hcd_lh7a404_drv_probe,
 	.probe		= ohci_hcd_lh7a404_drv_probe,
 	.remove		= ohci_hcd_lh7a404_drv_remove,
 	.remove		= ohci_hcd_lh7a404_drv_remove,

+ 0 - 1
drivers/usb/host/ohci-mem.c

@@ -28,7 +28,6 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
 	ohci->next_statechange = jiffies;
 	ohci->next_statechange = jiffies;
 	spin_lock_init (&ohci->lock);
 	spin_lock_init (&ohci->lock);
 	INIT_LIST_HEAD (&ohci->pending);
 	INIT_LIST_HEAD (&ohci->pending);
-	INIT_WORK (&ohci->rh_resume, ohci_rh_resume, ohci_to_hcd(ohci));
 	ohci->reboot_notifier.notifier_call = ohci_reboot;
 	ohci->reboot_notifier.notifier_call = ohci_reboot;
 }
 }
 
 

+ 17 - 28
drivers/usb/host/ohci-omap.c

@@ -420,9 +420,9 @@ static const struct hc_driver ohci_omap_hc_driver = {
 	 */
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
 	.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
 #endif
 	.start_port_reset =	ohci_start_port_reset,
 	.start_port_reset =	ohci_start_port_reset,
 };
 };
@@ -458,41 +458,29 @@ static int ohci_hcd_omap_drv_remove(struct device *dev)
 static int ohci_omap_suspend(struct device *dev, pm_message_t message)
 static int ohci_omap_suspend(struct device *dev, pm_message_t message)
 {
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci(dev_get_drvdata(dev));
 	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)
 static int ohci_omap_resume(struct device *dev)
 {
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci(dev_get_drvdata(dev));
 	struct ohci_hcd	*ohci = hcd_to_ohci(dev_get_drvdata(dev));
-	int		status = 0;
 
 
 	if (time_before(jiffies, ohci->next_statechange))
 	if (time_before(jiffies, ohci->next_statechange))
 		msleep(5);
 		msleep(5);
 	ohci->next_statechange = jiffies;
 	ohci->next_statechange = jiffies;
+
 	omap_ohci_clock_power(1);
 	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
 #endif
@@ -504,6 +492,7 @@ static int ohci_omap_resume(struct device *dev)
  */
  */
 static struct device_driver ohci_hcd_omap_driver = {
 static struct device_driver ohci_hcd_omap_driver = {
 	.name		= "ohci",
 	.name		= "ohci",
+	.owner		= THIS_MODULE,
 	.bus		= &platform_bus_type,
 	.bus		= &platform_bus_type,
 	.probe		= ohci_hcd_omap_drv_probe,
 	.probe		= ohci_hcd_omap_drv_probe,
 	.remove		= ohci_hcd_omap_drv_remove,
 	.remove		= ohci_hcd_omap_drv_remove,

+ 12 - 35
drivers/usb/host/ohci-pci.c

@@ -112,23 +112,13 @@ ohci_pci_start (struct usb_hcd *hcd)
 
 
 static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
 static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
 {
 {
-	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
-
-	/* 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
+	/* root hub was already suspended */
 
 
-	/* 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
 #ifdef CONFIG_PPC_PMAC
 	if (_machine == _MACH_Pmac) {
 	if (_machine == _MACH_Pmac) {
 	   	struct device_node	*of_node;
 	   	struct device_node	*of_node;
@@ -145,9 +135,6 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
 
 
 static int ohci_pci_resume (struct usb_hcd *hcd)
 static int ohci_pci_resume (struct usb_hcd *hcd)
 {
 {
-	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
-	int			retval = 0;
-
 #ifdef CONFIG_PPC_PMAC
 #ifdef CONFIG_PPC_PMAC
 	if (_machine == _MACH_Pmac) {
 	if (_machine == _MACH_Pmac) {
 		struct device_node *of_node;
 		struct device_node *of_node;
@@ -159,19 +146,8 @@ static int ohci_pci_resume (struct usb_hcd *hcd)
 	}
 	}
 #endif /* CONFIG_PPC_PMAC */
 #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 */
 #endif	/* CONFIG_PM */
@@ -218,9 +194,9 @@ static const struct hc_driver ohci_pci_hc_driver = {
 	 */
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
 	.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
 #endif
 	.start_port_reset =	ohci_start_port_reset,
 	.start_port_reset =	ohci_start_port_reset,
 };
 };
@@ -240,6 +216,7 @@ MODULE_DEVICE_TABLE (pci, pci_ids);
 static struct pci_driver ohci_pci_driver = {
 static struct pci_driver ohci_pci_driver = {
 	.name =		(char *) hcd_name,
 	.name =		(char *) hcd_name,
 	.id_table =	pci_ids,
 	.id_table =	pci_ids,
+	.owner =	THIS_MODULE,
 
 
 	.probe =	usb_hcd_pci_probe,
 	.probe =	usb_hcd_pci_probe,
 	.remove =	usb_hcd_pci_remove,
 	.remove =	usb_hcd_pci_remove,

+ 5 - 4
drivers/usb/host/ohci-ppc-soc.c

@@ -163,9 +163,9 @@ static const struct hc_driver ohci_ppc_soc_hc_driver = {
 	 */
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
 	.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
 #endif
 	.start_port_reset =	ohci_start_port_reset,
 	.start_port_reset =	ohci_start_port_reset,
 };
 };
@@ -193,10 +193,11 @@ static int ohci_hcd_ppc_soc_drv_remove(struct device *dev)
 
 
 static struct device_driver ohci_hcd_ppc_soc_driver = {
 static struct device_driver ohci_hcd_ppc_soc_driver = {
 	.name		= "ppc-soc-ohci",
 	.name		= "ppc-soc-ohci",
+	.owner		= THIS_MODULE,
 	.bus		= &platform_bus_type,
 	.bus		= &platform_bus_type,
 	.probe		= ohci_hcd_ppc_soc_drv_probe,
 	.probe		= ohci_hcd_ppc_soc_drv_probe,
 	.remove		= ohci_hcd_ppc_soc_drv_remove,
 	.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,*/
 	/*.suspend	= ohci_hcd_ppc_soc_drv_suspend,*/
 	/*.resume	= ohci_hcd_ppc_soc_drv_resume,*/
 	/*.resume	= ohci_hcd_ppc_soc_drv_resume,*/
 #endif
 #endif

+ 4 - 3
drivers/usb/host/ohci-pxa27x.c

@@ -278,10 +278,11 @@ static const struct hc_driver ohci_pxa27x_hc_driver = {
 	 */
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
 	.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
 #endif
+	.start_port_reset =	ohci_start_port_reset,
 };
 };
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/

+ 5 - 4
drivers/usb/host/ohci-s3c2410.c

@@ -448,11 +448,11 @@ static const struct hc_driver ohci_s3c2410_hc_driver = {
 	 */
 	 */
 	.hub_status_data =	ohci_s3c2410_hub_status_data,
 	.hub_status_data =	ohci_s3c2410_hub_status_data,
 	.hub_control =		ohci_s3c2410_hub_control,
 	.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
 #endif
+	.start_port_reset =	ohci_start_port_reset,
 };
 };
 
 
 /* device driver */
 /* device driver */
@@ -474,6 +474,7 @@ static int ohci_hcd_s3c2410_drv_remove(struct device *dev)
 
 
 static struct device_driver ohci_hcd_s3c2410_driver = {
 static struct device_driver ohci_hcd_s3c2410_driver = {
 	.name		= "s3c2410-ohci",
 	.name		= "s3c2410-ohci",
+	.owner		= THIS_MODULE,
 	.bus		= &platform_bus_type,
 	.bus		= &platform_bus_type,
 	.probe		= ohci_hcd_s3c2410_drv_probe,
 	.probe		= ohci_hcd_s3c2410_drv_probe,
 	.remove		= ohci_hcd_s3c2410_drv_remove,
 	.remove		= ohci_hcd_s3c2410_drv_remove,

+ 4 - 3
drivers/usb/host/ohci-sa1111.c

@@ -235,10 +235,11 @@ static const struct hc_driver ohci_sa1111_hc_driver = {
 	 */
 	 */
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_status_data =	ohci_hub_status_data,
 	.hub_control =		ohci_hub_control,
 	.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
 #endif
+	.start_port_reset =	ohci_start_port_reset,
 };
 };
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/

+ 0 - 1
drivers/usb/host/ohci.h

@@ -389,7 +389,6 @@ struct ohci_hcd {
 	unsigned long		next_statechange;	/* suspend/resume */
 	unsigned long		next_statechange;	/* suspend/resume */
 	u32			fminterval;		/* saved register */
 	u32			fminterval;		/* saved register */
 
 
-	struct work_struct	rh_resume;
 	struct notifier_block	reboot_notifier;
 	struct notifier_block	reboot_notifier;
 
 
 	unsigned long		flags;		/* for HC bugs */
 	unsigned long		flags;		/* for HC bugs */

+ 296 - 0
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);

+ 9 - 8
drivers/usb/host/sl811-hcd.c

@@ -1363,7 +1363,7 @@ error:
 #ifdef	CONFIG_PM
 #ifdef	CONFIG_PM
 
 
 static int
 static int
-sl811h_hub_suspend(struct usb_hcd *hcd)
+sl811h_bus_suspend(struct usb_hcd *hcd)
 {
 {
 	// SOFs off
 	// SOFs off
 	DBG("%s\n", __FUNCTION__);
 	DBG("%s\n", __FUNCTION__);
@@ -1371,7 +1371,7 @@ sl811h_hub_suspend(struct usb_hcd *hcd)
 }
 }
 
 
 static int
 static int
-sl811h_hub_resume(struct usb_hcd *hcd)
+sl811h_bus_resume(struct usb_hcd *hcd)
 {
 {
 	// SOFs on
 	// SOFs on
 	DBG("%s\n", __FUNCTION__);
 	DBG("%s\n", __FUNCTION__);
@@ -1380,8 +1380,8 @@ sl811h_hub_resume(struct usb_hcd *hcd)
 
 
 #else
 #else
 
 
-#define	sl811h_hub_suspend	NULL
-#define	sl811h_hub_resume	NULL
+#define	sl811h_bus_suspend	NULL
+#define	sl811h_bus_resume	NULL
 
 
 #endif
 #endif
 
 
@@ -1623,8 +1623,8 @@ static struct hc_driver sl811h_hc_driver = {
 	 */
 	 */
 	.hub_status_data =	sl811h_hub_status_data,
 	.hub_status_data =	sl811h_hub_status_data,
 	.hub_control =		sl811h_hub_control,
 	.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 @@ sl811h_suspend(struct device *dev, pm_message_t state)
 	int		retval = 0;
 	int		retval = 0;
 
 
 	if (state.event == PM_EVENT_FREEZE)
 	if (state.event == PM_EVENT_FREEZE)
-		retval = sl811h_hub_suspend(hcd);
+		retval = sl811h_bus_suspend(hcd);
 	else if (state.event == PM_EVENT_SUSPEND)
 	else if (state.event == PM_EVENT_SUSPEND)
 		port_power(sl811, 0);
 		port_power(sl811, 0);
 	if (retval == 0)
 	if (retval == 0)
@@ -1816,7 +1816,7 @@ sl811h_resume(struct device *dev)
 	}
 	}
 
 
 	dev->power.power_state = PMSG_ON;
 	dev->power.power_state = PMSG_ON;
-	return sl811h_hub_resume(hcd);
+	return sl811h_bus_resume(hcd);
 }
 }
 
 
 #else
 #else
@@ -1831,6 +1831,7 @@ sl811h_resume(struct device *dev)
 struct device_driver sl811h_driver = {
 struct device_driver sl811h_driver = {
 	.name =		(char *) hcd_name,
 	.name =		(char *) hcd_name,
 	.bus =		&platform_bus_type,
 	.bus =		&platform_bus_type,
+	.owner =	THIS_MODULE,
 
 
 	.probe =	sl811h_probe,
 	.probe =	sl811h_probe,
 	.remove =	__devexit_p(sl811h_remove),
 	.remove =	__devexit_p(sl811h_remove),

+ 2 - 3
drivers/usb/host/uhci-debug.c

@@ -348,7 +348,6 @@ static int uhci_show_urbp(struct uhci_hcd *uhci, struct urb_priv *urbp, char *bu
 
 
 	if (urbp->urb->status != -EINPROGRESS)
 	if (urbp->urb->status != -EINPROGRESS)
 		out += sprintf(out, "Status=%d ", urbp->urb->status);
 		out += sprintf(out, "Status=%d ", urbp->urb->status);
-	//out += sprintf(out, "Inserttime=%lx ",urbp->inserttime);
 	//out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime);
 	//out += sprintf(out, "FSBRtime=%lx ",urbp->fsbrtime);
 
 
 	count = 0;
 	count = 0;
@@ -446,11 +445,11 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
 	out += sprintf(out, "Frame List\n");
 	out += sprintf(out, "Frame List\n");
 	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
 	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
 		int shown = 0;
 		int shown = 0;
-		td = uhci->fl->frame_cpu[i];
+		td = uhci->frame_cpu[i];
 		if (!td)
 		if (!td)
 			continue;
 			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();
 			show_frame_num();
 			out += sprintf(out, "    frame list does not match td->dma_handle!\n");
 			out += sprintf(out, "    frame list does not match td->dma_handle!\n");
 		}
 		}

+ 51 - 127
drivers/usb/host/uhci-hcd.c

@@ -101,37 +101,16 @@ static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
 #include "uhci-q.c"
 #include "uhci-q.c"
 #include "uhci-hub.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;
 	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
 	/* HCRESET doesn't affect the Suspend, Reset, and Resume Detect
 	 * bits in the port status and control registers.
 	 * bits in the port status and control registers.
 	 * We have to clear them by hand.
 	 * We have to clear them by hand.
@@ -153,7 +132,8 @@ static void reset_hc(struct uhci_hcd *uhci)
  */
  */
 static void hc_died(struct uhci_hcd *uhci)
 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;
 	uhci->hc_inaccessible = 1;
 }
 }
 
 
@@ -163,44 +143,8 @@ static void hc_died(struct uhci_hcd *uhci)
  */
  */
 static void check_and_reset_hc(struct uhci_hcd *uhci)
 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 @@ static void configure_hc(struct uhci_hcd *uhci)
 	outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF);
 	outb(USBSOF_DEFAULT, uhci->io_addr + USBSOF);
 
 
 	/* Store the frame list base address */
 	/* 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 */
 	/* Set the current frame number */
 	outw(uhci->frame_number, uhci->io_addr + USBFRNUM);
 	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();
 	mb();
 
 
 	/* Enable PIRQ */
 	/* Enable PIRQ */
@@ -319,6 +263,7 @@ __acquires(uhci->lock)
 
 
 static void start_rh(struct uhci_hcd *uhci)
 static void start_rh(struct uhci_hcd *uhci)
 {
 {
+	uhci_to_hcd(uhci)->state = HC_STATE_RUNNING;
 	uhci->is_stopped = 0;
 	uhci->is_stopped = 0;
 	smp_wmb();
 	smp_wmb();
 
 
@@ -437,36 +382,21 @@ static void release_uhci(struct uhci_hcd *uhci)
 	int i;
 	int i;
 
 
 	for (i = 0; i < UHCI_NUM_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_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)
 static int uhci_reset(struct usb_hcd *hcd)
@@ -545,7 +475,6 @@ static int uhci_start(struct usb_hcd *hcd)
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 	int retval = -EBUSY;
 	int retval = -EBUSY;
 	int i;
 	int i;
-	dma_addr_t dma_handle;
 	struct dentry *dentry;
 	struct dentry *dentry;
 
 
 	hcd->uses_new_polling = 1;
 	hcd->uses_new_polling = 1;
@@ -579,17 +508,23 @@ static int uhci_start(struct usb_hcd *hcd)
 
 
 	init_waitqueue_head(&uhci->waitqh);
 	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 "
 		dev_err(uhci_dev(uhci), "unable to allocate "
 				"consistent memory for frame list\n");
 				"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),
 	uhci->td_pool = dma_pool_create("uhci_td", uhci_dev(uhci),
 			sizeof(struct uhci_td), 16, 0);
 			sizeof(struct uhci_td), 16, 0);
@@ -672,7 +607,7 @@ static int uhci_start(struct usb_hcd *hcd)
 			irq = 7;
 			irq = 7;
 
 
 		/* Only place we don't use the frame list routines */
 		/* 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);
 				cpu_to_le32(uhci->skelqh[irq]->dma_handle);
 	}
 	}
 
 
@@ -690,31 +625,29 @@ static int uhci_start(struct usb_hcd *hcd)
  * error exits:
  * error exits:
  */
  */
 err_alloc_skelqh:
 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_free_qh(uhci, uhci->skelqh[i]);
-			uhci->skelqh[i] = NULL;
-		}
+	}
 
 
 	uhci_free_td(uhci, uhci->term_td);
 	uhci_free_td(uhci, uhci->term_td);
-	uhci->term_td = NULL;
 
 
 err_alloc_term_td:
 err_alloc_term_td:
 	dma_pool_destroy(uhci->qh_pool);
 	dma_pool_destroy(uhci->qh_pool);
-	uhci->qh_pool = NULL;
 
 
 err_create_qh_pool:
 err_create_qh_pool:
 	dma_pool_destroy(uhci->td_pool);
 	dma_pool_destroy(uhci->td_pool);
-	uhci->td_pool = NULL;
 
 
 err_create_td_pool:
 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_frame_cpu:
+	dma_free_coherent(uhci_dev(uhci),
+			UHCI_NUMFRAMES * sizeof(*uhci->frame),
+			uhci->frame, uhci->frame_dma_handle);
 
 
-err_alloc_fl:
+err_alloc_frame:
 	debugfs_remove(uhci->dentry);
 	debugfs_remove(uhci->dentry);
-	uhci->dentry = NULL;
 
 
 err_create_debug_entry:
 err_create_debug_entry:
 	return retval;
 	return retval;
@@ -726,7 +659,7 @@ static void uhci_stop(struct usb_hcd *hcd)
 
 
 	spin_lock_irq(&uhci->lock);
 	spin_lock_irq(&uhci->lock);
 	if (!uhci->hc_inaccessible)
 	if (!uhci->hc_inaccessible)
-		reset_hc(uhci);
+		hc_died(uhci);
 	uhci_scan_schedule(uhci, NULL);
 	uhci_scan_schedule(uhci, NULL);
 	spin_unlock_irq(&uhci->lock);
 	spin_unlock_irq(&uhci->lock);
 
 
@@ -774,14 +707,8 @@ static int uhci_suspend(struct usb_hcd *hcd, pm_message_t message)
 	if (uhci->hc_inaccessible)	/* Dead or already suspended */
 	if (uhci->hc_inaccessible)	/* Dead or already suspended */
 		goto done;
 		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) {
 	if (uhci->rh_state > UHCI_RH_SUSPENDED) {
 		dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n");
 		dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n");
-		hcd->state = HC_STATE_RUNNING;
 		rc = -EBUSY;
 		rc = -EBUSY;
 		goto done;
 		goto done;
 	};
 	};
@@ -820,10 +747,6 @@ static int uhci_resume(struct usb_hcd *hcd)
 	check_and_reset_hc(uhci);
 	check_and_reset_hc(uhci);
 	configure_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)
 	if (uhci->rh_state == UHCI_RH_RESET)
 		suspend_rh(uhci, UHCI_RH_SUSPENDED);
 		suspend_rh(uhci, UHCI_RH_SUSPENDED);
 
 
@@ -881,8 +804,8 @@ static const struct hc_driver uhci_driver = {
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 	.suspend =		uhci_suspend,
 	.suspend =		uhci_suspend,
 	.resume =		uhci_resume,
 	.resume =		uhci_resume,
-	.hub_suspend =		uhci_rh_suspend,
-	.hub_resume =		uhci_rh_resume,
+	.bus_suspend =		uhci_rh_suspend,
+	.bus_resume =		uhci_rh_resume,
 #endif
 #endif
 	.stop =			uhci_stop,
 	.stop =			uhci_stop,
 
 
@@ -908,6 +831,7 @@ MODULE_DEVICE_TABLE(pci, uhci_pci_ids);
 static struct pci_driver uhci_pci_driver = {
 static struct pci_driver uhci_pci_driver = {
 	.name =		(char *)hcd_name,
 	.name =		(char *)hcd_name,
 	.id_table =	uhci_pci_ids,
 	.id_table =	uhci_pci_ids,
+	.owner =	THIS_MODULE,
 
 
 	.probe =	usb_hcd_pci_probe,
 	.probe =	usb_hcd_pci_probe,
 	.remove =	usb_hcd_pci_remove,
 	.remove =	usb_hcd_pci_remove,

+ 53 - 45
drivers/usb/host/uhci-hcd.h

@@ -7,6 +7,7 @@
 #define usb_packetid(pipe)	(usb_pipein(pipe) ? USB_PID_IN : USB_PID_OUT)
 #define usb_packetid(pipe)	(usb_pipein(pipe) ? USB_PID_IN : USB_PID_OUT)
 #define PIPE_DEVEP_MASK		0x0007ff00
 #define PIPE_DEVEP_MASK		0x0007ff00
 
 
+
 /*
 /*
  * Universal Host Controller Interface data structures and defines
  * Universal Host Controller Interface data structures and defines
  */
  */
@@ -82,15 +83,10 @@
 #define UHCI_MAX_SOF_NUMBER	2047	/* in an SOF packet */
 #define UHCI_MAX_SOF_NUMBER	2047	/* in an SOF packet */
 #define CAN_SCHEDULE_FRAMES	1000	/* how far future frames can be scheduled */
 #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
  * One role of a QH is to hold a queue of TDs for some endpoint.  Each QH is
@@ -116,13 +112,13 @@ struct uhci_qh {
 
 
 	struct urb_priv *urbp;
 	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)));
 } __attribute__((aligned(16)));
 
 
 /*
 /*
  * We need a special accessor for the element pointer because it is
  * 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) {
 static __le32 inline qh_element(struct uhci_qh *qh) {
 	__le32 element = qh->element;
 	__le32 element = qh->element;
@@ -131,6 +127,11 @@ static __le32 inline qh_element(struct uhci_qh *qh) {
 	return element;
 	return element;
 }
 }
 
 
+
+/*
+ *	Transfer Descriptors
+ */
+
 /*
 /*
  * for TD <status>:
  * for TD <status>:
  */
  */
@@ -183,17 +184,10 @@ static __le32 inline qh_element(struct uhci_qh *qh) {
  *
  *
  * That's silly, the hardware doesn't care. The hardware only cares that
  * 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
  * 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
  * 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 {
 struct uhci_td {
 	/* Hardware fields */
 	/* Hardware fields */
@@ -205,18 +199,16 @@ struct uhci_td {
 	/* Software fields */
 	/* Software fields */
 	dma_addr_t dma_handle;
 	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? */
 	int frame;			/* for iso: what frame? */
-	struct list_head fl_list;	/* P: uhci->frame_list_lock */
+	struct list_head fl_list;
 } __attribute__((aligned(16)));
 } __attribute__((aligned(16)));
 
 
 /*
 /*
  * We need a special accessor for the control/status word because it is
  * 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) {
 static u32 inline td_status(struct uhci_td *td) {
 	__le32 status = td->status;
 	__le32 status = td->status;
@@ -226,6 +218,10 @@ static u32 inline td_status(struct uhci_td *td) {
 }
 }
 
 
 
 
+/*
+ *	Skeleton Queue Headers
+ */
+
 /*
 /*
  * The UHCI driver places Interrupt, Control and Bulk into QH's both
  * 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
  * to group together TD's for one transfer, and also to faciliate queuing
@@ -256,15 +252,15 @@ static u32 inline td_status(struct uhci_td *td) {
  *
  *
  * The terminating QH is used for 2 reasons:
  * The terminating QH is used for 2 reasons:
  * - To place a terminating TD which is used to workaround a PIIX bug
  * - 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
  * - 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
  * 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
  * 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
 #define UHCI_NUM_SKELQH		12
@@ -314,8 +310,13 @@ static inline int __interval_to_skel(int interval)
 	return 0;				/* int128 for 128-255 ms (Max.) */
 	return 0;				/* int128 for 128-255 ms (Max.) */
 }
 }
 
 
+
+/*
+ *	The UHCI controller and root hub
+ */
+
 /*
 /*
- * States for the root hub.
+ * States for the root hub:
  *
  *
  * To prevent "bouncing" in the presence of electrical noise,
  * To prevent "bouncing" in the presence of electrical noise,
  * when there are no devices attached we delay for 1 second in the
  * when there are no devices attached we delay for 1 second in the
@@ -326,7 +327,7 @@ static inline int __interval_to_skel(int interval)
  */
  */
 enum uhci_rh_state {
 enum uhci_rh_state {
 	/* In the following states the HC must be halted.
 	/* In the following states the HC must be halted.
-	 * These two must come first */
+	 * These two must come first. */
 	UHCI_RH_RESET,
 	UHCI_RH_RESET,
 	UHCI_RH_SUSPENDED,
 	UHCI_RH_SUSPENDED,
 
 
@@ -338,13 +339,13 @@ enum uhci_rh_state {
 	UHCI_RH_SUSPENDING,
 	UHCI_RH_SUSPENDING,
 
 
 	/* In the following states it's an error if the HC is halted.
 	/* 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,		/* The normal state */
 	UHCI_RH_RUNNING_NODEVS,		/* Running with no devices attached */
 	UHCI_RH_RUNNING_NODEVS,		/* Running with no devices attached */
 };
 };
 
 
 /*
 /*
- * This describes the full uhci information.
+ * The full UHCI controller information:
  */
  */
 struct uhci_hcd {
 struct uhci_hcd {
 
 
@@ -361,7 +362,11 @@ struct uhci_hcd {
 	struct uhci_qh *skelqh[UHCI_NUM_SKELQH];	/* Skeleton QH's */
 	struct uhci_qh *skelqh[UHCI_NUM_SKELQH];	/* Skeleton QH's */
 
 
 	spinlock_t lock;
 	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 */
 	int fsbr;				/* Full-speed bandwidth reclamation */
 	unsigned long fsbrtimeout;		/* FSBR delay */
 	unsigned long fsbrtimeout;		/* FSBR delay */
 
 
@@ -385,22 +390,22 @@ struct uhci_hcd {
 	unsigned long ports_timeout;		/* Time to stop signalling */
 	unsigned long ports_timeout;		/* Time to stop signalling */
 
 
 	/* Main list of URB's currently controlled by this HC */
 	/* 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) */
 	/* 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 */
 	unsigned int qh_remove_age;		/* Age in frames */
 
 
 	/* List of TD's that are done, but waiting to be freed (race) */
 	/* 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 */
 	unsigned int td_remove_age;		/* Age in frames */
 
 
 	/* List of asynchronously unlinked URB's */
 	/* 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 */
 	unsigned int urb_remove_age;		/* Age in frames */
 
 
 	/* List of URB's awaiting completion callback */
 	/* 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 */
 	int rh_numports;			/* Number of root-hub ports */
 
 
@@ -419,13 +424,17 @@ static inline struct usb_hcd *uhci_to_hcd(struct uhci_hcd *uhci)
 
 
 #define uhci_dev(u)	(uhci_to_hcd(u)->self.controller)
 #define uhci_dev(u)	(uhci_to_hcd(u)->self.controller)
 
 
+
+/*
+ *	Private per-URB data
+ */
 struct urb_priv {
 struct urb_priv {
 	struct list_head urb_list;
 	struct list_head urb_list;
 
 
 	struct urb *urb;
 	struct urb *urb;
 
 
 	struct uhci_qh *qh;		/* QH for this 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 : 1;		/* URB turned on FSBR */
 	unsigned fsbr_timeout : 1;	/* URB timed out on FSBR */
 	unsigned fsbr_timeout : 1;	/* URB timed out on FSBR */
@@ -434,12 +443,12 @@ struct urb_priv {
 						/*  a control transfer, retrigger */
 						/*  a control transfer, retrigger */
 						/*  the status phase */
 						/*  the status phase */
 
 
-	unsigned long inserttime;	/* In jiffies */
 	unsigned long fsbrtime;		/* 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
  * Locking in uhci.c
  *
  *
@@ -459,6 +468,5 @@ struct urb_priv {
 
 
 #define PCI_VENDOR_ID_GENESYS		0x17a0
 #define PCI_VENDOR_ID_GENESYS		0x17a0
 #define PCI_DEVICE_ID_GL880S_UHCI	0x8083
 #define PCI_DEVICE_ID_GL880S_UHCI	0x8083
-#define PCI_DEVICE_ID_GL880S_EHCI	0x8084
 
 
 #endif
 #endif

+ 35 - 27
drivers/usb/host/uhci-q.c

@@ -89,10 +89,10 @@ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td,
 	td->frame = framenum;
 	td->frame = framenum;
 
 
 	/* Is there a TD already mapped there? */
 	/* Is there a TD already mapped there? */
-	if (uhci->fl->frame_cpu[framenum]) {
+	if (uhci->frame_cpu[framenum]) {
 		struct uhci_td *ftd, *ltd;
 		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);
 		ltd = list_entry(ftd->fl_list.prev, struct uhci_td, fl_list);
 
 
 		list_add_tail(&td->fl_list, &ftd->fl_list);
 		list_add_tail(&td->fl_list, &ftd->fl_list);
@@ -101,29 +101,32 @@ static void uhci_insert_td_frame_list(struct uhci_hcd *uhci, struct uhci_td *td,
 		wmb();
 		wmb();
 		ltd->link = cpu_to_le32(td->dma_handle);
 		ltd->link = cpu_to_le32(td->dma_handle);
 	} else {
 	} else {
-		td->link = uhci->fl->frame[framenum];
+		td->link = uhci->frame[framenum];
 		wmb();
 		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 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;
 		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)) {
 		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 {
 		} else {
 			struct uhci_td *ntd;
 			struct uhci_td *ntd;
 
 
 			ntd = list_entry(td->fl_list.next, struct uhci_td, fl_list);
 			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 {
 	} else {
 		struct uhci_td *ptd;
 		struct uhci_td *ptd;
@@ -132,13 +135,20 @@ static void uhci_remove_td(struct uhci_hcd *uhci, struct uhci_td *td)
 		ptd->link = td->link;
 		ptd->link = td->link;
 	}
 	}
 
 
-	wmb();
-	td->link = UHCI_PTR_TERM;
-
 	list_del_init(&td->fl_list);
 	list_del_init(&td->fl_list);
 	td->frame = -1;
 	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.
  * Inserts a td list into qh.
  */
  */
@@ -443,7 +453,6 @@ static struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci, struct urb *u
 
 
 	memset((void *)urbp, 0, sizeof(*urbp));
 	memset((void *)urbp, 0, sizeof(*urbp));
 
 
-	urbp->inserttime = jiffies;
 	urbp->fsbrtime = jiffies;
 	urbp->fsbrtime = jiffies;
 	urbp->urb = urb;
 	urbp->urb = urb;
 	
 	
@@ -462,8 +471,6 @@ static void uhci_add_td_to_urb(struct urb *urb, struct uhci_td *td)
 {
 {
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 
 
-	td->urb = urb;
-
 	list_add_tail(&td->list, &urbp->td_list);
 	list_add_tail(&td->list, &urbp->td_list);
 }
 }
 
 
@@ -473,8 +480,6 @@ static void uhci_remove_td_from_urb(struct uhci_td *td)
 		return;
 		return;
 
 
 	list_del_init(&td->list);
 	list_del_init(&td->list);
-
-	td->urb = NULL;
 }
 }
 
 
 static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
 static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
@@ -503,7 +508,6 @@ static void uhci_destroy_urb_priv(struct uhci_hcd *uhci, struct urb *urb)
 
 
 	list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
 	list_for_each_entry_safe(td, tmp, &urbp->td_list, list) {
 		uhci_remove_td_from_urb(td);
 		uhci_remove_td_from_urb(td);
-		uhci_remove_td(uhci, td);
 		list_add(&td->remove_list, &uhci->td_remove_list);
 		list_add(&td->remove_list, &uhci->td_remove_list);
 	}
 	}
 
 
@@ -1073,6 +1077,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
 	struct uhci_td *td;
 	struct uhci_td *td;
 	int i, ret, frame;
 	int i, ret, frame;
 	int status, destination;
 	int status, destination;
+	struct urb_priv *urbp = (struct urb_priv *) urb->hcpriv;
 
 
 	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
 	status = TD_CTRL_ACTIVE | TD_CTRL_IOS;
 	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
 	destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
@@ -1081,11 +1086,7 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
 	if (ret)
 	if (ret)
 		return 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);
 		td = uhci_alloc_td(uhci);
 		if (!td)
 		if (!td)
 			return -ENOMEM;
 			return -ENOMEM;
@@ -1096,8 +1097,12 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb)
 
 
 		if (i + 1 >= urb->number_of_packets)
 		if (i + 1 >= urb->number_of_packets)
 			td->status |= cpu_to_le32(TD_CTRL_IOC);
 			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);
 		uhci_insert_td_frame_list(uhci, td, frame);
+		frame += urb->interval;
 	}
 	}
 
 
 	return -EINPROGRESS;
 	return -EINPROGRESS;
@@ -1110,7 +1115,7 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
 	int status;
 	int status;
 	int i, ret = 0;
 	int i, ret = 0;
 
 
-	urb->actual_length = 0;
+	urb->actual_length = urb->error_count = 0;
 
 
 	i = 0;
 	i = 0;
 	list_for_each_entry(td, &urbp->td_list, list) {
 	list_for_each_entry(td, &urbp->td_list, list) {
@@ -1134,6 +1139,7 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
 
 
 		i++;
 		i++;
 	}
 	}
+	unlink_isochronous_tds(uhci, urb);
 
 
 	return ret;
 	return ret;
 }
 }
@@ -1366,6 +1372,8 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
 		goto done;
 		goto done;
 	list_del_init(&urbp->urb_list);
 	list_del_init(&urbp->urb_list);
 
 
+	if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS)
+		unlink_isochronous_tds(uhci, urb);
 	uhci_unlink_generic(uhci, urb);
 	uhci_unlink_generic(uhci, urb);
 
 
 	uhci_get_current_frame_number(uhci);
 	uhci_get_current_frame_number(uhci);

+ 22 - 11
drivers/usb/image/mdc800.c

@@ -425,9 +425,8 @@ static void mdc800_usb_download_notify (struct urb *urb, struct pt_regs *res)
 static struct usb_driver mdc800_usb_driver;
 static struct usb_driver mdc800_usb_driver;
 static struct file_operations mdc800_device_ops;
 static struct file_operations mdc800_device_ops;
 static struct usb_class_driver mdc800_class = {
 static struct usb_class_driver mdc800_class = {
-	.name =		"usb/mdc800%d",
+	.name =		"mdc800%d",
 	.fops =		&mdc800_device_ops,
 	.fops =		&mdc800_device_ops,
-	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
 	.minor_base =	MDC800_DEVICE_MINOR_BASE,
 	.minor_base =	MDC800_DEVICE_MINOR_BASE,
 };
 };
 
 
@@ -976,13 +975,13 @@ static struct usb_driver mdc800_usb_driver =
 	Init and Cleanup this driver (Main Functions)
 	Init and Cleanup this driver (Main Functions)
 *************************************************************************/
 *************************************************************************/
 
 
-#define try(A)           if (!(A)) goto cleanup_on_fail;
-
 static int __init usb_mdc800_init (void)
 static int __init usb_mdc800_init (void)
 {
 {
 	int retval = -ENODEV;
 	int retval = -ENODEV;
 	/* Allocate Memory */
 	/* 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));
 	memset(mdc800, 0, sizeof(struct mdc800_data));
 	mdc800->dev = NULL;
 	mdc800->dev = NULL;
@@ -998,13 +997,25 @@ static int __init usb_mdc800_init (void)
 	mdc800->downloaded = 0;
 	mdc800->downloaded = 0;
 	mdc800->written = 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 */
 	/* Register the driver */
 	retval = usb_register(&mdc800_usb_driver);
 	retval = usb_register(&mdc800_usb_driver);

+ 1 - 2
drivers/usb/image/microtek.c

@@ -773,11 +773,10 @@ static int mts_usb_probe(struct usb_interface *intf,
 	}
 	}
 	
 	
 	
 	
-	new_desc = kmalloc(sizeof(struct mts_desc), GFP_KERNEL);
+	new_desc = kzalloc(sizeof(struct mts_desc), GFP_KERNEL);
 	if (!new_desc)
 	if (!new_desc)
 		goto out;
 		goto out;
 
 
-	memset(new_desc, 0, sizeof(*new_desc));
 	new_desc->urb = usb_alloc_urb(0, GFP_KERNEL);
 	new_desc->urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!new_desc->urb)
 	if (!new_desc->urb)
 		goto out_kfree;
 		goto out_kfree;

+ 1 - 1
drivers/usb/input/aiptek.c

@@ -2154,7 +2154,7 @@ aiptek_probe(struct usb_interface *intf, const struct usb_device_id *id)
 	 * input_handles associated with this input device.
 	 * input_handles associated with this input device.
 	 * What identifies an evdev input_handler is that it begins
 	 * What identifies an evdev input_handler is that it begins
 	 * with 'event', continues with a digit, and that in turn
 	 * 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) {
 	list_for_each_safe(node, next, &inputdev->h_list) {
 		inputhandle = to_handle(node);
 		inputhandle = to_handle(node);

+ 3 - 2
drivers/usb/input/hid-core.c

@@ -1784,6 +1784,9 @@ static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 	hid->urbctrl->transfer_dma = hid->ctrlbuf_dma;
 	hid->urbctrl->transfer_dma = hid->ctrlbuf_dma;
 	hid->urbctrl->transfer_flags |= (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP);
 	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;
 	return hid;
 
 
 fail:
 fail:
@@ -1887,7 +1890,6 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message)
 	struct hid_device *hid = usb_get_intfdata (intf);
 	struct hid_device *hid = usb_get_intfdata (intf);
 
 
 	usb_kill_urb(hid->urbin);
 	usb_kill_urb(hid->urbin);
-	intf->dev.power.power_state = PMSG_SUSPEND;
 	dev_dbg(&intf->dev, "suspend\n");
 	dev_dbg(&intf->dev, "suspend\n");
 	return 0;
 	return 0;
 }
 }
@@ -1897,7 +1899,6 @@ static int hid_resume(struct usb_interface *intf)
 	struct hid_device *hid = usb_get_intfdata (intf);
 	struct hid_device *hid = usb_get_intfdata (intf);
 	int status;
 	int status;
 
 
-	intf->dev.power.power_state = PMSG_ON;
 	if (hid->open)
 	if (hid->open)
 		status = usb_submit_urb(hid->urbin, GFP_NOIO);
 		status = usb_submit_urb(hid->urbin, GFP_NOIO);
 	else
 	else

+ 1 - 2
drivers/usb/input/hiddev.c

@@ -732,9 +732,8 @@ static struct file_operations hiddev_fops = {
 };
 };
 
 
 static struct usb_class_driver hiddev_class = {
 static struct usb_class_driver hiddev_class = {
-	.name =		"usb/hid/hiddev%d",
+	.name =		"hiddev%d",
 	.fops =		&hiddev_fops,
 	.fops =		&hiddev_fops,
-	.mode =		S_IFCHR | S_IRUGO | S_IWUSR,
 	.minor_base =	HIDDEV_MINOR_BASE,
 	.minor_base =	HIDDEV_MINOR_BASE,
 };
 };
 
 

+ 1 - 1
drivers/usb/input/map_to_7segment.h

@@ -79,7 +79,7 @@ struct seg7_conversion_map {
 
 
 static inline int map_to_seg7(struct seg7_conversion_map *map, int c)
 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)	\
 #define SEG7_CONVERSION_MAP(_name, _map)	\

+ 2 - 0
drivers/usb/input/touchkitusb.c

@@ -75,7 +75,9 @@ struct touchkit_usb {
 
 
 static struct usb_device_id touchkit_devices[] = {
 static struct usb_device_id touchkit_devices[] = {
 	{USB_DEVICE(0x3823, 0x0001)},
 	{USB_DEVICE(0x3823, 0x0001)},
+	{USB_DEVICE(0x0123, 0x0001)},
 	{USB_DEVICE(0x0eef, 0x0001)},
 	{USB_DEVICE(0x0eef, 0x0001)},
+	{USB_DEVICE(0x0eef, 0x0002)},
 	{}
 	{}
 };
 };
 
 

+ 1 - 2
drivers/usb/media/dabusb.c

@@ -707,9 +707,8 @@ static struct file_operations dabusb_fops =
 };
 };
 
 
 static struct usb_class_driver dabusb_class = {
 static struct usb_class_driver dabusb_class = {
-	.name =		"usb/dabusb%d",
+	.name =		"dabusb%d",
 	.fops =		&dabusb_fops,
 	.fops =		&dabusb_fops,
-	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
 	.minor_base =	DABUSB_MINOR,
 	.minor_base =	DABUSB_MINOR,
 };
 };
 
 

+ 1 - 2
drivers/usb/misc/auerswald.c

@@ -1873,9 +1873,8 @@ static struct file_operations auerswald_fops =
 };
 };
 
 
 static struct usb_class_driver auerswald_class = {
 static struct usb_class_driver auerswald_class = {
-	.name =		"usb/auer%d",
+	.name =		"auer%d",
 	.fops =		&auerswald_fops,
 	.fops =		&auerswald_fops,
-	.mode =		S_IFCHR | S_IRUGO | S_IWUGO,
 	.minor_base =	AUER_MINOR_BASE,
 	.minor_base =	AUER_MINOR_BASE,
 };
 };
 
 

+ 2 - 3
drivers/usb/misc/idmouse.c

@@ -105,11 +105,10 @@ static struct file_operations idmouse_fops = {
 	.release = idmouse_release,
 	.release = idmouse_release,
 };
 };
 
 
-/* class driver information for devfs */
+/* class driver information */
 static struct usb_class_driver idmouse_class = {
 static struct usb_class_driver idmouse_class = {
-	.name = "usb/idmouse%d",
+	.name = "idmouse%d",
 	.fops = &idmouse_fops,
 	.fops = &idmouse_fops,
-	.mode = S_IFCHR | S_IRUSR | S_IRGRP | S_IROTH, /* filemode (char, 444) */
 	.minor_base = USB_IDMOUSE_MINOR_BASE,
 	.minor_base = USB_IDMOUSE_MINOR_BASE,
 };
 };
 
 

+ 2 - 3
drivers/usb/misc/legousbtower.c

@@ -271,12 +271,11 @@ static struct file_operations tower_fops = {
 
 
 /*
 /*
  * usb class driver info in order to get a minor number from the usb core,
  * 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 = {
 static struct usb_class_driver tower_class = {
-	.name =		"usb/legousbtower%d",
+	.name =		"legousbtower%d",
 	.fops =		&tower_fops,
 	.fops =		&tower_fops,
-	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
 	.minor_base =	LEGO_USB_TOWER_MINOR_BASE,
 	.minor_base =	LEGO_USB_TOWER_MINOR_BASE,
 };
 };
 
 

+ 1 - 2
drivers/usb/misc/rio500.c

@@ -443,9 +443,8 @@ file_operations usb_rio_fops = {
 };
 };
 
 
 static struct usb_class_driver usb_rio_class = {
 static struct usb_class_driver usb_rio_class = {
-	.name =		"usb/rio500%d",
+	.name =		"rio500%d",
 	.fops =		&usb_rio_fops,
 	.fops =		&usb_rio_fops,
-	.mode =		S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
 	.minor_base =	RIO_MINOR,
 	.minor_base =	RIO_MINOR,
 };
 };
 
 

+ 1 - 6
drivers/usb/misc/sisusbvga/sisusb.c

@@ -2440,7 +2440,7 @@ int
 sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
 sisusb_reset_text_mode(struct sisusb_usb_data *sisusb, int init)
 {
 {
 	int ret = 0, slot = sisusb->font_slot, i;
 	int ret = 0, slot = sisusb->font_slot, i;
-	struct font_desc *myfont;
+	const struct font_desc *myfont;
 	u8 *tempbuf;
 	u8 *tempbuf;
 	u16 *tempbufb;
 	u16 *tempbufb;
 	size_t written;
 	size_t written;
@@ -3239,12 +3239,7 @@ static struct file_operations usb_sisusb_fops = {
 };
 };
 
 
 static struct usb_class_driver usb_sisusb_class = {
 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",
 	.name =		"sisusbvga%d",
-#endif
 	.fops =		&usb_sisusb_fops,
 	.fops =		&usb_sisusb_fops,
 	.minor_base =	SISUSB_MINOR
 	.minor_base =	SISUSB_MINOR
 };
 };

+ 4 - 5
drivers/usb/misc/usblcd.c

@@ -251,13 +251,12 @@ static struct file_operations lcd_fops = {
 };
 };
 
 
 /*
 /*
- *  * 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 = {
 static struct usb_class_driver lcd_class = {
-        .name =         "usb/lcd%d",
+        .name =         "lcd%d",
         .fops =         &lcd_fops,
         .fops =         &lcd_fops,
-        .mode =         S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH,
         .minor_base =   USBLCD_MINOR,
         .minor_base =   USBLCD_MINOR,
 };
 };
 
 

+ 1 - 10
drivers/usb/misc/usbtest.c

@@ -983,6 +983,7 @@ test_ctrl_queue (struct usbtest_dev *dev, struct usbtest_param *param)
 		reqp->number = i % NUM_SUBCASES;
 		reqp->number = i % NUM_SUBCASES;
 		reqp->expected = expected;
 		reqp->expected = expected;
 		u->setup_packet = (char *) &reqp->setup;
 		u->setup_packet = (char *) &reqp->setup;
+		u->transfer_flags |= URB_NO_SETUP_DMA_MAP;
 
 
 		u->context = &context;
 		u->context = &context;
 		u->complete = ctrl_complete;
 		u->complete = ctrl_complete;
@@ -1948,21 +1949,11 @@ usbtest_probe (struct usb_interface *intf, const struct usb_device_id *id)
 
 
 static int usbtest_suspend (struct usb_interface *intf, pm_message_t message)
 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;
 	return 0;
 }
 }
 
 
 static int usbtest_resume (struct usb_interface *intf)
 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;
 	return 0;
 }
 }
 
 

+ 21 - 2
drivers/usb/mon/mon_main.c

@@ -11,6 +11,7 @@
 #include <linux/usb.h>
 #include <linux/usb.h>
 #include <linux/debugfs.h>
 #include <linux/debugfs.h>
 #include <linux/smp_lock.h>
 #include <linux/smp_lock.h>
+#include <linux/notifier.h>
 
 
 #include "usb_mon.h"
 #include "usb_mon.h"
 #include "../core/hcd.h"
 #include "../core/hcd.h"
@@ -205,6 +206,23 @@ static void mon_bus_remove(struct usb_bus *ubus)
 	up(&mon_lock);
 	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
  * Ops
  */
  */
@@ -212,8 +230,6 @@ static struct usb_mon_operations mon_ops_0 = {
 	.urb_submit =	mon_submit,
 	.urb_submit =	mon_submit,
 	.urb_submit_error = mon_submit_error,
 	.urb_submit_error = mon_submit_error,
 	.urb_complete =	mon_complete,
 	.urb_complete =	mon_complete,
-	.bus_add =	mon_bus_add,
-	.bus_remove =	mon_bus_remove,
 };
 };
 
 
 /*
 /*
@@ -329,6 +345,8 @@ static int __init mon_init(void)
 	}
 	}
 	// MOD_INC_USE_COUNT(which_module?);
 	// MOD_INC_USE_COUNT(which_module?);
 
 
+	usb_register_notify(&mon_nb);
+
 	down(&usb_bus_list_lock);
 	down(&usb_bus_list_lock);
 	list_for_each_entry (ubus, &usb_bus_list, bus_list) {
 	list_for_each_entry (ubus, &usb_bus_list, bus_list) {
 		mon_bus_init(mondir, ubus);
 		mon_bus_init(mondir, ubus);
@@ -342,6 +360,7 @@ static void __exit mon_exit(void)
 	struct mon_bus *mbus;
 	struct mon_bus *mbus;
 	struct list_head *p;
 	struct list_head *p;
 
 
+	usb_unregister_notify(&mon_nb);
 	usb_mon_deregister();
 	usb_mon_deregister();
 
 
 	down(&mon_lock);
 	down(&mon_lock);

+ 1 - 1
drivers/usb/net/Kconfig

@@ -294,7 +294,7 @@ config USB_NET_ZAURUS
 	  This also supports some related device firmware, as used in some
 	  This also supports some related device firmware, as used in some
 	  PDAs from Olympus and some cell phones from Motorola.
 	  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
 	  versions of OpenZaurus, you should no longer need to support this
 	  protocol.  Only the "eth-fd" or "net_fd" drivers in these devices
 	  protocol.  Only the "eth-fd" or "net_fd" drivers in these devices
 	  really need this non-conformant variant of CDC Ethernet (or in
 	  really need this non-conformant variant of CDC Ethernet (or in

+ 1 - 1
drivers/usb/net/kaweth.c

@@ -469,7 +469,7 @@ static int kaweth_reset(struct kaweth_device *kaweth)
 				0,
 				0,
 				KAWETH_CONTROL_TIMEOUT);
 				KAWETH_CONTROL_TIMEOUT);
 
 
-	udelay(10000);
+	mdelay(10);
 
 
 	kaweth_dbg("kaweth_reset() returns %d.",result);
 	kaweth_dbg("kaweth_reset() returns %d.",result);
 
 

+ 0 - 2
drivers/usb/net/pegasus.c

@@ -1384,7 +1384,6 @@ static int pegasus_suspend (struct usb_interface *intf, pm_message_t message)
 		usb_kill_urb(pegasus->rx_urb);
 		usb_kill_urb(pegasus->rx_urb);
 		usb_kill_urb(pegasus->intr_urb);
 		usb_kill_urb(pegasus->intr_urb);
 	}
 	}
-	intf->dev.power.power_state = PMSG_SUSPEND;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1392,7 +1391,6 @@ static int pegasus_resume (struct usb_interface *intf)
 {
 {
 	struct pegasus *pegasus = usb_get_intfdata(intf);
 	struct pegasus *pegasus = usb_get_intfdata(intf);
 
 
-	intf->dev.power.power_state = PMSG_ON;
 	netif_device_attach (pegasus->net);
 	netif_device_attach (pegasus->net);
 	if (netif_running(pegasus->net)) {
 	if (netif_running(pegasus->net)) {
 		pegasus->rx_urb->status = 0;
 		pegasus->rx_urb->status = 0;

+ 2 - 0
drivers/usb/net/pegasus.h

@@ -181,6 +181,8 @@ PEGASUS_DEV( "Accton USB 10/100 Ethernet Adapter", VENDOR_ACCTON, 0x1046,
 		DEFAULT_GPIO_RESET )
 		DEFAULT_GPIO_RESET )
 PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046,
 PEGASUS_DEV( "SpeedStream USB 10/100 Ethernet", VENDOR_ACCTON, 0x5046,
 		DEFAULT_GPIO_RESET | PEGASUS_II )
 		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",
 PEGASUS_DEV( "ADMtek ADM8511 \"Pegasus II\" USB Ethernet",
 		VENDOR_ADMTEK, 0x8511,
 		VENDOR_ADMTEK, 0x8511,
 		DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )
 		DEFAULT_GPIO_RESET | PEGASUS_II | HAS_HOME_PNA )

+ 1 - 0
drivers/usb/net/rtl8150.c

@@ -909,6 +909,7 @@ static void rtl8150_disconnect(struct usb_interface *intf)
 	usb_set_intfdata(intf, NULL);
 	usb_set_intfdata(intf, NULL);
 	if (dev) {
 	if (dev) {
 		set_bit(RTL8150_UNPLUG, &dev->flags);
 		set_bit(RTL8150_UNPLUG, &dev->flags);
+		tasklet_disable(&dev->tl);
 		unregister_netdev(dev->netdev);
 		unregister_netdev(dev->netdev);
 		unlink_all_urbs(dev);
 		unlink_all_urbs(dev);
 		free_all_urbs(dev);
 		free_all_urbs(dev);

+ 0 - 2
drivers/usb/net/usbnet.c

@@ -1185,7 +1185,6 @@ int usbnet_suspend (struct usb_interface *intf, pm_message_t message)
 	netif_device_detach (dev->net);
 	netif_device_detach (dev->net);
 	(void) unlink_urbs (dev, &dev->rxq);
 	(void) unlink_urbs (dev, &dev->rxq);
 	(void) unlink_urbs (dev, &dev->txq);
 	(void) unlink_urbs (dev, &dev->txq);
-	intf->dev.power.power_state = PMSG_SUSPEND;
 	return 0;
 	return 0;
 }
 }
 EXPORT_SYMBOL_GPL(usbnet_suspend);
 EXPORT_SYMBOL_GPL(usbnet_suspend);
@@ -1194,7 +1193,6 @@ int usbnet_resume (struct usb_interface *intf)
 {
 {
 	struct usbnet		*dev = usb_get_intfdata(intf);
 	struct usbnet		*dev = usb_get_intfdata(intf);
 
 
-	intf->dev.power.power_state = PMSG_ON;
 	netif_device_attach (dev->net);
 	netif_device_attach (dev->net);
 	tasklet_schedule (&dev->bh);
 	tasklet_schedule (&dev->bh);
 	return 0;
 	return 0;

+ 730 - 0
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.
+
+

+ 9 - 0
drivers/usb/serial/Kconfig

@@ -394,6 +394,15 @@ config USB_SERIAL_MCT_U232
 	  To compile this driver as a module, choose M here: the
 	  To compile this driver as a module, choose M here: the
 	  module will be called mct_u232.
 	  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
 config USB_SERIAL_PL2303
 	tristate "USB Prolific 2303 Single Port Serial Driver"
 	tristate "USB Prolific 2303 Single Port Serial Driver"
 	depends on USB_SERIAL
 	depends on USB_SERIAL

+ 1 - 0
drivers/usb/serial/Makefile

@@ -31,6 +31,7 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA)		+= keyspan_pda.o
 obj-$(CONFIG_USB_SERIAL_KLSI)			+= kl5kusb105.o
 obj-$(CONFIG_USB_SERIAL_KLSI)			+= kl5kusb105.o
 obj-$(CONFIG_USB_SERIAL_KOBIL_SCT)		+= kobil_sct.o
 obj-$(CONFIG_USB_SERIAL_KOBIL_SCT)		+= kobil_sct.o
 obj-$(CONFIG_USB_SERIAL_MCT_U232)		+= mct_u232.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_OMNINET)		+= omninet.o
 obj-$(CONFIG_USB_SERIAL_OPTION)			+= option.o
 obj-$(CONFIG_USB_SERIAL_OPTION)			+= option.o
 obj-$(CONFIG_USB_SERIAL_PL2303)			+= pl2303.o
 obj-$(CONFIG_USB_SERIAL_PL2303)			+= pl2303.o

+ 5 - 3
drivers/usb/serial/airprime.c

@@ -30,9 +30,11 @@ static struct usb_driver airprime_driver = {
 	.id_table =	id_table,
 	.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,
 	.id_table =		id_table,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,

+ 6 - 4
drivers/usb/serial/belkin_sa.c

@@ -121,10 +121,12 @@ static struct usb_driver belkin_driver = {
 };
 };
 
 
 /* All of the device info needed for the serial converters */
 /* 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,
 	.id_table =		id_table_combined,
 	.num_interrupt_in =	1,
 	.num_interrupt_in =	1,
 	.num_bulk_in =		1,
 	.num_bulk_in =		1,

+ 16 - 21
drivers/usb/serial/bus.c

@@ -18,7 +18,7 @@
 
 
 static int usb_serial_device_match (struct device *dev, struct device_driver *drv)
 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;
 	const struct usb_serial_port *port;
 
 
 	/*
 	/*
@@ -44,7 +44,7 @@ struct bus_type usb_serial_bus_type = {
 
 
 static int usb_serial_device_probe (struct device *dev)
 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;
 	struct usb_serial_port *port;
 	int retval = 0;
 	int retval = 0;
 	int minor;
 	int minor;
@@ -57,13 +57,13 @@ static int usb_serial_device_probe (struct device *dev)
 
 
 	driver = port->serial->type;
 	driver = port->serial->type;
 	if (driver->port_probe) {
 	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");
 			dev_err(dev, "module get failed, exiting\n");
 			retval = -EIO;
 			retval = -EIO;
 			goto exit;
 			goto exit;
 		}
 		}
 		retval = driver->port_probe (port);
 		retval = driver->port_probe (port);
-		module_put(driver->owner);
+		module_put(driver->driver.owner);
 		if (retval)
 		if (retval)
 			goto exit;
 			goto exit;
 	}
 	}
@@ -72,7 +72,7 @@ static int usb_serial_device_probe (struct device *dev)
 	tty_register_device (usb_serial_tty_driver, minor, dev);
 	tty_register_device (usb_serial_tty_driver, minor, dev);
 	dev_info(&port->serial->dev->dev, 
 	dev_info(&port->serial->dev->dev, 
 		 "%s converter now attached to ttyUSB%d\n",
 		 "%s converter now attached to ttyUSB%d\n",
-		 driver->name, minor);
+		 driver->description, minor);
 
 
 exit:
 exit:
 	return retval;
 	return retval;
@@ -80,7 +80,7 @@ exit:
 
 
 static int usb_serial_device_remove (struct device *dev)
 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;
 	struct usb_serial_port *port;
 	int retval = 0;
 	int retval = 0;
 	int minor;
 	int minor;
@@ -92,43 +92,38 @@ static int usb_serial_device_remove (struct device *dev)
 
 
 	driver = port->serial->type;
 	driver = port->serial->type;
 	if (driver->port_remove) {
 	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");
 			dev_err(dev, "module get failed, exiting\n");
 			retval = -EIO;
 			retval = -EIO;
 			goto exit;
 			goto exit;
 		}
 		}
 		retval = driver->port_remove (port);
 		retval = driver->port_remove (port);
-		module_put(driver->owner);
+		module_put(driver->driver.owner);
 	}
 	}
 exit:
 exit:
 	minor = port->number;
 	minor = port->number;
 	tty_unregister_device (usb_serial_tty_driver, minor);
 	tty_unregister_device (usb_serial_tty_driver, minor);
 	dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",
 	dev_info(dev, "%s converter now disconnected from ttyUSB%d\n",
-		 driver->name, minor);
+		 driver->description, minor);
 
 
 	return retval;
 	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;
 	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;
 	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);
 }
 }
 
 

+ 6 - 4
drivers/usb/serial/cp2101.c

@@ -67,15 +67,17 @@ MODULE_DEVICE_TABLE (usb, id_table);
 
 
 static struct usb_driver cp2101_driver = {
 static struct usb_driver cp2101_driver = {
 	.owner		= THIS_MODULE,
 	.owner		= THIS_MODULE,
-	.name		= "CP2101",
+	.name		= "cp2101",
 	.probe		= usb_serial_probe,
 	.probe		= usb_serial_probe,
 	.disconnect	= usb_serial_disconnect,
 	.disconnect	= usb_serial_disconnect,
 	.id_table	= id_table,
 	.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,
 	.id_table		= id_table,
 	.num_interrupt_in	= 0,
 	.num_interrupt_in	= 0,
 	.num_bulk_in		= 0,
 	.num_bulk_in		= 0,

+ 6 - 4
drivers/usb/serial/cyberjack.c

@@ -83,10 +83,12 @@ static struct usb_driver cyberjack_driver = {
 	.id_table =	id_table,
 	.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,
 	.id_table =		id_table,
 	.num_interrupt_in =	1,
 	.num_interrupt_in =	1,
 	.num_bulk_in =		1,
 	.num_bulk_in =		1,

+ 12 - 8
drivers/usb/serial/cypress_m8.c

@@ -176,10 +176,12 @@ static unsigned int	  cypress_buf_put(struct cypress_buf *cb, const char *buf, u
 static unsigned int	  cypress_buf_get(struct cypress_buf *cb, char *buf, unsigned int count);
 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,
 	.id_table =			id_table_earthmate,
 	.num_interrupt_in = 		1,
 	.num_interrupt_in = 		1,
 	.num_interrupt_out =		1,
 	.num_interrupt_out =		1,
@@ -203,10 +205,12 @@ static struct usb_serial_device_type cypress_earthmate_device = {
 	.write_int_callback =		cypress_write_int_callback,
 	.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,
 	.id_table =			id_table_cyphidcomrs232,
 	.num_interrupt_in =		1,
 	.num_interrupt_in =		1,
 	.num_interrupt_out =		1,
 	.num_interrupt_out =		1,

+ 12 - 8
drivers/usb/serial/digi_acceleport.c

@@ -503,10 +503,12 @@ static struct usb_driver digi_driver = {
 
 
 /* device info needed for the Digi serial converter */
 /* 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,
 	.id_table =			id_table_2,
 	.num_interrupt_in =		0,
 	.num_interrupt_in =		0,
 	.num_bulk_in =			4,
 	.num_bulk_in =			4,
@@ -530,10 +532,12 @@ static struct usb_serial_device_type digi_acceleport_2_device = {
 	.shutdown =			digi_shutdown,
 	.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,
 	.id_table =			id_table_4,
 	.num_interrupt_in =		0,
 	.num_interrupt_in =		0,
 	.num_bulk_in =			5,
 	.num_bulk_in =			5,

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно