Преглед изворни кода

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

* master.kernel.org:/pub/scm/linux/kernel/git/gregkh/usb-2.6: (70 commits)
  USB: remove duplicate device id from zc0301
  USB: remove duplicate device id from usb_storage
  USB: remove duplicate device id from keyspan
  USB: remove duplicate device id from ftdi_sio
  USB: remove duplicate device id from visor
  USB: a bit more coding style cleanup
  usbcore: trivial whitespace fixes
  usb-storage: use first bulk endpoints, not last
  EHCI: fix interrupt-driven remote wakeup
  USB: switch ehci-hcd to new polling scheme
  USB: autosuspend for usb printer driver
  USB Input: Added kernel module to support all GTCO CalComp USB InterWrite School products
  USB: Sierra Wireless auto set D0
  USB: usb ethernet gadget recognizes HUSB2DEV
  USB: list atmel husb2_udc gadget controller
  USB: gadgetfs AIO tweaks
  USB: gadgetfs behaves better on userspace init bug
  USB: gadgetfs race fix
  USB: gadgetfs simplifications
  USB: gadgetfs cleanups
  ...
Linus Torvalds пре 18 година
родитељ
комит
c96e2c9207
100 измењених фајлова са 5162 додато и 1371 уклоњено
  1. 11 10
      Documentation/usb/proc_usb_info.txt
  2. 150 2
      Documentation/usb/usbmon.txt
  3. 5 0
      arch/powerpc/Kconfig
  4. 1 1
      drivers/i2c/chips/isp1301_omap.c
  5. 0 1
      drivers/media/video/zc0301/zc0301_sensor.h
  6. 1 1
      drivers/usb/atm/speedtch.c
  7. 5 11
      drivers/usb/class/usblp.c
  8. 0 13
      drivers/usb/core/Kconfig
  9. 18 18
      drivers/usb/core/buffer.c
  10. 13 9
      drivers/usb/core/devices.c
  11. 13 12
      drivers/usb/core/devio.c
  12. 19 16
      drivers/usb/core/driver.c
  13. 6 7
      drivers/usb/core/file.c
  14. 20 8
      drivers/usb/core/generic.c
  15. 0 137
      drivers/usb/core/hcd.c
  16. 0 6
      drivers/usb/core/hcd.h
  17. 21 43
      drivers/usb/core/hub.c
  18. 1 5
      drivers/usb/core/message.c
  19. 49 49
      drivers/usb/core/sysfs.c
  20. 10 11
      drivers/usb/core/urb.c
  21. 48 48
      drivers/usb/core/usb.c
  22. 12 9
      drivers/usb/gadget/at91_udc.c
  23. 1 0
      drivers/usb/gadget/at91_udc.h
  24. 1 1
      drivers/usb/gadget/config.c
  25. 1 1
      drivers/usb/gadget/epautoconf.c
  26. 108 40
      drivers/usb/gadget/ether.c
  27. 16 17
      drivers/usb/gadget/file_storage.c
  28. 8 0
      drivers/usb/gadget/gadget_chips.h
  29. 1 1
      drivers/usb/gadget/gmidi.c
  30. 1 1
      drivers/usb/gadget/goku_udc.c
  31. 105 135
      drivers/usb/gadget/inode.c
  32. 1 1
      drivers/usb/gadget/lh7a40x_udc.h
  33. 1 1
      drivers/usb/gadget/net2280.c
  34. 1 1
      drivers/usb/gadget/omap_udc.c
  35. 1 1
      drivers/usb/gadget/pxa2xx_udc.c
  36. 1 1
      drivers/usb/gadget/serial.c
  37. 1 1
      drivers/usb/gadget/usbstring.c
  38. 1 1
      drivers/usb/gadget/zero.c
  39. 35 3
      drivers/usb/host/Kconfig
  40. 12 12
      drivers/usb/host/ehci-dbg.c
  41. 4 4
      drivers/usb/host/ehci-fsl.c
  42. 83 44
      drivers/usb/host/ehci-hcd.c
  43. 226 98
      drivers/usb/host/ehci-hub.c
  44. 27 11
      drivers/usb/host/ehci-pci.c
  45. 193 0
      drivers/usb/host/ehci-ps3.c
  46. 9 7
      drivers/usb/host/ehci-q.c
  47. 11 11
      drivers/usb/host/ehci-sched.c
  48. 45 1
      drivers/usb/host/ehci.h
  49. 5 18
      drivers/usb/host/ohci-at91.c
  50. 0 16
      drivers/usb/host/ohci-au1xxx.c
  51. 0 12
      drivers/usb/host/ohci-ep93xx.c
  52. 116 12
      drivers/usb/host/ohci-hcd.c
  53. 0 16
      drivers/usb/host/ohci-lh7a404.c
  54. 0 19
      drivers/usb/host/ohci-omap.c
  55. 136 83
      drivers/usb/host/ohci-pci.c
  56. 0 12
      drivers/usb/host/ohci-pnx4008.c
  57. 0 16
      drivers/usb/host/ohci-pnx8550.c
  58. 232 0
      drivers/usb/host/ohci-ppc-of.c
  59. 1 17
      drivers/usb/host/ohci-ppc-soc.c
  60. 196 0
      drivers/usb/host/ohci-ps3.c
  61. 0 16
      drivers/usb/host/ohci-pxa27x.c
  62. 0 12
      drivers/usb/host/ohci-s3c2410.c
  63. 0 16
      drivers/usb/host/ohci-sa1111.c
  64. 103 52
      drivers/usb/host/ohci.h
  65. 62 9
      drivers/usb/host/uhci-debug.c
  66. 29 22
      drivers/usb/host/uhci-hcd.c
  67. 8 0
      drivers/usb/host/uhci-hcd.h
  68. 185 73
      drivers/usb/host/uhci-q.c
  69. 4 0
      drivers/usb/image/mdc800.c
  70. 12 0
      drivers/usb/input/Kconfig
  71. 1 0
      drivers/usb/input/Makefile
  72. 1104 0
      drivers/usb/input/gtco.c
  73. 35 0
      drivers/usb/input/hid-core.c
  74. 4 6
      drivers/usb/misc/idmouse.c
  75. 30 24
      drivers/usb/misc/rio500.c
  76. 1 1
      drivers/usb/mon/Makefile
  77. 1172 0
      drivers/usb/mon/mon_bin.c
  78. 38 1
      drivers/usb/mon/mon_dma.c
  79. 48 49
      drivers/usb/mon/mon_main.c
  80. 66 1
      drivers/usb/mon/mon_text.c
  81. 27 3
      drivers/usb/mon/usb_mon.h
  82. 4 2
      drivers/usb/net/Kconfig
  83. 58 2
      drivers/usb/net/cdc_ether.c
  84. 32 5
      drivers/usb/net/kaweth.c
  85. 62 19
      drivers/usb/net/rndis_host.c
  86. 13 8
      drivers/usb/serial/aircable.c
  87. 1 0
      drivers/usb/serial/airprime.c
  88. 2 0
      drivers/usb/serial/ark3116.c
  89. 1 0
      drivers/usb/serial/belkin_sa.c
  90. 45 0
      drivers/usb/serial/bus.c
  91. 1 0
      drivers/usb/serial/cp2101.c
  92. 2 1
      drivers/usb/serial/cyberjack.c
  93. 3 0
      drivers/usb/serial/cypress_m8.c
  94. 2 0
      drivers/usb/serial/digi_acceleport.c
  95. 1 0
      drivers/usb/serial/empeg.c
  96. 1 1
      drivers/usb/serial/ftdi_sio.c
  97. 0 1
      drivers/usb/serial/ftdi_sio.h
  98. 1 0
      drivers/usb/serial/funsoft.c
  99. 1 0
      drivers/usb/serial/garmin_gps.c
  100. 20 15
      drivers/usb/serial/generic.c

+ 11 - 10
Documentation/usb/proc_usb_info.txt

@@ -213,15 +213,16 @@ C:* #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA
 
 
 Interface descriptor info (can be multiple per Config):
 Interface descriptor info (can be multiple per Config):
 
 
-I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
-|   |      |      |       |             |      |       |__Driver name
-|   |      |      |       |             |      |          or "(none)"
-|   |      |      |       |             |      |__InterfaceProtocol
-|   |      |      |       |             |__InterfaceSubClass
-|   |      |      |       |__InterfaceClass
-|   |      |      |__NumberOfEndpoints
-|   |      |__AlternateSettingNumber
-|   |__InterfaceNumber
+I:* If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=ssss
+| | |      |      |       |             |      |       |__Driver name
+| | |      |      |       |             |      |          or "(none)"
+| | |      |      |       |             |      |__InterfaceProtocol
+| | |      |      |       |             |__InterfaceSubClass
+| | |      |      |       |__InterfaceClass
+| | |      |      |__NumberOfEndpoints
+| | |      |__AlternateSettingNumber
+| | |__InterfaceNumber
+| |__ "*" indicates the active altsetting (others are " ")
 |__Interface info tag
 |__Interface info tag
 
 
     A given interface may have one or more "alternate" settings.
     A given interface may have one or more "alternate" settings.
@@ -277,7 +278,7 @@ of the USB devices on a system's root hub.  (See more below
 on how to do this.)
 on how to do this.)
 
 
 The Interface lines can be used to determine what driver is
 The Interface lines can be used to determine what driver is
-being used for each device.
+being used for each device, and which altsetting it activated.
 
 
 The Configuration lines could be used to list maximum power
 The Configuration lines could be used to list maximum power
 (in milliamps) that a system's USB devices are using.
 (in milliamps) that a system's USB devices are using.

+ 150 - 2
Documentation/usb/usbmon.txt

@@ -77,7 +77,7 @@ that the file size is not excessive for your favourite editor.
 
 
 The '1t' type data consists of a stream of events, such as URB submission,
 The '1t' type data consists of a stream of events, such as URB submission,
 URB callback, submission error. Every event is a text line, which consists
 URB callback, submission error. Every event is a text line, which consists
-of whitespace separated words. The number of position of words may depend
+of whitespace separated words. The number or position of words may depend
 on the event type, but there is a set of words, common for all types.
 on the event type, but there is a set of words, common for all types.
 
 
 Here is the list of words, from left to right:
 Here is the list of words, from left to right:
@@ -170,4 +170,152 @@ dd65f0e8 4128379808 C Bo:005:02 0 31 >
 
 
 * Raw binary format and API
 * Raw binary format and API
 
 
-TBD
+The overall architecture of the API is about the same as the one above,
+only the events are delivered in binary format. Each event is sent in
+the following structure (its name is made up, so that we can refer to it):
+
+struct usbmon_packet {
+	u64 id;			/*  0: URB ID - from submission to callback */
+	unsigned char type;	/*  8: Same as text; extensible. */
+	unsigned char xfer_type; /*    ISO (0), Intr, Control, Bulk (3) */
+	unsigned char epnum;	/*     Endpoint number and transfer direction */
+	unsigned char devnum;	/*     Device address */
+	u16 busnum;		/* 12: Bus number */
+	char flag_setup;	/* 14: Same as text */
+	char flag_data;		/* 15: Same as text; Binary zero is OK. */
+	s64 ts_sec;		/* 16: gettimeofday */
+	s32 ts_usec;		/* 24: gettimeofday */
+	int status;		/* 28: */
+	unsigned int length;	/* 32: Length of data (submitted or actual) */
+	unsigned int len_cap;	/* 36: Delivered length */
+	unsigned char setup[8];	/* 40: Only for Control 'S' */
+};				/* 48 bytes total */
+
+These events can be received from a character device by reading with read(2),
+with an ioctl(2), or by accessing the buffer with mmap.
+
+The character device is usually called /dev/usbmonN, where N is the USB bus
+number. Number zero (/dev/usbmon0) is special and means "all buses".
+However, this feature is not implemented yet. Note that specific naming
+policy is set by your Linux distribution.
+
+If you create /dev/usbmon0 by hand, make sure that it is owned by root
+and has mode 0600. Otherwise, unpriviledged users will be able to snoop
+keyboard traffic.
+
+The following ioctl calls are available, with MON_IOC_MAGIC 0x92:
+
+ MON_IOCQ_URB_LEN, defined as _IO(MON_IOC_MAGIC, 1)
+
+This call returns the length of data in the next event. Note that majority of
+events contain no data, so if this call returns zero, it does not mean that
+no events are available.
+
+ MON_IOCG_STATS, defined as _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)
+
+The argument is a pointer to the following structure:
+
+struct mon_bin_stats {
+	u32 queued;
+	u32 dropped;
+};
+
+The member "queued" refers to the number of events currently queued in the
+buffer (and not to the number of events processed since the last reset).
+
+The member "dropped" is the number of events lost since the last call
+to MON_IOCG_STATS.
+
+ MON_IOCT_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 4)
+
+This call sets the buffer size. The argument is the size in bytes.
+The size may be rounded down to the next chunk (or page). If the requested
+size is out of [unspecified] bounds for this kernel, the call fails with
+-EINVAL.
+
+ MON_IOCQ_RING_SIZE, defined as _IO(MON_IOC_MAGIC, 5)
+
+This call returns the current size of the buffer in bytes.
+
+ MON_IOCX_GET, defined as _IOW(MON_IOC_MAGIC, 6, struct mon_get_arg)
+
+This call waits for events to arrive if none were in the kernel buffer,
+then returns the first event. Its argument is a pointer to the following
+structure:
+
+struct mon_get_arg {
+	struct usbmon_packet *hdr;
+	void *data;
+	size_t alloc;		/* Length of data (can be zero) */
+};
+
+Before the call, hdr, data, and alloc should be filled. Upon return, the area
+pointed by hdr contains the next event structure, and the data buffer contains
+the data, if any. The event is removed from the kernel buffer.
+
+ MON_IOCX_MFETCH, defined as _IOWR(MON_IOC_MAGIC, 7, struct mon_mfetch_arg)
+
+This ioctl is primarily used when the application accesses the buffer
+with mmap(2). Its argument is a pointer to the following structure:
+
+struct mon_mfetch_arg {
+	uint32_t *offvec;	/* Vector of events fetched */
+	uint32_t nfetch;	/* Number of events to fetch (out: fetched) */
+	uint32_t nflush;	/* Number of events to flush */
+};
+
+The ioctl operates in 3 stages.
+
+First, it removes and discards up to nflush events from the kernel buffer.
+The actual number of events discarded is returned in nflush.
+
+Second, it waits for an event to be present in the buffer, unless the pseudo-
+device is open with O_NONBLOCK.
+
+Third, it extracts up to nfetch offsets into the mmap buffer, and stores
+them into the offvec. The actual number of event offsets is stored into
+the nfetch.
+
+ MON_IOCH_MFLUSH, defined as _IO(MON_IOC_MAGIC, 8)
+
+This call removes a number of events from the kernel buffer. Its argument
+is the number of events to remove. If the buffer contains fewer events
+than requested, all events present are removed, and no error is reported.
+This works when no events are available too.
+
+ FIONBIO
+
+The ioctl FIONBIO may be implemented in the future, if there's a need.
+
+In addition to ioctl(2) and read(2), the special file of binary API can
+be polled with select(2) and poll(2). But lseek(2) does not work.
+
+* Memory-mapped access of the kernel buffer for the binary API
+
+The basic idea is simple:
+
+To prepare, map the buffer by getting the current size, then using mmap(2).
+Then, execute a loop similar to the one written in pseudo-code below:
+
+   struct mon_mfetch_arg fetch;
+   struct usbmon_packet *hdr;
+   int nflush = 0;
+   for (;;) {
+      fetch.offvec = vec; // Has N 32-bit words
+      fetch.nfetch = N;   // Or less than N
+      fetch.nflush = nflush;
+      ioctl(fd, MON_IOCX_MFETCH, &fetch);   // Process errors, too
+      nflush = fetch.nfetch;       // This many packets to flush when done
+      for (i = 0; i < nflush; i++) {
+         hdr = (struct ubsmon_packet *) &mmap_area[vec[i]];
+         if (hdr->type == '@')     // Filler packet
+            continue;
+         caddr_t data = &mmap_area[vec[i]] + 64;
+         process_packet(hdr, data);
+      }
+   }
+
+Thus, the main idea is to execute only one ioctl per N events.
+
+Although the buffer is circular, the returned headers and data do not cross
+the end of the buffer, so the above pseudo-code does not need any gathering.

+ 5 - 0
arch/powerpc/Kconfig

@@ -529,6 +529,11 @@ config PPC_PS3
 	bool "Sony PS3 (incomplete)"
 	bool "Sony PS3 (incomplete)"
 	depends on PPC_MULTIPLATFORM && PPC64
 	depends on PPC_MULTIPLATFORM && PPC64
 	select PPC_CELL
 	select PPC_CELL
+	select USB_ARCH_HAS_OHCI
+	select USB_OHCI_LITTLE_ENDIAN
+	select USB_OHCI_BIG_ENDIAN_MMIO
+	select USB_ARCH_HAS_EHCI
+	select USB_EHCI_BIG_ENDIAN_MMIO
 	help
 	help
 	  This option enables support for the Sony PS3 game console
 	  This option enables support for the Sony PS3 game console
 	  and other platforms using the PS3 hypervisor.
 	  and other platforms using the PS3 hypervisor.

+ 1 - 1
drivers/i2c/chips/isp1301_omap.c

@@ -27,7 +27,7 @@
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/otg.h>

+ 0 - 1
drivers/media/video/zc0301/zc0301_sensor.h

@@ -75,7 +75,6 @@ static const struct usb_device_id zc0301_id_table[] =  {                      \
 	{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
 	{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
 	{ ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */           \
 	{ ZC0301_USB_DEVICE(0x055f, 0xd003, 0xff), }, /* TAS5130 */           \
 	{ ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */           \
 	{ ZC0301_USB_DEVICE(0x055f, 0xd004, 0xff), }, /* TAS5130 */           \
-	{ ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */            \
 	{ ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), },                         \
 	{ ZC0301_USB_DEVICE(0x0ac8, 0x0301, 0xff), },                         \
 	{ ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */    \
 	{ ZC0301_USB_DEVICE(0x0ac8, 0x301b, 0xff), }, /* PB-0330/HV7131 */    \
 	{ ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */           \
 	{ ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */           \

+ 1 - 1
drivers/usb/atm/speedtch.c

@@ -36,7 +36,7 @@
 #include <linux/stat.h>
 #include <linux/stat.h>
 #include <linux/timer.h>
 #include <linux/timer.h>
 #include <linux/types.h>
 #include <linux/types.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/workqueue.h>
 #include <linux/workqueue.h>
 
 
 #include "usbatm.h"
 #include "usbatm.h"

+ 5 - 11
drivers/usb/class/usblp.c

@@ -398,6 +398,9 @@ static int usblp_open(struct inode *inode, struct file *file)
 	retval = 0;
 	retval = 0;
 #endif
 #endif
 
 
+	retval = usb_autopm_get_interface(intf);
+	if (retval < 0)
+		goto out;
 	usblp->used = 1;
 	usblp->used = 1;
 	file->private_data = usblp;
 	file->private_data = usblp;
 
 
@@ -442,6 +445,7 @@ static int usblp_release(struct inode *inode, struct file *file)
 	usblp->used = 0;
 	usblp->used = 0;
 	if (usblp->present) {
 	if (usblp->present) {
 		usblp_unlink_urbs(usblp);
 		usblp_unlink_urbs(usblp);
+		usb_autopm_put_interface(usblp->intf);
 	} else 		/* finish cleanup from disconnect */
 	} else 		/* finish cleanup from disconnect */
 		usblp_cleanup (usblp);
 		usblp_cleanup (usblp);
 	mutex_unlock (&usblp_mutex);
 	mutex_unlock (&usblp_mutex);
@@ -1203,14 +1207,9 @@ static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
 {
 {
 	struct usblp *usblp = usb_get_intfdata (intf);
 	struct usblp *usblp = usb_get_intfdata (intf);
 
 
-	/* this races against normal access and open */
-	mutex_lock (&usblp_mutex);
-	mutex_lock (&usblp->mut);
 	/* we take no more IO */
 	/* we take no more IO */
 	usblp->sleeping = 1;
 	usblp->sleeping = 1;
 	usblp_unlink_urbs(usblp);
 	usblp_unlink_urbs(usblp);
-	mutex_unlock (&usblp->mut);
-	mutex_unlock (&usblp_mutex);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1220,15 +1219,9 @@ static int usblp_resume (struct usb_interface *intf)
 	struct usblp *usblp = usb_get_intfdata (intf);
 	struct usblp *usblp = usb_get_intfdata (intf);
 	int r;
 	int r;
 
 
-	mutex_lock (&usblp_mutex);
-	mutex_lock (&usblp->mut);
-
 	usblp->sleeping = 0;
 	usblp->sleeping = 0;
 	r = handle_bidir (usblp);
 	r = handle_bidir (usblp);
 
 
-	mutex_unlock (&usblp->mut);
-	mutex_unlock (&usblp_mutex);
-
 	return r;
 	return r;
 }
 }
 
 
@@ -1251,6 +1244,7 @@ static struct usb_driver usblp_driver = {
 	.suspend =	usblp_suspend,
 	.suspend =	usblp_suspend,
 	.resume =	usblp_resume,
 	.resume =	usblp_resume,
 	.id_table =	usblp_ids,
 	.id_table =	usblp_ids,
+	.supports_autosuspend =	1,
 };
 };
 
 
 static int __init usblp_init(void)
 static int __init usblp_init(void)

+ 0 - 13
drivers/usb/core/Kconfig

@@ -33,19 +33,6 @@ config USB_DEVICEFS
 
 
 	  Most users want to say Y here.
 	  Most users want to say Y here.
 
 
-config USB_BANDWIDTH
-	bool "Enforce USB bandwidth allocation (EXPERIMENTAL)"
-	depends on USB && EXPERIMENTAL
-	help
-	  If you say Y here, the USB subsystem enforces USB bandwidth
-	  allocation and will prevent some device opens from succeeding
-	  if they would cause USB bandwidth usage to go above 90% of
-	  the bus bandwidth.
-
-	  If you say N here, these conditions will cause warning messages
-	  about USB bandwidth usage to be logged and some devices or
-	  drivers may not work correctly.
-
 config USB_DYNAMIC_MINORS
 config USB_DYNAMIC_MINORS
 	bool "Dynamic USB minor allocation (EXPERIMENTAL)"
 	bool "Dynamic USB minor allocation (EXPERIMENTAL)"
 	depends on USB && EXPERIMENTAL
 	depends on USB && EXPERIMENTAL

+ 18 - 18
drivers/usb/core/buffer.c

@@ -49,9 +49,9 @@ static const size_t	pool_max [HCD_BUFFER_POOLS] = {
  *
  *
  * Call hcd_buffer_destroy() to clean up after using those pools.
  * Call hcd_buffer_destroy() to clean up after using those pools.
  */
  */
-int hcd_buffer_create (struct usb_hcd *hcd)
+int hcd_buffer_create(struct usb_hcd *hcd)
 {
 {
-	char		name [16];
+	char		name[16];
 	int 		i, size;
 	int 		i, size;
 
 
 	if (!hcd->self.controller->dma_mask)
 	if (!hcd->self.controller->dma_mask)
@@ -60,11 +60,11 @@ int hcd_buffer_create (struct usb_hcd *hcd)
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) { 
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) { 
 		if (!(size = pool_max [i]))
 		if (!(size = pool_max [i]))
 			continue;
 			continue;
-		snprintf (name, sizeof name, "buffer-%d", size);
-		hcd->pool [i] = dma_pool_create (name, hcd->self.controller,
+		snprintf(name, sizeof name, "buffer-%d", size);
+		hcd->pool[i] = dma_pool_create(name, hcd->self.controller,
 				size, size, 0);
 				size, size, 0);
 		if (!hcd->pool [i]) {
 		if (!hcd->pool [i]) {
-			hcd_buffer_destroy (hcd);
+			hcd_buffer_destroy(hcd);
 			return -ENOMEM;
 			return -ENOMEM;
 		}
 		}
 	}
 	}
@@ -79,14 +79,14 @@ int hcd_buffer_create (struct usb_hcd *hcd)
  *
  *
  * This frees the buffer pools created by hcd_buffer_create().
  * This frees the buffer pools created by hcd_buffer_create().
  */
  */
-void hcd_buffer_destroy (struct usb_hcd *hcd)
+void hcd_buffer_destroy(struct usb_hcd *hcd)
 {
 {
 	int		i;
 	int		i;
 
 
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) { 
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) { 
-		struct dma_pool		*pool = hcd->pool [i];
+		struct dma_pool		*pool = hcd->pool[i];
 		if (pool) {
 		if (pool) {
-			dma_pool_destroy (pool);
+			dma_pool_destroy(pool);
 			hcd->pool[i] = NULL;
 			hcd->pool[i] = NULL;
 		}
 		}
 	}
 	}
@@ -97,8 +97,8 @@ void hcd_buffer_destroy (struct usb_hcd *hcd)
  * better sharing and to leverage mm/slab.c intelligence.
  * better sharing and to leverage mm/slab.c intelligence.
  */
  */
 
 
-void *hcd_buffer_alloc (
-	struct usb_bus 		*bus,
+void *hcd_buffer_alloc(
+	struct usb_bus 	*bus,
 	size_t			size,
 	size_t			size,
 	gfp_t			mem_flags,
 	gfp_t			mem_flags,
 	dma_addr_t		*dma
 	dma_addr_t		*dma
@@ -110,18 +110,18 @@ void *hcd_buffer_alloc (
 	/* some USB hosts just use PIO */
 	/* some USB hosts just use PIO */
 	if (!bus->controller->dma_mask) {
 	if (!bus->controller->dma_mask) {
 		*dma = ~(dma_addr_t) 0;
 		*dma = ~(dma_addr_t) 0;
-		return kmalloc (size, mem_flags);
+		return kmalloc(size, mem_flags);
 	}
 	}
 
 
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
 		if (size <= pool_max [i])
 		if (size <= pool_max [i])
-			return dma_pool_alloc (hcd->pool [i], mem_flags, dma);
+			return dma_pool_alloc(hcd->pool [i], mem_flags, dma);
 	}
 	}
-	return dma_alloc_coherent (hcd->self.controller, size, dma, 0);
+	return dma_alloc_coherent(hcd->self.controller, size, dma, 0);
 }
 }
 
 
-void hcd_buffer_free (
-	struct usb_bus 		*bus,
+void hcd_buffer_free(
+	struct usb_bus 	*bus,
 	size_t			size,
 	size_t			size,
 	void 			*addr,
 	void 			*addr,
 	dma_addr_t		dma
 	dma_addr_t		dma
@@ -134,15 +134,15 @@ void hcd_buffer_free (
 		return;
 		return;
 
 
 	if (!bus->controller->dma_mask) {
 	if (!bus->controller->dma_mask) {
-		kfree (addr);
+		kfree(addr);
 		return;
 		return;
 	}
 	}
 
 
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
 	for (i = 0; i < HCD_BUFFER_POOLS; i++) {
 		if (size <= pool_max [i]) {
 		if (size <= pool_max [i]) {
-			dma_pool_free (hcd->pool [i], addr, dma);
+			dma_pool_free(hcd->pool [i], addr, dma);
 			return;
 			return;
 		}
 		}
 	}
 	}
-	dma_free_coherent (hcd->self.controller, size, addr, dma);
+	dma_free_coherent(hcd->self.controller, size, addr, dma);
 }
 }

+ 13 - 9
drivers/usb/core/devices.c

@@ -104,7 +104,7 @@ static const char *format_config =
   
   
 static const char *format_iface =
 static const char *format_iface =
 /* I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
 /* I:  If#=dd Alt=dd #EPs=dd Cls=xx(sssss) Sub=xx Prot=xx Driver=xxxx*/
-  "I:  If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
+  "I:%c If#=%2d Alt=%2d #EPs=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x Driver=%s\n";
 
 
 static const char *format_endpt =
 static const char *format_endpt =
 /* E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
 /* E:  Ad=xx(s) Atr=xx(ssss) MxPS=dddd Ivl=D?s */
@@ -164,10 +164,10 @@ static const char *class_decode(const int class)
 	for (ix = 0; clas_info[ix].class != -1; ix++)
 	for (ix = 0; clas_info[ix].class != -1; ix++)
 		if (clas_info[ix].class == class)
 		if (clas_info[ix].class == class)
 			break;
 			break;
-	return (clas_info[ix].class_name);
+	return clas_info[ix].class_name;
 }
 }
 
 
-static char *usb_dump_endpoint_descriptor (
+static char *usb_dump_endpoint_descriptor(
 	int speed,
 	int speed,
 	char *start,
 	char *start,
 	char *end,
 	char *end,
@@ -212,9 +212,9 @@ static char *usb_dump_endpoint_descriptor (
 		break;
 		break;
 	case USB_ENDPOINT_XFER_INT:
 	case USB_ENDPOINT_XFER_INT:
 		type = "Int.";
 		type = "Int.";
-		if (speed == USB_SPEED_HIGH) {
+		if (speed == USB_SPEED_HIGH)
 			interval = 1 << (desc->bInterval - 1);
 			interval = 1 << (desc->bInterval - 1);
-		} else
+		else
 			interval = desc->bInterval;
 			interval = desc->bInterval;
 		break;
 		break;
 	default:	/* "can't happen" */
 	default:	/* "can't happen" */
@@ -242,15 +242,19 @@ static char *usb_dump_interface_descriptor(char *start, char *end,
 {
 {
 	const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc;
 	const struct usb_interface_descriptor *desc = &intfc->altsetting[setno].desc;
 	const char *driver_name = "";
 	const char *driver_name = "";
+	int active = 0;
 
 
 	if (start > end)
 	if (start > end)
 		return start;
 		return start;
 	down_read(&usb_bus_type.subsys.rwsem);
 	down_read(&usb_bus_type.subsys.rwsem);
-	if (iface)
+	if (iface) {
 		driver_name = (iface->dev.driver
 		driver_name = (iface->dev.driver
 				? iface->dev.driver->name
 				? iface->dev.driver->name
 				: "(none)");
 				: "(none)");
+		active = (desc == &iface->cur_altsetting->desc);
+	}
 	start += sprintf(start, format_iface,
 	start += sprintf(start, format_iface,
+			 active ? '*' : ' ',	/* mark active altsetting */
 			 desc->bInterfaceNumber,
 			 desc->bInterfaceNumber,
 			 desc->bAlternateSetting,
 			 desc->bAlternateSetting,
 			 desc->bNumEndpoints,
 			 desc->bNumEndpoints,
@@ -343,7 +347,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb
 
 
 	if (start > end)
 	if (start > end)
 		return start;
 		return start;
-	start += sprintf (start, format_device1,
+	start += sprintf(start, format_device1,
 			  bcdUSB >> 8, bcdUSB & 0xff,
 			  bcdUSB >> 8, bcdUSB & 0xff,
 			  desc->bDeviceClass,
 			  desc->bDeviceClass,
 			  class_decode (desc->bDeviceClass),
 			  class_decode (desc->bDeviceClass),
@@ -363,7 +367,7 @@ static char *usb_dump_device_descriptor(char *start, char *end, const struct usb
 /*
 /*
  * Dump the different strings that this device holds.
  * Dump the different strings that this device holds.
  */
  */
-static char *usb_dump_device_strings (char *start, char *end, struct usb_device *dev)
+static char *usb_dump_device_strings(char *start, char *end, struct usb_device *dev)
 {
 {
 	if (start > end)
 	if (start > end)
 		return start;
 		return start;
@@ -395,7 +399,7 @@ static char *usb_dump_desc(char *start, char *end, struct usb_device *dev)
 	if (start > end)
 	if (start > end)
 		return start;
 		return start;
 	
 	
-	start = usb_dump_device_strings (start, end, dev);
+	start = usb_dump_device_strings(start, end, dev);
 
 
 	for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
 	for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
 		if (start > end)
 		if (start > end)

+ 13 - 12
drivers/usb/core/devio.c

@@ -522,19 +522,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype, unsig
 
 
 static struct usb_device *usbdev_lookup_minor(int minor)
 static struct usb_device *usbdev_lookup_minor(int minor)
 {
 {
-	struct class_device *class_dev;
-	struct usb_device *dev = NULL;
+	struct device *device;
+	struct usb_device *udev = NULL;
 
 
 	down(&usb_device_class->sem);
 	down(&usb_device_class->sem);
-	list_for_each_entry(class_dev, &usb_device_class->children, node) {
-		if (class_dev->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
-			dev = class_dev->class_data;
+	list_for_each_entry(device, &usb_device_class->devices, node) {
+		if (device->devt == MKDEV(USB_DEVICE_MAJOR, minor)) {
+			udev = device->platform_data;
 			break;
 			break;
 		}
 		}
 	}
 	}
 	up(&usb_device_class->sem);
 	up(&usb_device_class->sem);
 
 
-	return dev;
+	return udev;
 };
 };
 
 
 /*
 /*
@@ -570,6 +570,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
 	ps->dev = dev;
 	ps->dev = dev;
 	ps->file = file;
 	ps->file = file;
 	spin_lock_init(&ps->lock);
 	spin_lock_init(&ps->lock);
+	INIT_LIST_HEAD(&ps->list);
 	INIT_LIST_HEAD(&ps->async_pending);
 	INIT_LIST_HEAD(&ps->async_pending);
 	INIT_LIST_HEAD(&ps->async_completed);
 	INIT_LIST_HEAD(&ps->async_completed);
 	init_waitqueue_head(&ps->wait);
 	init_waitqueue_head(&ps->wait);
@@ -1596,19 +1597,19 @@ static int 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);
 
 
-	dev->class_dev = class_device_create(usb_device_class, NULL,
-				MKDEV(USB_DEVICE_MAJOR, minor), &dev->dev,
+	dev->usbfs_dev = device_create(usb_device_class, &dev->dev,
+				MKDEV(USB_DEVICE_MAJOR, minor),
 				"usbdev%d.%d", dev->bus->busnum, dev->devnum);
 				"usbdev%d.%d", dev->bus->busnum, dev->devnum);
-	if (IS_ERR(dev->class_dev))
-		return PTR_ERR(dev->class_dev);
+	if (IS_ERR(dev->usbfs_dev))
+		return PTR_ERR(dev->usbfs_dev);
 
 
-	dev->class_dev->class_data = dev;
+	dev->usbfs_dev->platform_data = dev;
 	return 0;
 	return 0;
 }
 }
 
 
 static void usbdev_remove(struct usb_device *dev)
 static void usbdev_remove(struct usb_device *dev)
 {
 {
-	class_device_unregister(dev->class_dev);
+	device_unregister(dev->usbfs_dev);
 }
 }
 
 
 static int usbdev_notify(struct notifier_block *self, unsigned long action,
 static int usbdev_notify(struct notifier_block *self, unsigned long action,

+ 19 - 16
drivers/usb/core/driver.c

@@ -28,24 +28,16 @@
 #include "hcd.h"
 #include "hcd.h"
 #include "usb.h"
 #include "usb.h"
 
 
-static int usb_match_one_id(struct usb_interface *interface,
-			    const struct usb_device_id *id);
-
-struct usb_dynid {
-	struct list_head node;
-	struct usb_device_id id;
-};
-
 #ifdef CONFIG_HOTPLUG
 #ifdef CONFIG_HOTPLUG
 
 
 /*
 /*
  * Adds a new dynamic USBdevice ID to this driver,
  * Adds a new dynamic USBdevice ID to this driver,
  * and cause the driver to probe for all devices again.
  * and cause the driver to probe for all devices again.
  */
  */
-static ssize_t store_new_id(struct device_driver *driver,
-			    const char *buf, size_t count)
+ssize_t usb_store_new_id(struct usb_dynids *dynids,
+			 struct device_driver *driver,
+			 const char *buf, size_t count)
 {
 {
-	struct usb_driver *usb_drv = to_usb_driver(driver);
 	struct usb_dynid *dynid;
 	struct usb_dynid *dynid;
 	u32 idVendor = 0;
 	u32 idVendor = 0;
 	u32 idProduct = 0;
 	u32 idProduct = 0;
@@ -65,9 +57,9 @@ static ssize_t store_new_id(struct device_driver *driver,
 	dynid->id.idProduct = idProduct;
 	dynid->id.idProduct = idProduct;
 	dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
 	dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
 
 
-	spin_lock(&usb_drv->dynids.lock);
-	list_add_tail(&usb_drv->dynids.list, &dynid->node);
-	spin_unlock(&usb_drv->dynids.lock);
+	spin_lock(&dynids->lock);
+	list_add_tail(&dynids->list, &dynid->node);
+	spin_unlock(&dynids->lock);
 
 
 	if (get_driver(driver)) {
 	if (get_driver(driver)) {
 		retval = driver_attach(driver);
 		retval = driver_attach(driver);
@@ -78,6 +70,15 @@ static ssize_t store_new_id(struct device_driver *driver,
 		return retval;
 		return retval;
 	return count;
 	return count;
 }
 }
+EXPORT_SYMBOL_GPL(usb_store_new_id);
+
+static ssize_t store_new_id(struct device_driver *driver,
+			    const char *buf, size_t count)
+{
+	struct usb_driver *usb_drv = to_usb_driver(driver);
+
+	return usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+}
 static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
 static DRIVER_ATTR(new_id, S_IWUSR, NULL, store_new_id);
 
 
 static int usb_create_newid_file(struct usb_driver *usb_drv)
 static int usb_create_newid_file(struct usb_driver *usb_drv)
@@ -365,8 +366,8 @@ void usb_driver_release_interface(struct usb_driver *driver,
 EXPORT_SYMBOL(usb_driver_release_interface);
 EXPORT_SYMBOL(usb_driver_release_interface);
 
 
 /* returns 0 if no match, 1 if match */
 /* returns 0 if no match, 1 if match */
-static int usb_match_one_id(struct usb_interface *interface,
-			    const struct usb_device_id *id)
+int usb_match_one_id(struct usb_interface *interface,
+		     const struct usb_device_id *id)
 {
 {
 	struct usb_host_interface *intf;
 	struct usb_host_interface *intf;
 	struct usb_device *dev;
 	struct usb_device *dev;
@@ -432,6 +433,8 @@ static int usb_match_one_id(struct usb_interface *interface,
 
 
 	return 1;
 	return 1;
 }
 }
+EXPORT_SYMBOL_GPL(usb_match_one_id);
+
 /**
 /**
  * usb_match_id - find first usb_device_id matching device or interface
  * usb_match_id - find first usb_device_id matching device or interface
  * @interface: the interface of interest
  * @interface: the interface of interest

+ 6 - 7
drivers/usb/core/file.c

@@ -194,14 +194,13 @@ int usb_register_dev(struct usb_interface *intf,
 		++temp;
 		++temp;
 	else
 	else
 		temp = name;
 		temp = name;
-	intf->class_dev = class_device_create(usb_class->class, NULL,
-					      MKDEV(USB_MAJOR, minor),
-					      &intf->dev, "%s", temp);
-	if (IS_ERR(intf->class_dev)) {
+	intf->usb_dev = device_create(usb_class->class, &intf->dev,
+				      MKDEV(USB_MAJOR, minor), "%s", temp);
+	if (IS_ERR(intf->usb_dev)) {
 		spin_lock (&minor_lock);
 		spin_lock (&minor_lock);
 		usb_minors[intf->minor] = NULL;
 		usb_minors[intf->minor] = NULL;
 		spin_unlock (&minor_lock);
 		spin_unlock (&minor_lock);
-		retval = PTR_ERR(intf->class_dev);
+		retval = PTR_ERR(intf->usb_dev);
 	}
 	}
 exit:
 exit:
 	return retval;
 	return retval;
@@ -242,8 +241,8 @@ 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);
-	class_device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
-	intf->class_dev = NULL;
+	device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
+	intf->usb_dev = NULL;
 	intf->minor = -1;
 	intf->minor = -1;
 	destroy_usb_class();
 	destroy_usb_class();
 }
 }

+ 20 - 8
drivers/usb/core/generic.c

@@ -25,6 +25,20 @@ static inline const char *plural(int n)
 	return (n == 1 ? "" : "s");
 	return (n == 1 ? "" : "s");
 }
 }
 
 
+static int is_rndis(struct usb_interface_descriptor *desc)
+{
+	return desc->bInterfaceClass == USB_CLASS_COMM
+		&& desc->bInterfaceSubClass == 2
+		&& desc->bInterfaceProtocol == 0xff;
+}
+
+static int is_activesync(struct usb_interface_descriptor *desc)
+{
+	return desc->bInterfaceClass == USB_CLASS_MISC
+		&& desc->bInterfaceSubClass == 1
+		&& desc->bInterfaceProtocol == 1;
+}
+
 static int choose_configuration(struct usb_device *udev)
 static int choose_configuration(struct usb_device *udev)
 {
 {
 	int i;
 	int i;
@@ -87,14 +101,12 @@ static int choose_configuration(struct usb_device *udev)
 			continue;
 			continue;
 		}
 		}
 
 
-		/* If the first config's first interface is COMM/2/0xff
-		 * (MSFT RNDIS), rule it out unless Linux has host-side
-		 * RNDIS support. */
-		if (i == 0 && desc
-				&& desc->bInterfaceClass == USB_CLASS_COMM
-				&& desc->bInterfaceSubClass == 2
-				&& desc->bInterfaceProtocol == 0xff) {
-#ifndef CONFIG_USB_NET_RNDIS_HOST
+		/* When the first config's first interface is one of Microsoft's
+		 * pet nonstandard Ethernet-over-USB protocols, ignore it unless
+		 * this kernel has enabled the necessary host side driver.
+		 */
+		if (i == 0 && desc && (is_rndis(desc) || is_activesync(desc))) {
+#if !defined(CONFIG_USB_NET_RNDIS_HOST) && !defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
 			continue;
 			continue;
 #else
 #else
 			best = c;
 			best = c;

+ 0 - 137
drivers/usb/core/hcd.c

@@ -45,8 +45,6 @@
 #include "hub.h"
 #include "hub.h"
 
 
 
 
-// #define USB_BANDWIDTH_MESSAGES
-
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 /*
 /*
@@ -891,136 +889,6 @@ long usb_calc_bus_time (int speed, int is_input, int isoc, int bytecount)
 }
 }
 EXPORT_SYMBOL (usb_calc_bus_time);
 EXPORT_SYMBOL (usb_calc_bus_time);
 
 
-/*
- * usb_check_bandwidth():
- *
- * old_alloc is from host_controller->bandwidth_allocated in microseconds;
- * bustime is from calc_bus_time(), but converted to microseconds.
- *
- * returns <bustime in us> if successful,
- * or -ENOSPC if bandwidth request fails.
- *
- * FIXME:
- * This initial implementation does not use Endpoint.bInterval
- * in managing bandwidth allocation.
- * It probably needs to be expanded to use Endpoint.bInterval.
- * This can be done as a later enhancement (correction).
- *
- * This will also probably require some kind of
- * frame allocation tracking...meaning, for example,
- * that if multiple drivers request interrupts every 10 USB frames,
- * they don't all have to be allocated at
- * frame numbers N, N+10, N+20, etc.  Some of them could be at
- * N+11, N+21, N+31, etc., and others at
- * N+12, N+22, N+32, etc.
- *
- * Similarly for isochronous transfers...
- *
- * Individual HCDs can schedule more directly ... this logic
- * is not correct for high speed transfers.
- */
-int usb_check_bandwidth (struct usb_device *dev, struct urb *urb)
-{
-	unsigned int	pipe = urb->pipe;
-	long		bustime;
-	int		is_in = usb_pipein (pipe);
-	int		is_iso = usb_pipeisoc (pipe);
-	int		old_alloc = dev->bus->bandwidth_allocated;
-	int		new_alloc;
-
-
-	bustime = NS_TO_US (usb_calc_bus_time (dev->speed, is_in, is_iso,
-			usb_maxpacket (dev, pipe, !is_in)));
-	if (is_iso)
-		bustime /= urb->number_of_packets;
-
-	new_alloc = old_alloc + (int) bustime;
-	if (new_alloc > FRAME_TIME_MAX_USECS_ALLOC) {
-#ifdef	DEBUG
-		char	*mode = 
-#ifdef CONFIG_USB_BANDWIDTH
-			"";
-#else
-			"would have ";
-#endif
-		dev_dbg (&dev->dev, "usb_check_bandwidth %sFAILED: %d + %ld = %d usec\n",
-			mode, old_alloc, bustime, new_alloc);
-#endif
-#ifdef CONFIG_USB_BANDWIDTH
-		bustime = -ENOSPC;	/* report error */
-#endif
-	}
-
-	return bustime;
-}
-EXPORT_SYMBOL (usb_check_bandwidth);
-
-
-/**
- * usb_claim_bandwidth - records bandwidth for a periodic transfer
- * @dev: source/target of request
- * @urb: request (urb->dev == dev)
- * @bustime: bandwidth consumed, in (average) microseconds per frame
- * @isoc: true iff the request is isochronous
- *
- * Bus bandwidth reservations are recorded purely for diagnostic purposes.
- * HCDs are expected not to overcommit periodic bandwidth, and to record such
- * reservations whenever endpoints are added to the periodic schedule.
- *
- * FIXME averaging per-frame is suboptimal.  Better to sum over the HCD's
- * entire periodic schedule ... 32 frames for OHCI, 1024 for UHCI, settable
- * for EHCI (256/512/1024 frames, default 1024) and have the bus expose how
- * large its periodic schedule is.
- */
-void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb, int bustime, int isoc)
-{
-	dev->bus->bandwidth_allocated += bustime;
-	if (isoc)
-		dev->bus->bandwidth_isoc_reqs++;
-	else
-		dev->bus->bandwidth_int_reqs++;
-	urb->bandwidth = bustime;
-
-#ifdef USB_BANDWIDTH_MESSAGES
-	dev_dbg (&dev->dev, "bandwidth alloc increased by %d (%s) to %d for %d requesters\n",
-		bustime,
-		isoc ? "ISOC" : "INTR",
-		dev->bus->bandwidth_allocated,
-		dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
-#endif
-}
-EXPORT_SYMBOL (usb_claim_bandwidth);
-
-
-/**
- * usb_release_bandwidth - reverses effect of usb_claim_bandwidth()
- * @dev: source/target of request
- * @urb: request (urb->dev == dev)
- * @isoc: true iff the request is isochronous
- *
- * This records that previously allocated bandwidth has been released.
- * Bandwidth is released when endpoints are removed from the host controller's
- * periodic schedule.
- */
-void usb_release_bandwidth (struct usb_device *dev, struct urb *urb, int isoc)
-{
-	dev->bus->bandwidth_allocated -= urb->bandwidth;
-	if (isoc)
-		dev->bus->bandwidth_isoc_reqs--;
-	else
-		dev->bus->bandwidth_int_reqs--;
-
-#ifdef USB_BANDWIDTH_MESSAGES
-	dev_dbg (&dev->dev, "bandwidth alloc reduced by %d (%s) to %d for %d requesters\n",
-		urb->bandwidth,
-		isoc ? "ISOC" : "INTR",
-		dev->bus->bandwidth_allocated,
-		dev->bus->bandwidth_int_reqs + dev->bus->bandwidth_isoc_reqs);
-#endif
-	urb->bandwidth = 0;
-}
-EXPORT_SYMBOL (usb_release_bandwidth);
-
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
@@ -1034,11 +902,6 @@ static void urb_unlink (struct urb *urb)
 {
 {
 	unsigned long		flags;
 	unsigned long		flags;
 
 
-	/* Release any periodic transfer bandwidth */
-	if (urb->bandwidth)
-		usb_release_bandwidth (urb->dev, urb,
-			usb_pipeisoc (urb->pipe));
-
 	/* clear all state linking urb to this dev (and hcd) */
 	/* clear all state linking urb to this dev (and hcd) */
 
 
 	spin_lock_irqsave (&hcd_data_lock, flags);
 	spin_lock_irqsave (&hcd_data_lock, flags);

+ 0 - 6
drivers/usb/core/hcd.h

@@ -308,10 +308,6 @@ extern void usb_destroy_configuration(struct usb_device *dev);
 #define NS_TO_US(ns)	((ns + 500L) / 1000L)
 #define NS_TO_US(ns)	((ns + 500L) / 1000L)
 			/* convert & round nanoseconds to microseconds */
 			/* convert & round nanoseconds to microseconds */
 
 
-extern void usb_claim_bandwidth (struct usb_device *dev, struct urb *urb,
-		int bustime, int isoc);
-extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb,
-		int isoc);
 
 
 /*
 /*
  * Full/low speed bandwidth allocation constants/support.
  * Full/low speed bandwidth allocation constants/support.
@@ -324,8 +320,6 @@ extern void usb_release_bandwidth (struct usb_device *dev, struct urb *urb,
 #define FRAME_TIME_MAX_BITS_ALLOC	(90L * FRAME_TIME_BITS / 100L)
 #define FRAME_TIME_MAX_BITS_ALLOC	(90L * FRAME_TIME_BITS / 100L)
 #define FRAME_TIME_MAX_USECS_ALLOC	(90L * FRAME_TIME_USECS / 100L)
 #define FRAME_TIME_MAX_USECS_ALLOC	(90L * FRAME_TIME_USECS / 100L)
 
 
-extern int usb_check_bandwidth (struct usb_device *dev, struct urb *urb);
-
 /*
 /*
  * Ceiling [nano/micro]seconds (typical) for that many bytes at high speed
  * Ceiling [nano/micro]seconds (typical) for that many bytes at high speed
  * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed
  * ISO is a bit less, no ACK ... from USB 2.0 spec, 5.11.3 (and needed

+ 21 - 43
drivers/usb/core/hub.c

@@ -87,9 +87,6 @@ static DECLARE_WAIT_QUEUE_HEAD(khubd_wait);
 
 
 static struct task_struct *khubd_task;
 static struct task_struct *khubd_task;
 
 
-/* multithreaded probe logic */
-static int multithread_probe = 0;
-
 /* cycle leds on hubs that aren't blinking for attention */
 /* cycle leds on hubs that aren't blinking for attention */
 static int blinkenlights = 0;
 static int blinkenlights = 0;
 module_param (blinkenlights, bool, S_IRUGO);
 module_param (blinkenlights, bool, S_IRUGO);
@@ -1256,9 +1253,28 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
 static int __usb_port_suspend(struct usb_device *, int port1);
 static int __usb_port_suspend(struct usb_device *, int port1);
 #endif
 #endif
 
 
-static int __usb_new_device(void *void_data)
+/**
+ * usb_new_device - perform initial device setup (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is called with devices which have been enumerated, but not yet
+ * configured.  The device descriptor is available, but not descriptors
+ * for any device configuration.  The caller must have locked either
+ * the parent hub (if udev is a normal device) or else the
+ * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
+ * udev has already been installed, but udev is not yet visible through
+ * sysfs or other filesystem code.
+ *
+ * It will return if the device is configured properly or not.  Zero if
+ * the interface was registered with the driver core; else a negative
+ * errno value.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only the hub driver or root-hub registrar should ever call this.
+ */
+int usb_new_device(struct usb_device *udev)
 {
 {
-	struct usb_device *udev = void_data;
 	int err;
 	int err;
 
 
 	/* Lock ourself into memory in order to keep a probe sequence
 	/* Lock ourself into memory in order to keep a probe sequence
@@ -1375,44 +1391,6 @@ fail:
 	goto exit;
 	goto exit;
 }
 }
 
 
-/**
- * usb_new_device - perform initial device setup (usbcore-internal)
- * @udev: newly addressed device (in ADDRESS state)
- *
- * This is called with devices which have been enumerated, but not yet
- * configured.  The device descriptor is available, but not descriptors
- * for any device configuration.  The caller must have locked either
- * the parent hub (if udev is a normal device) or else the
- * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
- * udev has already been installed, but udev is not yet visible through
- * sysfs or other filesystem code.
- *
- * The return value for this function depends on if the
- * multithread_probe variable is set or not.  If it's set, it will
- * return a if the probe thread was successfully created or not.  If the
- * variable is not set, it will return if the device is configured
- * properly or not.  interfaces, in sysfs); else a negative errno value.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Only the hub driver or root-hub registrar should ever call this.
- */
-int usb_new_device(struct usb_device *udev)
-{
-	struct task_struct *probe_task;
-	int ret = 0;
-
-	if (multithread_probe) {
-		probe_task = kthread_run(__usb_new_device, udev,
-					 "usb-probe-%s", udev->devnum);
-		if (IS_ERR(probe_task))
-			ret = PTR_ERR(probe_task);
-	} else
-		ret = __usb_new_device(udev);
-
-	return ret;
-}
-
 static int hub_port_status(struct usb_hub *hub, int port1,
 static int hub_port_status(struct usb_hub *hub, int port1,
 			       u16 *status, u16 *change)
 			       u16 *status, u16 *change)
 {
 {

+ 1 - 5
drivers/usb/core/message.c

@@ -1545,11 +1545,7 @@ int usb_driver_set_configuration(struct usb_device *udev, int config)
 	INIT_WORK(&req->work, driver_set_config_work);
 	INIT_WORK(&req->work, driver_set_config_work);
 
 
 	usb_get_dev(udev);
 	usb_get_dev(udev);
-	if (!schedule_work(&req->work)) {
-		usb_put_dev(udev);
-		kfree(req);
-		return -EINVAL;
-	}
+	schedule_work(&req->work);
 	return 0;
 	return 0;
 }
 }
 EXPORT_SYMBOL_GPL(usb_driver_set_configuration);
 EXPORT_SYMBOL_GPL(usb_driver_set_configuration);

+ 49 - 49
drivers/usb/core/sysfs.c

@@ -16,16 +16,16 @@
 
 
 /* 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,			\
+static ssize_t  show_##field(struct device *dev,			\
 		struct device_attribute *attr, char *buf)		\
 		struct device_attribute *attr, char *buf)		\
 {									\
 {									\
 	struct usb_device *udev;					\
 	struct usb_device *udev;					\
 	struct usb_host_config *actconfig;				\
 	struct usb_host_config *actconfig;				\
 									\
 									\
-	udev = to_usb_device (dev);					\
+	udev = to_usb_device(dev);					\
 	actconfig = udev->actconfig;					\
 	actconfig = udev->actconfig;					\
 	if (actconfig)							\
 	if (actconfig)							\
-		return sprintf (buf, format_string,			\
+		return sprintf(buf, format_string,			\
 				actconfig->desc.field * multiplier);	\
 				actconfig->desc.field * multiplier);	\
 	else								\
 	else								\
 		return 0;						\
 		return 0;						\
@@ -35,9 +35,9 @@ static ssize_t  show_##field (struct device *dev,			\
 usb_actconfig_show(field, multiplier, format_string)			\
 usb_actconfig_show(field, multiplier, format_string)			\
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
 
 
-usb_actconfig_attr (bNumInterfaces, 1, "%2d\n")
-usb_actconfig_attr (bmAttributes, 1, "%2x\n")
-usb_actconfig_attr (bMaxPower, 2, "%3dmA\n")
+usb_actconfig_attr(bNumInterfaces, 1, "%2d\n")
+usb_actconfig_attr(bmAttributes, 1, "%2x\n")
+usb_actconfig_attr(bMaxPower, 2, "%3dmA\n")
 
 
 static ssize_t show_configuration_string(struct device *dev,
 static ssize_t show_configuration_string(struct device *dev,
 		struct device_attribute *attr, char *buf)
 		struct device_attribute *attr, char *buf)
@@ -45,7 +45,7 @@ static ssize_t show_configuration_string(struct device *dev,
 	struct usb_device *udev;
 	struct usb_device *udev;
 	struct usb_host_config *actconfig;
 	struct usb_host_config *actconfig;
 
 
-	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;
@@ -57,16 +57,16 @@ 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,
+set_bConfigurationValue(struct device *dev, struct device_attribute *attr,
 		const char *buf, size_t count)
 		const char *buf, size_t count)
 {
 {
-	struct usb_device	*udev = to_usb_device (dev);
+	struct usb_device	*udev = to_usb_device(dev);
 	int			config, value;
 	int			config, value;
 
 
-	if (sscanf (buf, "%u", &config) != 1 || config > 255)
+	if (sscanf(buf, "%u", &config) != 1 || config > 255)
 		return -EINVAL;
 		return -EINVAL;
 	usb_lock_device(udev);
 	usb_lock_device(udev);
-	value = usb_set_configuration (udev, config);
+	value = usb_set_configuration(udev, config);
 	usb_unlock_device(udev);
 	usb_unlock_device(udev);
 	return (value < 0) ? value : count;
 	return (value < 0) ? value : count;
 }
 }
@@ -81,7 +81,7 @@ static ssize_t  show_##name(struct device *dev,				\
 {									\
 {									\
 	struct usb_device *udev;					\
 	struct usb_device *udev;					\
 									\
 									\
-	udev = to_usb_device (dev);					\
+	udev = to_usb_device(dev);					\
 	return sprintf(buf, "%s\n", udev->name);			\
 	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);
@@ -91,12 +91,12 @@ usb_string_attr(manufacturer);
 usb_string_attr(serial);
 usb_string_attr(serial);
 
 
 static ssize_t
 static ssize_t
-show_speed (struct device *dev, struct device_attribute *attr, char *buf)
+show_speed(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
 	struct usb_device *udev;
 	struct usb_device *udev;
 	char *speed;
 	char *speed;
 
 
-	udev = to_usb_device (dev);
+	udev = to_usb_device(dev);
 
 
 	switch (udev->speed) {
 	switch (udev->speed) {
 	case USB_SPEED_LOW:
 	case USB_SPEED_LOW:
@@ -112,22 +112,22 @@ show_speed (struct device *dev, struct device_attribute *attr, char *buf)
 	default:
 	default:
 		speed = "unknown";
 		speed = "unknown";
 	}
 	}
-	return sprintf (buf, "%s\n", speed);
+	return sprintf(buf, "%s\n", speed);
 }
 }
 static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL);
 static DEVICE_ATTR(speed, S_IRUGO, show_speed, NULL);
 
 
 static ssize_t
 static ssize_t
-show_devnum (struct device *dev, struct device_attribute *attr, char *buf)
+show_devnum(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
 	struct usb_device *udev;
 	struct usb_device *udev;
 
 
-	udev = to_usb_device (dev);
-	return sprintf (buf, "%d\n", udev->devnum);
+	udev = to_usb_device(dev);
+	return sprintf(buf, "%d\n", udev->devnum);
 }
 }
 static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL);
 static DEVICE_ATTR(devnum, S_IRUGO, show_devnum, NULL);
 
 
 static ssize_t
 static ssize_t
-show_version (struct device *dev, struct device_attribute *attr, char *buf)
+show_version(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
 	struct usb_device *udev;
 	struct usb_device *udev;
 	u16 bcdUSB;
 	u16 bcdUSB;
@@ -139,25 +139,25 @@ show_version (struct device *dev, struct device_attribute *attr, char *buf)
 static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
 static DEVICE_ATTR(version, S_IRUGO, show_version, NULL);
 
 
 static ssize_t
 static ssize_t
-show_maxchild (struct device *dev, struct device_attribute *attr, char *buf)
+show_maxchild(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
 	struct usb_device *udev;
 	struct usb_device *udev;
 
 
-	udev = to_usb_device (dev);
-	return sprintf (buf, "%d\n", udev->maxchild);
+	udev = to_usb_device(dev);
+	return sprintf(buf, "%d\n", udev->maxchild);
 }
 }
 static DEVICE_ATTR(maxchild, S_IRUGO, show_maxchild, NULL);
 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,	\
+show_##field(struct device *dev, struct device_attribute *attr,	\
 		char *buf)						\
 		char *buf)						\
 {									\
 {									\
 	struct usb_device *udev;					\
 	struct usb_device *udev;					\
 									\
 									\
-	udev = to_usb_device (dev);					\
-	return sprintf (buf, format_string, 				\
+	udev = to_usb_device(dev);					\
+	return sprintf(buf, format_string, 				\
 			le16_to_cpu(udev->descriptor.field));		\
 			le16_to_cpu(udev->descriptor.field));		\
 }									\
 }									\
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
@@ -168,21 +168,21 @@ 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,	\
+show_##field(struct device *dev, struct device_attribute *attr,	\
 		char *buf)						\
 		char *buf)						\
 {									\
 {									\
 	struct usb_device *udev;					\
 	struct usb_device *udev;					\
 									\
 									\
-	udev = to_usb_device (dev);					\
-	return sprintf (buf, format_string, udev->descriptor.field);	\
+	udev = to_usb_device(dev);					\
+	return sprintf(buf, format_string, udev->descriptor.field);	\
 }									\
 }									\
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
 
 
-usb_descriptor_attr (bDeviceClass, "%02x\n")
-usb_descriptor_attr (bDeviceSubClass, "%02x\n")
-usb_descriptor_attr (bDeviceProtocol, "%02x\n")
-usb_descriptor_attr (bNumConfigurations, "%d\n")
-usb_descriptor_attr (bMaxPacketSize0, "%d\n")
+usb_descriptor_attr(bDeviceClass, "%02x\n")
+usb_descriptor_attr(bDeviceSubClass, "%02x\n")
+usb_descriptor_attr(bDeviceProtocol, "%02x\n")
+usb_descriptor_attr(bNumConfigurations, "%d\n")
+usb_descriptor_attr(bMaxPacketSize0, "%d\n")
 
 
 static struct attribute *dev_attrs[] = {
 static struct attribute *dev_attrs[] = {
 	/* current configuration's attributes */
 	/* current configuration's attributes */
@@ -220,17 +220,17 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
 		return retval;
 		return retval;
 
 
 	if (udev->manufacturer) {
 	if (udev->manufacturer) {
-		retval = device_create_file (dev, &dev_attr_manufacturer);
+		retval = device_create_file(dev, &dev_attr_manufacturer);
 		if (retval)
 		if (retval)
 			goto error;
 			goto error;
 	}
 	}
 	if (udev->product) {
 	if (udev->product) {
-		retval = device_create_file (dev, &dev_attr_product);
+		retval = device_create_file(dev, &dev_attr_product);
 		if (retval)
 		if (retval)
 			goto error;
 			goto error;
 	}
 	}
 	if (udev->serial) {
 	if (udev->serial) {
-		retval = device_create_file (dev, &dev_attr_serial);
+		retval = device_create_file(dev, &dev_attr_serial);
 		if (retval)
 		if (retval)
 			goto error;
 			goto error;
 	}
 	}
@@ -246,7 +246,7 @@ error:
 	return retval;
 	return retval;
 }
 }
 
 
-void usb_remove_sysfs_dev_files (struct usb_device *udev)
+void usb_remove_sysfs_dev_files(struct usb_device *udev)
 {
 {
 	struct device *dev = &udev->dev;
 	struct device *dev = &udev->dev;
 
 
@@ -264,22 +264,22 @@ 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,	\
+show_##field(struct device *dev, struct device_attribute *attr,	\
 		char *buf)						\
 		char *buf)						\
 {									\
 {									\
-	struct usb_interface *intf = to_usb_interface (dev);		\
+	struct usb_interface *intf = to_usb_interface(dev);		\
 									\
 									\
-	return sprintf (buf, format_string,				\
+	return sprintf(buf, format_string,				\
 			intf->cur_altsetting->desc.field); 		\
 			intf->cur_altsetting->desc.field); 		\
 }									\
 }									\
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
 static DEVICE_ATTR(field, S_IRUGO, show_##field, NULL);
 
 
-usb_intf_attr (bInterfaceNumber, "%02x\n")
-usb_intf_attr (bAlternateSetting, "%2d\n")
-usb_intf_attr (bNumEndpoints, "%02x\n")
-usb_intf_attr (bInterfaceClass, "%02x\n")
-usb_intf_attr (bInterfaceSubClass, "%02x\n")
-usb_intf_attr (bInterfaceProtocol, "%02x\n")
+usb_intf_attr(bInterfaceNumber, "%02x\n")
+usb_intf_attr(bAlternateSetting, "%2d\n")
+usb_intf_attr(bNumEndpoints, "%02x\n")
+usb_intf_attr(bInterfaceClass, "%02x\n")
+usb_intf_attr(bInterfaceSubClass, "%02x\n")
+usb_intf_attr(bInterfaceProtocol, "%02x\n")
 
 
 static ssize_t show_interface_string(struct device *dev,
 static ssize_t show_interface_string(struct device *dev,
 		struct device_attribute *attr, char *buf)
 		struct device_attribute *attr, char *buf)
@@ -288,8 +288,8 @@ static ssize_t show_interface_string(struct device *dev,
 	struct usb_device *udev;
 	struct usb_device *udev;
 	int len;
 	int len;
 
 
-	intf = to_usb_interface (dev);
-	udev = interface_to_usbdev (intf);
+	intf = to_usb_interface(dev);
+	udev = interface_to_usbdev(intf);
 	len = snprintf(buf, 256, "%s", intf->cur_altsetting->string);
 	len = snprintf(buf, 256, "%s", intf->cur_altsetting->string);
 	if (len < 0)
 	if (len < 0)
 		return 0;
 		return 0;
@@ -384,7 +384,7 @@ error:
 	return retval;
 	return retval;
 }
 }
 
 
-void usb_remove_sysfs_intf_files (struct usb_interface *intf)
+void usb_remove_sysfs_intf_files(struct usb_interface *intf)
 {
 {
 	usb_remove_intf_ep_files(intf);
 	usb_remove_intf_ep_files(intf);
 	sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);
 	sysfs_remove_group(&intf->dev.kobj, &intf_attr_grp);

+ 10 - 11
drivers/usb/core/urb.c

@@ -235,16 +235,15 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 
 
 	urb->status = -EINPROGRESS;
 	urb->status = -EINPROGRESS;
 	urb->actual_length = 0;
 	urb->actual_length = 0;
-	urb->bandwidth = 0;
 
 
 	/* Lots of sanity checks, so HCDs can rely on clean data
 	/* Lots of sanity checks, so HCDs can rely on clean data
 	 * and don't need to duplicate tests
 	 * and don't need to duplicate tests
 	 */
 	 */
 	pipe = urb->pipe;
 	pipe = urb->pipe;
-	temp = usb_pipetype (pipe);
-	is_out = usb_pipeout (pipe);
+	temp = usb_pipetype(pipe);
+	is_out = usb_pipeout(pipe);
 
 
-	if (!usb_pipecontrol (pipe) && dev->state < USB_STATE_CONFIGURED)
+	if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
 		return -ENODEV;
 		return -ENODEV;
 
 
 	/* FIXME there should be a sharable lock protecting us against
 	/* FIXME there should be a sharable lock protecting us against
@@ -253,11 +252,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 	 * checks get made.)
 	 * checks get made.)
 	 */
 	 */
 
 
-	max = usb_maxpacket (dev, pipe, is_out);
+	max = usb_maxpacket(dev, pipe, is_out);
 	if (max <= 0) {
 	if (max <= 0) {
 		dev_dbg(&dev->dev,
 		dev_dbg(&dev->dev,
 			"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
 			"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
-			usb_pipeendpoint (pipe), is_out ? "out" : "in",
+			usb_pipeendpoint(pipe), is_out ? "out" : "in",
 			__FUNCTION__, max);
 			__FUNCTION__, max);
 		return -EMSGSIZE;
 		return -EMSGSIZE;
 	}
 	}
@@ -279,11 +278,11 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 		if (urb->number_of_packets <= 0)		    
 		if (urb->number_of_packets <= 0)		    
 			return -EINVAL;
 			return -EINVAL;
 		for (n = 0; n < urb->number_of_packets; n++) {
 		for (n = 0; n < urb->number_of_packets; n++) {
-			len = urb->iso_frame_desc [n].length;
+			len = urb->iso_frame_desc[n].length;
 			if (len < 0 || len > max) 
 			if (len < 0 || len > max) 
 				return -EMSGSIZE;
 				return -EMSGSIZE;
-			urb->iso_frame_desc [n].status = -EXDEV;
-			urb->iso_frame_desc [n].actual_length = 0;
+			urb->iso_frame_desc[n].status = -EXDEV;
+			urb->iso_frame_desc[n].actual_length = 0;
 		}
 		}
 	}
 	}
 
 
@@ -322,7 +321,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 
 
 	/* fail if submitter gave bogus flags */
 	/* fail if submitter gave bogus flags */
 	if (urb->transfer_flags != orig_flags) {
 	if (urb->transfer_flags != orig_flags) {
-		err ("BOGUS urb flags, %x --> %x",
+		err("BOGUS urb flags, %x --> %x",
 			orig_flags, urb->transfer_flags);
 			orig_flags, urb->transfer_flags);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
@@ -373,7 +372,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 		urb->interval = temp;
 		urb->interval = temp;
 	}
 	}
 
 
-	return usb_hcd_submit_urb (urb, mem_flags);
+	return usb_hcd_submit_urb(urb, mem_flags);
 }
 }
 
 
 /*-------------------------------------------------------------------*/
 /*-------------------------------------------------------------------*/

+ 48 - 48
drivers/usb/core/usb.c

@@ -233,7 +233,7 @@ static void usb_autosuspend_work(struct work_struct *work)
  * @parent: hub to which device is connected; null to allocate a root hub
  * @parent: hub to which device is connected; null to allocate a root hub
  * @bus: bus used to access the device
  * @bus: bus used to access the device
  * @port1: one-based index of port; ignored for root hubs
  * @port1: one-based index of port; ignored for root hubs
- * Context: !in_interrupt ()
+ * Context: !in_interrupt()
  *
  *
  * Only hub drivers (including virtual root hub drivers for host
  * Only hub drivers (including virtual root hub drivers for host
  * controllers) should ever call this.
  * controllers) should ever call this.
@@ -277,22 +277,22 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
 	 * as stable:  bus->busnum changes easily from modprobe order,
 	 * as stable:  bus->busnum changes easily from modprobe order,
 	 * cardbus or pci hotplugging, and so on.
 	 * cardbus or pci hotplugging, and so on.
 	 */
 	 */
-	if (unlikely (!parent)) {
-		dev->devpath [0] = '0';
+	if (unlikely(!parent)) {
+		dev->devpath[0] = '0';
 
 
 		dev->dev.parent = bus->controller;
 		dev->dev.parent = bus->controller;
-		sprintf (&dev->dev.bus_id[0], "usb%d", bus->busnum);
+		sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
 	} else {
 	} else {
 		/* match any labeling on the hubs; it's one-based */
 		/* match any labeling on the hubs; it's one-based */
-		if (parent->devpath [0] == '0')
-			snprintf (dev->devpath, sizeof dev->devpath,
+		if (parent->devpath[0] == '0')
+			snprintf(dev->devpath, sizeof dev->devpath,
 				"%d", port1);
 				"%d", port1);
 		else
 		else
-			snprintf (dev->devpath, sizeof dev->devpath,
+			snprintf(dev->devpath, sizeof dev->devpath,
 				"%s.%d", parent->devpath, port1);
 				"%s.%d", parent->devpath, port1);
 
 
 		dev->dev.parent = &parent->dev;
 		dev->dev.parent = &parent->dev;
-		sprintf (&dev->dev.bus_id[0], "%d-%s",
+		sprintf(&dev->dev.bus_id[0], "%d-%s",
 			bus->busnum, dev->devpath);
 			bus->busnum, dev->devpath);
 
 
 		/* hub driver sets up TT records */
 		/* hub driver sets up TT records */
@@ -463,7 +463,7 @@ static struct usb_device *match_device(struct usb_device *dev,
 	/* see if this device matches */
 	/* see if this device matches */
 	if ((vendor_id == le16_to_cpu(dev->descriptor.idVendor)) &&
 	if ((vendor_id == le16_to_cpu(dev->descriptor.idVendor)) &&
 	    (product_id == le16_to_cpu(dev->descriptor.idProduct))) {
 	    (product_id == le16_to_cpu(dev->descriptor.idProduct))) {
-		dev_dbg (&dev->dev, "matched this device!\n");
+		dev_dbg(&dev->dev, "matched this device!\n");
 		ret_dev = usb_get_dev(dev);
 		ret_dev = usb_get_dev(dev);
 		goto exit;
 		goto exit;
 	}
 	}
@@ -535,7 +535,7 @@ exit:
  */
  */
 int usb_get_current_frame_number(struct usb_device *dev)
 int usb_get_current_frame_number(struct usb_device *dev)
 {
 {
-	return usb_hcd_get_frame_number (dev);
+	return usb_hcd_get_frame_number(dev);
 }
 }
 
 
 /*-------------------------------------------------------------------*/
 /*-------------------------------------------------------------------*/
@@ -593,7 +593,7 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
  *
  *
  * When the buffer is no longer used, free it with usb_buffer_free().
  * When the buffer is no longer used, free it with usb_buffer_free().
  */
  */
-void *usb_buffer_alloc (
+void *usb_buffer_alloc(
 	struct usb_device *dev,
 	struct usb_device *dev,
 	size_t size,
 	size_t size,
 	gfp_t mem_flags,
 	gfp_t mem_flags,
@@ -602,7 +602,7 @@ void *usb_buffer_alloc (
 {
 {
 	if (!dev || !dev->bus)
 	if (!dev || !dev->bus)
 		return NULL;
 		return NULL;
-	return hcd_buffer_alloc (dev->bus, size, mem_flags, dma);
+	return hcd_buffer_alloc(dev->bus, size, mem_flags, dma);
 }
 }
 
 
 /**
 /**
@@ -616,7 +616,7 @@ void *usb_buffer_alloc (
  * been allocated using usb_buffer_alloc(), and the parameters must match
  * been allocated using usb_buffer_alloc(), and the parameters must match
  * those provided in that allocation request. 
  * those provided in that allocation request. 
  */
  */
-void usb_buffer_free (
+void usb_buffer_free(
 	struct usb_device *dev,
 	struct usb_device *dev,
 	size_t size,
 	size_t size,
 	void *addr,
 	void *addr,
@@ -627,7 +627,7 @@ void usb_buffer_free (
 		return;
 		return;
 	if (!addr)
 	if (!addr)
 		return;
 		return;
-	hcd_buffer_free (dev->bus, size, addr, dma);
+	hcd_buffer_free(dev->bus, size, addr, dma);
 }
 }
 
 
 /**
 /**
@@ -647,7 +647,7 @@ void usb_buffer_free (
  * Reverse the effect of this call with usb_buffer_unmap().
  * Reverse the effect of this call with usb_buffer_unmap().
  */
  */
 #if 0
 #if 0
-struct urb *usb_buffer_map (struct urb *urb)
+struct urb *usb_buffer_map(struct urb *urb)
 {
 {
 	struct usb_bus		*bus;
 	struct usb_bus		*bus;
 	struct device		*controller;
 	struct device		*controller;
@@ -659,14 +659,14 @@ struct urb *usb_buffer_map (struct urb *urb)
 		return NULL;
 		return NULL;
 
 
 	if (controller->dma_mask) {
 	if (controller->dma_mask) {
-		urb->transfer_dma = dma_map_single (controller,
+		urb->transfer_dma = dma_map_single(controller,
 			urb->transfer_buffer, urb->transfer_buffer_length,
 			urb->transfer_buffer, urb->transfer_buffer_length,
-			usb_pipein (urb->pipe)
+			usb_pipein(urb->pipe)
 				? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 				? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-		if (usb_pipecontrol (urb->pipe))
-			urb->setup_dma = dma_map_single (controller,
+		if (usb_pipecontrol(urb->pipe))
+			urb->setup_dma = dma_map_single(controller,
 					urb->setup_packet,
 					urb->setup_packet,
-					sizeof (struct usb_ctrlrequest),
+					sizeof(struct usb_ctrlrequest),
 					DMA_TO_DEVICE);
 					DMA_TO_DEVICE);
 	// FIXME generic api broken like pci, can't report errors
 	// FIXME generic api broken like pci, can't report errors
 	// if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
 	// if (urb->transfer_dma == DMA_ADDR_INVALID) return 0;
@@ -689,7 +689,7 @@ struct urb *usb_buffer_map (struct urb *urb)
  * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s)
  * usb_buffer_dmasync - synchronize DMA and CPU view of buffer(s)
  * @urb: urb whose transfer_buffer/setup_packet will be synchronized
  * @urb: urb whose transfer_buffer/setup_packet will be synchronized
  */
  */
-void usb_buffer_dmasync (struct urb *urb)
+void usb_buffer_dmasync(struct urb *urb)
 {
 {
 	struct usb_bus		*bus;
 	struct usb_bus		*bus;
 	struct device		*controller;
 	struct device		*controller;
@@ -702,14 +702,14 @@ void usb_buffer_dmasync (struct urb *urb)
 		return;
 		return;
 
 
 	if (controller->dma_mask) {
 	if (controller->dma_mask) {
-		dma_sync_single (controller,
+		dma_sync_single(controller,
 			urb->transfer_dma, urb->transfer_buffer_length,
 			urb->transfer_dma, urb->transfer_buffer_length,
-			usb_pipein (urb->pipe)
+			usb_pipein(urb->pipe)
 				? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 				? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-		if (usb_pipecontrol (urb->pipe))
-			dma_sync_single (controller,
+		if (usb_pipecontrol(urb->pipe))
+			dma_sync_single(controller,
 					urb->setup_dma,
 					urb->setup_dma,
-					sizeof (struct usb_ctrlrequest),
+					sizeof(struct usb_ctrlrequest),
 					DMA_TO_DEVICE);
 					DMA_TO_DEVICE);
 	}
 	}
 }
 }
@@ -722,7 +722,7 @@ void usb_buffer_dmasync (struct urb *urb)
  * Reverses the effect of usb_buffer_map().
  * Reverses the effect of usb_buffer_map().
  */
  */
 #if 0
 #if 0
-void usb_buffer_unmap (struct urb *urb)
+void usb_buffer_unmap(struct urb *urb)
 {
 {
 	struct usb_bus		*bus;
 	struct usb_bus		*bus;
 	struct device		*controller;
 	struct device		*controller;
@@ -735,14 +735,14 @@ void usb_buffer_unmap (struct urb *urb)
 		return;
 		return;
 
 
 	if (controller->dma_mask) {
 	if (controller->dma_mask) {
-		dma_unmap_single (controller,
+		dma_unmap_single(controller,
 			urb->transfer_dma, urb->transfer_buffer_length,
 			urb->transfer_dma, urb->transfer_buffer_length,
-			usb_pipein (urb->pipe)
+			usb_pipein(urb->pipe)
 				? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 				? DMA_FROM_DEVICE : DMA_TO_DEVICE);
-		if (usb_pipecontrol (urb->pipe))
-			dma_unmap_single (controller,
+		if (usb_pipecontrol(urb->pipe))
+			dma_unmap_single(controller,
 					urb->setup_dma,
 					urb->setup_dma,
-					sizeof (struct usb_ctrlrequest),
+					sizeof(struct usb_ctrlrequest),
 					DMA_TO_DEVICE);
 					DMA_TO_DEVICE);
 	}
 	}
 	urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP
 	urb->transfer_flags &= ~(URB_NO_TRANSFER_DMA_MAP
@@ -783,15 +783,15 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
 	struct device		*controller;
 	struct device		*controller;
 
 
 	if (!dev
 	if (!dev
-			|| usb_pipecontrol (pipe)
+			|| usb_pipecontrol(pipe)
 			|| !(bus = dev->bus)
 			|| !(bus = dev->bus)
 			|| !(controller = bus->controller)
 			|| !(controller = bus->controller)
 			|| !controller->dma_mask)
 			|| !controller->dma_mask)
 		return -1;
 		return -1;
 
 
 	// FIXME generic api broken like pci, can't report errors
 	// FIXME generic api broken like pci, can't report errors
-	return dma_map_sg (controller, sg, nents,
-			usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+	return dma_map_sg(controller, sg, nents,
+			usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 }
 
 
 /* XXX DISABLED, no users currently.  If you wish to re-enable this
 /* XXX DISABLED, no users currently.  If you wish to re-enable this
@@ -823,8 +823,8 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
 			|| !controller->dma_mask)
 			|| !controller->dma_mask)
 		return;
 		return;
 
 
-	dma_sync_sg (controller, sg, n_hw_ents,
-			usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+	dma_sync_sg(controller, sg, n_hw_ents,
+			usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 }
 #endif
 #endif
 
 
@@ -849,8 +849,8 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
 			|| !controller->dma_mask)
 			|| !controller->dma_mask)
 		return;
 		return;
 
 
-	dma_unmap_sg (controller, sg, n_hw_ents,
-			usb_pipein (pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+	dma_unmap_sg(controller, sg, n_hw_ents,
+			usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 }
 
 
 /* format to disable USB on kernel command line is: nousb */
 /* format to disable USB on kernel command line is: nousb */
@@ -871,7 +871,7 @@ static int __init usb_init(void)
 {
 {
 	int retval;
 	int retval;
 	if (nousb) {
 	if (nousb) {
-		pr_info ("%s: USB support disabled\n", usbcore_name);
+		pr_info("%s: USB support disabled\n", usbcore_name);
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -971,19 +971,19 @@ EXPORT_SYMBOL(__usb_get_extra_descriptor);
 EXPORT_SYMBOL(usb_find_device);
 EXPORT_SYMBOL(usb_find_device);
 EXPORT_SYMBOL(usb_get_current_frame_number);
 EXPORT_SYMBOL(usb_get_current_frame_number);
 
 
-EXPORT_SYMBOL (usb_buffer_alloc);
-EXPORT_SYMBOL (usb_buffer_free);
+EXPORT_SYMBOL(usb_buffer_alloc);
+EXPORT_SYMBOL(usb_buffer_free);
 
 
 #if 0
 #if 0
-EXPORT_SYMBOL (usb_buffer_map);
-EXPORT_SYMBOL (usb_buffer_dmasync);
-EXPORT_SYMBOL (usb_buffer_unmap);
+EXPORT_SYMBOL(usb_buffer_map);
+EXPORT_SYMBOL(usb_buffer_dmasync);
+EXPORT_SYMBOL(usb_buffer_unmap);
 #endif
 #endif
 
 
-EXPORT_SYMBOL (usb_buffer_map_sg);
+EXPORT_SYMBOL(usb_buffer_map_sg);
 #if 0
 #if 0
-EXPORT_SYMBOL (usb_buffer_dmasync_sg);
+EXPORT_SYMBOL(usb_buffer_dmasync_sg);
 #endif
 #endif
-EXPORT_SYMBOL (usb_buffer_unmap_sg);
+EXPORT_SYMBOL(usb_buffer_unmap_sg);
 
 
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");

+ 12 - 9
drivers/usb/gadget/at91_udc.c

@@ -39,7 +39,7 @@
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/proc_fs.h>
 #include <linux/proc_fs.h>
 #include <linux/clk.h>
 #include <linux/clk.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb_gadget.h>
 
 
 #include <asm/byteorder.h>
 #include <asm/byteorder.h>
@@ -1807,16 +1807,13 @@ static int at91udc_suspend(struct platform_device *pdev, pm_message_t mesg)
 			|| !wake
 			|| !wake
 			|| at91_suspend_entering_slow_clock()) {
 			|| at91_suspend_entering_slow_clock()) {
 		pullup(udc, 0);
 		pullup(udc, 0);
-		disable_irq_wake(udc->udp_irq);
+		wake = 0;
 	} else
 	} else
 		enable_irq_wake(udc->udp_irq);
 		enable_irq_wake(udc->udp_irq);
 
 
-	if (udc->board.vbus_pin > 0) {
-		if (wake)
-			enable_irq_wake(udc->board.vbus_pin);
-		else
-			disable_irq_wake(udc->board.vbus_pin);
-	}
+	udc->active_suspend = wake;
+	if (udc->board.vbus_pin > 0 && wake)
+		enable_irq_wake(udc->board.vbus_pin);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1824,8 +1821,14 @@ static int at91udc_resume(struct platform_device *pdev)
 {
 {
 	struct at91_udc *udc = platform_get_drvdata(pdev);
 	struct at91_udc *udc = platform_get_drvdata(pdev);
 
 
+	if (udc->board.vbus_pin > 0 && udc->active_suspend)
+		disable_irq_wake(udc->board.vbus_pin);
+
 	/* maybe reconnect to host; if so, clocks on */
 	/* maybe reconnect to host; if so, clocks on */
-	pullup(udc, 1);
+	if (udc->active_suspend)
+		disable_irq_wake(udc->udp_irq);
+	else
+		pullup(udc, 1);
 	return 0;
 	return 0;
 }
 }
 #else
 #else

+ 1 - 0
drivers/usb/gadget/at91_udc.h

@@ -136,6 +136,7 @@ struct at91_udc {
 	unsigned			wait_for_addr_ack:1;
 	unsigned			wait_for_addr_ack:1;
 	unsigned			wait_for_config_ack:1;
 	unsigned			wait_for_config_ack:1;
 	unsigned			selfpowered:1;
 	unsigned			selfpowered:1;
+	unsigned			active_suspend:1;
 	u8				addr;
 	u8				addr;
 	struct at91_udc_data		board;
 	struct at91_udc_data		board;
 	struct clk			*iclk, *fclk;
 	struct clk			*iclk, *fclk;

+ 1 - 1
drivers/usb/gadget/config.c

@@ -24,7 +24,7 @@
 #include <linux/string.h>
 #include <linux/string.h>
 #include <linux/device.h>
 #include <linux/device.h>
 
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb_gadget.h>
 
 
 
 

+ 1 - 1
drivers/usb/gadget/epautoconf.c

@@ -27,7 +27,7 @@
 #include <linux/ctype.h>
 #include <linux/ctype.h>
 #include <linux/string.h>
 #include <linux/string.h>
 
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb_gadget.h>
 
 
 #include "gadget_chips.h"
 #include "gadget_chips.h"

+ 108 - 40
drivers/usb/gadget/ether.c

@@ -47,7 +47,7 @@
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 #include <asm/unaligned.h>
 
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
 #include <linux/usb/cdc.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb_gadget.h>
 
 
@@ -72,9 +72,18 @@
  *
  *
  * There's some hardware that can't talk CDC.  We make that hardware
  * There's some hardware that can't talk CDC.  We make that hardware
  * implement a "minimalist" vendor-agnostic CDC core:  same framing, but
  * implement a "minimalist" vendor-agnostic CDC core:  same framing, but
- * link-level setup only requires activating the configuration.
- * Linux supports it, but other host operating systems may not.
- * (This is a subset of CDC Ethernet.)
+ * link-level setup only requires activating the configuration.  Only the
+ * endpoint descriptors, and product/vendor IDs, are relevant; no control
+ * operations are available.  Linux supports it, but other host operating
+ * systems may not.  (This is a subset of CDC Ethernet.)
+ *
+ * It turns out that if you add a few descriptors to that "CDC Subset",
+ * (Windows) host side drivers from MCCI can treat it as one submode of
+ * a proprietary scheme called "SAFE" ... without needing to know about
+ * specific product/vendor IDs.  So we do that, making it easier to use
+ * those MS-Windows drivers.  Those added descriptors make it resemble a
+ * CDC MDLM device, but they don't change device behavior at all.  (See
+ * MCCI Engineering report 950198 "SAFE Networking Functions".)
  *
  *
  * A third option is also in use.  Rather than CDC Ethernet, or something
  * A third option is also in use.  Rather than CDC Ethernet, or something
  * simpler, Microsoft pushes their own approach: RNDIS.  The published
  * simpler, Microsoft pushes their own approach: RNDIS.  The published
@@ -254,6 +263,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 #define DEV_CONFIG_CDC
 #define DEV_CONFIG_CDC
 #endif
 #endif
 
 
+#ifdef CONFIG_USB_GADGET_S3C2410
+#define DEV_CONFIG_CDC
+#endif
+
 #ifdef CONFIG_USB_GADGET_AT91
 #ifdef CONFIG_USB_GADGET_AT91
 #define DEV_CONFIG_CDC
 #define DEV_CONFIG_CDC
 #endif
 #endif
@@ -266,6 +279,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 #define DEV_CONFIG_CDC
 #define DEV_CONFIG_CDC
 #endif
 #endif
 
 
+#ifdef CONFIG_USB_GADGET_HUSB2DEV
+#define DEV_CONFIG_CDC
+#endif
+
 
 
 /* For CDC-incapable hardware, choose the simple cdc subset.
 /* For CDC-incapable hardware, choose the simple cdc subset.
  * Anything that talks bulk (without notable bugs) can do this.
  * Anything that talks bulk (without notable bugs) can do this.
@@ -283,9 +300,6 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 #define	DEV_CONFIG_SUBSET
 #define	DEV_CONFIG_SUBSET
 #endif
 #endif
 
 
-#ifdef CONFIG_USB_GADGET_S3C2410
-#define DEV_CONFIG_CDC
-#endif
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
@@ -487,8 +501,17 @@ rndis_config = {
  * endpoint.  Both have a "data" interface and two bulk endpoints.
  * endpoint.  Both have a "data" interface and two bulk endpoints.
  * There are also differences in how control requests are handled.
  * There are also differences in how control requests are handled.
  *
  *
- * RNDIS shares a lot with CDC-Ethernet, since it's a variant of
- * the CDC-ACM (modem) spec.
+ * RNDIS shares a lot with CDC-Ethernet, since it's a variant of the
+ * CDC-ACM (modem) spec.  Unfortunately MSFT's RNDIS driver is buggy; it
+ * may hang or oops.  Since bugfixes (or accurate specs, letting Linux
+ * work around those bugs) are unlikely to ever come from MSFT, you may
+ * wish to avoid using RNDIS.
+ *
+ * MCCI offers an alternative to RNDIS if you need to connect to Windows
+ * but have hardware that can't support CDC Ethernet.   We add descriptors
+ * to present the CDC Subset as a (nonconformant) CDC MDLM variant called
+ * "SAFE".  That borrows from both CDC Ethernet and CDC MDLM.  You can
+ * get those drivers from MCCI, or bundled with various products.
  */
  */
 
 
 #ifdef	DEV_CONFIG_CDC
 #ifdef	DEV_CONFIG_CDC
@@ -522,8 +545,6 @@ rndis_control_intf = {
 };
 };
 #endif
 #endif
 
 
-#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
-
 static const struct usb_cdc_header_desc header_desc = {
 static const struct usb_cdc_header_desc header_desc = {
 	.bLength =		sizeof header_desc,
 	.bLength =		sizeof header_desc,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
@@ -532,6 +553,8 @@ static const struct usb_cdc_header_desc header_desc = {
 	.bcdCDC =		__constant_cpu_to_le16 (0x0110),
 	.bcdCDC =		__constant_cpu_to_le16 (0x0110),
 };
 };
 
 
+#if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
+
 static const struct usb_cdc_union_desc union_desc = {
 static const struct usb_cdc_union_desc union_desc = {
 	.bLength =		sizeof union_desc,
 	.bLength =		sizeof union_desc,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
 	.bDescriptorType =	USB_DT_CS_INTERFACE,
@@ -564,7 +587,40 @@ static const struct usb_cdc_acm_descriptor acm_descriptor = {
 
 
 #endif
 #endif
 
 
-#ifdef	DEV_CONFIG_CDC
+#ifndef DEV_CONFIG_CDC
+
+/* "SAFE" loosely follows CDC WMC MDLM, violating the spec in various
+ * ways:  data endpoints live in the control interface, there's no data
+ * interface, and it's not used to talk to a cell phone radio.
+ */
+
+static const struct usb_cdc_mdlm_desc mdlm_desc = {
+	.bLength =		sizeof mdlm_desc,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_MDLM_TYPE,
+
+	.bcdVersion =		__constant_cpu_to_le16(0x0100),
+	.bGUID = {
+		0x5d, 0x34, 0xcf, 0x66, 0x11, 0x18, 0x11, 0xd6,
+		0xa2, 0x1a, 0x00, 0x01, 0x02, 0xca, 0x9a, 0x7f,
+	},
+};
+
+/* since "usb_cdc_mdlm_detail_desc" is a variable length structure, we
+ * can't really use its struct.  All we do here is say that we're using
+ * the submode of "SAFE" which directly matches the CDC Subset.
+ */
+static const u8 mdlm_detail_desc[] = {
+	6,
+	USB_DT_CS_INTERFACE,
+	USB_CDC_MDLM_DETAIL_TYPE,
+
+	0,	/* "SAFE" */
+	0,	/* network control capabilities (none) */
+	0,	/* network data capabilities ("raw" encapsulation) */
+};
+
+#endif
 
 
 static const struct usb_cdc_ether_desc ether_desc = {
 static const struct usb_cdc_ether_desc ether_desc = {
 	.bLength =		sizeof ether_desc,
 	.bLength =		sizeof ether_desc,
@@ -579,7 +635,6 @@ static const struct usb_cdc_ether_desc ether_desc = {
 	.bNumberPowerFilters =	0,
 	.bNumberPowerFilters =	0,
 };
 };
 
 
-#endif
 
 
 #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
 #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
 
 
@@ -672,6 +727,9 @@ rndis_data_intf = {
 /*
 /*
  * "Simple" CDC-subset option is a simple vendor-neutral model that most
  * "Simple" CDC-subset option is a simple vendor-neutral model that most
  * full speed controllers can handle:  one interface, two bulk endpoints.
  * full speed controllers can handle:  one interface, two bulk endpoints.
+ *
+ * To assist host side drivers, we fancy it up a bit, and add descriptors
+ * so some host side drivers will understand it as a "SAFE" variant.
  */
  */
 
 
 static const struct usb_interface_descriptor
 static const struct usb_interface_descriptor
@@ -682,8 +740,8 @@ subset_data_intf = {
 	.bInterfaceNumber =	0,
 	.bInterfaceNumber =	0,
 	.bAlternateSetting =	0,
 	.bAlternateSetting =	0,
 	.bNumEndpoints =	2,
 	.bNumEndpoints =	2,
-	.bInterfaceClass =	USB_CLASS_VENDOR_SPEC,
-	.bInterfaceSubClass =	0,
+	.bInterfaceClass =      USB_CLASS_COMM,
+	.bInterfaceSubClass =	USB_CDC_SUBCLASS_MDLM,
 	.bInterfaceProtocol =	0,
 	.bInterfaceProtocol =	0,
 	.iInterface =		STRING_DATA,
 	.iInterface =		STRING_DATA,
 };
 };
@@ -731,10 +789,15 @@ static const struct usb_descriptor_header *fs_eth_function [11] = {
 static inline void __init fs_subset_descriptors(void)
 static inline void __init fs_subset_descriptors(void)
 {
 {
 #ifdef DEV_CONFIG_SUBSET
 #ifdef DEV_CONFIG_SUBSET
+	/* behavior is "CDC Subset"; extra descriptors say "SAFE" */
 	fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
 	fs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
-	fs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
-	fs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
-	fs_eth_function[4] = NULL;
+	fs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+	fs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+	fs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+	fs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+	fs_eth_function[6] = (struct usb_descriptor_header *) &fs_source_desc;
+	fs_eth_function[7] = (struct usb_descriptor_header *) &fs_sink_desc;
+	fs_eth_function[8] = NULL;
 #else
 #else
 	fs_eth_function[1] = NULL;
 	fs_eth_function[1] = NULL;
 #endif
 #endif
@@ -828,10 +891,15 @@ static const struct usb_descriptor_header *hs_eth_function [11] = {
 static inline void __init hs_subset_descriptors(void)
 static inline void __init hs_subset_descriptors(void)
 {
 {
 #ifdef DEV_CONFIG_SUBSET
 #ifdef DEV_CONFIG_SUBSET
+	/* behavior is "CDC Subset"; extra descriptors say "SAFE" */
 	hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
 	hs_eth_function[1] = (struct usb_descriptor_header *) &subset_data_intf;
-	hs_eth_function[2] = (struct usb_descriptor_header *) &fs_source_desc;
-	hs_eth_function[3] = (struct usb_descriptor_header *) &fs_sink_desc;
-	hs_eth_function[4] = NULL;
+	hs_eth_function[2] = (struct usb_descriptor_header *) &header_desc;
+	hs_eth_function[3] = (struct usb_descriptor_header *) &mdlm_desc;
+	hs_eth_function[4] = (struct usb_descriptor_header *) &mdlm_detail_desc;
+	hs_eth_function[5] = (struct usb_descriptor_header *) &ether_desc;
+	hs_eth_function[6] = (struct usb_descriptor_header *) &hs_source_desc;
+	hs_eth_function[7] = (struct usb_descriptor_header *) &hs_sink_desc;
+	hs_eth_function[8] = NULL;
 #else
 #else
 	hs_eth_function[1] = NULL;
 	hs_eth_function[1] = NULL;
 #endif
 #endif
@@ -878,10 +946,8 @@ static char				manufacturer [50];
 static char				product_desc [40] = DRIVER_DESC;
 static char				product_desc [40] = DRIVER_DESC;
 static char				serial_number [20];
 static char				serial_number [20];
 
 
-#ifdef	DEV_CONFIG_CDC
 /* address that the host will use ... usually assigned at random */
 /* address that the host will use ... usually assigned at random */
 static char				ethaddr [2 * ETH_ALEN + 1];
 static char				ethaddr [2 * ETH_ALEN + 1];
-#endif
 
 
 /* static strings, in UTF-8 */
 /* static strings, in UTF-8 */
 static struct usb_string		strings [] = {
 static struct usb_string		strings [] = {
@@ -889,9 +955,9 @@ static struct usb_string		strings [] = {
 	{ STRING_PRODUCT,	product_desc, },
 	{ STRING_PRODUCT,	product_desc, },
 	{ STRING_SERIALNUMBER,	serial_number, },
 	{ STRING_SERIALNUMBER,	serial_number, },
 	{ STRING_DATA,		"Ethernet Data", },
 	{ STRING_DATA,		"Ethernet Data", },
+	{ STRING_ETHADDR,	ethaddr, },
 #ifdef	DEV_CONFIG_CDC
 #ifdef	DEV_CONFIG_CDC
 	{ STRING_CDC,		"CDC Ethernet", },
 	{ STRING_CDC,		"CDC Ethernet", },
-	{ STRING_ETHADDR,	ethaddr, },
 	{ STRING_CONTROL,	"CDC Communications Control", },
 	{ STRING_CONTROL,	"CDC Communications Control", },
 #endif
 #endif
 #ifdef	DEV_CONFIG_SUBSET
 #ifdef	DEV_CONFIG_SUBSET
@@ -986,10 +1052,10 @@ set_ether_config (struct eth_dev *dev, gfp_t gfp_flags)
 	}
 	}
 #endif
 #endif
 
 
-	dev->in = ep_desc (dev->gadget, &hs_source_desc, &fs_source_desc);
+	dev->in = ep_desc(gadget, &hs_source_desc, &fs_source_desc);
 	dev->in_ep->driver_data = dev;
 	dev->in_ep->driver_data = dev;
 
 
-	dev->out = ep_desc (dev->gadget, &hs_sink_desc, &fs_sink_desc);
+	dev->out = ep_desc(gadget, &hs_sink_desc, &fs_sink_desc);
 	dev->out_ep->driver_data = dev;
 	dev->out_ep->driver_data = dev;
 
 
 	/* With CDC,  the host isn't allowed to use these two data
 	/* With CDC,  the host isn't allowed to use these two data
@@ -2278,10 +2344,10 @@ eth_bind (struct usb_gadget *gadget)
 			"RNDIS/%s", driver_desc);
 			"RNDIS/%s", driver_desc);
 
 
 	/* CDC subset ... recognized by Linux since 2.4.10, but Windows
 	/* CDC subset ... recognized by Linux since 2.4.10, but Windows
-	 * drivers aren't widely available.
+	 * drivers aren't widely available.  (That may be improved by
+	 * supporting one submode of the "SAFE" variant of MDLM.)
 	 */
 	 */
 	} else if (!cdc) {
 	} else if (!cdc) {
-		device_desc.bDeviceClass = USB_CLASS_VENDOR_SPEC;
 		device_desc.idVendor =
 		device_desc.idVendor =
 			__constant_cpu_to_le16(SIMPLE_VENDOR_NUM);
 			__constant_cpu_to_le16(SIMPLE_VENDOR_NUM);
 		device_desc.idProduct =
 		device_desc.idProduct =
@@ -2352,6 +2418,10 @@ autoconf_fail:
 	if (!cdc) {
 	if (!cdc) {
 		eth_config.bNumInterfaces = 1;
 		eth_config.bNumInterfaces = 1;
 		eth_config.iConfiguration = STRING_SUBSET;
 		eth_config.iConfiguration = STRING_SUBSET;
+
+		/* use functions to set these up, in case we're built to work
+		 * with multiple controllers and must override CDC Ethernet.
+		 */
 		fs_subset_descriptors();
 		fs_subset_descriptors();
 		hs_subset_descriptors();
 		hs_subset_descriptors();
 	}
 	}
@@ -2415,22 +2485,20 @@ autoconf_fail:
 
 
 	/* Module params for these addresses should come from ID proms.
 	/* Module params for these addresses should come from ID proms.
 	 * The host side address is used with CDC and RNDIS, and commonly
 	 * The host side address is used with CDC and RNDIS, and commonly
-	 * ends up in a persistent config database.
+	 * ends up in a persistent config database.  It's not clear if
+	 * host side code for the SAFE thing cares -- its original BLAN
+	 * thing didn't, Sharp never assigned those addresses on Zaurii.
 	 */
 	 */
 	if (get_ether_addr(dev_addr, net->dev_addr))
 	if (get_ether_addr(dev_addr, net->dev_addr))
 		dev_warn(&gadget->dev,
 		dev_warn(&gadget->dev,
 			"using random %s ethernet address\n", "self");
 			"using random %s ethernet address\n", "self");
-	if (cdc || rndis) {
-		if (get_ether_addr(host_addr, dev->host_mac))
-			dev_warn(&gadget->dev,
-				"using random %s ethernet address\n", "host");
-#ifdef	DEV_CONFIG_CDC
-		snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
-			dev->host_mac [0], dev->host_mac [1],
-			dev->host_mac [2], dev->host_mac [3],
-			dev->host_mac [4], dev->host_mac [5]);
-#endif
-	}
+	if (get_ether_addr(host_addr, dev->host_mac))
+		dev_warn(&gadget->dev,
+			"using random %s ethernet address\n", "host");
+	snprintf (ethaddr, sizeof ethaddr, "%02X%02X%02X%02X%02X%02X",
+		dev->host_mac [0], dev->host_mac [1],
+		dev->host_mac [2], dev->host_mac [3],
+		dev->host_mac [4], dev->host_mac [5]);
 
 
 	if (rndis) {
 	if (rndis) {
 		status = rndis_init();
 		status = rndis_init();

+ 16 - 17
drivers/usb/gadget/file_storage.c

@@ -253,7 +253,7 @@
 #include <linux/freezer.h>
 #include <linux/freezer.h>
 #include <linux/utsname.h>
 #include <linux/utsname.h>
 
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb_gadget.h>
 
 
 #include "gadget_chips.h"
 #include "gadget_chips.h"
@@ -1148,7 +1148,7 @@ static int ep0_queue(struct fsg_dev *fsg)
 
 
 static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
 static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
 {
 {
-	struct fsg_dev		*fsg = (struct fsg_dev *) ep->driver_data;
+	struct fsg_dev		*fsg = ep->driver_data;
 
 
 	if (req->actual > 0)
 	if (req->actual > 0)
 		dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
 		dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual);
@@ -1170,8 +1170,8 @@ static void ep0_complete(struct usb_ep *ep, struct usb_request *req)
 
 
 static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
 static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
 {
 {
-	struct fsg_dev		*fsg = (struct fsg_dev *) ep->driver_data;
-	struct fsg_buffhd	*bh = (struct fsg_buffhd *) req->context;
+	struct fsg_dev		*fsg = ep->driver_data;
+	struct fsg_buffhd	*bh = req->context;
 
 
 	if (req->status || req->actual != req->length)
 	if (req->status || req->actual != req->length)
 		DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
 		DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
@@ -1190,8 +1190,8 @@ static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req)
 
 
 static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
 static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
 {
 {
-	struct fsg_dev		*fsg = (struct fsg_dev *) ep->driver_data;
-	struct fsg_buffhd	*bh = (struct fsg_buffhd *) req->context;
+	struct fsg_dev		*fsg = ep->driver_data;
+	struct fsg_buffhd	*bh = req->context;
 
 
 	dump_msg(fsg, "bulk-out", req->buf, req->actual);
 	dump_msg(fsg, "bulk-out", req->buf, req->actual);
 	if (req->status || req->actual != bh->bulk_out_intended_length)
 	if (req->status || req->actual != bh->bulk_out_intended_length)
@@ -1214,8 +1214,8 @@ static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req)
 #ifdef CONFIG_USB_FILE_STORAGE_TEST
 #ifdef CONFIG_USB_FILE_STORAGE_TEST
 static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
 static void intr_in_complete(struct usb_ep *ep, struct usb_request *req)
 {
 {
-	struct fsg_dev		*fsg = (struct fsg_dev *) ep->driver_data;
-	struct fsg_buffhd	*bh = (struct fsg_buffhd *) req->context;
+	struct fsg_dev		*fsg = ep->driver_data;
+	struct fsg_buffhd	*bh = req->context;
 
 
 	if (req->status || req->actual != req->length)
 	if (req->status || req->actual != req->length)
 		DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
 		DBG(fsg, "%s --> %d, %u/%u\n", __FUNCTION__,
@@ -2577,7 +2577,7 @@ static int send_status(struct fsg_dev *fsg)
 	}
 	}
 
 
 	if (transport_is_bbb()) {
 	if (transport_is_bbb()) {
-		struct bulk_cs_wrap	*csw = (struct bulk_cs_wrap *) bh->buf;
+		struct bulk_cs_wrap	*csw = bh->buf;
 
 
 		/* Store and send the Bulk-only CSW */
 		/* Store and send the Bulk-only CSW */
 		csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG);
 		csw->Signature = __constant_cpu_to_le32(USB_BULK_CS_SIG);
@@ -2596,8 +2596,7 @@ static int send_status(struct fsg_dev *fsg)
 		return 0;
 		return 0;
 
 
 	} else {			// USB_PR_CBI
 	} else {			// USB_PR_CBI
-		struct interrupt_data	*buf = (struct interrupt_data *)
-						bh->buf;
+		struct interrupt_data	*buf = bh->buf;
 
 
 		/* Store and send the Interrupt data.  UFI sends the ASC
 		/* Store and send the Interrupt data.  UFI sends the ASC
 		 * and ASCQ bytes.  Everything else sends a Type (which
 		 * and ASCQ bytes.  Everything else sends a Type (which
@@ -2982,7 +2981,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
 static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
 static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
 {
 {
 	struct usb_request	*req = bh->outreq;
 	struct usb_request	*req = bh->outreq;
-	struct bulk_cb_wrap	*cbw = (struct bulk_cb_wrap *) req->buf;
+	struct bulk_cb_wrap	*cbw = req->buf;
 
 
 	/* Was this a real packet? */
 	/* Was this a real packet? */
 	if (req->status)
 	if (req->status)
@@ -3428,7 +3427,7 @@ static void handle_exception(struct fsg_dev *fsg)
 
 
 static int fsg_main_thread(void *fsg_)
 static int fsg_main_thread(void *fsg_)
 {
 {
-	struct fsg_dev		*fsg = (struct fsg_dev *) fsg_;
+	struct fsg_dev		*fsg = fsg_;
 
 
 	/* Allow the thread to be killed by a signal, but set the signal mask
 	/* 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. */
@@ -3600,7 +3599,7 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *
 static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf)
 static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
 	struct lun	*curlun = dev_to_lun(dev);
 	struct lun	*curlun = dev_to_lun(dev);
-	struct fsg_dev	*fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+	struct fsg_dev	*fsg = dev_get_drvdata(dev);
 	char		*p;
 	char		*p;
 	ssize_t		rc;
 	ssize_t		rc;
 
 
@@ -3629,7 +3628,7 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
 {
 {
 	ssize_t		rc = count;
 	ssize_t		rc = count;
 	struct lun	*curlun = dev_to_lun(dev);
 	struct lun	*curlun = dev_to_lun(dev);
-	struct fsg_dev	*fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+	struct fsg_dev	*fsg = dev_get_drvdata(dev);
 	int		i;
 	int		i;
 
 
 	if (sscanf(buf, "%d", &i) != 1)
 	if (sscanf(buf, "%d", &i) != 1)
@@ -3652,7 +3651,7 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
 static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
 {
 {
 	struct lun	*curlun = dev_to_lun(dev);
 	struct lun	*curlun = dev_to_lun(dev);
-	struct fsg_dev	*fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+	struct fsg_dev	*fsg = dev_get_drvdata(dev);
 	int		rc = 0;
 	int		rc = 0;
 
 
 	if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) {
 	if (curlun->prevent_medium_removal && backing_file_is_open(curlun)) {
@@ -3700,7 +3699,7 @@ static void fsg_release(struct kref *ref)
 
 
 static void lun_release(struct device *dev)
 static void lun_release(struct device *dev)
 {
 {
-	struct fsg_dev	*fsg = (struct fsg_dev *) dev_get_drvdata(dev);
+	struct fsg_dev	*fsg = dev_get_drvdata(dev);
 
 
 	kref_put(&fsg->ref, fsg_release);
 	kref_put(&fsg->ref, fsg_release);
 }
 }

+ 8 - 0
drivers/usb/gadget/gadget_chips.h

@@ -75,6 +75,12 @@
 #define	gadget_is_pxa27x(g)	0
 #define	gadget_is_pxa27x(g)	0
 #endif
 #endif
 
 
+#ifdef CONFIG_USB_GADGET_HUSB2DEV
+#define gadget_is_husb2dev(g)	!strcmp("husb2_udc", (g)->name)
+#else
+#define gadget_is_husb2dev(g)	0
+#endif
+
 #ifdef CONFIG_USB_GADGET_S3C2410
 #ifdef CONFIG_USB_GADGET_S3C2410
 #define gadget_is_s3c2410(g)    !strcmp("s3c2410_udc", (g)->name)
 #define gadget_is_s3c2410(g)    !strcmp("s3c2410_udc", (g)->name)
 #else
 #else
@@ -169,5 +175,7 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x16;
 		return 0x16;
 	else if (gadget_is_mpc8272(gadget))
 	else if (gadget_is_mpc8272(gadget))
 		return 0x17;
 		return 0x17;
+	else if (gadget_is_husb2dev(gadget))
+		return 0x18;
 	return -ENOENT;
 	return -ENOENT;
 }
 }

+ 1 - 1
drivers/usb/gadget/gmidi.c

@@ -35,7 +35,7 @@
 #include <sound/initval.h>
 #include <sound/initval.h>
 #include <sound/rawmidi.h>
 #include <sound/rawmidi.h>
 
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb/audio.h>
 #include <linux/usb/audio.h>
 #include <linux/usb/midi.h>
 #include <linux/usb/midi.h>

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

@@ -39,7 +39,7 @@
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/proc_fs.h>
 #include <linux/proc_fs.h>
 #include <linux/device.h>
 #include <linux/device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb_gadget.h>
 
 
 #include <asm/byteorder.h>
 #include <asm/byteorder.h>

+ 105 - 135
drivers/usb/gadget/inode.c

@@ -20,7 +20,7 @@
  */
  */
 
 
 
 
-// #define	DEBUG 			/* data to help fault diagnosis */
+// #define	DEBUG			/* data to help fault diagnosis */
 // #define	VERBOSE		/* extra debug messages (success too) */
 // #define	VERBOSE		/* extra debug messages (success too) */
 
 
 #include <linux/init.h>
 #include <linux/init.h>
@@ -59,11 +59,11 @@
  *   may serve as a source of device events, used to handle all control
  *   may serve as a source of device events, used to handle all control
  *   requests other than basic enumeration.
  *   requests other than basic enumeration.
  *
  *
- * - Then either immediately, or after a SET_CONFIGURATION control request,
- *   ep_config() is called when each /dev/gadget/ep* file is configured
- *   (by writing endpoint descriptors).  Afterwards these files are used
- *   to write() IN data or to read() OUT data.  To halt the endpoint, a
- *   "wrong direction" request is issued (like reading an IN endpoint).
+ * - Then, after a SET_CONFIGURATION control request, ep_config() is
+ *   called when each /dev/gadget/ep* file is configured (by writing
+ *   endpoint descriptors).  Afterwards these files are used to write()
+ *   IN data or to read() OUT data.  To halt the endpoint, a "wrong
+ *   direction" request is issued (like reading an IN endpoint).
  *
  *
  * Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe
  * Unlike "usbfs" the only ioctl()s are for things that are rare, and maybe
  * not possible on all hardware.  For example, precise fault handling with
  * not possible on all hardware.  For example, precise fault handling with
@@ -98,16 +98,16 @@ enum ep0_state {
 	 * must always write descriptors to initialize the device, then
 	 * must always write descriptors to initialize the device, then
 	 * the device becomes UNCONNECTED until enumeration.
 	 * the device becomes UNCONNECTED until enumeration.
 	 */
 	 */
-	STATE_OPENED,
+	STATE_DEV_OPENED,
 
 
 	/* From then on, ep0 fd is in either of two basic modes:
 	/* From then on, ep0 fd is in either of two basic modes:
 	 * - (UN)CONNECTED: read usb_gadgetfs_event(s) from it
 	 * - (UN)CONNECTED: read usb_gadgetfs_event(s) from it
 	 * - SETUP: read/write will transfer control data and succeed;
 	 * - SETUP: read/write will transfer control data and succeed;
 	 *   or if "wrong direction", performs protocol stall
 	 *   or if "wrong direction", performs protocol stall
 	 */
 	 */
-	STATE_UNCONNECTED,
-	STATE_CONNECTED,
-	STATE_SETUP,
+	STATE_DEV_UNCONNECTED,
+	STATE_DEV_CONNECTED,
+	STATE_DEV_SETUP,
 
 
 	/* UNBOUND means the driver closed ep0, so the device won't be
 	/* UNBOUND means the driver closed ep0, so the device won't be
 	 * accessible again (DEV_DISABLED) until all fds are closed.
 	 * accessible again (DEV_DISABLED) until all fds are closed.
@@ -121,7 +121,7 @@ enum ep0_state {
 struct dev_data {
 struct dev_data {
 	spinlock_t			lock;
 	spinlock_t			lock;
 	atomic_t			count;
 	atomic_t			count;
-	enum ep0_state			state;
+	enum ep0_state			state;		/* P: lock */
 	struct usb_gadgetfs_event	event [N_EVENT];
 	struct usb_gadgetfs_event	event [N_EVENT];
 	unsigned			ev_next;
 	unsigned			ev_next;
 	struct fasync_struct		*fasync;
 	struct fasync_struct		*fasync;
@@ -188,7 +188,6 @@ static struct dev_data *dev_new (void)
 enum ep_state {
 enum ep_state {
 	STATE_EP_DISABLED = 0,
 	STATE_EP_DISABLED = 0,
 	STATE_EP_READY,
 	STATE_EP_READY,
-	STATE_EP_DEFER_ENABLE,
 	STATE_EP_ENABLED,
 	STATE_EP_ENABLED,
 	STATE_EP_UNBOUND,
 	STATE_EP_UNBOUND,
 };
 };
@@ -313,18 +312,10 @@ nonblock:
 
 
 	if ((val = down_interruptible (&epdata->lock)) < 0)
 	if ((val = down_interruptible (&epdata->lock)) < 0)
 		return val;
 		return val;
-newstate:
+
 	switch (epdata->state) {
 	switch (epdata->state) {
 	case STATE_EP_ENABLED:
 	case STATE_EP_ENABLED:
 		break;
 		break;
-	case STATE_EP_DEFER_ENABLE:
-		DBG (epdata->dev, "%s wait for host\n", epdata->name);
-		if ((val = wait_event_interruptible (epdata->wait, 
-				epdata->state != STATE_EP_DEFER_ENABLE
-				|| epdata->dev->state == STATE_DEV_UNBOUND
-				)) < 0)
-			goto fail;
-		goto newstate;
 	// case STATE_EP_DISABLED:		/* "can't happen" */
 	// case STATE_EP_DISABLED:		/* "can't happen" */
 	// case STATE_EP_READY:			/* "can't happen" */
 	// case STATE_EP_READY:			/* "can't happen" */
 	default:				/* error! */
 	default:				/* error! */
@@ -333,7 +324,6 @@ newstate:
 		// FALLTHROUGH
 		// FALLTHROUGH
 	case STATE_EP_UNBOUND:			/* clean disconnect */
 	case STATE_EP_UNBOUND:			/* clean disconnect */
 		val = -ENODEV;
 		val = -ENODEV;
-fail:
 		up (&epdata->lock);
 		up (&epdata->lock);
 	}
 	}
 	return val;
 	return val;
@@ -565,29 +555,28 @@ static ssize_t ep_aio_read_retry(struct kiocb *iocb)
 	ssize_t			len, total;
 	ssize_t			len, total;
 	int			i;
 	int			i;
 
 
-  	/* we "retry" to get the right mm context for this: */
-
- 	/* copy stuff into user buffers */
- 	total = priv->actual;
- 	len = 0;
- 	for (i=0; i < priv->nr_segs; i++) {
- 		ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
-
- 		if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
- 			if (len == 0)
- 				len = -EFAULT;
- 			break;
- 		}
-
- 		total -= this;
- 		len += this;
- 		if (total == 0)
- 			break;
- 	}
-  	kfree(priv->buf);
-  	kfree(priv);
-  	aio_put_req(iocb);
- 	return len;
+	/* we "retry" to get the right mm context for this: */
+
+	/* copy stuff into user buffers */
+	total = priv->actual;
+	len = 0;
+	for (i=0; i < priv->nr_segs; i++) {
+		ssize_t this = min((ssize_t)(priv->iv[i].iov_len), total);
+
+		if (copy_to_user(priv->iv[i].iov_base, priv->buf, this)) {
+			if (len == 0)
+				len = -EFAULT;
+			break;
+		}
+
+		total -= this;
+		len += this;
+		if (total == 0)
+			break;
+	}
+	kfree(priv->buf);
+	kfree(priv);
+	return len;
 }
 }
 
 
 static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
 static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
@@ -600,18 +589,17 @@ static void ep_aio_complete(struct usb_ep *ep, struct usb_request *req)
 	spin_lock(&epdata->dev->lock);
 	spin_lock(&epdata->dev->lock);
 	priv->req = NULL;
 	priv->req = NULL;
 	priv->epdata = NULL;
 	priv->epdata = NULL;
-	if (priv->iv == NULL
-			|| unlikely(req->actual == 0)
-			|| unlikely(kiocbIsCancelled(iocb))) {
+
+	/* if this was a write or a read returning no data then we
+	 * don't need to copy anything to userspace, so we can
+	 * complete the aio request immediately.
+	 */
+	if (priv->iv == NULL || unlikely(req->actual == 0)) {
 		kfree(req->buf);
 		kfree(req->buf);
 		kfree(priv);
 		kfree(priv);
 		iocb->private = NULL;
 		iocb->private = NULL;
 		/* aio_complete() reports bytes-transferred _and_ faults */
 		/* aio_complete() reports bytes-transferred _and_ faults */
-		if (unlikely(kiocbIsCancelled(iocb)))
-			aio_put_req(iocb);
-		else
-			aio_complete(iocb,
-				req->actual ? req->actual : req->status,
+		aio_complete(iocb, req->actual ? req->actual : req->status,
 				req->status);
 				req->status);
 	} else {
 	} else {
 		/* retry() won't report both; so we hide some faults */
 		/* retry() won't report both; so we hide some faults */
@@ -636,7 +624,7 @@ ep_aio_rwtail(
 	size_t		len,
 	size_t		len,
 	struct ep_data	*epdata,
 	struct ep_data	*epdata,
 	const struct iovec *iv,
 	const struct iovec *iv,
-	unsigned long 	nr_segs
+	unsigned long	nr_segs
 )
 )
 {
 {
 	struct kiocb_priv	*priv;
 	struct kiocb_priv	*priv;
@@ -852,9 +840,9 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
 		break;
 		break;
 #endif
 #endif
 	default:
 	default:
-		DBG (data->dev, "unconnected, %s init deferred\n",
+		DBG(data->dev, "unconnected, %s init abandoned\n",
 				data->name);
 				data->name);
-		data->state = STATE_EP_DEFER_ENABLE;
+		value = -EINVAL;
 	}
 	}
 	if (value == 0) {
 	if (value == 0) {
 		fd->f_op = &ep_io_operations;
 		fd->f_op = &ep_io_operations;
@@ -943,22 +931,24 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req)
 static void ep0_complete (struct usb_ep *ep, struct usb_request *req)
 static void ep0_complete (struct usb_ep *ep, struct usb_request *req)
 {
 {
 	struct dev_data		*dev = ep->driver_data;
 	struct dev_data		*dev = ep->driver_data;
+	unsigned long		flags;
 	int			free = 1;
 	int			free = 1;
 
 
 	/* for control OUT, data must still get to userspace */
 	/* for control OUT, data must still get to userspace */
+	spin_lock_irqsave(&dev->lock, flags);
 	if (!dev->setup_in) {
 	if (!dev->setup_in) {
 		dev->setup_out_error = (req->status != 0);
 		dev->setup_out_error = (req->status != 0);
 		if (!dev->setup_out_error)
 		if (!dev->setup_out_error)
 			free = 0;
 			free = 0;
 		dev->setup_out_ready = 1;
 		dev->setup_out_ready = 1;
 		ep0_readable (dev);
 		ep0_readable (dev);
-	} else if (dev->state == STATE_SETUP)
-		dev->state = STATE_CONNECTED;
+	}
 
 
 	/* clean up as appropriate */
 	/* clean up as appropriate */
 	if (free && req->buf != &dev->rbuf)
 	if (free && req->buf != &dev->rbuf)
 		clean_req (ep, req);
 		clean_req (ep, req);
 	req->complete = epio_complete;
 	req->complete = epio_complete;
+	spin_unlock_irqrestore(&dev->lock, flags);
 }
 }
 
 
 static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
 static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
@@ -998,13 +988,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
 	}
 	}
 
 
 	/* control DATA stage */
 	/* control DATA stage */
-	if ((state = dev->state) == STATE_SETUP) {
+	if ((state = dev->state) == STATE_DEV_SETUP) {
 
 
 		if (dev->setup_in) {		/* stall IN */
 		if (dev->setup_in) {		/* stall IN */
 			VDEBUG(dev, "ep0in stall\n");
 			VDEBUG(dev, "ep0in stall\n");
 			(void) usb_ep_set_halt (dev->gadget->ep0);
 			(void) usb_ep_set_halt (dev->gadget->ep0);
 			retval = -EL2HLT;
 			retval = -EL2HLT;
-			dev->state = STATE_CONNECTED;
+			dev->state = STATE_DEV_CONNECTED;
 
 
 		} else if (len == 0) {		/* ack SET_CONFIGURATION etc */
 		} else if (len == 0) {		/* ack SET_CONFIGURATION etc */
 			struct usb_ep		*ep = dev->gadget->ep0;
 			struct usb_ep		*ep = dev->gadget->ep0;
@@ -1012,7 +1002,7 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
 
 
 			if ((retval = setup_req (ep, req, 0)) == 0)
 			if ((retval = setup_req (ep, req, 0)) == 0)
 				retval = usb_ep_queue (ep, req, GFP_ATOMIC);
 				retval = usb_ep_queue (ep, req, GFP_ATOMIC);
-			dev->state = STATE_CONNECTED;
+			dev->state = STATE_DEV_CONNECTED;
 
 
 			/* assume that was SET_CONFIGURATION */
 			/* assume that was SET_CONFIGURATION */
 			if (dev->current_config) {
 			if (dev->current_config) {
@@ -1040,6 +1030,13 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
 			spin_lock_irq (&dev->lock);
 			spin_lock_irq (&dev->lock);
 			if (retval)
 			if (retval)
 				goto done;
 				goto done;
+
+			if (dev->state != STATE_DEV_SETUP) {
+				retval = -ECANCELED;
+				goto done;
+			}
+			dev->state = STATE_DEV_CONNECTED;
+
 			if (dev->setup_out_error)
 			if (dev->setup_out_error)
 				retval = -EIO;
 				retval = -EIO;
 			else {
 			else {
@@ -1066,39 +1063,36 @@ scan:
 	/* return queued events right away */
 	/* return queued events right away */
 	if (dev->ev_next != 0) {
 	if (dev->ev_next != 0) {
 		unsigned		i, n;
 		unsigned		i, n;
-		int			tmp = dev->ev_next;
 
 
-		len = min (len, tmp * sizeof (struct usb_gadgetfs_event));
 		n = len / sizeof (struct usb_gadgetfs_event);
 		n = len / sizeof (struct usb_gadgetfs_event);
+		if (dev->ev_next < n)
+			n = dev->ev_next;
 
 
-		/* ep0 can't deliver events when STATE_SETUP */
+		/* ep0 i/o has special semantics during STATE_DEV_SETUP */
 		for (i = 0; i < n; i++) {
 		for (i = 0; i < n; i++) {
 			if (dev->event [i].type == GADGETFS_SETUP) {
 			if (dev->event [i].type == GADGETFS_SETUP) {
-				len = i + 1;
-				len *= sizeof (struct usb_gadgetfs_event);
-				n = 0;
+				dev->state = STATE_DEV_SETUP;
+				n = i + 1;
 				break;
 				break;
 			}
 			}
 		}
 		}
 		spin_unlock_irq (&dev->lock);
 		spin_unlock_irq (&dev->lock);
+		len = n * sizeof (struct usb_gadgetfs_event);
 		if (copy_to_user (buf, &dev->event, len))
 		if (copy_to_user (buf, &dev->event, len))
 			retval = -EFAULT;
 			retval = -EFAULT;
 		else
 		else
 			retval = len;
 			retval = len;
 		if (len > 0) {
 		if (len > 0) {
-			len /= sizeof (struct usb_gadgetfs_event);
-
 			/* NOTE this doesn't guard against broken drivers;
 			/* NOTE this doesn't guard against broken drivers;
 			 * concurrent ep0 readers may lose events.
 			 * concurrent ep0 readers may lose events.
 			 */
 			 */
 			spin_lock_irq (&dev->lock);
 			spin_lock_irq (&dev->lock);
-			dev->ev_next -= len;
-			if (dev->ev_next != 0)
-				memmove (&dev->event, &dev->event [len],
+			if (dev->ev_next > n) {
+				memmove(&dev->event[0], &dev->event[n],
 					sizeof (struct usb_gadgetfs_event)
 					sizeof (struct usb_gadgetfs_event)
-						* (tmp - len));
-			if (n == 0)
-				dev->state = STATE_SETUP;
+						* (dev->ev_next - n));
+			}
+			dev->ev_next -= n;
 			spin_unlock_irq (&dev->lock);
 			spin_unlock_irq (&dev->lock);
 		}
 		}
 		return retval;
 		return retval;
@@ -1113,8 +1107,8 @@ scan:
 		DBG (dev, "fail %s, state %d\n", __FUNCTION__, state);
 		DBG (dev, "fail %s, state %d\n", __FUNCTION__, state);
 		retval = -ESRCH;
 		retval = -ESRCH;
 		break;
 		break;
-	case STATE_UNCONNECTED:
-	case STATE_CONNECTED:
+	case STATE_DEV_UNCONNECTED:
+	case STATE_DEV_CONNECTED:
 		spin_unlock_irq (&dev->lock);
 		spin_unlock_irq (&dev->lock);
 		DBG (dev, "%s wait\n", __FUNCTION__);
 		DBG (dev, "%s wait\n", __FUNCTION__);
 
 
@@ -1141,7 +1135,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
 	switch (type) {
 	switch (type) {
 	/* these events purge the queue */
 	/* these events purge the queue */
 	case GADGETFS_DISCONNECT:
 	case GADGETFS_DISCONNECT:
-		if (dev->state == STATE_SETUP)
+		if (dev->state == STATE_DEV_SETUP)
 			dev->setup_abort = 1;
 			dev->setup_abort = 1;
 		// FALL THROUGH
 		// FALL THROUGH
 	case GADGETFS_CONNECT:
 	case GADGETFS_CONNECT:
@@ -1153,7 +1147,7 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
 		for (i = 0; i != dev->ev_next; i++) {
 		for (i = 0; i != dev->ev_next; i++) {
 			if (dev->event [i].type != type)
 			if (dev->event [i].type != type)
 				continue;
 				continue;
-			DBG (dev, "discard old event %d\n", type);
+			DBG(dev, "discard old event[%d] %d\n", i, type);
 			dev->ev_next--;
 			dev->ev_next--;
 			if (i == dev->ev_next)
 			if (i == dev->ev_next)
 				break;
 				break;
@@ -1166,9 +1160,9 @@ next_event (struct dev_data *dev, enum usb_gadgetfs_event_type type)
 	default:
 	default:
 		BUG ();
 		BUG ();
 	}
 	}
+	VDEBUG(dev, "event[%d] = %d\n", dev->ev_next, type);
 	event = &dev->event [dev->ev_next++];
 	event = &dev->event [dev->ev_next++];
 	BUG_ON (dev->ev_next > N_EVENT);
 	BUG_ON (dev->ev_next > N_EVENT);
-	VDEBUG (dev, "ev %d, next %d\n", type, dev->ev_next);
 	memset (event, 0, sizeof *event);
 	memset (event, 0, sizeof *event);
 	event->type = type;
 	event->type = type;
 	return event;
 	return event;
@@ -1188,12 +1182,13 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
 		retval = -EIDRM;
 		retval = -EIDRM;
 
 
 	/* data and/or status stage for control request */
 	/* data and/or status stage for control request */
-	} else if (dev->state == STATE_SETUP) {
+	} else if (dev->state == STATE_DEV_SETUP) {
 
 
 		/* IN DATA+STATUS caller makes len <= wLength */
 		/* IN DATA+STATUS caller makes len <= wLength */
 		if (dev->setup_in) {
 		if (dev->setup_in) {
 			retval = setup_req (dev->gadget->ep0, dev->req, len);
 			retval = setup_req (dev->gadget->ep0, dev->req, len);
 			if (retval == 0) {
 			if (retval == 0) {
+				dev->state = STATE_DEV_CONNECTED;
 				spin_unlock_irq (&dev->lock);
 				spin_unlock_irq (&dev->lock);
 				if (copy_from_user (dev->req->buf, buf, len))
 				if (copy_from_user (dev->req->buf, buf, len))
 					retval = -EFAULT;
 					retval = -EFAULT;
@@ -1219,7 +1214,7 @@ ep0_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
 			VDEBUG(dev, "ep0out stall\n");
 			VDEBUG(dev, "ep0out stall\n");
 			(void) usb_ep_set_halt (dev->gadget->ep0);
 			(void) usb_ep_set_halt (dev->gadget->ep0);
 			retval = -EL2HLT;
 			retval = -EL2HLT;
-			dev->state = STATE_CONNECTED;
+			dev->state = STATE_DEV_CONNECTED;
 		} else {
 		} else {
 			DBG(dev, "bogus ep0out stall!\n");
 			DBG(dev, "bogus ep0out stall!\n");
 		}
 		}
@@ -1261,7 +1256,9 @@ dev_release (struct inode *inode, struct file *fd)
 	put_dev (dev);
 	put_dev (dev);
 
 
 	/* other endpoints were all decoupled from this device */
 	/* other endpoints were all decoupled from this device */
+	spin_lock_irq(&dev->lock);
 	dev->state = STATE_DEV_DISABLED;
 	dev->state = STATE_DEV_DISABLED;
+	spin_unlock_irq(&dev->lock);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1282,7 +1279,7 @@ ep0_poll (struct file *fd, poll_table *wait)
                goto out;
                goto out;
        }
        }
 
 
-       if (dev->state == STATE_SETUP) {
+       if (dev->state == STATE_DEV_SETUP) {
                if (dev->setup_in || dev->setup_can_stall)
                if (dev->setup_in || dev->setup_can_stall)
                        mask = POLLOUT;
                        mask = POLLOUT;
        } else {
        } else {
@@ -1392,52 +1389,29 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 
 
 	spin_lock (&dev->lock);
 	spin_lock (&dev->lock);
 	dev->setup_abort = 0;
 	dev->setup_abort = 0;
-	if (dev->state == STATE_UNCONNECTED) {
-		struct usb_ep	*ep;
-		struct ep_data	*data;
-
-		dev->state = STATE_CONNECTED;
-		dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
-
+	if (dev->state == STATE_DEV_UNCONNECTED) {
 #ifdef	CONFIG_USB_GADGET_DUALSPEED
 #ifdef	CONFIG_USB_GADGET_DUALSPEED
 		if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == 0) {
 		if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == 0) {
+			spin_unlock(&dev->lock);
 			ERROR (dev, "no high speed config??\n");
 			ERROR (dev, "no high speed config??\n");
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
 #endif	/* CONFIG_USB_GADGET_DUALSPEED */
 #endif	/* CONFIG_USB_GADGET_DUALSPEED */
 
 
+		dev->state = STATE_DEV_CONNECTED;
+		dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
+
 		INFO (dev, "connected\n");
 		INFO (dev, "connected\n");
 		event = next_event (dev, GADGETFS_CONNECT);
 		event = next_event (dev, GADGETFS_CONNECT);
 		event->u.speed = gadget->speed;
 		event->u.speed = gadget->speed;
 		ep0_readable (dev);
 		ep0_readable (dev);
 
 
-		list_for_each_entry (ep, &gadget->ep_list, ep_list) {
-			data = ep->driver_data;
-			/* ... down_trylock (&data->lock) ... */
-			if (data->state != STATE_EP_DEFER_ENABLE)
-				continue;
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-			if (gadget->speed == USB_SPEED_HIGH)
-				value = usb_ep_enable (ep, &data->hs_desc);
-			else
-#endif	/* CONFIG_USB_GADGET_DUALSPEED */
-				value = usb_ep_enable (ep, &data->desc);
-			if (value) {
-				ERROR (dev, "deferred %s enable --> %d\n",
-					data->name, value);
-				continue;
-			}
-			data->state = STATE_EP_ENABLED;
-			wake_up (&data->wait);
-			DBG (dev, "woke up %s waiters\n", data->name);
-		}
-
 	/* host may have given up waiting for response.  we can miss control
 	/* host may have given up waiting for response.  we can miss control
 	 * requests handled lower down (device/endpoint status and features);
 	 * requests handled lower down (device/endpoint status and features);
 	 * then ep0_{read,write} will report the wrong status. controller
 	 * then ep0_{read,write} will report the wrong status. controller
 	 * driver will have aborted pending i/o.
 	 * driver will have aborted pending i/o.
 	 */
 	 */
-	} else if (dev->state == STATE_SETUP)
+	} else if (dev->state == STATE_DEV_SETUP)
 		dev->setup_abort = 1;
 		dev->setup_abort = 1;
 
 
 	req->buf = dev->rbuf;
 	req->buf = dev->rbuf;
@@ -1583,7 +1557,7 @@ delegate:
 	}
 	}
 
 
 	/* proceed with data transfer and status phases? */
 	/* proceed with data transfer and status phases? */
-	if (value >= 0 && dev->state != STATE_SETUP) {
+	if (value >= 0 && dev->state != STATE_DEV_SETUP) {
 		req->length = value;
 		req->length = value;
 		req->zero = value < w_length;
 		req->zero = value < w_length;
 		value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
 		value = usb_ep_queue (gadget->ep0, req, GFP_ATOMIC);
@@ -1747,7 +1721,9 @@ gadgetfs_bind (struct usb_gadget *gadget)
 		goto enomem;
 		goto enomem;
 
 
 	INFO (dev, "bound to %s driver\n", gadget->name);
 	INFO (dev, "bound to %s driver\n", gadget->name);
-	dev->state = STATE_UNCONNECTED;
+	spin_lock_irq(&dev->lock);
+	dev->state = STATE_DEV_UNCONNECTED;
+	spin_unlock_irq(&dev->lock);
 	get_dev (dev);
 	get_dev (dev);
 	return 0;
 	return 0;
 
 
@@ -1762,11 +1738,9 @@ gadgetfs_disconnect (struct usb_gadget *gadget)
 	struct dev_data		*dev = get_gadget_data (gadget);
 	struct dev_data		*dev = get_gadget_data (gadget);
 
 
 	spin_lock (&dev->lock);
 	spin_lock (&dev->lock);
-	if (dev->state == STATE_UNCONNECTED) {
-		DBG (dev, "already unconnected\n");
+	if (dev->state == STATE_DEV_UNCONNECTED)
 		goto exit;
 		goto exit;
-	}
-	dev->state = STATE_UNCONNECTED;
+	dev->state = STATE_DEV_UNCONNECTED;
 
 
 	INFO (dev, "disconnected\n");
 	INFO (dev, "disconnected\n");
 	next_event (dev, GADGETFS_DISCONNECT);
 	next_event (dev, GADGETFS_DISCONNECT);
@@ -1783,9 +1757,9 @@ gadgetfs_suspend (struct usb_gadget *gadget)
 	INFO (dev, "suspended from state %d\n", dev->state);
 	INFO (dev, "suspended from state %d\n", dev->state);
 	spin_lock (&dev->lock);
 	spin_lock (&dev->lock);
 	switch (dev->state) {
 	switch (dev->state) {
-	case STATE_SETUP:		// VERY odd... host died??
-	case STATE_CONNECTED:
-	case STATE_UNCONNECTED:
+	case STATE_DEV_SETUP:		// VERY odd... host died??
+	case STATE_DEV_CONNECTED:
+	case STATE_DEV_UNCONNECTED:
 		next_event (dev, GADGETFS_SUSPEND);
 		next_event (dev, GADGETFS_SUSPEND);
 		ep0_readable (dev);
 		ep0_readable (dev);
 		/* FALLTHROUGH */
 		/* FALLTHROUGH */
@@ -1808,7 +1782,7 @@ static struct usb_gadget_driver gadgetfs_driver = {
 	.disconnect	= gadgetfs_disconnect,
 	.disconnect	= gadgetfs_disconnect,
 	.suspend	= gadgetfs_suspend,
 	.suspend	= gadgetfs_suspend,
 
 
-	.driver 	= {
+	.driver	= {
 		.name		= (char *) shortname,
 		.name		= (char *) shortname,
 	},
 	},
 };
 };
@@ -1829,7 +1803,7 @@ static struct usb_gadget_driver probe_driver = {
 	.unbind		= gadgetfs_nop,
 	.unbind		= gadgetfs_nop,
 	.setup		= (void *)gadgetfs_nop,
 	.setup		= (void *)gadgetfs_nop,
 	.disconnect	= gadgetfs_nop,
 	.disconnect	= gadgetfs_nop,
-	.driver 	= {
+	.driver	= {
 		.name		= "nop",
 		.name		= "nop",
 	},
 	},
 };
 };
@@ -1849,19 +1823,16 @@ static struct usb_gadget_driver probe_driver = {
  * . full/low speed config ... all wTotalLength bytes (with interface,
  * . full/low speed config ... all wTotalLength bytes (with interface,
  *	class, altsetting, endpoint, and other descriptors)
  *	class, altsetting, endpoint, and other descriptors)
  * . high speed config ... all descriptors, for high speed operation;
  * . high speed config ... all descriptors, for high speed operation;
- * 	this one's optional except for high-speed hardware
+ *	this one's optional except for high-speed hardware
  * . device descriptor
  * . device descriptor
  *
  *
- * Endpoints are not yet enabled. Drivers may want to immediately
- * initialize them, using the /dev/gadget/ep* files that are available
- * as soon as the kernel sees the configuration, or they can wait
- * until device configuration and interface altsetting changes create
+ * Endpoints are not yet enabled. Drivers must wait until device
+ * configuration and interface altsetting changes create
  * the need to configure (or unconfigure) them.
  * the need to configure (or unconfigure) them.
  *
  *
  * After initialization, the device stays active for as long as that
  * After initialization, the device stays active for as long as that
- * $CHIP file is open.  Events may then be read from that descriptor,
- * such as configuration notifications.  More complex drivers will handle
- * some control requests in user space.
+ * $CHIP file is open.  Events must then be read from that descriptor,
+ * such as configuration notifications.
  */
  */
 
 
 static int is_valid_config (struct usb_config_descriptor *config)
 static int is_valid_config (struct usb_config_descriptor *config)
@@ -1884,9 +1855,6 @@ dev_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
 	u32			tag;
 	u32			tag;
 	char			*kbuf;
 	char			*kbuf;
 
 
-	if (dev->state != STATE_OPENED)
-		return -EEXIST;
-
 	if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4))
 	if (len < (USB_DT_CONFIG_SIZE + USB_DT_DEVICE_SIZE + 4))
 		return -EINVAL;
 		return -EINVAL;
 
 
@@ -1978,13 +1946,15 @@ dev_open (struct inode *inode, struct file *fd)
 	struct dev_data		*dev = inode->i_private;
 	struct dev_data		*dev = inode->i_private;
 	int			value = -EBUSY;
 	int			value = -EBUSY;
 
 
+	spin_lock_irq(&dev->lock);
 	if (dev->state == STATE_DEV_DISABLED) {
 	if (dev->state == STATE_DEV_DISABLED) {
 		dev->ev_next = 0;
 		dev->ev_next = 0;
-		dev->state = STATE_OPENED;
+		dev->state = STATE_DEV_OPENED;
 		fd->private_data = dev;
 		fd->private_data = dev;
 		get_dev (dev);
 		get_dev (dev);
 		value = 0;
 		value = 0;
 	}
 	}
+	spin_unlock_irq(&dev->lock);
 	return value;
 	return value;
 }
 }
 
 

+ 1 - 1
drivers/usb/gadget/lh7a40x_udc.h

@@ -49,7 +49,7 @@
 #include <asm/unaligned.h>
 #include <asm/unaligned.h>
 #include <asm/hardware.h>
 #include <asm/hardware.h>
 
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb_gadget.h>
 
 
 /*
 /*

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

@@ -63,7 +63,7 @@
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
 #include <linux/moduleparam.h>
 #include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb_gadget.h>
 
 
 #include <asm/byteorder.h>
 #include <asm/byteorder.h>

+ 1 - 1
drivers/usb/gadget/omap_udc.c

@@ -38,7 +38,7 @@
 #include <linux/mm.h>
 #include <linux/mm.h>
 #include <linux/moduleparam.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/otg.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>

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

@@ -56,7 +56,7 @@
 #include <asm/arch/pxa-regs.h>
 #include <asm/arch/pxa-regs.h>
 #endif
 #endif
 
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb_gadget.h>
 
 
 #include <asm/arch/udc.h>
 #include <asm/arch/udc.h>

+ 1 - 1
drivers/usb/gadget/serial.c

@@ -43,7 +43,7 @@
 #include <asm/unaligned.h>
 #include <asm/unaligned.h>
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
 #include <linux/usb/cdc.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb_gadget.h>
 
 

+ 1 - 1
drivers/usb/gadget/usbstring.c

@@ -14,7 +14,7 @@
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/init.h>
 #include <linux/init.h>
 
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb_gadget.h>
 
 
 #include <asm/unaligned.h>
 #include <asm/unaligned.h>

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

@@ -84,7 +84,7 @@
 #include <asm/system.h>
 #include <asm/system.h>
 #include <asm/unaligned.h>
 #include <asm/unaligned.h>
 
 
-#include <linux/usb_ch9.h>
+#include <linux/usb/ch9.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb_gadget.h>
 
 
 #include "gadget_chips.h"
 #include "gadget_chips.h"

+ 35 - 3
drivers/usb/host/Kconfig

@@ -67,6 +67,11 @@ config USB_EHCI_TT_NEWSCHED
 
 
 	  If unsure, say N.
 	  If unsure, say N.
 
 
+config USB_EHCI_BIG_ENDIAN_MMIO
+	bool
+	depends on USB_EHCI_HCD
+	default n
+
 config USB_ISP116X_HCD
 config USB_ISP116X_HCD
 	tristate "ISP116X HCD support"
 	tristate "ISP116X HCD support"
 	depends on USB
 	depends on USB
@@ -101,21 +106,48 @@ config USB_OHCI_HCD_PPC_SOC
 	bool "OHCI support for on-chip PPC USB controller"
 	bool "OHCI support for on-chip PPC USB controller"
 	depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
 	depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
 	default y
 	default y
-	select USB_OHCI_BIG_ENDIAN
+	select USB_OHCI_BIG_ENDIAN_DESC
+	select USB_OHCI_BIG_ENDIAN_MMIO
 	---help---
 	---help---
 	  Enables support for the USB controller on the MPC52xx or
 	  Enables support for the USB controller on the MPC52xx or
 	  STB03xxx processor chip.  If unsure, say Y.
 	  STB03xxx processor chip.  If unsure, say Y.
 
 
+config USB_OHCI_HCD_PPC_OF
+	bool "OHCI support for PPC USB controller on OF platform bus"
+	depends on USB_OHCI_HCD && PPC_OF
+	default y
+	---help---
+	  Enables support for the USB controller PowerPC present on the
+	  OpenFirmware platform bus.
+
+config USB_OHCI_HCD_PPC_OF_BE
+	bool "Support big endian HC"
+	depends on USB_OHCI_HCD_PPC_OF
+	default y
+	select USB_OHCI_BIG_ENDIAN_DESC
+	select USB_OHCI_BIG_ENDIAN_MMIO
+
+config USB_OHCI_HCD_PPC_OF_LE
+	bool "Support little endian HC"
+	depends on USB_OHCI_HCD_PPC_OF
+	default n
+	select USB_OHCI_LITTLE_ENDIAN
+
 config USB_OHCI_HCD_PCI
 config USB_OHCI_HCD_PCI
 	bool "OHCI support for PCI-bus USB controllers"
 	bool "OHCI support for PCI-bus USB controllers"
-	depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx)
+	depends on USB_OHCI_HCD && PCI && (STB03xxx || PPC_MPC52xx || USB_OHCI_HCD_PPC_OF)
 	default y
 	default y
 	select USB_OHCI_LITTLE_ENDIAN
 	select USB_OHCI_LITTLE_ENDIAN
 	---help---
 	---help---
 	  Enables support for PCI-bus plug-in USB controller cards.
 	  Enables support for PCI-bus plug-in USB controller cards.
 	  If unsure, say Y.
 	  If unsure, say Y.
 
 
-config USB_OHCI_BIG_ENDIAN
+config USB_OHCI_BIG_ENDIAN_DESC
+	bool
+	depends on USB_OHCI_HCD
+	default n
+
+config USB_OHCI_BIG_ENDIAN_MMIO
 	bool
 	bool
 	depends on USB_OHCI_HCD
 	depends on USB_OHCI_HCD
 	default n
 	default n

+ 12 - 12
drivers/usb/host/ehci-dbg.c

@@ -43,7 +43,7 @@
  */
  */
 static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
 static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
 {
 {
-	u32	params = readl (&ehci->caps->hcs_params);
+	u32	params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
 
 	ehci_dbg (ehci,
 	ehci_dbg (ehci,
 		"%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n",
 		"%s hcs_params 0x%x dbg=%d%s cc=%d pcc=%d%s%s ports=%d\n",
@@ -87,7 +87,7 @@ static inline void dbg_hcs_params (struct ehci_hcd *ehci, char *label) {}
  * */
  * */
 static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
 static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
 {
 {
-	u32	params = readl (&ehci->caps->hcc_params);
+	u32	params = ehci_readl(ehci, &ehci->caps->hcc_params);
 
 
 	if (HCC_ISOC_CACHE (params)) {
 	if (HCC_ISOC_CACHE (params)) {
 		ehci_dbg (ehci,
 		ehci_dbg (ehci,
@@ -653,7 +653,7 @@ show_registers (struct class_device *class_dev, char *buf)
 	}
 	}
 
 
 	/* Capability Registers */
 	/* Capability Registers */
-	i = HC_VERSION(readl (&ehci->caps->hc_capbase));
+	i = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
 	temp = scnprintf (next, size,
 	temp = scnprintf (next, size,
 		"bus %s, device %s (driver " DRIVER_VERSION ")\n"
 		"bus %s, device %s (driver " DRIVER_VERSION ")\n"
 		"%s\n"
 		"%s\n"
@@ -673,7 +673,7 @@ show_registers (struct class_device *class_dev, char *buf)
 		unsigned	count = 256/4;
 		unsigned	count = 256/4;
 
 
 		pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
 		pdev = to_pci_dev(ehci_to_hcd(ehci)->self.controller);
-		offset = HCC_EXT_CAPS (readl (&ehci->caps->hcc_params));
+		offset = HCC_EXT_CAPS (ehci_readl(ehci, &ehci->caps->hcc_params));
 		while (offset && count--) {
 		while (offset && count--) {
 			pci_read_config_dword (pdev, offset, &cap);
 			pci_read_config_dword (pdev, offset, &cap);
 			switch (cap & 0xff) {
 			switch (cap & 0xff) {
@@ -704,50 +704,50 @@ show_registers (struct class_device *class_dev, char *buf)
 #endif
 #endif
 
 
 	// FIXME interpret both types of params
 	// FIXME interpret both types of params
-	i = readl (&ehci->caps->hcs_params);
+	i = ehci_readl(ehci, &ehci->caps->hcs_params);
 	temp = scnprintf (next, size, "structural params 0x%08x\n", i);
 	temp = scnprintf (next, size, "structural params 0x%08x\n", i);
 	size -= temp;
 	size -= temp;
 	next += temp;
 	next += temp;
 
 
-	i = readl (&ehci->caps->hcc_params);
+	i = ehci_readl(ehci, &ehci->caps->hcc_params);
 	temp = scnprintf (next, size, "capability params 0x%08x\n", i);
 	temp = scnprintf (next, size, "capability params 0x%08x\n", i);
 	size -= temp;
 	size -= temp;
 	next += temp;
 	next += temp;
 
 
 	/* Operational Registers */
 	/* Operational Registers */
 	temp = dbg_status_buf (scratch, sizeof scratch, label,
 	temp = dbg_status_buf (scratch, sizeof scratch, label,
-			readl (&ehci->regs->status));
+			ehci_readl(ehci, &ehci->regs->status));
 	temp = scnprintf (next, size, fmt, temp, scratch);
 	temp = scnprintf (next, size, fmt, temp, scratch);
 	size -= temp;
 	size -= temp;
 	next += temp;
 	next += temp;
 
 
 	temp = dbg_command_buf (scratch, sizeof scratch, label,
 	temp = dbg_command_buf (scratch, sizeof scratch, label,
-			readl (&ehci->regs->command));
+			ehci_readl(ehci, &ehci->regs->command));
 	temp = scnprintf (next, size, fmt, temp, scratch);
 	temp = scnprintf (next, size, fmt, temp, scratch);
 	size -= temp;
 	size -= temp;
 	next += temp;
 	next += temp;
 
 
 	temp = dbg_intr_buf (scratch, sizeof scratch, label,
 	temp = dbg_intr_buf (scratch, sizeof scratch, label,
-			readl (&ehci->regs->intr_enable));
+			ehci_readl(ehci, &ehci->regs->intr_enable));
 	temp = scnprintf (next, size, fmt, temp, scratch);
 	temp = scnprintf (next, size, fmt, temp, scratch);
 	size -= temp;
 	size -= temp;
 	next += temp;
 	next += temp;
 
 
 	temp = scnprintf (next, size, "uframe %04x\n",
 	temp = scnprintf (next, size, "uframe %04x\n",
-			readl (&ehci->regs->frame_index));
+			ehci_readl(ehci, &ehci->regs->frame_index));
 	size -= temp;
 	size -= temp;
 	next += temp;
 	next += temp;
 
 
 	for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) {
 	for (i = 1; i <= HCS_N_PORTS (ehci->hcs_params); i++) {
 		temp = dbg_port_buf (scratch, sizeof scratch, label, i,
 		temp = dbg_port_buf (scratch, sizeof scratch, label, i,
-				readl (&ehci->regs->port_status [i - 1]));
+				ehci_readl(ehci, &ehci->regs->port_status [i - 1]));
 		temp = scnprintf (next, size, fmt, temp, scratch);
 		temp = scnprintf (next, size, fmt, temp, scratch);
 		size -= temp;
 		size -= temp;
 		next += temp;
 		next += temp;
 		if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) {
 		if (i == HCS_DEBUG_PORT(ehci->hcs_params) && ehci->debug) {
 			temp = scnprintf (next, size,
 			temp = scnprintf (next, size,
 					"    debug control %08x\n",
 					"    debug control %08x\n",
-					readl (&ehci->debug->control));
+					ehci_readl(ehci, &ehci->debug->control));
 			size -= temp;
 			size -= temp;
 			next += temp;
 			next += temp;
 		}
 		}

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

@@ -177,7 +177,7 @@ static void mpc83xx_setup_phy(struct ehci_hcd *ehci,
 	case FSL_USB2_PHY_NONE:
 	case FSL_USB2_PHY_NONE:
 		break;
 		break;
 	}
 	}
-	writel(portsc, &ehci->regs->port_status[port_offset]);
+	ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
 }
 }
 
 
 static void mpc83xx_usb_setup(struct usb_hcd *hcd)
 static void mpc83xx_usb_setup(struct usb_hcd *hcd)
@@ -214,7 +214,7 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
 	}
 	}
 
 
 	/* put controller in host mode. */
 	/* put controller in host mode. */
-	writel(0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
+	ehci_writel(ehci, 0x00000003, non_ehci + FSL_SOC_USB_USBMODE);
 	out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
 	out_be32(non_ehci + FSL_SOC_USB_PRICTRL, 0x0000000c);
 	out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
 	out_be32(non_ehci + FSL_SOC_USB_AGECNTTHRSH, 0x00000040);
 	out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
 	out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
@@ -238,12 +238,12 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
 	/* EHCI registers start at offset 0x100 */
 	/* EHCI registers start at offset 0x100 */
 	ehci->caps = hcd->regs + 0x100;
 	ehci->caps = hcd->regs + 0x100;
 	ehci->regs = hcd->regs + 0x100 +
 	ehci->regs = hcd->regs + 0x100 +
-	    HC_LENGTH(readl(&ehci->caps->hc_capbase));
+	    HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
 	dbg_hcs_params(ehci, "reset");
 	dbg_hcs_params(ehci, "reset");
 	dbg_hcc_params(ehci, "reset");
 	dbg_hcc_params(ehci, "reset");
 
 
 	/* cache this readonly data; minimize chip reads */
 	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = readl(&ehci->caps->hcs_params);
+	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
 
 	retval = ehci_halt(ehci);
 	retval = ehci_halt(ehci);
 	if (retval)
 	if (retval)

+ 83 - 44
drivers/usb/host/ehci-hcd.c

@@ -157,12 +157,13 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");
  * before driver shutdown. But it also seems to be caused by bugs in cardbus
  * before driver shutdown. But it also seems to be caused by bugs in cardbus
  * bridge shutdown:  shutting down the bridge before the devices using it.
  * bridge shutdown:  shutting down the bridge before the devices using it.
  */
  */
-static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec)
+static int handshake (struct ehci_hcd *ehci, void __iomem *ptr,
+		      u32 mask, u32 done, int usec)
 {
 {
 	u32	result;
 	u32	result;
 
 
 	do {
 	do {
-		result = readl (ptr);
+		result = ehci_readl(ehci, ptr);
 		if (result == ~(u32)0)		/* card removed */
 		if (result == ~(u32)0)		/* card removed */
 			return -ENODEV;
 			return -ENODEV;
 		result &= mask;
 		result &= mask;
@@ -177,18 +178,19 @@ static int handshake (void __iomem *ptr, u32 mask, u32 done, int usec)
 /* force HC to halt state from unknown (EHCI spec section 2.3) */
 /* force HC to halt state from unknown (EHCI spec section 2.3) */
 static int ehci_halt (struct ehci_hcd *ehci)
 static int ehci_halt (struct ehci_hcd *ehci)
 {
 {
-	u32	temp = readl (&ehci->regs->status);
+	u32	temp = ehci_readl(ehci, &ehci->regs->status);
 
 
 	/* disable any irqs left enabled by previous code */
 	/* disable any irqs left enabled by previous code */
-	writel (0, &ehci->regs->intr_enable);
+	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 
 
 	if ((temp & STS_HALT) != 0)
 	if ((temp & STS_HALT) != 0)
 		return 0;
 		return 0;
 
 
-	temp = readl (&ehci->regs->command);
+	temp = ehci_readl(ehci, &ehci->regs->command);
 	temp &= ~CMD_RUN;
 	temp &= ~CMD_RUN;
-	writel (temp, &ehci->regs->command);
-	return handshake (&ehci->regs->status, STS_HALT, STS_HALT, 16 * 125);
+	ehci_writel(ehci, temp, &ehci->regs->command);
+	return handshake (ehci, &ehci->regs->status,
+			  STS_HALT, STS_HALT, 16 * 125);
 }
 }
 
 
 /* put TDI/ARC silicon into EHCI mode */
 /* put TDI/ARC silicon into EHCI mode */
@@ -198,23 +200,24 @@ static void tdi_reset (struct ehci_hcd *ehci)
 	u32		tmp;
 	u32		tmp;
 
 
 	reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68);
 	reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68);
-	tmp = readl (reg_ptr);
+	tmp = ehci_readl(ehci, reg_ptr);
 	tmp |= 0x3;
 	tmp |= 0x3;
-	writel (tmp, reg_ptr);
+	ehci_writel(ehci, tmp, reg_ptr);
 }
 }
 
 
 /* reset a non-running (STS_HALT == 1) controller */
 /* reset a non-running (STS_HALT == 1) controller */
 static int ehci_reset (struct ehci_hcd *ehci)
 static int ehci_reset (struct ehci_hcd *ehci)
 {
 {
 	int	retval;
 	int	retval;
-	u32	command = readl (&ehci->regs->command);
+	u32	command = ehci_readl(ehci, &ehci->regs->command);
 
 
 	command |= CMD_RESET;
 	command |= CMD_RESET;
 	dbg_cmd (ehci, "reset", command);
 	dbg_cmd (ehci, "reset", command);
-	writel (command, &ehci->regs->command);
+	ehci_writel(ehci, command, &ehci->regs->command);
 	ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 	ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 	ehci->next_statechange = jiffies;
 	ehci->next_statechange = jiffies;
-	retval = handshake (&ehci->regs->command, CMD_RESET, 0, 250 * 1000);
+	retval = handshake (ehci, &ehci->regs->command,
+			    CMD_RESET, 0, 250 * 1000);
 
 
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
@@ -236,21 +239,21 @@ static void ehci_quiesce (struct ehci_hcd *ehci)
 #endif
 #endif
 
 
 	/* wait for any schedule enables/disables to take effect */
 	/* wait for any schedule enables/disables to take effect */
-	temp = readl (&ehci->regs->command) << 10;
+	temp = ehci_readl(ehci, &ehci->regs->command) << 10;
 	temp &= STS_ASS | STS_PSS;
 	temp &= STS_ASS | STS_PSS;
-	if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+	if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
 				temp, 16 * 125) != 0) {
 				temp, 16 * 125) != 0) {
 		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 		return;
 		return;
 	}
 	}
 
 
 	/* then disable anything that's still active */
 	/* then disable anything that's still active */
-	temp = readl (&ehci->regs->command);
+	temp = ehci_readl(ehci, &ehci->regs->command);
 	temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
 	temp &= ~(CMD_ASE | CMD_IAAD | CMD_PSE);
-	writel (temp, &ehci->regs->command);
+	ehci_writel(ehci, temp, &ehci->regs->command);
 
 
 	/* hardware can take 16 microframes to turn off ... */
 	/* hardware can take 16 microframes to turn off ... */
-	if (handshake (&ehci->regs->status, STS_ASS | STS_PSS,
+	if (handshake (ehci, &ehci->regs->status, STS_ASS | STS_PSS,
 				0, 16 * 125) != 0) {
 				0, 16 * 125) != 0) {
 		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 		return;
 		return;
@@ -277,11 +280,11 @@ static void ehci_watchdog (unsigned long param)
 
 
 	/* lost IAA irqs wedge things badly; seen with a vt8235 */
 	/* lost IAA irqs wedge things badly; seen with a vt8235 */
 	if (ehci->reclaim) {
 	if (ehci->reclaim) {
-		u32		status = readl (&ehci->regs->status);
+		u32		status = ehci_readl(ehci, &ehci->regs->status);
 		if (status & STS_IAA) {
 		if (status & STS_IAA) {
 			ehci_vdbg (ehci, "lost IAA\n");
 			ehci_vdbg (ehci, "lost IAA\n");
 			COUNT (ehci->stats.lost_iaa);
 			COUNT (ehci->stats.lost_iaa);
-			writel (STS_IAA, &ehci->regs->status);
+			ehci_writel(ehci, STS_IAA, &ehci->regs->status);
 			ehci->reclaim_ready = 1;
 			ehci->reclaim_ready = 1;
 		}
 		}
 	}
 	}
@@ -309,7 +312,7 @@ ehci_shutdown (struct usb_hcd *hcd)
 	(void) ehci_halt (ehci);
 	(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);
+	ehci_writel(ehci, 0, &ehci->regs->configured_flag);
 }
 }
 
 
 static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
 static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
@@ -379,12 +382,13 @@ static void ehci_stop (struct usb_hcd *hcd)
 		ehci_quiesce (ehci);
 		ehci_quiesce (ehci);
 
 
 	ehci_reset (ehci);
 	ehci_reset (ehci);
-	writel (0, &ehci->regs->intr_enable);
+	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 	spin_unlock_irq(&ehci->lock);
 	spin_unlock_irq(&ehci->lock);
 
 
 	/* let companion controllers work when we aren't */
 	/* let companion controllers work when we aren't */
-	writel (0, &ehci->regs->configured_flag);
+	ehci_writel(ehci, 0, &ehci->regs->configured_flag);
 
 
+	remove_companion_file(ehci);
 	remove_debug_files (ehci);
 	remove_debug_files (ehci);
 
 
 	/* root hub is shut down separately (first, when possible) */
 	/* root hub is shut down separately (first, when possible) */
@@ -402,7 +406,8 @@ static void ehci_stop (struct usb_hcd *hcd)
 		ehci->stats.complete, ehci->stats.unlink);
 		ehci->stats.complete, ehci->stats.unlink);
 #endif
 #endif
 
 
-	dbg_status (ehci, "ehci_stop completed", readl (&ehci->regs->status));
+	dbg_status (ehci, "ehci_stop completed",
+		    ehci_readl(ehci, &ehci->regs->status));
 }
 }
 
 
 /* one-time init, only for memory state */
 /* one-time init, only for memory state */
@@ -428,7 +433,7 @@ static int ehci_init(struct usb_hcd *hcd)
 		return retval;
 		return retval;
 
 
 	/* controllers may cache some of the periodic schedule ... */
 	/* controllers may cache some of the periodic schedule ... */
-	hcc_params = readl(&ehci->caps->hcc_params);
+	hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
 	if (HCC_ISOC_CACHE(hcc_params))		// full frame cache
 	if (HCC_ISOC_CACHE(hcc_params))		// full frame cache
 		ehci->i_thresh = 8;
 		ehci->i_thresh = 8;
 	else					// N microframes cached
 	else					// N microframes cached
@@ -496,13 +501,16 @@ static int ehci_run (struct usb_hcd *hcd)
 	u32			temp;
 	u32			temp;
 	u32			hcc_params;
 	u32			hcc_params;
 
 
+	hcd->uses_new_polling = 1;
+	hcd->poll_rh = 0;
+
 	/* EHCI spec section 4.1 */
 	/* EHCI spec section 4.1 */
 	if ((retval = ehci_reset(ehci)) != 0) {
 	if ((retval = ehci_reset(ehci)) != 0) {
 		ehci_mem_cleanup(ehci);
 		ehci_mem_cleanup(ehci);
 		return retval;
 		return retval;
 	}
 	}
-	writel(ehci->periodic_dma, &ehci->regs->frame_list);
-	writel((u32)ehci->async->qh_dma, &ehci->regs->async_next);
+	ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+	ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
 
 
 	/*
 	/*
 	 * hcc_params controls whether ehci->regs->segment must (!!!)
 	 * hcc_params controls whether ehci->regs->segment must (!!!)
@@ -516,9 +524,9 @@ static int ehci_run (struct usb_hcd *hcd)
 	 * Scsi_Host.highmem_io, and so forth.  It's readonly to all
 	 * Scsi_Host.highmem_io, and so forth.  It's readonly to all
 	 * host side drivers though.
 	 * host side drivers though.
 	 */
 	 */
-	hcc_params = readl(&ehci->caps->hcc_params);
+	hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
 	if (HCC_64BIT_ADDR(hcc_params)) {
 	if (HCC_64BIT_ADDR(hcc_params)) {
-		writel(0, &ehci->regs->segment);
+		ehci_writel(ehci, 0, &ehci->regs->segment);
 #if 0
 #if 0
 // this is deeply broken on almost all architectures
 // this is deeply broken on almost all architectures
 		if (!dma_set_mask(hcd->self.controller, DMA_64BIT_MASK))
 		if (!dma_set_mask(hcd->self.controller, DMA_64BIT_MASK))
@@ -531,7 +539,7 @@ static int ehci_run (struct usb_hcd *hcd)
 	// root hub will detect new devices (why?); NEC doesn't
 	// root hub will detect new devices (why?); NEC doesn't
 	ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
 	ehci->command &= ~(CMD_LRESET|CMD_IAAD|CMD_PSE|CMD_ASE|CMD_RESET);
 	ehci->command |= CMD_RUN;
 	ehci->command |= CMD_RUN;
-	writel (ehci->command, &ehci->regs->command);
+	ehci_writel(ehci, ehci->command, &ehci->regs->command);
 	dbg_cmd (ehci, "init", ehci->command);
 	dbg_cmd (ehci, "init", ehci->command);
 
 
 	/*
 	/*
@@ -541,23 +549,25 @@ static int ehci_run (struct usb_hcd *hcd)
 	 * and there's no companion controller unless maybe for USB OTG.)
 	 * and there's no companion controller unless maybe for USB OTG.)
 	 */
 	 */
 	hcd->state = HC_STATE_RUNNING;
 	hcd->state = HC_STATE_RUNNING;
-	writel (FLAG_CF, &ehci->regs->configured_flag);
-	readl (&ehci->regs->command);	/* unblock posted writes */
+	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
 
 
-	temp = HC_VERSION(readl (&ehci->caps->hc_capbase));
+	temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
 	ehci_info (ehci,
 	ehci_info (ehci,
 		"USB %x.%x started, EHCI %x.%02x, driver %s%s\n",
 		"USB %x.%x started, EHCI %x.%02x, driver %s%s\n",
 		((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
 		((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
 		temp >> 8, temp & 0xff, DRIVER_VERSION,
 		temp >> 8, temp & 0xff, DRIVER_VERSION,
 		ignore_oc ? ", overcurrent ignored" : "");
 		ignore_oc ? ", overcurrent ignored" : "");
 
 
-	writel (INTR_MASK, &ehci->regs->intr_enable); /* Turn On Interrupts */
+	ehci_writel(ehci, INTR_MASK,
+		    &ehci->regs->intr_enable); /* Turn On Interrupts */
 
 
 	/* GRR this is run-once init(), being done every time the HC starts.
 	/* GRR this is run-once init(), being done every time the HC starts.
 	 * So long as they're part of class devices, we can't do it init()
 	 * So long as they're part of class devices, we can't do it init()
 	 * since the class device isn't created that early.
 	 * since the class device isn't created that early.
 	 */
 	 */
 	create_debug_files(ehci);
 	create_debug_files(ehci);
+	create_companion_file(ehci);
 
 
 	return 0;
 	return 0;
 }
 }
@@ -567,12 +577,12 @@ static int ehci_run (struct usb_hcd *hcd)
 static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 {
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	u32			status;
+	u32			status, pcd_status = 0;
 	int			bh;
 	int			bh;
 
 
 	spin_lock (&ehci->lock);
 	spin_lock (&ehci->lock);
 
 
-	status = readl (&ehci->regs->status);
+	status = ehci_readl(ehci, &ehci->regs->status);
 
 
 	/* e.g. cardbus physical eject */
 	/* e.g. cardbus physical eject */
 	if (status == ~(u32) 0) {
 	if (status == ~(u32) 0) {
@@ -587,8 +597,8 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 	}
 	}
 
 
 	/* clear (just) interrupts */
 	/* clear (just) interrupts */
-	writel (status, &ehci->regs->status);
-	readl (&ehci->regs->command);	/* unblock posted write */
+	ehci_writel(ehci, status, &ehci->regs->status);
+	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted write */
 	bh = 0;
 	bh = 0;
 
 
 #ifdef	EHCI_VERBOSE_DEBUG
 #ifdef	EHCI_VERBOSE_DEBUG
@@ -617,13 +627,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 	/* remote wakeup [4.3.1] */
 	/* remote wakeup [4.3.1] */
 	if (status & STS_PCD) {
 	if (status & STS_PCD) {
 		unsigned	i = HCS_N_PORTS (ehci->hcs_params);
 		unsigned	i = HCS_N_PORTS (ehci->hcs_params);
+		pcd_status = status;
 
 
 		/* resume root hub? */
 		/* resume root hub? */
-		if (!(readl(&ehci->regs->command) & CMD_RUN))
+		if (!(ehci_readl(ehci, &ehci->regs->command) & CMD_RUN))
 			usb_hcd_resume_root_hub(hcd);
 			usb_hcd_resume_root_hub(hcd);
 
 
 		while (i--) {
 		while (i--) {
-			int pstatus = readl (&ehci->regs->port_status [i]);
+			int pstatus = ehci_readl(ehci,
+						 &ehci->regs->port_status [i]);
 
 
 			if (pstatus & PORT_OWNER)
 			if (pstatus & PORT_OWNER)
 				continue;
 				continue;
@@ -643,14 +655,15 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
 	/* PCI errors [4.15.2.4] */
 	/* PCI errors [4.15.2.4] */
 	if (unlikely ((status & STS_FATAL) != 0)) {
 	if (unlikely ((status & STS_FATAL) != 0)) {
 		/* bogus "fatal" IRQs appear on some chips... why?  */
 		/* bogus "fatal" IRQs appear on some chips... why?  */
-		status = readl (&ehci->regs->status);
-		dbg_cmd (ehci, "fatal", readl (&ehci->regs->command));
+		status = ehci_readl(ehci, &ehci->regs->status);
+		dbg_cmd (ehci, "fatal", ehci_readl(ehci,
+						   &ehci->regs->command));
 		dbg_status (ehci, "fatal", status);
 		dbg_status (ehci, "fatal", status);
 		if (status & STS_HALT) {
 		if (status & STS_HALT) {
 			ehci_err (ehci, "fatal error\n");
 			ehci_err (ehci, "fatal error\n");
 dead:
 dead:
 			ehci_reset (ehci);
 			ehci_reset (ehci);
-			writel (0, &ehci->regs->configured_flag);
+			ehci_writel(ehci, 0, &ehci->regs->configured_flag);
 			/* generic layer kills/unlinks all urbs, then
 			/* generic layer kills/unlinks all urbs, then
 			 * uses ehci_stop to clean up the rest
 			 * uses ehci_stop to clean up the rest
 			 */
 			 */
@@ -661,6 +674,8 @@ dead:
 	if (bh)
 	if (bh)
 		ehci_work (ehci);
 		ehci_work (ehci);
 	spin_unlock (&ehci->lock);
 	spin_unlock (&ehci->lock);
+	if (pcd_status & STS_PCD)
+		usb_hcd_poll_rh_status(hcd);
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }
 
 
@@ -873,7 +888,8 @@ done:
 static int ehci_get_frame (struct usb_hcd *hcd)
 static int ehci_get_frame (struct usb_hcd *hcd)
 {
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
-	return (readl (&ehci->regs->frame_index) >> 3) % ehci->periodic_size;
+	return (ehci_readl(ehci, &ehci->regs->frame_index) >> 3) %
+		ehci->periodic_size;
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -899,7 +915,13 @@ MODULE_LICENSE ("GPL");
 #define	PLATFORM_DRIVER		ehci_hcd_au1xxx_driver
 #define	PLATFORM_DRIVER		ehci_hcd_au1xxx_driver
 #endif
 #endif
 
 
-#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER)
+#ifdef CONFIG_PPC_PS3
+#include "ehci-ps3.c"
+#define	PS3_SYSTEM_BUS_DRIVER	ps3_ehci_sb_driver
+#endif
+
+#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
+    !defined(PS3_SYSTEM_BUS_DRIVER)
 #error "missing bus glue for ehci-hcd"
 #error "missing bus glue for ehci-hcd"
 #endif
 #endif
 
 
@@ -924,6 +946,20 @@ static int __init ehci_hcd_init(void)
 #ifdef PLATFORM_DRIVER
 #ifdef PLATFORM_DRIVER
 		platform_driver_unregister(&PLATFORM_DRIVER);
 		platform_driver_unregister(&PLATFORM_DRIVER);
 #endif
 #endif
+		return retval;
+	}
+#endif
+
+#ifdef PS3_SYSTEM_BUS_DRIVER
+	retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+	if (retval < 0) {
+#ifdef PLATFORM_DRIVER
+		platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+#ifdef PCI_DRIVER
+		pci_unregister_driver(&PCI_DRIVER);
+#endif
+		return retval;
 	}
 	}
 #endif
 #endif
 
 
@@ -939,6 +975,9 @@ static void __exit ehci_hcd_cleanup(void)
 #ifdef PCI_DRIVER
 #ifdef PCI_DRIVER
 	pci_unregister_driver(&PCI_DRIVER);
 	pci_unregister_driver(&PCI_DRIVER);
 #endif
 #endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+	ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+#endif
 }
 }
 module_exit(ehci_hcd_cleanup);
 module_exit(ehci_hcd_cleanup);
 
 

+ 226 - 98
drivers/usb/host/ehci-hub.c

@@ -47,7 +47,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
 		ehci_quiesce (ehci);
 		ehci_quiesce (ehci);
 		hcd->state = HC_STATE_QUIESCING;
 		hcd->state = HC_STATE_QUIESCING;
 	}
 	}
-	ehci->command = readl (&ehci->regs->command);
+	ehci->command = ehci_readl(ehci, &ehci->regs->command);
 	if (ehci->reclaim)
 	if (ehci->reclaim)
 		ehci->reclaim_ready = 1;
 		ehci->reclaim_ready = 1;
 	ehci_work(ehci);
 	ehci_work(ehci);
@@ -60,7 +60,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
 	ehci->bus_suspended = 0;
 	ehci->bus_suspended = 0;
 	while (port--) {
 	while (port--) {
 		u32 __iomem	*reg = &ehci->regs->port_status [port];
 		u32 __iomem	*reg = &ehci->regs->port_status [port];
-		u32		t1 = readl (reg) & ~PORT_RWC_BITS;
+		u32		t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
 		u32		t2 = t1;
 		u32		t2 = t1;
 
 
 		/* keep track of which ports we suspend */
 		/* keep track of which ports we suspend */
@@ -79,7 +79,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
 		if (t1 != t2) {
 		if (t1 != t2) {
 			ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
 			ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
 				port + 1, t1, t2);
 				port + 1, t1, t2);
-			writel (t2, reg);
+			ehci_writel(ehci, t2, reg);
 		}
 		}
 	}
 	}
 
 
@@ -92,8 +92,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
 	mask = INTR_MASK;
 	mask = INTR_MASK;
 	if (!device_may_wakeup(&hcd->self.root_hub->dev))
 	if (!device_may_wakeup(&hcd->self.root_hub->dev))
 		mask &= ~STS_PCD;
 		mask &= ~STS_PCD;
-	writel(mask, &ehci->regs->intr_enable);
-	readl(&ehci->regs->intr_enable);
+	ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+	ehci_readl(ehci, &ehci->regs->intr_enable);
 
 
 	ehci->next_statechange = jiffies + msecs_to_jiffies(10);
 	ehci->next_statechange = jiffies + msecs_to_jiffies(10);
 	spin_unlock_irq (&ehci->lock);
 	spin_unlock_irq (&ehci->lock);
@@ -118,26 +118,26 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
 	 * the last user of the controller, not reset/pm hardware keeping
 	 * the last user of the controller, not reset/pm hardware keeping
 	 * state we gave to it.
 	 * state we gave to it.
 	 */
 	 */
-	temp = readl(&ehci->regs->intr_enable);
+	temp = ehci_readl(ehci, &ehci->regs->intr_enable);
 	ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss");
 	ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss");
 
 
 	/* at least some APM implementations will try to deliver
 	/* at least some APM implementations will try to deliver
 	 * IRQs right away, so delay them until we're ready.
 	 * IRQs right away, so delay them until we're ready.
 	 */
 	 */
-	writel(0, &ehci->regs->intr_enable);
+	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 
 
 	/* re-init operational registers */
 	/* re-init operational registers */
-	writel(0, &ehci->regs->segment);
-	writel(ehci->periodic_dma, &ehci->regs->frame_list);
-	writel((u32) ehci->async->qh_dma, &ehci->regs->async_next);
+	ehci_writel(ehci, 0, &ehci->regs->segment);
+	ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
+	ehci_writel(ehci, (u32) ehci->async->qh_dma, &ehci->regs->async_next);
 
 
 	/* restore CMD_RUN, framelist size, and irq threshold */
 	/* restore CMD_RUN, framelist size, and irq threshold */
-	writel (ehci->command, &ehci->regs->command);
+	ehci_writel(ehci, ehci->command, &ehci->regs->command);
 
 
 	/* manually resume the ports we suspended during bus_suspend() */
 	/* manually resume the ports we suspended during bus_suspend() */
 	i = HCS_N_PORTS (ehci->hcs_params);
 	i = HCS_N_PORTS (ehci->hcs_params);
 	while (i--) {
 	while (i--) {
-		temp = readl (&ehci->regs->port_status [i]);
+		temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
 		temp &= ~(PORT_RWC_BITS
 		temp &= ~(PORT_RWC_BITS
 			| PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
 			| PORT_WKOC_E | PORT_WKDISC_E | PORT_WKCONN_E);
 		if (test_bit(i, &ehci->bus_suspended) &&
 		if (test_bit(i, &ehci->bus_suspended) &&
@@ -145,20 +145,20 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
 			ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
 			ehci->reset_done [i] = jiffies + msecs_to_jiffies (20);
 			temp |= PORT_RESUME;
 			temp |= PORT_RESUME;
 		}
 		}
-		writel (temp, &ehci->regs->port_status [i]);
+		ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
 	}
 	}
 	i = HCS_N_PORTS (ehci->hcs_params);
 	i = HCS_N_PORTS (ehci->hcs_params);
 	mdelay (20);
 	mdelay (20);
 	while (i--) {
 	while (i--) {
-		temp = readl (&ehci->regs->port_status [i]);
+		temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
 		if (test_bit(i, &ehci->bus_suspended) &&
 		if (test_bit(i, &ehci->bus_suspended) &&
 				(temp & PORT_SUSPEND)) {
 				(temp & PORT_SUSPEND)) {
 			temp &= ~(PORT_RWC_BITS | PORT_RESUME);
 			temp &= ~(PORT_RWC_BITS | PORT_RESUME);
-			writel (temp, &ehci->regs->port_status [i]);
+			ehci_writel(ehci, temp, &ehci->regs->port_status [i]);
 			ehci_vdbg (ehci, "resumed port %d\n", i + 1);
 			ehci_vdbg (ehci, "resumed port %d\n", i + 1);
 		}
 		}
 	}
 	}
-	(void) readl (&ehci->regs->command);
+	(void) ehci_readl(ehci, &ehci->regs->command);
 
 
 	/* maybe re-activate the schedule(s) */
 	/* maybe re-activate the schedule(s) */
 	temp = 0;
 	temp = 0;
@@ -168,14 +168,14 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
 		temp |= CMD_PSE;
 		temp |= CMD_PSE;
 	if (temp) {
 	if (temp) {
 		ehci->command |= temp;
 		ehci->command |= temp;
-		writel (ehci->command, &ehci->regs->command);
+		ehci_writel(ehci, ehci->command, &ehci->regs->command);
 	}
 	}
 
 
 	ehci->next_statechange = jiffies + msecs_to_jiffies(5);
 	ehci->next_statechange = jiffies + msecs_to_jiffies(5);
 	hcd->state = HC_STATE_RUNNING;
 	hcd->state = HC_STATE_RUNNING;
 
 
 	/* Now we can safely re-enable irqs */
 	/* Now we can safely re-enable irqs */
-	writel(INTR_MASK, &ehci->regs->intr_enable);
+	ehci_writel(ehci, INTR_MASK, &ehci->regs->intr_enable);
 
 
 	spin_unlock_irq (&ehci->lock);
 	spin_unlock_irq (&ehci->lock);
 	return 0;
 	return 0;
@@ -188,11 +188,109 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
 
 
 #endif	/* CONFIG_PM */
 #endif	/* CONFIG_PM */
 
 
+/*-------------------------------------------------------------------------*/
+
+/* Display the ports dedicated to the companion controller */
+static ssize_t show_companion(struct class_device *class_dev, char *buf)
+{
+	struct ehci_hcd		*ehci;
+	int			nports, index, n;
+	int			count = PAGE_SIZE;
+	char			*ptr = buf;
+
+	ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
+	nports = HCS_N_PORTS(ehci->hcs_params);
+
+	for (index = 0; index < nports; ++index) {
+		if (test_bit(index, &ehci->companion_ports)) {
+			n = scnprintf(ptr, count, "%d\n", index + 1);
+			ptr += n;
+			count -= n;
+		}
+	}
+	return ptr - buf;
+}
+
+/*
+ * Dedicate or undedicate a port to the companion controller.
+ * Syntax is "[-]portnum", where a leading '-' sign means
+ * return control of the port to the EHCI controller.
+ */
+static ssize_t store_companion(struct class_device *class_dev,
+		const char *buf, size_t count)
+{
+	struct ehci_hcd		*ehci;
+	int			portnum, new_owner, try;
+	u32 __iomem		*status_reg;
+	u32			port_status;
+
+	ehci = hcd_to_ehci(bus_to_hcd(class_get_devdata(class_dev)));
+	new_owner = PORT_OWNER;		/* Owned by companion */
+	if (sscanf(buf, "%d", &portnum) != 1)
+		return -EINVAL;
+	if (portnum < 0) {
+		portnum = - portnum;
+		new_owner = 0;		/* Owned by EHCI */
+	}
+	if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
+		return -ENOENT;
+	status_reg = &ehci->regs->port_status[--portnum];
+	if (new_owner)
+		set_bit(portnum, &ehci->companion_ports);
+	else
+		clear_bit(portnum, &ehci->companion_ports);
+
+	/*
+	 * The controller won't set the OWNER bit if the port is
+	 * enabled, so this loop will sometimes require at least two
+	 * iterations: one to disable the port and one to set OWNER.
+	 */
+
+	for (try = 4; try > 0; --try) {
+		spin_lock_irq(&ehci->lock);
+		port_status = ehci_readl(ehci, status_reg);
+		if ((port_status & PORT_OWNER) == new_owner
+				|| (port_status & (PORT_OWNER | PORT_CONNECT))
+					== 0)
+			try = 0;
+		else {
+			port_status ^= PORT_OWNER;
+			port_status &= ~(PORT_PE | PORT_RWC_BITS);
+			ehci_writel(ehci, port_status, status_reg);
+		}
+		spin_unlock_irq(&ehci->lock);
+		if (try > 1)
+			msleep(5);
+	}
+	return count;
+}
+static CLASS_DEVICE_ATTR(companion, 0644, show_companion, store_companion);
+
+static inline void create_companion_file(struct ehci_hcd *ehci)
+{
+	int	i;
+
+	/* with integrated TT there is no companion! */
+	if (!ehci_is_TDI(ehci))
+		i = class_device_create_file(ehci_to_hcd(ehci)->self.class_dev,
+				&class_device_attr_companion);
+}
+
+static inline void remove_companion_file(struct ehci_hcd *ehci)
+{
+	/* with integrated TT there is no companion! */
+	if (!ehci_is_TDI(ehci))
+		class_device_remove_file(ehci_to_hcd(ehci)->self.class_dev,
+				&class_device_attr_companion);
+}
+
+
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 static int check_reset_complete (
 static int check_reset_complete (
 	struct ehci_hcd	*ehci,
 	struct ehci_hcd	*ehci,
 	int		index,
 	int		index,
+	u32 __iomem	*status_reg,
 	int		port_status
 	int		port_status
 ) {
 ) {
 	if (!(port_status & PORT_CONNECT)) {
 	if (!(port_status & PORT_CONNECT)) {
@@ -217,7 +315,7 @@ static int check_reset_complete (
 		// what happens if HCS_N_CC(params) == 0 ?
 		// what happens if HCS_N_CC(params) == 0 ?
 		port_status |= PORT_OWNER;
 		port_status |= PORT_OWNER;
 		port_status &= ~PORT_RWC_BITS;
 		port_status &= ~PORT_RWC_BITS;
-		writel (port_status, &ehci->regs->port_status [index]);
+		ehci_writel(ehci, port_status, status_reg);
 
 
 	} else
 	} else
 		ehci_dbg (ehci, "port %d high speed\n", index + 1);
 		ehci_dbg (ehci, "port %d high speed\n", index + 1);
@@ -268,22 +366,21 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
 	/* port N changes (bit N)? */
 	/* port N changes (bit N)? */
 	spin_lock_irqsave (&ehci->lock, flags);
 	spin_lock_irqsave (&ehci->lock, flags);
 	for (i = 0; i < ports; i++) {
 	for (i = 0; i < ports; i++) {
-		temp = readl (&ehci->regs->port_status [i]);
-		if (temp & PORT_OWNER) {
-			/* don't report this in GetPortStatus */
-			if (temp & PORT_CSC) {
-				temp &= ~PORT_RWC_BITS;
-				temp |= PORT_CSC;
-				writel (temp, &ehci->regs->port_status [i]);
-			}
-			continue;
-		}
+		temp = ehci_readl(ehci, &ehci->regs->port_status [i]);
+
+		/*
+		 * Return status information even for ports with OWNER set.
+		 * Otherwise khubd wouldn't see the disconnect event when a
+		 * high-speed device is switched over to the companion
+		 * controller by the user.
+		 */
+
 		if (!(temp & PORT_CONNECT))
 		if (!(temp & PORT_CONNECT))
 			ehci->reset_done [i] = 0;
 			ehci->reset_done [i] = 0;
 		if ((temp & mask) != 0
 		if ((temp & mask) != 0
 				|| ((temp & PORT_RESUME) != 0
 				|| ((temp & PORT_RESUME) != 0
-					&& time_after (jiffies,
-						ehci->reset_done [i]))) {
+					&& time_after_eq(jiffies,
+						ehci->reset_done[i]))) {
 			if (i < 7)
 			if (i < 7)
 			    buf [0] |= 1 << (i + 1);
 			    buf [0] |= 1 << (i + 1);
 			else
 			else
@@ -345,6 +442,7 @@ static int ehci_hub_control (
 ) {
 ) {
 	struct ehci_hcd	*ehci = hcd_to_ehci (hcd);
 	struct ehci_hcd	*ehci = hcd_to_ehci (hcd);
 	int		ports = HCS_N_PORTS (ehci->hcs_params);
 	int		ports = HCS_N_PORTS (ehci->hcs_params);
+	u32 __iomem	*status_reg = &ehci->regs->port_status[wIndex - 1];
 	u32		temp, status;
 	u32		temp, status;
 	unsigned long	flags;
 	unsigned long	flags;
 	int		retval = 0;
 	int		retval = 0;
@@ -373,18 +471,22 @@ static int ehci_hub_control (
 		if (!wIndex || wIndex > ports)
 		if (!wIndex || wIndex > ports)
 			goto error;
 			goto error;
 		wIndex--;
 		wIndex--;
-		temp = readl (&ehci->regs->port_status [wIndex]);
-		if (temp & PORT_OWNER)
-			break;
+		temp = ehci_readl(ehci, status_reg);
+
+		/*
+		 * Even if OWNER is set, so the port is owned by the
+		 * companion controller, khubd needs to be able to clear
+		 * the port-change status bits (especially
+		 * USB_PORT_FEAT_C_CONNECTION).
+		 */
 
 
 		switch (wValue) {
 		switch (wValue) {
 		case USB_PORT_FEAT_ENABLE:
 		case USB_PORT_FEAT_ENABLE:
-			writel (temp & ~PORT_PE,
-				&ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, temp & ~PORT_PE, status_reg);
 			break;
 			break;
 		case USB_PORT_FEAT_C_ENABLE:
 		case USB_PORT_FEAT_C_ENABLE:
-			writel((temp & ~PORT_RWC_BITS) | PORT_PEC,
-				&ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_PEC,
+					status_reg);
 			break;
 			break;
 		case USB_PORT_FEAT_SUSPEND:
 		case USB_PORT_FEAT_SUSPEND:
 			if (temp & PORT_RESET)
 			if (temp & PORT_RESET)
@@ -396,8 +498,8 @@ static int ehci_hub_control (
 					goto error;
 					goto error;
 				/* resume signaling for 20 msec */
 				/* resume signaling for 20 msec */
 				temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
 				temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
-				writel (temp | PORT_RESUME,
-					&ehci->regs->port_status [wIndex]);
+				ehci_writel(ehci, temp | PORT_RESUME,
+						status_reg);
 				ehci->reset_done [wIndex] = jiffies
 				ehci->reset_done [wIndex] = jiffies
 						+ msecs_to_jiffies (20);
 						+ msecs_to_jiffies (20);
 			}
 			}
@@ -407,16 +509,17 @@ static int ehci_hub_control (
 			break;
 			break;
 		case USB_PORT_FEAT_POWER:
 		case USB_PORT_FEAT_POWER:
 			if (HCS_PPC (ehci->hcs_params))
 			if (HCS_PPC (ehci->hcs_params))
-				writel (temp & ~(PORT_RWC_BITS | PORT_POWER),
-					&ehci->regs->port_status [wIndex]);
+				ehci_writel(ehci,
+					  temp & ~(PORT_RWC_BITS | PORT_POWER),
+					  status_reg);
 			break;
 			break;
 		case USB_PORT_FEAT_C_CONNECTION:
 		case USB_PORT_FEAT_C_CONNECTION:
-			writel((temp & ~PORT_RWC_BITS) | PORT_CSC,
-				&ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC,
+					status_reg);
 			break;
 			break;
 		case USB_PORT_FEAT_C_OVER_CURRENT:
 		case USB_PORT_FEAT_C_OVER_CURRENT:
-			writel((temp & ~PORT_RWC_BITS) | PORT_OCC,
-				&ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_OCC,
+					status_reg);
 			break;
 			break;
 		case USB_PORT_FEAT_C_RESET:
 		case USB_PORT_FEAT_C_RESET:
 			/* GetPortStatus clears reset */
 			/* GetPortStatus clears reset */
@@ -424,7 +527,7 @@ static int ehci_hub_control (
 		default:
 		default:
 			goto error;
 			goto error;
 		}
 		}
-		readl (&ehci->regs->command);	/* unblock posted write */
+		ehci_readl(ehci, &ehci->regs->command);	/* unblock posted write */
 		break;
 		break;
 	case GetHubDescriptor:
 	case GetHubDescriptor:
 		ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)
 		ehci_hub_descriptor (ehci, (struct usb_hub_descriptor *)
@@ -440,7 +543,7 @@ static int ehci_hub_control (
 			goto error;
 			goto error;
 		wIndex--;
 		wIndex--;
 		status = 0;
 		status = 0;
-		temp = readl (&ehci->regs->port_status [wIndex]);
+		temp = ehci_readl(ehci, status_reg);
 
 
 		// wPortChange bits
 		// wPortChange bits
 		if (temp & PORT_CSC)
 		if (temp & PORT_CSC)
@@ -451,42 +554,55 @@ static int ehci_hub_control (
 			status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
 			status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
 
 
 		/* whoever resumes must GetPortStatus to complete it!! */
 		/* whoever resumes must GetPortStatus to complete it!! */
-		if ((temp & PORT_RESUME)
-				&& time_after (jiffies,
-					ehci->reset_done [wIndex])) {
-			status |= 1 << USB_PORT_FEAT_C_SUSPEND;
-			ehci->reset_done [wIndex] = 0;
+		if (temp & PORT_RESUME) {
 
 
-			/* stop resume signaling */
-			temp = readl (&ehci->regs->port_status [wIndex]);
-			writel (temp & ~(PORT_RWC_BITS | PORT_RESUME),
-				&ehci->regs->port_status [wIndex]);
-			retval = handshake (
-					&ehci->regs->port_status [wIndex],
-					PORT_RESUME, 0, 2000 /* 2msec */);
-			if (retval != 0) {
-				ehci_err (ehci, "port %d resume error %d\n",
-					wIndex + 1, retval);
-				goto error;
+			/* Remote Wakeup received? */
+			if (!ehci->reset_done[wIndex]) {
+				/* resume signaling for 20 msec */
+				ehci->reset_done[wIndex] = jiffies
+						+ msecs_to_jiffies(20);
+				/* check the port again */
+				mod_timer(&ehci_to_hcd(ehci)->rh_timer,
+						ehci->reset_done[wIndex]);
+			}
+
+			/* resume completed? */
+			else if (time_after_eq(jiffies,
+					ehci->reset_done[wIndex])) {
+				status |= 1 << USB_PORT_FEAT_C_SUSPEND;
+				ehci->reset_done[wIndex] = 0;
+
+				/* stop resume signaling */
+				temp = ehci_readl(ehci, status_reg);
+				ehci_writel(ehci,
+					temp & ~(PORT_RWC_BITS | PORT_RESUME),
+					status_reg);
+				retval = handshake(ehci, status_reg,
+					   PORT_RESUME, 0, 2000 /* 2msec */);
+				if (retval != 0) {
+					ehci_err(ehci,
+						"port %d resume error %d\n",
+						wIndex + 1, retval);
+					goto error;
+				}
+				temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
 			}
 			}
-			temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
 		}
 		}
 
 
 		/* whoever resets must GetPortStatus to complete it!! */
 		/* whoever resets must GetPortStatus to complete it!! */
 		if ((temp & PORT_RESET)
 		if ((temp & PORT_RESET)
-				&& time_after (jiffies,
-					ehci->reset_done [wIndex])) {
+				&& time_after_eq(jiffies,
+					ehci->reset_done[wIndex])) {
 			status |= 1 << USB_PORT_FEAT_C_RESET;
 			status |= 1 << USB_PORT_FEAT_C_RESET;
 			ehci->reset_done [wIndex] = 0;
 			ehci->reset_done [wIndex] = 0;
 
 
 			/* force reset to complete */
 			/* force reset to complete */
-			writel (temp & ~(PORT_RWC_BITS | PORT_RESET),
-					&ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET),
+					status_reg);
 			/* REVISIT:  some hardware needs 550+ usec to clear
 			/* REVISIT:  some hardware needs 550+ usec to clear
 			 * this bit; seems too long to spin routinely...
 			 * this bit; seems too long to spin routinely...
 			 */
 			 */
-			retval = handshake (
-					&ehci->regs->port_status [wIndex],
+			retval = handshake(ehci, status_reg,
 					PORT_RESET, 0, 750);
 					PORT_RESET, 0, 750);
 			if (retval != 0) {
 			if (retval != 0) {
 				ehci_err (ehci, "port %d reset error %d\n",
 				ehci_err (ehci, "port %d reset error %d\n",
@@ -495,28 +611,41 @@ static int ehci_hub_control (
 			}
 			}
 
 
 			/* see what we found out */
 			/* see what we found out */
-			temp = check_reset_complete (ehci, wIndex,
-				readl (&ehci->regs->port_status [wIndex]));
+			temp = check_reset_complete (ehci, wIndex, status_reg,
+					ehci_readl(ehci, status_reg));
 		}
 		}
 
 
-		// don't show wPortStatus if it's owned by a companion hc
-		if (!(temp & PORT_OWNER)) {
-			if (temp & PORT_CONNECT) {
-				status |= 1 << USB_PORT_FEAT_CONNECTION;
-				// status may be from integrated TT
-				status |= ehci_port_speed(ehci, temp);
-			}
-			if (temp & PORT_PE)
-				status |= 1 << USB_PORT_FEAT_ENABLE;
-			if (temp & (PORT_SUSPEND|PORT_RESUME))
-				status |= 1 << USB_PORT_FEAT_SUSPEND;
-			if (temp & PORT_OC)
-				status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
-			if (temp & PORT_RESET)
-				status |= 1 << USB_PORT_FEAT_RESET;
-			if (temp & PORT_POWER)
-				status |= 1 << USB_PORT_FEAT_POWER;
+		/* transfer dedicated ports to the companion hc */
+		if ((temp & PORT_CONNECT) &&
+				test_bit(wIndex, &ehci->companion_ports)) {
+			temp &= ~PORT_RWC_BITS;
+			temp |= PORT_OWNER;
+			ehci_writel(ehci, temp, status_reg);
+			ehci_dbg(ehci, "port %d --> companion\n", wIndex + 1);
+			temp = ehci_readl(ehci, status_reg);
+		}
+
+		/*
+		 * Even if OWNER is set, there's no harm letting khubd
+		 * see the wPortStatus values (they should all be 0 except
+		 * for PORT_POWER anyway).
+		 */
+
+		if (temp & PORT_CONNECT) {
+			status |= 1 << USB_PORT_FEAT_CONNECTION;
+			// status may be from integrated TT
+			status |= ehci_port_speed(ehci, temp);
 		}
 		}
+		if (temp & PORT_PE)
+			status |= 1 << USB_PORT_FEAT_ENABLE;
+		if (temp & (PORT_SUSPEND|PORT_RESUME))
+			status |= 1 << USB_PORT_FEAT_SUSPEND;
+		if (temp & PORT_OC)
+			status |= 1 << USB_PORT_FEAT_OVER_CURRENT;
+		if (temp & PORT_RESET)
+			status |= 1 << USB_PORT_FEAT_RESET;
+		if (temp & PORT_POWER)
+			status |= 1 << USB_PORT_FEAT_POWER;
 
 
 #ifndef	EHCI_VERBOSE_DEBUG
 #ifndef	EHCI_VERBOSE_DEBUG
 	if (status & ~0xffff)	/* only if wPortChange is interesting */
 	if (status & ~0xffff)	/* only if wPortChange is interesting */
@@ -541,7 +670,7 @@ static int ehci_hub_control (
 		if (!wIndex || wIndex > ports)
 		if (!wIndex || wIndex > ports)
 			goto error;
 			goto error;
 		wIndex--;
 		wIndex--;
-		temp = readl (&ehci->regs->port_status [wIndex]);
+		temp = ehci_readl(ehci, status_reg);
 		if (temp & PORT_OWNER)
 		if (temp & PORT_OWNER)
 			break;
 			break;
 
 
@@ -555,13 +684,12 @@ static int ehci_hub_control (
 				goto error;
 				goto error;
 			if (device_may_wakeup(&hcd->self.root_hub->dev))
 			if (device_may_wakeup(&hcd->self.root_hub->dev))
 				temp |= PORT_WAKE_BITS;
 				temp |= PORT_WAKE_BITS;
-			writel (temp | PORT_SUSPEND,
-				&ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
 			break;
 			break;
 		case USB_PORT_FEAT_POWER:
 		case USB_PORT_FEAT_POWER:
 			if (HCS_PPC (ehci->hcs_params))
 			if (HCS_PPC (ehci->hcs_params))
-				writel (temp | PORT_POWER,
-					&ehci->regs->port_status [wIndex]);
+				ehci_writel(ehci, temp | PORT_POWER,
+						status_reg);
 			break;
 			break;
 		case USB_PORT_FEAT_RESET:
 		case USB_PORT_FEAT_RESET:
 			if (temp & PORT_RESUME)
 			if (temp & PORT_RESUME)
@@ -589,7 +717,7 @@ static int ehci_hub_control (
 				ehci->reset_done [wIndex] = jiffies
 				ehci->reset_done [wIndex] = jiffies
 						+ msecs_to_jiffies (50);
 						+ msecs_to_jiffies (50);
 			}
 			}
-			writel (temp, &ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, temp, status_reg);
 			break;
 			break;
 
 
 		/* For downstream facing ports (these):  one hub port is put
 		/* For downstream facing ports (these):  one hub port is put
@@ -604,13 +732,13 @@ static int ehci_hub_control (
 			ehci_quiesce(ehci);
 			ehci_quiesce(ehci);
 			ehci_halt(ehci);
 			ehci_halt(ehci);
 			temp |= selector << 16;
 			temp |= selector << 16;
-			writel (temp, &ehci->regs->port_status [wIndex]);
+			ehci_writel(ehci, temp, status_reg);
 			break;
 			break;
 
 
 		default:
 		default:
 			goto error;
 			goto error;
 		}
 		}
-		readl (&ehci->regs->command);	/* unblock posted writes */
+		ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
 		break;
 		break;
 
 
 	default:
 	default:

+ 27 - 11
drivers/usb/host/ehci-pci.c

@@ -38,7 +38,7 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
 		if ((temp & (3 << 13)) == (1 << 13)) {
 		if ((temp & (3 << 13)) == (1 << 13)) {
 			temp &= 0x1fff;
 			temp &= 0x1fff;
 			ehci->debug = ehci_to_hcd(ehci)->regs + temp;
 			ehci->debug = ehci_to_hcd(ehci)->regs + temp;
-			temp = readl(&ehci->debug->control);
+			temp = ehci_readl(ehci, &ehci->debug->control);
 			ehci_info(ehci, "debug port %d%s\n",
 			ehci_info(ehci, "debug port %d%s\n",
 				HCS_DEBUG_PORT(ehci->hcs_params),
 				HCS_DEBUG_PORT(ehci->hcs_params),
 				(temp & DBGP_ENABLED)
 				(temp & DBGP_ENABLED)
@@ -71,8 +71,24 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
 	u32			temp;
 	u32			temp;
 	int			retval;
 	int			retval;
 
 
+	switch (pdev->vendor) {
+	case PCI_VENDOR_ID_TOSHIBA_2:
+		/* celleb's companion chip */
+		if (pdev->device == 0x01b5) {
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+			ehci->big_endian_mmio = 1;
+#else
+			ehci_warn(ehci,
+				  "unsupported big endian Toshiba quirk\n");
+#endif
+		}
+		break;
+	}
+
 	ehci->caps = hcd->regs;
 	ehci->caps = hcd->regs;
-	ehci->regs = hcd->regs + HC_LENGTH(readl(&ehci->caps->hc_capbase));
+	ehci->regs = hcd->regs +
+		HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+
 	dbg_hcs_params(ehci, "reset");
 	dbg_hcs_params(ehci, "reset");
 	dbg_hcc_params(ehci, "reset");
 	dbg_hcc_params(ehci, "reset");
 
 
@@ -101,7 +117,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
 	}
 	}
 
 
 	/* cache this readonly data; minimize chip reads */
 	/* cache this readonly data; minimize chip reads */
-	ehci->hcs_params = readl(&ehci->caps->hcs_params);
+	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
 
 	retval = ehci_halt(ehci);
 	retval = ehci_halt(ehci);
 	if (retval)
 	if (retval)
@@ -235,8 +251,8 @@ static int ehci_pci_suspend(struct usb_hcd *hcd, pm_message_t message)
 		rc = -EINVAL;
 		rc = -EINVAL;
 		goto bail;
 		goto bail;
 	}
 	}
-	writel (0, &ehci->regs->intr_enable);
-	(void)readl(&ehci->regs->intr_enable);
+	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+	(void)ehci_readl(ehci, &ehci->regs->intr_enable);
 
 
 	/* make sure snapshot being resumed re-enumerates everything */
 	/* make sure snapshot being resumed re-enumerates everything */
 	if (message.event == PM_EVENT_PRETHAW) {
 	if (message.event == PM_EVENT_PRETHAW) {
@@ -270,13 +286,13 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
 	/* If CF is still set, we maintained PCI Vaux power.
 	/* If CF is still set, we maintained PCI Vaux power.
 	 * Just undo the effect of ehci_pci_suspend().
 	 * Just undo the effect of ehci_pci_suspend().
 	 */
 	 */
-	if (readl(&ehci->regs->configured_flag) == FLAG_CF) {
+	if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
 		int	mask = INTR_MASK;
 		int	mask = INTR_MASK;
 
 
 		if (!device_may_wakeup(&hcd->self.root_hub->dev))
 		if (!device_may_wakeup(&hcd->self.root_hub->dev))
 			mask &= ~STS_PCD;
 			mask &= ~STS_PCD;
-		writel(mask, &ehci->regs->intr_enable);
-		readl(&ehci->regs->intr_enable);
+		ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+		ehci_readl(ehci, &ehci->regs->intr_enable);
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -300,9 +316,9 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
 	/* here we "know" root ports should always stay powered */
 	/* here we "know" root ports should always stay powered */
 	ehci_port_power(ehci, 1);
 	ehci_port_power(ehci, 1);
 
 
-	writel(ehci->command, &ehci->regs->command);
-	writel(FLAG_CF, &ehci->regs->configured_flag);
-	readl(&ehci->regs->command);	/* unblock posted writes */
+	ehci_writel(ehci, ehci->command, &ehci->regs->command);
+	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
 
 
 	hcd->state = HC_STATE_SUSPENDED;
 	hcd->state = HC_STATE_SUSPENDED;
 	return 0;
 	return 0;

+ 193 - 0
drivers/usb/host/ehci-ps3.c

@@ -0,0 +1,193 @@
+/*
+ *  PS3 EHCI Host Controller driver
+ *
+ *  Copyright (C) 2006 Sony Computer Entertainment Inc.
+ *  Copyright 2006 Sony Corp.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <asm/ps3.h>
+
+static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
+{
+	int result;
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+	ehci->big_endian_mmio = 1;
+
+	ehci->caps = hcd->regs;
+	ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci,
+		&ehci->caps->hc_capbase));
+
+	dbg_hcs_params(ehci, "reset");
+	dbg_hcc_params(ehci, "reset");
+
+	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+	result = ehci_halt(ehci);
+
+	if (result)
+		return result;
+
+	result = ehci_init(hcd);
+
+	if (result)
+		return result;
+
+	ehci_port_power(ehci, 0);
+
+	return result;
+}
+
+static const struct hc_driver ps3_ehci_hc_driver = {
+	.description		= hcd_name,
+	.product_desc		= "PS3 EHCI Host Controller",
+	.hcd_priv_size		= sizeof(struct ehci_hcd),
+	.irq			= ehci_irq,
+	.flags			= HCD_MEMORY | HCD_USB2,
+	.reset			= ps3_ehci_hc_reset,
+	.start			= ehci_run,
+	.stop			= ehci_stop,
+	.shutdown		= ehci_shutdown,
+	.urb_enqueue		= ehci_urb_enqueue,
+	.urb_dequeue		= ehci_urb_dequeue,
+	.endpoint_disable	= ehci_endpoint_disable,
+	.get_frame_number	= ehci_get_frame,
+	.hub_status_data	= ehci_hub_status_data,
+	.hub_control		= ehci_hub_control,
+#if defined(CONFIG_PM)
+	.bus_suspend		= ehci_bus_suspend,
+	.bus_resume		= ehci_bus_resume,
+#endif
+};
+
+#if !defined(DEBUG)
+#undef dev_dbg
+static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+	const struct device *_dev, const char *fmt, ...) {return 0;}
+#endif
+
+
+static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
+{
+	int result;
+	struct usb_hcd *hcd;
+	unsigned int virq;
+	static u64 dummy_mask = DMA_32BIT_MASK;
+
+	if (usb_disabled()) {
+		result = -ENODEV;
+		goto fail_start;
+	}
+
+	result = ps3_mmio_region_create(dev->m_region);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
+			__func__, __LINE__);
+		result = -EPERM;
+		goto fail_mmio;
+	}
+
+	dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
+		__LINE__, dev->m_region->lpar_addr);
+
+	result = ps3_alloc_io_irq(dev->interrupt_id, &virq);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
+			__func__, __LINE__, virq);
+		result = -EPERM;
+		goto fail_irq;
+	}
+
+	dev->core.power.power_state = PMSG_ON;
+	dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
+
+	hcd = usb_create_hcd(&ps3_ehci_hc_driver, &dev->core, dev->core.bus_id);
+
+	if (!hcd) {
+		dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
+			__LINE__);
+		result = -ENOMEM;
+		goto fail_create_hcd;
+	}
+
+	hcd->rsrc_start = dev->m_region->lpar_addr;
+	hcd->rsrc_len = dev->m_region->len;
+	hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
+
+	if (!hcd->regs) {
+		dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
+			__LINE__);
+		result = -EPERM;
+		goto fail_ioremap;
+	}
+
+	dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
+		(unsigned long)hcd->rsrc_start);
+	dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len   %lxh\n", __func__, __LINE__,
+		(unsigned long)hcd->rsrc_len);
+	dev_dbg(&dev->core, "%s:%d: hcd->regs       %lxh\n", __func__, __LINE__,
+		(unsigned long)hcd->regs);
+	dev_dbg(&dev->core, "%s:%d: virq            %lu\n", __func__, __LINE__,
+		(unsigned long)virq);
+
+	ps3_system_bus_set_driver_data(dev, hcd);
+
+	result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
+			__func__, __LINE__, result);
+		goto fail_add_hcd;
+	}
+
+	return result;
+
+fail_add_hcd:
+	iounmap(hcd->regs);
+fail_ioremap:
+	usb_put_hcd(hcd);
+fail_create_hcd:
+	ps3_free_io_irq(virq);
+fail_irq:
+	ps3_free_mmio_region(dev->m_region);
+fail_mmio:
+fail_start:
+	return result;
+}
+
+static int ps3_ehci_sb_remove(struct ps3_system_bus_device *dev)
+{
+	struct usb_hcd *hcd =
+		(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+
+	usb_put_hcd(hcd);
+	ps3_system_bus_set_driver_data(dev, NULL);
+
+	return 0;
+}
+
+MODULE_ALIAS("ps3-ehci");
+
+static struct ps3_system_bus_driver ps3_ehci_sb_driver = {
+	.match_id = PS3_MATCH_ID_EHCI,
+	.core = {
+		.name = "ps3-ehci-driver",
+	},
+	.probe = ps3_ehci_sb_probe,
+	.remove = ps3_ehci_sb_remove,
+};

+ 9 - 7
drivers/usb/host/ehci-q.c

@@ -789,13 +789,14 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 	head = ehci->async;
 	head = ehci->async;
 	timer_action_done (ehci, TIMER_ASYNC_OFF);
 	timer_action_done (ehci, TIMER_ASYNC_OFF);
 	if (!head->qh_next.qh) {
 	if (!head->qh_next.qh) {
-		u32	cmd = readl (&ehci->regs->command);
+		u32	cmd = ehci_readl(ehci, &ehci->regs->command);
 
 
 		if (!(cmd & CMD_ASE)) {
 		if (!(cmd & CMD_ASE)) {
 			/* in case a clear of CMD_ASE didn't take yet */
 			/* in case a clear of CMD_ASE didn't take yet */
-			(void) handshake (&ehci->regs->status, STS_ASS, 0, 150);
+			(void)handshake(ehci, &ehci->regs->status,
+					STS_ASS, 0, 150);
 			cmd |= CMD_ASE | CMD_RUN;
 			cmd |= CMD_ASE | CMD_RUN;
-			writel (cmd, &ehci->regs->command);
+			ehci_writel(ehci, cmd, &ehci->regs->command);
 			ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
 			ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
 			/* posted write need not be known to HC yet ... */
 			/* posted write need not be known to HC yet ... */
 		}
 		}
@@ -1007,7 +1008,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
 
 
 static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
 {
-	int		cmd = readl (&ehci->regs->command);
+	int		cmd = ehci_readl(ehci, &ehci->regs->command);
 	struct ehci_qh	*prev;
 	struct ehci_qh	*prev;
 
 
 #ifdef DEBUG
 #ifdef DEBUG
@@ -1025,7 +1026,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 		if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
 		if (ehci_to_hcd(ehci)->state != HC_STATE_HALT
 				&& !ehci->reclaim) {
 				&& !ehci->reclaim) {
 			/* ... and CMD_IAAD clear */
 			/* ... and CMD_IAAD clear */
-			writel (cmd & ~CMD_ASE, &ehci->regs->command);
+			ehci_writel(ehci, cmd & ~CMD_ASE,
+				    &ehci->regs->command);
 			wmb ();
 			wmb ();
 			// handshake later, if we need to
 			// handshake later, if we need to
 			timer_action_done (ehci, TIMER_ASYNC_OFF);
 			timer_action_done (ehci, TIMER_ASYNC_OFF);
@@ -1054,8 +1056,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
 
 	ehci->reclaim_ready = 0;
 	ehci->reclaim_ready = 0;
 	cmd |= CMD_IAAD;
 	cmd |= CMD_IAAD;
-	writel (cmd, &ehci->regs->command);
-	(void) readl (&ehci->regs->command);
+	ehci_writel(ehci, cmd, &ehci->regs->command);
+	(void)ehci_readl(ehci, &ehci->regs->command);
 	timer_action (ehci, TIMER_IAA_WATCHDOG);
 	timer_action (ehci, TIMER_IAA_WATCHDOG);
 }
 }
 
 

+ 11 - 11
drivers/usb/host/ehci-sched.c

@@ -433,20 +433,20 @@ static int enable_periodic (struct ehci_hcd *ehci)
 	/* did clearing PSE did take effect yet?
 	/* did clearing PSE did take effect yet?
 	 * takes effect only at frame boundaries...
 	 * takes effect only at frame boundaries...
 	 */
 	 */
-	status = handshake (&ehci->regs->status, STS_PSS, 0, 9 * 125);
+	status = handshake(ehci, &ehci->regs->status, STS_PSS, 0, 9 * 125);
 	if (status != 0) {
 	if (status != 0) {
 		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 		return status;
 		return status;
 	}
 	}
 
 
-	cmd = readl (&ehci->regs->command) | CMD_PSE;
-	writel (cmd, &ehci->regs->command);
+	cmd = ehci_readl(ehci, &ehci->regs->command) | CMD_PSE;
+	ehci_writel(ehci, cmd, &ehci->regs->command);
 	/* posted write ... PSS happens later */
 	/* posted write ... PSS happens later */
 	ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
 	ehci_to_hcd(ehci)->state = HC_STATE_RUNNING;
 
 
 	/* make sure ehci_work scans these */
 	/* make sure ehci_work scans these */
-	ehci->next_uframe = readl (&ehci->regs->frame_index)
-				% (ehci->periodic_size << 3);
+	ehci->next_uframe = ehci_readl(ehci, &ehci->regs->frame_index)
+		% (ehci->periodic_size << 3);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -458,14 +458,14 @@ static int disable_periodic (struct ehci_hcd *ehci)
 	/* did setting PSE not take effect yet?
 	/* did setting PSE not take effect yet?
 	 * takes effect only at frame boundaries...
 	 * takes effect only at frame boundaries...
 	 */
 	 */
-	status = handshake (&ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
+	status = handshake(ehci, &ehci->regs->status, STS_PSS, STS_PSS, 9 * 125);
 	if (status != 0) {
 	if (status != 0) {
 		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 		ehci_to_hcd(ehci)->state = HC_STATE_HALT;
 		return status;
 		return status;
 	}
 	}
 
 
-	cmd = readl (&ehci->regs->command) & ~CMD_PSE;
-	writel (cmd, &ehci->regs->command);
+	cmd = ehci_readl(ehci, &ehci->regs->command) & ~CMD_PSE;
+	ehci_writel(ehci, cmd, &ehci->regs->command);
 	/* posted write ... */
 	/* posted write ... */
 
 
 	ehci->next_uframe = -1;
 	ehci->next_uframe = -1;
@@ -1336,7 +1336,7 @@ iso_stream_schedule (
 		goto fail;
 		goto fail;
 	}
 	}
 
 
-	now = readl (&ehci->regs->frame_index) % mod;
+	now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
 
 
 	/* when's the last uframe this urb could start? */
 	/* when's the last uframe this urb could start? */
 	max = now + mod;
 	max = now + mod;
@@ -2088,7 +2088,7 @@ scan_periodic (struct ehci_hcd *ehci)
 	 */
 	 */
 	now_uframe = ehci->next_uframe;
 	now_uframe = ehci->next_uframe;
 	if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
 	if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
-		clock = readl (&ehci->regs->frame_index);
+		clock = ehci_readl(ehci, &ehci->regs->frame_index);
 	else
 	else
 		clock = now_uframe + mod - 1;
 		clock = now_uframe + mod - 1;
 	clock %= mod;
 	clock %= mod;
@@ -2213,7 +2213,7 @@ restart:
 			if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
 			if (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
 				break;
 				break;
 			ehci->next_uframe = now_uframe;
 			ehci->next_uframe = now_uframe;
-			now = readl (&ehci->regs->frame_index) % mod;
+			now = ehci_readl(ehci, &ehci->regs->frame_index) % mod;
 			if (now_uframe == now)
 			if (now_uframe == now)
 				break;
 				break;
 
 

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

@@ -74,7 +74,11 @@ struct ehci_hcd {			/* one per controller */
 
 
 	/* per root hub port */
 	/* per root hub port */
 	unsigned long		reset_done [EHCI_MAX_ROOT_PORTS];
 	unsigned long		reset_done [EHCI_MAX_ROOT_PORTS];
-	unsigned long		bus_suspended;
+	/* bit vectors (one bit per port) */
+	unsigned long		bus_suspended;		/* which ports were
+			already suspended at the start of a bus suspend */
+	unsigned long		companion_ports;	/* which ports are
+			dedicated to the companion controller */
 
 
 	/* per-HC memory pools (could be per-bus, but ...) */
 	/* per-HC memory pools (could be per-bus, but ...) */
 	struct dma_pool		*qh_pool;	/* qh per active urb */
 	struct dma_pool		*qh_pool;	/* qh per active urb */
@@ -92,6 +96,7 @@ struct ehci_hcd {			/* one per controller */
 	unsigned		is_tdi_rh_tt:1;	/* TDI roothub with TT */
 	unsigned		is_tdi_rh_tt:1;	/* TDI roothub with TT */
 	unsigned		no_selective_suspend:1;
 	unsigned		no_selective_suspend:1;
 	unsigned		has_fsl_port_bug:1; /* FreeScale */
 	unsigned		has_fsl_port_bug:1; /* FreeScale */
+	unsigned		big_endian_mmio:1;
 
 
 	u8			sbrn;		/* packed release number */
 	u8			sbrn;		/* packed release number */
 
 
@@ -651,6 +656,45 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
 #define	ehci_has_fsl_portno_bug(e)		(0)
 #define	ehci_has_fsl_portno_bug(e)		(0)
 #endif
 #endif
 
 
+/*
+ * While most USB host controllers implement their registers in
+ * little-endian format, a minority (celleb companion chip) implement
+ * them in big endian format.
+ *
+ * This attempts to support either format at compile time without a
+ * runtime penalty, or both formats with the additional overhead
+ * of checking a flag bit.
+ */
+
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+#define ehci_big_endian_mmio(e)		((e)->big_endian_mmio)
+#else
+#define ehci_big_endian_mmio(e)		0
+#endif
+
+static inline unsigned int ehci_readl (const struct ehci_hcd *ehci,
+				       __u32 __iomem * regs)
+{
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+	return ehci_big_endian_mmio(ehci) ?
+		readl_be((__force u32 *)regs) :
+		readl((__force u32 *)regs);
+#else
+	return readl((__force u32 *)regs);
+#endif
+}
+
+static inline void ehci_writel (const struct ehci_hcd *ehci,
+				const unsigned int val, __u32 __iomem *regs)
+{
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
+	ehci_big_endian_mmio(ehci) ?
+		writel_be(val, (__force u32 *)regs) :
+		writel(val, (__force u32 *)regs);
+#else
+	writel(val, (__force u32 *)regs);
+#endif
+}
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 

+ 5 - 18
drivers/usb/host/ohci-at91.c

@@ -170,7 +170,6 @@ static int usb_hcd_at91_remove(struct usb_hcd *hcd,
 	at91_stop_hc(pdev);
 	at91_stop_hc(pdev);
 	iounmap(hcd->regs);
 	iounmap(hcd->regs);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-	disable_irq_wake(hcd->irq);
 
 
 	clk_put(fclk);
 	clk_put(fclk);
 	clk_put(iclk);
 	clk_put(iclk);
@@ -271,8 +270,6 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
 
 
 	if (device_may_wakeup(&pdev->dev))
 	if (device_may_wakeup(&pdev->dev))
 		enable_irq_wake(hcd->irq);
 		enable_irq_wake(hcd->irq);
-	else
-		disable_irq_wake(hcd->irq);
 
 
 	/*
 	/*
 	 * The integrated transceivers seem unable to notice disconnect,
 	 * The integrated transceivers seem unable to notice disconnect,
@@ -293,6 +290,11 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
 
 
 static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
 static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
 {
 {
+	struct usb_hcd	*hcd = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(&pdev->dev))
+		disable_irq_wake(hcd->irq);
+
 	if (!clocked) {
 	if (!clocked) {
 		clk_enable(iclk);
 		clk_enable(iclk);
 		clk_enable(fclk);
 		clk_enable(fclk);
@@ -320,18 +322,3 @@ static struct platform_driver ohci_hcd_at91_driver = {
 	},
 	},
 };
 };
 
 
-static int __init ohci_hcd_at91_init (void)
-{
-	if (usb_disabled())
-		return -ENODEV;
-
-	return platform_driver_register(&ohci_hcd_at91_driver);
-}
-
-static void __exit ohci_hcd_at91_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_at91_driver);
-}
-
-module_init (ohci_hcd_at91_init);
-module_exit (ohci_hcd_at91_cleanup);

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

@@ -345,19 +345,3 @@ static struct platform_driver ohci_hcd_au1xxx_driver = {
 	},
 	},
 };
 };
 
 
-static int __init ohci_hcd_au1xxx_init (void)
-{
-	pr_debug (DRIVER_INFO " (Au1xxx)");
-	pr_debug ("block sizes: ed %d td %d\n",
-		sizeof (struct ed), sizeof (struct td));
-
-	return platform_driver_register(&ohci_hcd_au1xxx_driver);
-}
-
-static void __exit ohci_hcd_au1xxx_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_au1xxx_driver);
-}
-
-module_init (ohci_hcd_au1xxx_init);
-module_exit (ohci_hcd_au1xxx_cleanup);

+ 0 - 12
drivers/usb/host/ohci-ep93xx.c

@@ -214,15 +214,3 @@ static struct platform_driver ohci_hcd_ep93xx_driver = {
 	},
 	},
 };
 };
 
 
-static int __init ohci_hcd_ep93xx_init(void)
-{
-	return platform_driver_register(&ohci_hcd_ep93xx_driver);
-}
-
-static void __exit ohci_hcd_ep93xx_cleanup(void)
-{
-	platform_driver_unregister(&ohci_hcd_ep93xx_driver);
-}
-
-module_init(ohci_hcd_ep93xx_init);
-module_exit(ohci_hcd_ep93xx_cleanup);

+ 116 - 12
drivers/usb/host/ohci-hcd.c

@@ -855,63 +855,167 @@ MODULE_LICENSE ("GPL");
 
 
 #ifdef CONFIG_PCI
 #ifdef CONFIG_PCI
 #include "ohci-pci.c"
 #include "ohci-pci.c"
+#define PCI_DRIVER		ohci_pci_driver
 #endif
 #endif
 
 
 #ifdef CONFIG_SA1111
 #ifdef CONFIG_SA1111
 #include "ohci-sa1111.c"
 #include "ohci-sa1111.c"
+#define SA1111_DRIVER		ohci_hcd_sa1111_driver
 #endif
 #endif
 
 
 #ifdef CONFIG_ARCH_S3C2410
 #ifdef CONFIG_ARCH_S3C2410
 #include "ohci-s3c2410.c"
 #include "ohci-s3c2410.c"
+#define PLATFORM_DRIVER		ohci_hcd_s3c2410_driver
 #endif
 #endif
 
 
 #ifdef CONFIG_ARCH_OMAP
 #ifdef CONFIG_ARCH_OMAP
 #include "ohci-omap.c"
 #include "ohci-omap.c"
+#define PLATFORM_DRIVER		ohci_hcd_omap_driver
 #endif
 #endif
 
 
 #ifdef CONFIG_ARCH_LH7A404
 #ifdef CONFIG_ARCH_LH7A404
 #include "ohci-lh7a404.c"
 #include "ohci-lh7a404.c"
+#define PLATFORM_DRIVER		ohci_hcd_lh7a404_driver
 #endif
 #endif
 
 
 #ifdef CONFIG_PXA27x
 #ifdef CONFIG_PXA27x
 #include "ohci-pxa27x.c"
 #include "ohci-pxa27x.c"
+#define PLATFORM_DRIVER		ohci_hcd_pxa27x_driver
 #endif
 #endif
 
 
 #ifdef CONFIG_ARCH_EP93XX
 #ifdef CONFIG_ARCH_EP93XX
 #include "ohci-ep93xx.c"
 #include "ohci-ep93xx.c"
+#define PLATFORM_DRIVER		ohci_hcd_ep93xx_driver
 #endif
 #endif
 
 
 #ifdef CONFIG_SOC_AU1X00
 #ifdef CONFIG_SOC_AU1X00
 #include "ohci-au1xxx.c"
 #include "ohci-au1xxx.c"
+#define PLATFORM_DRIVER		ohci_hcd_au1xxx_driver
 #endif
 #endif
 
 
 #ifdef CONFIG_PNX8550
 #ifdef CONFIG_PNX8550
 #include "ohci-pnx8550.c"
 #include "ohci-pnx8550.c"
+#define PLATFORM_DRIVER		ohci_hcd_pnx8550_driver
 #endif
 #endif
 
 
 #ifdef CONFIG_USB_OHCI_HCD_PPC_SOC
 #ifdef CONFIG_USB_OHCI_HCD_PPC_SOC
 #include "ohci-ppc-soc.c"
 #include "ohci-ppc-soc.c"
+#define PLATFORM_DRIVER		ohci_hcd_ppc_soc_driver
 #endif
 #endif
 
 
 #ifdef CONFIG_ARCH_AT91
 #ifdef CONFIG_ARCH_AT91
 #include "ohci-at91.c"
 #include "ohci-at91.c"
+#define PLATFORM_DRIVER		ohci_hcd_at91_driver
 #endif
 #endif
 
 
 #ifdef CONFIG_ARCH_PNX4008
 #ifdef CONFIG_ARCH_PNX4008
 #include "ohci-pnx4008.c"
 #include "ohci-pnx4008.c"
+#define PLATFORM_DRIVER		usb_hcd_pnx4008_driver
 #endif
 #endif
 
 
-#if !(defined(CONFIG_PCI) \
-      || defined(CONFIG_SA1111) \
-      || defined(CONFIG_ARCH_S3C2410) \
-      || defined(CONFIG_ARCH_OMAP) \
-      || defined (CONFIG_ARCH_LH7A404) \
-      || defined (CONFIG_PXA27x) \
-      || defined (CONFIG_ARCH_EP93XX) \
-      || defined (CONFIG_SOC_AU1X00) \
-      || defined (CONFIG_USB_OHCI_HCD_PPC_SOC) \
-      || defined (CONFIG_ARCH_AT91) \
-      || defined (CONFIG_ARCH_PNX4008) \
-	)
+
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF
+#include "ohci-ppc-of.c"
+#define OF_PLATFORM_DRIVER	ohci_hcd_ppc_of_driver
+#endif
+
+#ifdef CONFIG_PPC_PS3
+#include "ohci-ps3.c"
+#define PS3_SYSTEM_BUS_DRIVER	ps3_ohci_sb_driver
+#endif
+
+#if	!defined(PCI_DRIVER) &&		\
+	!defined(PLATFORM_DRIVER) &&	\
+	!defined(OF_PLATFORM_DRIVER) &&	\
+	!defined(SA1111_DRIVER) &&	\
+	!defined(PS3_SYSTEM_BUS_DRIVER)
 #error "missing bus glue for ohci-hcd"
 #error "missing bus glue for ohci-hcd"
 #endif
 #endif
+
+static int __init ohci_hcd_mod_init(void)
+{
+	int retval = 0;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	printk (KERN_DEBUG "%s: " DRIVER_INFO "\n", hcd_name);
+	pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
+		sizeof (struct ed), sizeof (struct td));
+
+#ifdef PS3_SYSTEM_BUS_DRIVER
+	retval = ps3_system_bus_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+	if (retval < 0)
+		goto error_ps3;
+#endif
+
+#ifdef PLATFORM_DRIVER
+	retval = platform_driver_register(&PLATFORM_DRIVER);
+	if (retval < 0)
+		goto error_platform;
+#endif
+
+#ifdef OF_PLATFORM_DRIVER
+	retval = of_register_platform_driver(&OF_PLATFORM_DRIVER);
+	if (retval < 0)
+		goto error_of_platform;
+#endif
+
+#ifdef SA1111_DRIVER
+	retval = sa1111_driver_register(&SA1111_DRIVER);
+	if (retval < 0)
+		goto error_sa1111;
+#endif
+
+#ifdef PCI_DRIVER
+	retval = pci_register_driver(&PCI_DRIVER);
+	if (retval < 0)
+		goto error_pci;
+#endif
+
+	return retval;
+
+	/* Error path */
+#ifdef PCI_DRIVER
+ error_pci:
+#endif
+#ifdef SA1111_DRIVER
+	sa1111_driver_unregister(&SA1111_DRIVER);
+ error_sa1111:
+#endif
+#ifdef OF_PLATFORM_DRIVER
+	of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
+ error_of_platform:
+#endif
+#ifdef PLATFORM_DRIVER
+	platform_driver_unregister(&PLATFORM_DRIVER);
+ error_platform:
+#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+	ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+ error_ps3:
+#endif
+	return retval;
+}
+module_init(ohci_hcd_mod_init);
+
+static void __exit ohci_hcd_mod_exit(void)
+{
+#ifdef PCI_DRIVER
+	pci_unregister_driver(&PCI_DRIVER);
+#endif
+#ifdef SA1111_DRIVER
+	sa1111_driver_unregister(&SA1111_DRIVER);
+#endif
+#ifdef OF_PLATFORM_DRIVER
+	of_unregister_platform_driver(&OF_PLATFORM_DRIVER);
+#endif
+#ifdef PLATFORM_DRIVER
+	platform_driver_unregister(&PLATFORM_DRIVER);
+#endif
+#ifdef PS3_SYSTEM_BUS_DRIVER
+	ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+#endif
+}
+module_exit(ohci_hcd_mod_exit);
+

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

@@ -251,19 +251,3 @@ static struct platform_driver ohci_hcd_lh7a404_driver = {
 	},
 	},
 };
 };
 
 
-static int __init ohci_hcd_lh7a404_init (void)
-{
-	pr_debug (DRIVER_INFO " (LH7A404)");
-	pr_debug ("block sizes: ed %d td %d\n",
-		sizeof (struct ed), sizeof (struct td));
-
-	return platform_driver_register(&ohci_hcd_lh7a404_driver);
-}
-
-static void __exit ohci_hcd_lh7a404_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_lh7a404_driver);
-}
-
-module_init (ohci_hcd_lh7a404_init);
-module_exit (ohci_hcd_lh7a404_cleanup);

+ 0 - 19
drivers/usb/host/ohci-omap.c

@@ -544,22 +544,3 @@ static struct platform_driver ohci_hcd_omap_driver = {
 	},
 	},
 };
 };
 
 
-static int __init ohci_hcd_omap_init (void)
-{
-	printk (KERN_DEBUG "%s: " DRIVER_INFO " (OMAP)\n", hcd_name);
-	if (usb_disabled())
-		return -ENODEV;
-
-	pr_debug("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
-		sizeof (struct ed), sizeof (struct td));
-
-	return platform_driver_register(&ohci_hcd_omap_driver);
-}
-
-static void __exit ohci_hcd_omap_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_omap_driver);
-}
-
-module_init (ohci_hcd_omap_init);
-module_exit (ohci_hcd_omap_cleanup);

+ 136 - 83
drivers/usb/host/ohci-pci.c

@@ -20,79 +20,154 @@
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-static int
-ohci_pci_reset (struct usb_hcd *hcd)
+/* AMD 756, for most chips (early revs), corrupts register
+ * values on read ... so enable the vendor workaround.
+ */
+static int __devinit ohci_quirk_amd756(struct usb_hcd *hcd)
 {
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 
 
-	ohci_hcd_init (ohci);
-	return ohci_init (ohci);
+	ohci->flags = OHCI_QUIRK_AMD756;
+	ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
+
+	/* also erratum 10 (suspend/resume issues) */
+	device_init_wakeup(&hcd->self.root_hub->dev, 0);
+
+	return 0;
 }
 }
 
 
-static int __devinit
-ohci_pci_start (struct usb_hcd *hcd)
+/* Apple's OHCI driver has a lot of bizarre workarounds
+ * for this chip.  Evidently control and bulk lists
+ * can get confused.  (B&W G3 models, and ...)
+ */
+static int __devinit ohci_quirk_opti(struct usb_hcd *hcd)
 {
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
-	int		ret;
 
 
-	/* REVISIT this whole block should move to reset(), which handles
-	 * all the other one-time init.
+	ohci_dbg (ohci, "WARNING: OPTi workarounds unavailable\n");
+
+	return 0;
+}
+
+/* Check for NSC87560. We have to look at the bridge (fn1) to
+ * identify the USB (fn2). This quirk might apply to more or
+ * even all NSC stuff.
+ */
+static int __devinit ohci_quirk_ns(struct usb_hcd *hcd)
+{
+	struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+	struct pci_dev	*b;
+
+	b  = pci_get_slot (pdev->bus, PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
+	if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
+	    && b->vendor == PCI_VENDOR_ID_NS) {
+		struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+
+		ohci->flags |= OHCI_QUIRK_SUPERIO;
+		ohci_dbg (ohci, "Using NSC SuperIO setup\n");
+	}
+	pci_dev_put(b);
+
+	return 0;
+}
+
+/* Check for Compaq's ZFMicro chipset, which needs short
+ * delays before control or bulk queues get re-activated
+ * in finish_unlinks()
+ */
+static int __devinit ohci_quirk_zfmicro(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+
+	ohci->flags |= OHCI_QUIRK_ZFMICRO;
+	ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n");
+
+	return 0;
+}
+
+/* Check for Toshiba SCC OHCI which has big endian registers
+ * and little endian in memory data structures
+ */
+static int __devinit ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+
+	/* That chip is only present in the southbridge of some
+	 * cell based platforms which are supposed to select
+	 * CONFIG_USB_OHCI_BIG_ENDIAN_MMIO. We verify here if
+	 * that was the case though.
+	 */
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+	ohci->flags |= OHCI_QUIRK_BE_MMIO;
+	ohci_dbg (ohci, "enabled big endian Toshiba quirk\n");
+	return 0;
+#else
+	ohci_err (ohci, "unsupported big endian Toshiba quirk\n");
+	return -ENXIO;
+#endif
+}
+
+/* List of quirks for OHCI */
+static const struct pci_device_id ohci_pci_quirks[] = {
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x740c),
+		.driver_data = (unsigned long)ohci_quirk_amd756,
+	},
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_OPTI, 0xc861),
+		.driver_data = (unsigned long)ohci_quirk_opti,
+	},
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_ANY_ID),
+		.driver_data = (unsigned long)ohci_quirk_ns,
+	},
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xa0f8),
+		.driver_data = (unsigned long)ohci_quirk_zfmicro,
+	},
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6),
+		.driver_data = (unsigned long)ohci_quirk_toshiba_scc,
+	},
+	/* FIXME for some of the early AMD 760 southbridges, OHCI
+	 * won't work at all.  blacklist them.
 	 */
 	 */
+
+	{},
+};
+
+static int ohci_pci_reset (struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	int ret = 0;
+
 	if (hcd->self.controller) {
 	if (hcd->self.controller) {
 		struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
 		struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+		const struct pci_device_id *quirk_id;
 
 
-		/* AMD 756, for most chips (early revs), corrupts register
-		 * values on read ... so enable the vendor workaround.
-		 */
-		if (pdev->vendor == PCI_VENDOR_ID_AMD
-				&& pdev->device == 0x740c) {
-			ohci->flags = OHCI_QUIRK_AMD756;
-			ohci_dbg (ohci, "AMD756 erratum 4 workaround\n");
-			/* also erratum 10 (suspend/resume issues) */
-			device_init_wakeup(&hcd->self.root_hub->dev, 0);
+		quirk_id = pci_match_id(ohci_pci_quirks, pdev);
+		if (quirk_id != NULL) {
+			int (*quirk)(struct usb_hcd *ohci);
+			quirk = (void *)quirk_id->driver_data;
+			ret = quirk(hcd);
 		}
 		}
+	}
+	if (ret == 0) {
+		ohci_hcd_init (ohci);
+		return ohci_init (ohci);
+	}
+	return ret;
+}
 
 
-		/* FIXME for some of the early AMD 760 southbridges, OHCI
-		 * won't work at all.  blacklist them.
-		 */
-
-		/* Apple's OHCI driver has a lot of bizarre workarounds
-		 * for this chip.  Evidently control and bulk lists
-		 * can get confused.  (B&W G3 models, and ...)
-		 */
-		else if (pdev->vendor == PCI_VENDOR_ID_OPTI
-				&& pdev->device == 0xc861) {
-			ohci_dbg (ohci,
-				"WARNING: OPTi workarounds unavailable\n");
-		}
 
 
-		/* Check for NSC87560. We have to look at the bridge (fn1) to
-		 * identify the USB (fn2). This quirk might apply to more or
-		 * even all NSC stuff.
-		 */
-		else if (pdev->vendor == PCI_VENDOR_ID_NS) {
-			struct pci_dev	*b;
-
-			b  = pci_get_slot (pdev->bus,
-					PCI_DEVFN (PCI_SLOT (pdev->devfn), 1));
-			if (b && b->device == PCI_DEVICE_ID_NS_87560_LIO
-					&& b->vendor == PCI_VENDOR_ID_NS) {
-				ohci->flags |= OHCI_QUIRK_SUPERIO;
-				ohci_dbg (ohci, "Using NSC SuperIO setup\n");
-			}
-			pci_dev_put(b);
-		}
+static int __devinit ohci_pci_start (struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+	int		ret;
 
 
-		/* Check for Compaq's ZFMicro chipset, which needs short
-		 * delays before control or bulk queues get re-activated
-		 * in finish_unlinks()
-		 */
-		else if (pdev->vendor == PCI_VENDOR_ID_COMPAQ
-				&& pdev->device  == 0xa0f8) {
-			ohci->flags |= OHCI_QUIRK_ZFMICRO;
-			ohci_dbg (ohci,
-				"enabled Compaq ZFMicro chipset quirk\n");
-		}
+#ifdef CONFIG_PM /* avoid warnings about unused pdev */
+	if (hcd->self.controller) {
+		struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
 
 
 		/* RWC may not be set for add-in PCI cards, since boot
 		/* RWC may not be set for add-in PCI cards, since boot
 		 * firmware probably ignored them.  This transfers PCI
 		 * firmware probably ignored them.  This transfers PCI
@@ -101,16 +176,14 @@ ohci_pci_start (struct usb_hcd *hcd)
 		if (device_may_wakeup(&pdev->dev))
 		if (device_may_wakeup(&pdev->dev))
 			ohci->hc_control |= OHCI_CTRL_RWC;
 			ohci->hc_control |= OHCI_CTRL_RWC;
 	}
 	}
+#endif /* CONFIG_PM */
 
 
-	/* NOTE: there may have already been a first reset, to
-	 * keep bios/smm irqs from making trouble
-	 */
-	if ((ret = ohci_run (ohci)) < 0) {
+	ret = ohci_run (ohci);
+	if (ret < 0) {
 		ohci_err (ohci, "can't start\n");
 		ohci_err (ohci, "can't start\n");
 		ohci_stop (hcd);
 		ohci_stop (hcd);
-		return ret;
 	}
 	}
-	return 0;
+	return ret;
 }
 }
 
 
 #ifdef	CONFIG_PM
 #ifdef	CONFIG_PM
@@ -238,23 +311,3 @@ static struct pci_driver ohci_pci_driver = {
 	.shutdown =	usb_hcd_pci_shutdown,
 	.shutdown =	usb_hcd_pci_shutdown,
 };
 };
 
 
-
-static int __init ohci_hcd_pci_init (void)
-{
-	printk (KERN_DEBUG "%s: " DRIVER_INFO " (PCI)\n", hcd_name);
-	if (usb_disabled())
-		return -ENODEV;
-
-	pr_debug ("%s: block sizes: ed %Zd td %Zd\n", hcd_name,
-		sizeof (struct ed), sizeof (struct td));
-	return pci_register_driver (&ohci_pci_driver);
-}
-module_init (ohci_hcd_pci_init);
-
-/*-------------------------------------------------------------------------*/
-
-static void __exit ohci_hcd_pci_cleanup (void)
-{
-	pci_unregister_driver (&ohci_pci_driver);
-}
-module_exit (ohci_hcd_pci_cleanup);

+ 0 - 12
drivers/usb/host/ohci-pnx4008.c

@@ -465,15 +465,3 @@ static struct platform_driver usb_hcd_pnx4008_driver = {
 	.remove = usb_hcd_pnx4008_remove,
 	.remove = usb_hcd_pnx4008_remove,
 };
 };
 
 
-static int __init usb_hcd_pnx4008_init(void)
-{
-	return platform_driver_register(&usb_hcd_pnx4008_driver);
-}
-
-static void __exit usb_hcd_pnx4008_cleanup(void)
-{
-	return platform_driver_unregister(&usb_hcd_pnx4008_driver);
-}
-
-module_init(usb_hcd_pnx4008_init);
-module_exit(usb_hcd_pnx4008_cleanup);

+ 0 - 16
drivers/usb/host/ohci-pnx8550.c

@@ -240,19 +240,3 @@ static struct platform_driver ohci_hcd_pnx8550_driver = {
 	.remove		= ohci_hcd_pnx8550_drv_remove,
 	.remove		= ohci_hcd_pnx8550_drv_remove,
 };
 };
 
 
-static int __init ohci_hcd_pnx8550_init (void)
-{
-	pr_debug (DRIVER_INFO " (pnx8550)");
-	pr_debug ("block sizes: ed %d td %d\n",
-		sizeof (struct ed), sizeof (struct td));
-
-	return platform_driver_register(&ohci_hcd_pnx8550_driver);
-}
-
-static void __exit ohci_hcd_pnx8550_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_pnx8550_driver);
-}
-
-module_init (ohci_hcd_pnx8550_init);
-module_exit (ohci_hcd_pnx8550_cleanup);

+ 232 - 0
drivers/usb/host/ohci-ppc-of.c

@@ -0,0 +1,232 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
+ * (C) Copyright 2002 Hewlett-Packard Company
+ * (C) Copyright 2006 Sylvain Munaut <tnt@246tNt.com>
+ *
+ * Bus glue for OHCI HC on the of_platform bus
+ *
+ * Modified for of_platform bus from ohci-sa1111.c
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/signal.h>
+
+#include <asm/of_platform.h>
+#include <asm/prom.h>
+
+
+static int __devinit
+ohci_ppc_of_start(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
+	int		ret;
+
+	if ((ret = ohci_init(ohci)) < 0)
+		return ret;
+
+	if ((ret = ohci_run(ohci)) < 0) {
+		err("can't start %s", ohci_to_hcd(ohci)->self.bus_name);
+		ohci_stop(hcd);
+		return ret;
+	}
+
+	return 0;
+}
+
+static const struct hc_driver ohci_ppc_of_hc_driver = {
+	.description =		hcd_name,
+	.product_desc =		"OF OHCI",
+	.hcd_priv_size =	sizeof(struct ohci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ohci_irq,
+	.flags =		HCD_USB11 | HCD_MEMORY,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.start =		ohci_ppc_of_start,
+	.stop =			ohci_stop,
+	.shutdown = 		ohci_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ohci_urb_enqueue,
+	.urb_dequeue =		ohci_urb_dequeue,
+	.endpoint_disable =	ohci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ohci_hub_status_data,
+	.hub_control =		ohci_hub_control,
+	.hub_irq_enable =	ohci_rhsc_enable,
+#ifdef	CONFIG_PM
+	.bus_suspend =		ohci_bus_suspend,
+	.bus_resume =		ohci_bus_resume,
+#endif
+	.start_port_reset =	ohci_start_port_reset,
+};
+
+
+static int __devinit
+ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
+{
+	struct device_node *dn = op->node;
+	struct usb_hcd *hcd;
+	struct ohci_hcd	*ohci;
+	struct resource res;
+	int irq;
+
+	int rv;
+	int is_bigendian;
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	is_bigendian =
+		device_is_compatible(dn, "ohci-bigendian") ||
+		device_is_compatible(dn, "ohci-be");
+
+	dev_dbg(&op->dev, "initializing PPC-OF USB Controller\n");
+
+	rv = of_address_to_resource(dn, 0, &res);
+	if (rv)
+		return rv;
+
+	hcd = usb_create_hcd(&ohci_ppc_of_hc_driver, &op->dev, "PPC-OF USB");
+	if (!hcd)
+		return -ENOMEM;
+
+	hcd->rsrc_start = res.start;
+	hcd->rsrc_len = res.end - res.start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
+		rv = -EBUSY;
+		goto err_rmr;
+	}
+
+	irq = irq_of_parse_and_map(dn, 0);
+	if (irq == NO_IRQ) {
+		printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+		rv = -EBUSY;
+		goto err_irq;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		printk(KERN_ERR __FILE__ ": ioremap failed\n");
+		rv = -ENOMEM;
+		goto err_ioremap;
+	}
+
+	ohci = hcd_to_ohci(hcd);
+	if (is_bigendian)
+		ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+
+	ohci_hcd_init(ohci);
+
+	rv = usb_add_hcd(hcd, irq, 0);
+	if (rv == 0)
+		return 0;
+
+	iounmap(hcd->regs);
+err_ioremap:
+	irq_dispose_mapping(irq);
+err_irq:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_rmr:
+ 	usb_put_hcd(hcd);
+
+	return rv;
+}
+
+static int ohci_hcd_ppc_of_remove(struct of_device *op)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+	dev_set_drvdata(&op->dev, NULL);
+
+	dev_dbg(&op->dev, "stopping PPC-OF USB Controller\n");
+
+	usb_remove_hcd(hcd);
+
+	iounmap(hcd->regs);
+	irq_dispose_mapping(hcd->irq);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+	usb_put_hcd(hcd);
+
+	return 0;
+}
+
+static int ohci_hcd_ppc_of_shutdown(struct of_device *op)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(&op->dev);
+
+        if (hcd->driver->shutdown)
+                hcd->driver->shutdown(hcd);
+
+	return 0;
+}
+
+
+static struct of_device_id ohci_hcd_ppc_of_match[] = {
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
+	{
+		.name = "usb",
+		.compatible = "ohci-bigendian",
+	},
+	{
+		.name = "usb",
+		.compatible = "ohci-be",
+	},
+#endif
+#ifdef CONFIG_USB_OHCI_HCD_PPC_OF_LE
+	{
+		.name = "usb",
+		.compatible = "ohci-littledian",
+	},
+	{
+		.name = "usb",
+		.compatible = "ohci-le",
+	},
+#endif
+	{},
+};
+MODULE_DEVICE_TABLE(of, ohci_hcd_ppc_of_match);
+
+#if	!defined(CONFIG_USB_OHCI_HCD_PPC_OF_BE) && \
+	!defined(CONFIG_USB_OHCI_HCD_PPC_OF_LE)
+#error "No endianess selected for ppc-of-ohci"
+#endif
+
+
+static struct of_platform_driver ohci_hcd_ppc_of_driver = {
+	.name		= "ppc-of-ohci",
+	.match_table	= ohci_hcd_ppc_of_match,
+	.probe		= ohci_hcd_ppc_of_probe,
+	.remove		= ohci_hcd_ppc_of_remove,
+	.shutdown 	= ohci_hcd_ppc_of_shutdown,
+#ifdef CONFIG_PM
+	/*.suspend	= ohci_hcd_ppc_soc_drv_suspend,*/
+	/*.resume	= ohci_hcd_ppc_soc_drv_resume,*/
+#endif
+	.driver		= {
+		.name	= "ppc-of-ohci",
+		.owner	= THIS_MODULE,
+	},
+};
+

+ 1 - 17
drivers/usb/host/ohci-ppc-soc.c

@@ -72,7 +72,7 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
 	}
 	}
 
 
 	ohci = hcd_to_ohci(hcd);
 	ohci = hcd_to_ohci(hcd);
-	ohci->flags |= OHCI_BIG_ENDIAN;
+	ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
 	ohci_hcd_init(ohci);
 	ohci_hcd_init(ohci);
 
 
 	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
 	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
@@ -208,19 +208,3 @@ static struct platform_driver ohci_hcd_ppc_soc_driver = {
 	},
 	},
 };
 };
 
 
-static int __init ohci_hcd_ppc_soc_init(void)
-{
-	pr_debug(DRIVER_INFO " (PPC SOC)\n");
-	pr_debug("block sizes: ed %d td %d\n", sizeof(struct ed),
-							sizeof(struct td));
-
-	return platform_driver_register(&ohci_hcd_ppc_soc_driver);
-}
-
-static void __exit ohci_hcd_ppc_soc_cleanup(void)
-{
-	platform_driver_unregister(&ohci_hcd_ppc_soc_driver);
-}
-
-module_init(ohci_hcd_ppc_soc_init);
-module_exit(ohci_hcd_ppc_soc_cleanup);

+ 196 - 0
drivers/usb/host/ohci-ps3.c

@@ -0,0 +1,196 @@
+/*
+ *  PS3 OHCI Host Controller driver
+ *
+ *  Copyright (C) 2006 Sony Computer Entertainment Inc.
+ *  Copyright 2006 Sony Corp.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <asm/ps3.h>
+
+static int ps3_ohci_hc_reset(struct usb_hcd *hcd)
+{
+	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+	ohci->flags |= OHCI_QUIRK_BE_MMIO;
+	ohci_hcd_init(ohci);
+	return ohci_init(ohci);
+}
+
+static int __devinit ps3_ohci_hc_start(struct usb_hcd *hcd)
+{
+	int result;
+	struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+	/* Handle root hub init quirk in spider south bridge. */
+	/* Also set PwrOn2PwrGood to 0x7f (254ms). */
+
+	ohci_writel(ohci, 0x7f000000 | RH_A_PSM | RH_A_OCPM,
+		&ohci->regs->roothub.a);
+	ohci_writel(ohci, 0x00060000, &ohci->regs->roothub.b);
+
+	result = ohci_run(ohci);
+
+	if (result < 0) {
+		err("can't start %s", hcd->self.bus_name);
+		ohci_stop(hcd);
+	}
+
+	return result;
+}
+
+static const struct hc_driver ps3_ohci_hc_driver = {
+	.description		= hcd_name,
+	.product_desc		= "PS3 OHCI Host Controller",
+	.hcd_priv_size		= sizeof(struct ohci_hcd),
+	.irq			= ohci_irq,
+	.flags			= HCD_MEMORY | HCD_USB11,
+	.reset			= ps3_ohci_hc_reset,
+	.start			= ps3_ohci_hc_start,
+	.stop			= ohci_stop,
+	.shutdown		= ohci_shutdown,
+	.urb_enqueue		= ohci_urb_enqueue,
+	.urb_dequeue		= ohci_urb_dequeue,
+	.endpoint_disable	= ohci_endpoint_disable,
+	.get_frame_number	= ohci_get_frame,
+	.hub_status_data	= ohci_hub_status_data,
+	.hub_control		= ohci_hub_control,
+	.hub_irq_enable		= ohci_rhsc_enable,
+	.start_port_reset	= ohci_start_port_reset,
+#if defined(CONFIG_PM)
+	.bus_suspend 		= ohci_bus_suspend,
+	.bus_resume 		= ohci_bus_resume,
+#endif
+};
+
+/* redefine dev_dbg to do a syntax check */
+
+#if !defined(DEBUG)
+#undef dev_dbg
+static inline int __attribute__ ((format (printf, 2, 3))) dev_dbg(
+	const struct device *_dev, const char *fmt, ...) {return 0;}
+#endif
+
+static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
+{
+	int result;
+	struct usb_hcd *hcd;
+	unsigned int virq;
+	static u64 dummy_mask = DMA_32BIT_MASK;
+
+	if (usb_disabled()) {
+		result = -ENODEV;
+		goto fail_start;
+	}
+
+	result = ps3_mmio_region_create(dev->m_region);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
+			__func__, __LINE__);
+		result = -EPERM;
+		goto fail_mmio;
+	}
+
+	dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
+		__LINE__, dev->m_region->lpar_addr);
+
+	result = ps3_alloc_io_irq(dev->interrupt_id, &virq);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: ps3_construct_io_irq(%d) failed.\n",
+			__func__, __LINE__, virq);
+		result = -EPERM;
+		goto fail_irq;
+	}
+
+	dev->core.power.power_state = PMSG_ON;
+	dev->core.dma_mask = &dummy_mask; /* FIXME: for improper usb code */
+
+	hcd = usb_create_hcd(&ps3_ohci_hc_driver, &dev->core, dev->core.bus_id);
+
+	if (!hcd) {
+		dev_dbg(&dev->core, "%s:%d: usb_create_hcd failed\n", __func__,
+			__LINE__);
+		result = -ENOMEM;
+		goto fail_create_hcd;
+	}
+
+	hcd->rsrc_start = dev->m_region->lpar_addr;
+	hcd->rsrc_len = dev->m_region->len;
+	hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
+
+	if (!hcd->regs) {
+		dev_dbg(&dev->core, "%s:%d: ioremap failed\n", __func__,
+			__LINE__);
+		result = -EPERM;
+		goto fail_ioremap;
+	}
+
+	dev_dbg(&dev->core, "%s:%d: hcd->rsrc_start %lxh\n", __func__, __LINE__,
+		(unsigned long)hcd->rsrc_start);
+	dev_dbg(&dev->core, "%s:%d: hcd->rsrc_len   %lxh\n", __func__, __LINE__,
+		(unsigned long)hcd->rsrc_len);
+	dev_dbg(&dev->core, "%s:%d: hcd->regs       %lxh\n", __func__, __LINE__,
+		(unsigned long)hcd->regs);
+	dev_dbg(&dev->core, "%s:%d: virq            %lu\n", __func__, __LINE__,
+		(unsigned long)virq);
+
+	ps3_system_bus_set_driver_data(dev, hcd);
+
+	result = usb_add_hcd(hcd, virq, IRQF_DISABLED);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: usb_add_hcd failed (%d)\n",
+			__func__, __LINE__, result);
+		goto fail_add_hcd;
+	}
+
+	return result;
+
+fail_add_hcd:
+	iounmap(hcd->regs);
+fail_ioremap:
+	usb_put_hcd(hcd);
+fail_create_hcd:
+	ps3_free_io_irq(virq);
+fail_irq:
+	ps3_free_mmio_region(dev->m_region);
+fail_mmio:
+fail_start:
+	return result;
+}
+
+static int ps3_ohci_sb_remove (struct ps3_system_bus_device *dev)
+{
+	struct usb_hcd *hcd =
+		(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
+
+	usb_put_hcd(hcd);
+	ps3_system_bus_set_driver_data(dev, NULL);
+
+	return 0;
+}
+
+MODULE_ALIAS("ps3-ohci");
+
+static struct ps3_system_bus_driver ps3_ohci_sb_driver = {
+	.match_id = PS3_MATCH_ID_OHCI,
+	.core = {
+		.name = "ps3-ohci-driver",
+	},
+	.probe = ps3_ohci_sb_probe,
+	.remove = ps3_ohci_sb_remove,
+};

+ 0 - 16
drivers/usb/host/ohci-pxa27x.c

@@ -369,19 +369,3 @@ static struct platform_driver ohci_hcd_pxa27x_driver = {
 	},
 	},
 };
 };
 
 
-static int __init ohci_hcd_pxa27x_init (void)
-{
-	pr_debug (DRIVER_INFO " (pxa27x)");
-	pr_debug ("block sizes: ed %d td %d\n",
-		sizeof (struct ed), sizeof (struct td));
-
-	return platform_driver_register(&ohci_hcd_pxa27x_driver);
-}
-
-static void __exit ohci_hcd_pxa27x_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_pxa27x_driver);
-}
-
-module_init (ohci_hcd_pxa27x_init);
-module_exit (ohci_hcd_pxa27x_cleanup);

+ 0 - 12
drivers/usb/host/ohci-s3c2410.c

@@ -501,15 +501,3 @@ static struct platform_driver ohci_hcd_s3c2410_driver = {
 	},
 	},
 };
 };
 
 
-static int __init ohci_hcd_s3c2410_init (void)
-{
-	return platform_driver_register(&ohci_hcd_s3c2410_driver);
-}
-
-static void __exit ohci_hcd_s3c2410_cleanup (void)
-{
-	platform_driver_unregister(&ohci_hcd_s3c2410_driver);
-}
-
-module_init (ohci_hcd_s3c2410_init);
-module_exit (ohci_hcd_s3c2410_cleanup);

+ 0 - 16
drivers/usb/host/ohci-sa1111.c

@@ -269,19 +269,3 @@ static struct sa1111_driver ohci_hcd_sa1111_driver = {
 	.remove		= ohci_hcd_sa1111_drv_remove,
 	.remove		= ohci_hcd_sa1111_drv_remove,
 };
 };
 
 
-static int __init ohci_hcd_sa1111_init (void)
-{
-	dbg (DRIVER_INFO " (SA-1111)");
-	dbg ("block sizes: ed %d td %d",
-		sizeof (struct ed), sizeof (struct td));
-
-	return sa1111_driver_register(&ohci_hcd_sa1111_driver);
-}
-
-static void __exit ohci_hcd_sa1111_cleanup (void)
-{
-	sa1111_driver_unregister(&ohci_hcd_sa1111_driver);
-}
-
-module_init (ohci_hcd_sa1111_init);
-module_exit (ohci_hcd_sa1111_cleanup);

+ 103 - 52
drivers/usb/host/ohci.h

@@ -394,8 +394,9 @@ struct ohci_hcd {
 #define	OHCI_QUIRK_AMD756	0x01			/* erratum #4 */
 #define	OHCI_QUIRK_AMD756	0x01			/* erratum #4 */
 #define	OHCI_QUIRK_SUPERIO	0x02			/* natsemi */
 #define	OHCI_QUIRK_SUPERIO	0x02			/* natsemi */
 #define	OHCI_QUIRK_INITRESET	0x04			/* SiS, OPTi, ... */
 #define	OHCI_QUIRK_INITRESET	0x04			/* SiS, OPTi, ... */
-#define	OHCI_BIG_ENDIAN		0x08			/* big endian HC */
-#define	OHCI_QUIRK_ZFMICRO	0x10			/* Compaq ZFMicro chipset*/
+#define	OHCI_QUIRK_BE_DESC	0x08			/* BE descriptors */
+#define	OHCI_QUIRK_BE_MMIO	0x10			/* BE registers */
+#define	OHCI_QUIRK_ZFMICRO	0x20			/* Compaq ZFMicro chipset*/
 	// there are also chip quirks/bugs in init logic
 	// there are also chip quirks/bugs in init logic
 
 
 };
 };
@@ -439,117 +440,164 @@ static inline struct usb_hcd *ohci_to_hcd (const struct ohci_hcd *ohci)
  * a minority (notably the IBM STB04XXX and the Motorola MPC5200
  * a minority (notably the IBM STB04XXX and the Motorola MPC5200
  * processors) implement them in big endian format.
  * processors) implement them in big endian format.
  *
  *
+ * In addition some more exotic implementations like the Toshiba
+ * Spider (aka SCC) cell southbridge are "mixed" endian, that is,
+ * they have a different endianness for registers vs. in-memory
+ * descriptors.
+ *
  * This attempts to support either format at compile time without a
  * This attempts to support either format at compile time without a
  * runtime penalty, or both formats with the additional overhead
  * runtime penalty, or both formats with the additional overhead
  * of checking a flag bit.
  * of checking a flag bit.
+ *
+ * That leads to some tricky Kconfig rules howevber. There are
+ * different defaults based on some arch/ppc platforms, though
+ * the basic rules are:
+ *
+ * Controller type              Kconfig options needed
+ * ---------------              ----------------------
+ * little endian                CONFIG_USB_OHCI_LITTLE_ENDIAN
+ *
+ * fully big endian             CONFIG_USB_OHCI_BIG_ENDIAN_DESC _and_
+ *                              CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+ *
+ * mixed endian                 CONFIG_USB_OHCI_LITTLE_ENDIAN _and_
+ *                              CONFIG_USB_OHCI_BIG_ENDIAN_{MMIO,DESC}
+ *
+ * (If you have a mixed endian controller, you -must- also define
+ * CONFIG_USB_OHCI_LITTLE_ENDIAN or things will not work when building
+ * both your mixed endian and a fully big endian controller support in
+ * the same kernel image).
  */
  */
 
 
-#ifdef CONFIG_USB_OHCI_BIG_ENDIAN
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_DESC
+#ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
+#define big_endian_desc(ohci)	(ohci->flags & OHCI_QUIRK_BE_DESC)
+#else
+#define big_endian_desc(ohci)	1		/* only big endian */
+#endif
+#else
+#define big_endian_desc(ohci)	0		/* only little endian */
+#endif
 
 
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
 #ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
 #ifdef CONFIG_USB_OHCI_LITTLE_ENDIAN
-#define big_endian(ohci)	(ohci->flags & OHCI_BIG_ENDIAN) /* either */
+#define big_endian_mmio(ohci)	(ohci->flags & OHCI_QUIRK_BE_MMIO)
 #else
 #else
-#define big_endian(ohci)	1		/* only big endian */
+#define big_endian_mmio(ohci)	1		/* only big endian */
+#endif
+#else
+#define big_endian_mmio(ohci)	0		/* only little endian */
 #endif
 #endif
 
 
 /*
 /*
  * Big-endian read/write functions are arch-specific.
  * Big-endian read/write functions are arch-specific.
  * Other arches can be added if/when they're needed.
  * Other arches can be added if/when they're needed.
+ *
+ * REVISIT: arch/powerpc now has readl/writel_be, so the
+ * definition below can die once the STB04xxx support is
+ * finally ported over.
  */
  */
-#if defined(CONFIG_PPC)
+#if defined(CONFIG_PPC) && !defined(CONFIG_PPC_MERGE)
 #define readl_be(addr)		in_be32((__force unsigned *)addr)
 #define readl_be(addr)		in_be32((__force unsigned *)addr)
 #define writel_be(val, addr)	out_be32((__force unsigned *)addr, val)
 #define writel_be(val, addr)	out_be32((__force unsigned *)addr, val)
 #endif
 #endif
 
 
-static inline unsigned int ohci_readl (const struct ohci_hcd *ohci,
-							__hc32 __iomem * regs)
+static inline unsigned int _ohci_readl (const struct ohci_hcd *ohci,
+					__hc32 __iomem * regs)
 {
 {
-	return big_endian(ohci) ? readl_be (regs) : readl ((__force u32 *)regs);
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+	return big_endian_mmio(ohci) ?
+		readl_be ((__force u32 *)regs) :
+		readl ((__force u32 *)regs);
+#else
+	return readl ((__force u32 *)regs);
+#endif
 }
 }
 
 
-static inline void ohci_writel (const struct ohci_hcd *ohci,
-				const unsigned int val, __hc32 __iomem *regs)
+static inline void _ohci_writel (const struct ohci_hcd *ohci,
+				 const unsigned int val, __hc32 __iomem *regs)
 {
 {
-	big_endian(ohci) ? writel_be (val, regs) :
-			   writel (val, (__force u32 *)regs);
+#ifdef CONFIG_USB_OHCI_BIG_ENDIAN_MMIO
+	big_endian_mmio(ohci) ?
+		writel_be (val, (__force u32 *)regs) :
+		writel (val, (__force u32 *)regs);
+#else
+		writel (val, (__force u32 *)regs);
+#endif
 }
 }
 
 
-#else	/* !CONFIG_USB_OHCI_BIG_ENDIAN */
-
-#define big_endian(ohci)	0		/* only little endian */
-
 #ifdef CONFIG_ARCH_LH7A404
 #ifdef CONFIG_ARCH_LH7A404
-	/* Marc Singer: at the time this code was written, the LH7A404
-	 * had a problem reading the USB host registers.  This
-	 * implementation of the ohci_readl function performs the read
-	 * twice as a work-around.
-	 */
-static inline unsigned int
-ohci_readl (const struct ohci_hcd *ohci, const __hc32 *regs)
-{
-	*(volatile __force unsigned int*) regs;
-	return *(volatile __force unsigned int*) regs;
-}
+/* Marc Singer: at the time this code was written, the LH7A404
+ * had a problem reading the USB host registers.  This
+ * implementation of the ohci_readl function performs the read
+ * twice as a work-around.
+ */
+#define ohci_readl(o,r)		(_ohci_readl(o,r),_ohci_readl(o,r))
+#define ohci_writel(o,v,r)	_ohci_writel(o,v,r)
 #else
 #else
-	/* Standard version of ohci_readl uses standard, platform
-	 * specific implementation. */
-static inline unsigned int
-ohci_readl (const struct ohci_hcd *ohci, __hc32 __iomem * regs)
-{
-	return readl(regs);
-}
+#define ohci_readl(o,r)		_ohci_readl(o,r)
+#define ohci_writel(o,v,r)	_ohci_writel(o,v,r)
 #endif
 #endif
 
 
-static inline void ohci_writel (const struct ohci_hcd *ohci,
-				const unsigned int val, __hc32 __iomem *regs)
-{
-	writel (val, regs);
-}
-
-#endif	/* !CONFIG_USB_OHCI_BIG_ENDIAN */
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 /* cpu to ohci */
 /* cpu to ohci */
 static inline __hc16 cpu_to_hc16 (const struct ohci_hcd *ohci, const u16 x)
 static inline __hc16 cpu_to_hc16 (const struct ohci_hcd *ohci, const u16 x)
 {
 {
-	return big_endian(ohci) ? (__force __hc16)cpu_to_be16(x) : (__force __hc16)cpu_to_le16(x);
+	return big_endian_desc(ohci) ?
+		(__force __hc16)cpu_to_be16(x) :
+		(__force __hc16)cpu_to_le16(x);
 }
 }
 
 
 static inline __hc16 cpu_to_hc16p (const struct ohci_hcd *ohci, const u16 *x)
 static inline __hc16 cpu_to_hc16p (const struct ohci_hcd *ohci, const u16 *x)
 {
 {
-	return big_endian(ohci) ? cpu_to_be16p(x) : cpu_to_le16p(x);
+	return big_endian_desc(ohci) ?
+		cpu_to_be16p(x) :
+		cpu_to_le16p(x);
 }
 }
 
 
 static inline __hc32 cpu_to_hc32 (const struct ohci_hcd *ohci, const u32 x)
 static inline __hc32 cpu_to_hc32 (const struct ohci_hcd *ohci, const u32 x)
 {
 {
-	return big_endian(ohci) ? (__force __hc32)cpu_to_be32(x) : (__force __hc32)cpu_to_le32(x);
+	return big_endian_desc(ohci) ?
+		(__force __hc32)cpu_to_be32(x) :
+		(__force __hc32)cpu_to_le32(x);
 }
 }
 
 
 static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x)
 static inline __hc32 cpu_to_hc32p (const struct ohci_hcd *ohci, const u32 *x)
 {
 {
-	return big_endian(ohci) ? cpu_to_be32p(x) : cpu_to_le32p(x);
+	return big_endian_desc(ohci) ?
+		cpu_to_be32p(x) :
+		cpu_to_le32p(x);
 }
 }
 
 
 /* ohci to cpu */
 /* ohci to cpu */
 static inline u16 hc16_to_cpu (const struct ohci_hcd *ohci, const __hc16 x)
 static inline u16 hc16_to_cpu (const struct ohci_hcd *ohci, const __hc16 x)
 {
 {
-	return big_endian(ohci) ? be16_to_cpu((__force __be16)x) : le16_to_cpu((__force __le16)x);
+	return big_endian_desc(ohci) ?
+		be16_to_cpu((__force __be16)x) :
+		le16_to_cpu((__force __le16)x);
 }
 }
 
 
 static inline u16 hc16_to_cpup (const struct ohci_hcd *ohci, const __hc16 *x)
 static inline u16 hc16_to_cpup (const struct ohci_hcd *ohci, const __hc16 *x)
 {
 {
-	return big_endian(ohci) ? be16_to_cpup((__force __be16 *)x) : le16_to_cpup((__force __le16 *)x);
+	return big_endian_desc(ohci) ?
+		be16_to_cpup((__force __be16 *)x) :
+		le16_to_cpup((__force __le16 *)x);
 }
 }
 
 
 static inline u32 hc32_to_cpu (const struct ohci_hcd *ohci, const __hc32 x)
 static inline u32 hc32_to_cpu (const struct ohci_hcd *ohci, const __hc32 x)
 {
 {
-	return big_endian(ohci) ? be32_to_cpu((__force __be32)x) : le32_to_cpu((__force __le32)x);
+	return big_endian_desc(ohci) ?
+		be32_to_cpu((__force __be32)x) :
+		le32_to_cpu((__force __le32)x);
 }
 }
 
 
 static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
 static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
 {
 {
-	return big_endian(ohci) ? be32_to_cpup((__force __be32 *)x) : le32_to_cpup((__force __le32 *)x);
+	return big_endian_desc(ohci) ?
+		be32_to_cpup((__force __be32 *)x) :
+		le32_to_cpup((__force __le32 *)x);
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -557,6 +605,9 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
 /* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
 /* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
  * hardware handles 16 bit reads.  That creates a different confusion on
  * hardware handles 16 bit reads.  That creates a different confusion on
  * some big-endian SOC implementations.  Same thing happens with PSW access.
  * some big-endian SOC implementations.  Same thing happens with PSW access.
+ *
+ * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over
+ * to arch/powerpc
  */
  */
 
 
 #ifdef CONFIG_STB03xxx
 #ifdef CONFIG_STB03xxx
@@ -568,7 +619,7 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
 static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
 static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
 {
 {
 	u32 tmp;
 	u32 tmp;
-	if (big_endian(ohci)) {
+	if (big_endian_desc(ohci)) {
 		tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
 		tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
 		tmp >>= OHCI_BE_FRAME_NO_SHIFT;
 		tmp >>= OHCI_BE_FRAME_NO_SHIFT;
 	} else
 	} else
@@ -580,7 +631,7 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
 static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci,
 static inline __hc16 *ohci_hwPSWp(const struct ohci_hcd *ohci,
                                  const struct td *td, int index)
                                  const struct td *td, int index)
 {
 {
-	return (__hc16 *)(big_endian(ohci) ?
+	return (__hc16 *)(big_endian_desc(ohci) ?
 			&td->hwPSW[index ^ 1] : &td->hwPSW[index]);
 			&td->hwPSW[index ^ 1] : &td->hwPSW[index]);
 }
 }
 
 

+ 62 - 9
drivers/usb/host/uhci-debug.c

@@ -168,9 +168,13 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
 			space, "", qh, qtype,
 			space, "", qh, qtype,
 			le32_to_cpu(qh->link), le32_to_cpu(element));
 			le32_to_cpu(qh->link), le32_to_cpu(element));
 	if (qh->type == USB_ENDPOINT_XFER_ISOC)
 	if (qh->type == USB_ENDPOINT_XFER_ISOC)
-		out += sprintf(out, "%*s    period %d frame %x desc [%p]\n",
-				space, "", qh->period, qh->iso_frame,
-				qh->iso_packet_desc);
+		out += sprintf(out, "%*s    period %d phase %d load %d us, "
+				"frame %x desc [%p]\n",
+				space, "", qh->period, qh->phase, qh->load,
+				qh->iso_frame, qh->iso_packet_desc);
+	else if (qh->type == USB_ENDPOINT_XFER_INT)
+		out += sprintf(out, "%*s    period %d phase %d load %d us\n",
+				space, "", qh->period, qh->phase, qh->load);
 
 
 	if (element & UHCI_PTR_QH)
 	if (element & UHCI_PTR_QH)
 		out += sprintf(out, "%*s  Element points to QH (bug?)\n", space, "");
 		out += sprintf(out, "%*s  Element points to QH (bug?)\n", space, "");
@@ -208,7 +212,7 @@ static int uhci_show_qh(struct uhci_qh *qh, char *buf, int len, int space)
 					space, "", nurbs);
 					space, "", nurbs);
 	}
 	}
 
 
-	if (qh->udev) {
+	if (qh->dummy_td) {
 		out += sprintf(out, "%*s  Dummy TD\n", space, "");
 		out += sprintf(out, "%*s  Dummy TD\n", space, "");
 		out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0);
 		out += uhci_show_td(qh->dummy_td, out, len - (out - buf), 0);
 	}
 	}
@@ -347,31 +351,80 @@ static int uhci_sprint_schedule(struct uhci_hcd *uhci, char *buf, int len)
 	struct uhci_qh *qh;
 	struct uhci_qh *qh;
 	struct uhci_td *td;
 	struct uhci_td *td;
 	struct list_head *tmp, *head;
 	struct list_head *tmp, *head;
+	int nframes, nerrs;
 
 
 	out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
 	out += uhci_show_root_hub_state(uhci, out, len - (out - buf));
 	out += sprintf(out, "HC status\n");
 	out += sprintf(out, "HC status\n");
 	out += uhci_show_status(uhci, out, len - (out - buf));
 	out += uhci_show_status(uhci, out, len - (out - buf));
+
+	out += sprintf(out, "Periodic load table\n");
+	for (i = 0; i < MAX_PHASE; ++i) {
+		out += sprintf(out, "\t%d", uhci->load[i]);
+		if (i % 8 == 7)
+			*out++ = '\n';
+	}
+	out += sprintf(out, "Total: %d, #INT: %d, #ISO: %d\n",
+			uhci->total_load,
+			uhci_to_hcd(uhci)->self.bandwidth_int_reqs,
+			uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs);
 	if (debug <= 1)
 	if (debug <= 1)
 		return out - buf;
 		return out - buf;
 
 
 	out += sprintf(out, "Frame List\n");
 	out += sprintf(out, "Frame List\n");
+	nframes = 10;
+	nerrs = 0;
 	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
 	for (i = 0; i < UHCI_NUMFRAMES; ++i) {
+		__le32 link, qh_dma;
+
+		j = 0;
 		td = uhci->frame_cpu[i];
 		td = uhci->frame_cpu[i];
+		link = uhci->frame[i];
 		if (!td)
 		if (!td)
-			continue;
+			goto check_link;
 
 
-		out += sprintf(out, "- Frame %d\n", i); \
-		if (td->dma_handle != (dma_addr_t)uhci->frame[i])
-			out += sprintf(out, "    frame list does not match td->dma_handle!\n");
+		if (nframes > 0) {
+			out += sprintf(out, "- Frame %d -> (%08x)\n",
+					i, le32_to_cpu(link));
+			j = 1;
+		}
 
 
 		head = &td->fl_list;
 		head = &td->fl_list;
 		tmp = head;
 		tmp = head;
 		do {
 		do {
 			td = list_entry(tmp, struct uhci_td, fl_list);
 			td = list_entry(tmp, struct uhci_td, fl_list);
 			tmp = tmp->next;
 			tmp = tmp->next;
-			out += uhci_show_td(td, out, len - (out - buf), 4);
+			if (cpu_to_le32(td->dma_handle) != link) {
+				if (nframes > 0)
+					out += sprintf(out, "    link does "
+						"not match list entry!\n");
+				else
+					++nerrs;
+			}
+			if (nframes > 0)
+				out += uhci_show_td(td, out,
+						len - (out - buf), 4);
+			link = td->link;
 		} while (tmp != head);
 		} while (tmp != head);
+
+check_link:
+		qh_dma = uhci_frame_skel_link(uhci, i);
+		if (link != qh_dma) {
+			if (nframes > 0) {
+				if (!j) {
+					out += sprintf(out,
+						"- Frame %d -> (%08x)\n",
+						i, le32_to_cpu(link));
+					j = 1;
+				}
+				out += sprintf(out, "   link does not match "
+					"QH (%08x)!\n", le32_to_cpu(qh_dma));
+			} else
+				++nerrs;
+		}
+		nframes -= j;
 	}
 	}
+	if (nerrs > 0)
+		out += sprintf(out, "Skipped %d bad links\n", nerrs);
 
 
 	out += sprintf(out, "Skeleton QHs\n");
 	out += sprintf(out, "Skeleton QHs\n");
 
 

+ 29 - 22
drivers/usb/host/uhci-hcd.c

@@ -92,6 +92,34 @@ static void suspend_rh(struct uhci_hcd *uhci, enum uhci_rh_state new_state);
 static void wakeup_rh(struct uhci_hcd *uhci);
 static void wakeup_rh(struct uhci_hcd *uhci);
 static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
 static void uhci_get_current_frame_number(struct uhci_hcd *uhci);
 
 
+/*
+ * Calculate the link pointer DMA value for the first Skeleton QH in a frame.
+ */
+static __le32 uhci_frame_skel_link(struct uhci_hcd *uhci, int frame)
+{
+	int skelnum;
+
+	/*
+	 * The interrupt queues will be interleaved as evenly as possible.
+	 * There's not much to be done about period-1 interrupts; they have
+	 * to occur in every frame.  But we can schedule period-2 interrupts
+	 * in odd-numbered frames, period-4 interrupts in frames congruent
+	 * to 2 (mod 4), and so on.  This way each frame only has two
+	 * interrupt QHs, which will help spread out bandwidth utilization.
+	 *
+	 * ffs (Find First bit Set) does exactly what we need:
+	 * 1,3,5,...  => ffs = 0 => use skel_int2_qh = skelqh[8],
+	 * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
+	 * ffs >= 7 => not on any high-period queue, so use
+	 *	skel_int1_qh = skelqh[9].
+	 * Add in UHCI_NUMFRAMES to insure at least one bit is set.
+	 */
+	skelnum = 8 - (int) __ffs(frame | UHCI_NUMFRAMES);
+	if (skelnum <= 1)
+		skelnum = 9;
+	return UHCI_PTR_QH | cpu_to_le32(uhci->skelqh[skelnum]->dma_handle);
+}
+
 #include "uhci-debug.c"
 #include "uhci-debug.c"
 #include "uhci-q.c"
 #include "uhci-q.c"
 #include "uhci-hub.c"
 #include "uhci-hub.c"
@@ -631,32 +659,11 @@ static int uhci_start(struct usb_hcd *hcd)
 	/*
 	/*
 	 * Fill the frame list: make all entries point to the proper
 	 * Fill the frame list: make all entries point to the proper
 	 * interrupt queue.
 	 * interrupt queue.
-	 *
-	 * The interrupt queues will be interleaved as evenly as possible.
-	 * There's not much to be done about period-1 interrupts; they have
-	 * to occur in every frame.  But we can schedule period-2 interrupts
-	 * in odd-numbered frames, period-4 interrupts in frames congruent
-	 * to 2 (mod 4), and so on.  This way each frame only has two
-	 * interrupt QHs, which will help spread out bandwidth utilization.
 	 */
 	 */
 	for (i = 0; i < UHCI_NUMFRAMES; i++) {
 	for (i = 0; i < UHCI_NUMFRAMES; i++) {
-		int irq;
-
-		/*
-		 * ffs (Find First bit Set) does exactly what we need:
-		 * 1,3,5,...  => ffs = 0 => use skel_int2_qh = skelqh[8],
-		 * 2,6,10,... => ffs = 1 => use skel_int4_qh = skelqh[7], etc.
-		 * ffs >= 7 => not on any high-period queue, so use
-		 *	skel_int1_qh = skelqh[9].
-		 * Add UHCI_NUMFRAMES to insure at least one bit is set.
-		 */
-		irq = 8 - (int) __ffs(i + UHCI_NUMFRAMES);
-		if (irq <= 1)
-			irq = 9;
 
 
 		/* Only place we don't use the frame list routines */
 		/* Only place we don't use the frame list routines */
-		uhci->frame[i] = UHCI_PTR_QH |
-				cpu_to_le32(uhci->skelqh[irq]->dma_handle);
+		uhci->frame[i] = uhci_frame_skel_link(uhci, i);
 	}
 	}
 
 
 	/*
 	/*

+ 8 - 0
drivers/usb/host/uhci-hcd.h

@@ -83,6 +83,7 @@
 #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 in the future frames
 #define CAN_SCHEDULE_FRAMES	1000	/* how far in the future frames
 					 * can be scheduled */
 					 * can be scheduled */
+#define MAX_PHASE		32	/* Periodic scheduling length */
 
 
 /* When no queues need Full-Speed Bandwidth Reclamation,
 /* When no queues need Full-Speed Bandwidth Reclamation,
  * delay this long before turning FSBR off */
  * delay this long before turning FSBR off */
@@ -141,6 +142,8 @@ struct uhci_qh {
 	unsigned long advance_jiffies;	/* Time of last queue advance */
 	unsigned long advance_jiffies;	/* Time of last queue advance */
 	unsigned int unlink_frame;	/* When the QH was unlinked */
 	unsigned int unlink_frame;	/* When the QH was unlinked */
 	unsigned int period;		/* For Interrupt and Isochronous QHs */
 	unsigned int period;		/* For Interrupt and Isochronous QHs */
+	short phase;			/* Between 0 and period-1 */
+	short load;			/* Periodic time requirement, in us */
 	unsigned int iso_frame;		/* Frame # for iso_packet_desc */
 	unsigned int iso_frame;		/* Frame # for iso_packet_desc */
 	int iso_status;			/* Status for Isochronous URBs */
 	int iso_status;			/* Status for Isochronous URBs */
 
 
@@ -153,6 +156,8 @@ struct uhci_qh {
 	unsigned int needs_fixup:1;	/* Must fix the TD toggle values */
 	unsigned int needs_fixup:1;	/* Must fix the TD toggle values */
 	unsigned int is_stopped:1;	/* Queue was stopped by error/unlink */
 	unsigned int is_stopped:1;	/* Queue was stopped by error/unlink */
 	unsigned int wait_expired:1;	/* QH_WAIT_TIMEOUT has expired */
 	unsigned int wait_expired:1;	/* QH_WAIT_TIMEOUT has expired */
+	unsigned int bandwidth_reserved:1;	/* Periodic bandwidth has
+						 * been allocated */
 } __attribute__((aligned(16)));
 } __attribute__((aligned(16)));
 
 
 /*
 /*
@@ -414,6 +419,9 @@ struct uhci_hcd {
 
 
 	wait_queue_head_t waitqh;		/* endpoint_disable waiters */
 	wait_queue_head_t waitqh;		/* endpoint_disable waiters */
 	int num_waiting;			/* Number of waiters */
 	int num_waiting;			/* Number of waiters */
+
+	int total_load;				/* Sum of array values */
+	short load[MAX_PHASE];			/* Periodic allocations */
 };
 };
 
 
 /* Convert between a usb_hcd pointer and the corresponding uhci_hcd */
 /* Convert between a usb_hcd pointer and the corresponding uhci_hcd */

+ 185 - 73
drivers/usb/host/uhci-q.c

@@ -248,16 +248,26 @@ static struct uhci_qh *uhci_alloc_qh(struct uhci_hcd *uhci,
 	INIT_LIST_HEAD(&qh->node);
 	INIT_LIST_HEAD(&qh->node);
 
 
 	if (udev) {		/* Normal QH */
 	if (udev) {		/* Normal QH */
-		qh->dummy_td = uhci_alloc_td(uhci);
-		if (!qh->dummy_td) {
-			dma_pool_free(uhci->qh_pool, qh, dma_handle);
-			return NULL;
+		qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+		if (qh->type != USB_ENDPOINT_XFER_ISOC) {
+			qh->dummy_td = uhci_alloc_td(uhci);
+			if (!qh->dummy_td) {
+				dma_pool_free(uhci->qh_pool, qh, dma_handle);
+				return NULL;
+			}
 		}
 		}
 		qh->state = QH_STATE_IDLE;
 		qh->state = QH_STATE_IDLE;
 		qh->hep = hep;
 		qh->hep = hep;
 		qh->udev = udev;
 		qh->udev = udev;
 		hep->hcpriv = qh;
 		hep->hcpriv = qh;
-		qh->type = hep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
+
+		if (qh->type == USB_ENDPOINT_XFER_INT ||
+				qh->type == USB_ENDPOINT_XFER_ISOC)
+			qh->load = usb_calc_bus_time(udev->speed,
+					usb_endpoint_dir_in(&hep->desc),
+					qh->type == USB_ENDPOINT_XFER_ISOC,
+					le16_to_cpu(hep->desc.wMaxPacketSize))
+				/ 1000 + 1;
 
 
 	} else {		/* Skeleton QH */
 	} else {		/* Skeleton QH */
 		qh->state = QH_STATE_ACTIVE;
 		qh->state = QH_STATE_ACTIVE;
@@ -275,7 +285,8 @@ static void uhci_free_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
 	list_del(&qh->node);
 	list_del(&qh->node);
 	if (qh->udev) {
 	if (qh->udev) {
 		qh->hep->hcpriv = NULL;
 		qh->hep->hcpriv = NULL;
-		uhci_free_td(uhci, qh->dummy_td);
+		if (qh->dummy_td)
+			uhci_free_td(uhci, qh->dummy_td);
 	}
 	}
 	dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
 	dma_pool_free(uhci->qh_pool, qh, qh->dma_handle);
 }
 }
@@ -327,7 +338,7 @@ static int uhci_cleanup_queue(struct uhci_hcd *uhci, struct uhci_qh *qh,
 		goto done;
 		goto done;
 	qh->element = UHCI_PTR_TERM;
 	qh->element = UHCI_PTR_TERM;
 
 
-	/* Control pipes have to worry about toggles */
+	/* Control pipes don't have to worry about toggles */
 	if (qh->type == USB_ENDPOINT_XFER_CONTROL)
 	if (qh->type == USB_ENDPOINT_XFER_CONTROL)
 		goto done;
 		goto done;
 
 
@@ -493,6 +504,121 @@ static void uhci_make_qh_idle(struct uhci_hcd *uhci, struct uhci_qh *qh)
 		wake_up_all(&uhci->waitqh);
 		wake_up_all(&uhci->waitqh);
 }
 }
 
 
+/*
+ * Find the highest existing bandwidth load for a given phase and period.
+ */
+static int uhci_highest_load(struct uhci_hcd *uhci, int phase, int period)
+{
+	int highest_load = uhci->load[phase];
+
+	for (phase += period; phase < MAX_PHASE; phase += period)
+		highest_load = max_t(int, highest_load, uhci->load[phase]);
+	return highest_load;
+}
+
+/*
+ * Set qh->phase to the optimal phase for a periodic transfer and
+ * check whether the bandwidth requirement is acceptable.
+ */
+static int uhci_check_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+	int minimax_load;
+
+	/* Find the optimal phase (unless it is already set) and get
+	 * its load value. */
+	if (qh->phase >= 0)
+		minimax_load = uhci_highest_load(uhci, qh->phase, qh->period);
+	else {
+		int phase, load;
+		int max_phase = min_t(int, MAX_PHASE, qh->period);
+
+		qh->phase = 0;
+		minimax_load = uhci_highest_load(uhci, qh->phase, qh->period);
+		for (phase = 1; phase < max_phase; ++phase) {
+			load = uhci_highest_load(uhci, phase, qh->period);
+			if (load < minimax_load) {
+				minimax_load = load;
+				qh->phase = phase;
+			}
+		}
+	}
+
+	/* Maximum allowable periodic bandwidth is 90%, or 900 us per frame */
+	if (minimax_load + qh->load > 900) {
+		dev_dbg(uhci_dev(uhci), "bandwidth allocation failed: "
+				"period %d, phase %d, %d + %d us\n",
+				qh->period, qh->phase, minimax_load, qh->load);
+		return -ENOSPC;
+	}
+	return 0;
+}
+
+/*
+ * Reserve a periodic QH's bandwidth in the schedule
+ */
+static void uhci_reserve_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+	int i;
+	int load = qh->load;
+	char *p = "??";
+
+	for (i = qh->phase; i < MAX_PHASE; i += qh->period) {
+		uhci->load[i] += load;
+		uhci->total_load += load;
+	}
+	uhci_to_hcd(uhci)->self.bandwidth_allocated =
+			uhci->total_load / MAX_PHASE;
+	switch (qh->type) {
+	case USB_ENDPOINT_XFER_INT:
+		++uhci_to_hcd(uhci)->self.bandwidth_int_reqs;
+		p = "INT";
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		++uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs;
+		p = "ISO";
+		break;
+	}
+	qh->bandwidth_reserved = 1;
+	dev_dbg(uhci_dev(uhci),
+			"%s dev %d ep%02x-%s, period %d, phase %d, %d us\n",
+			"reserve", qh->udev->devnum,
+			qh->hep->desc.bEndpointAddress, p,
+			qh->period, qh->phase, load);
+}
+
+/*
+ * Release a periodic QH's bandwidth reservation
+ */
+static void uhci_release_bandwidth(struct uhci_hcd *uhci, struct uhci_qh *qh)
+{
+	int i;
+	int load = qh->load;
+	char *p = "??";
+
+	for (i = qh->phase; i < MAX_PHASE; i += qh->period) {
+		uhci->load[i] -= load;
+		uhci->total_load -= load;
+	}
+	uhci_to_hcd(uhci)->self.bandwidth_allocated =
+			uhci->total_load / MAX_PHASE;
+	switch (qh->type) {
+	case USB_ENDPOINT_XFER_INT:
+		--uhci_to_hcd(uhci)->self.bandwidth_int_reqs;
+		p = "INT";
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		--uhci_to_hcd(uhci)->self.bandwidth_isoc_reqs;
+		p = "ISO";
+		break;
+	}
+	qh->bandwidth_reserved = 0;
+	dev_dbg(uhci_dev(uhci),
+			"%s dev %d ep%02x-%s, period %d, phase %d, %d us\n",
+			"release", qh->udev->devnum,
+			qh->hep->desc.bEndpointAddress, p,
+			qh->period, qh->phase, load);
+}
+
 static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci,
 static inline struct urb_priv *uhci_alloc_urb_priv(struct uhci_hcd *uhci,
 		struct urb *urb)
 		struct urb *urb)
 {
 {
@@ -796,7 +922,6 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
 	wmb();
 	wmb();
 	qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
 	qh->dummy_td->status |= __constant_cpu_to_le32(TD_CTRL_ACTIVE);
 	qh->dummy_td = td;
 	qh->dummy_td = td;
-	qh->period = urb->interval;
 
 
 	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
 	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
 			usb_pipeout(urb->pipe), toggle);
 			usb_pipeout(urb->pipe), toggle);
@@ -827,28 +952,42 @@ static inline int uhci_submit_bulk(struct uhci_hcd *uhci, struct urb *urb,
 static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
 static int uhci_submit_interrupt(struct uhci_hcd *uhci, struct urb *urb,
 		struct uhci_qh *qh)
 		struct uhci_qh *qh)
 {
 {
-	int exponent;
+	int ret;
 
 
 	/* USB 1.1 interrupt transfers only involve one packet per interval.
 	/* USB 1.1 interrupt transfers only involve one packet per interval.
 	 * Drivers can submit URBs of any length, but longer ones will need
 	 * Drivers can submit URBs of any length, but longer ones will need
 	 * multiple intervals to complete.
 	 * multiple intervals to complete.
 	 */
 	 */
 
 
-	/* Figure out which power-of-two queue to use */
-	for (exponent = 7; exponent >= 0; --exponent) {
-		if ((1 << exponent) <= urb->interval)
-			break;
-	}
-	if (exponent < 0)
-		return -EINVAL;
-	urb->interval = 1 << exponent;
+	if (!qh->bandwidth_reserved) {
+		int exponent;
 
 
-	if (qh->period == 0)
+		/* Figure out which power-of-two queue to use */
+		for (exponent = 7; exponent >= 0; --exponent) {
+			if ((1 << exponent) <= urb->interval)
+				break;
+		}
+		if (exponent < 0)
+			return -EINVAL;
+		qh->period = 1 << exponent;
 		qh->skel = uhci->skelqh[UHCI_SKEL_INDEX(exponent)];
 		qh->skel = uhci->skelqh[UHCI_SKEL_INDEX(exponent)];
-	else if (qh->period != urb->interval)
-		return -EINVAL;		/* Can't change the period */
 
 
-	return uhci_submit_common(uhci, urb, qh);
+		/* For now, interrupt phase is fixed by the layout
+		 * of the QH lists. */
+		qh->phase = (qh->period / 2) & (MAX_PHASE - 1);
+		ret = uhci_check_bandwidth(uhci, qh);
+		if (ret)
+			return ret;
+	} else if (qh->period > urb->interval)
+		return -EINVAL;		/* Can't decrease the period */
+
+	ret = uhci_submit_common(uhci, urb, qh);
+	if (ret == 0) {
+		urb->interval = qh->period;
+		if (!qh->bandwidth_reserved)
+			uhci_reserve_bandwidth(uhci, qh);
+	}
+	return ret;
 }
 }
 
 
 /*
 /*
@@ -995,15 +1134,32 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
 		return -EFBIG;
 		return -EFBIG;
 
 
 	/* Check the period and figure out the starting frame number */
 	/* Check the period and figure out the starting frame number */
-	if (qh->period == 0) {
+	if (!qh->bandwidth_reserved) {
+		qh->period = urb->interval;
 		if (urb->transfer_flags & URB_ISO_ASAP) {
 		if (urb->transfer_flags & URB_ISO_ASAP) {
+			qh->phase = -1;		/* Find the best phase */
+			i = uhci_check_bandwidth(uhci, qh);
+			if (i)
+				return i;
+
+			/* Allow a little time to allocate the TDs */
 			uhci_get_current_frame_number(uhci);
 			uhci_get_current_frame_number(uhci);
-			urb->start_frame = uhci->frame_number + 10;
+			frame = uhci->frame_number + 10;
+
+			/* Move forward to the first frame having the
+			 * correct phase */
+			urb->start_frame = frame + ((qh->phase - frame) &
+					(qh->period - 1));
 		} else {
 		} else {
 			i = urb->start_frame - uhci->last_iso_frame;
 			i = urb->start_frame - uhci->last_iso_frame;
 			if (i <= 0 || i >= UHCI_NUMFRAMES)
 			if (i <= 0 || i >= UHCI_NUMFRAMES)
 				return -EINVAL;
 				return -EINVAL;
+			qh->phase = urb->start_frame & (qh->period - 1);
+			i = uhci_check_bandwidth(uhci, qh);
+			if (i)
+				return i;
 		}
 		}
+
 	} else if (qh->period != urb->interval) {
 	} else if (qh->period != urb->interval) {
 		return -EINVAL;		/* Can't change the period */
 		return -EINVAL;		/* Can't change the period */
 
 
@@ -1049,9 +1205,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
 	/* Set the interrupt-on-completion flag on the last packet. */
 	/* Set the interrupt-on-completion flag on the last packet. */
 	td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
 	td->status |= __constant_cpu_to_le32(TD_CTRL_IOC);
 
 
-	qh->skel = uhci->skel_iso_qh;
-	qh->period = urb->interval;
-
 	/* Add the TDs to the frame list */
 	/* Add the TDs to the frame list */
 	frame = urb->start_frame;
 	frame = urb->start_frame;
 	list_for_each_entry(td, &urbp->td_list, list) {
 	list_for_each_entry(td, &urbp->td_list, list) {
@@ -1065,6 +1218,9 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
 		qh->iso_status = 0;
 		qh->iso_status = 0;
 	}
 	}
 
 
+	qh->skel = uhci->skel_iso_qh;
+	if (!qh->bandwidth_reserved)
+		uhci_reserve_bandwidth(uhci, qh);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1119,7 +1275,6 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
 	unsigned long flags;
 	unsigned long flags;
 	struct urb_priv *urbp;
 	struct urb_priv *urbp;
 	struct uhci_qh *qh;
 	struct uhci_qh *qh;
-	int bustime;
 
 
 	spin_lock_irqsave(&uhci->lock, flags);
 	spin_lock_irqsave(&uhci->lock, flags);
 
 
@@ -1149,35 +1304,11 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
 		ret = uhci_submit_bulk(uhci, urb, qh);
 		ret = uhci_submit_bulk(uhci, urb, qh);
 		break;
 		break;
 	case USB_ENDPOINT_XFER_INT:
 	case USB_ENDPOINT_XFER_INT:
-		if (list_empty(&qh->queue)) {
-			bustime = usb_check_bandwidth(urb->dev, urb);
-			if (bustime < 0)
-				ret = bustime;
-			else {
-				ret = uhci_submit_interrupt(uhci, urb, qh);
-				if (ret == 0)
-					usb_claim_bandwidth(urb->dev, urb, bustime, 0);
-			}
-		} else {	/* inherit from parent */
-			struct urb_priv *eurbp;
-
-			eurbp = list_entry(qh->queue.prev, struct urb_priv,
-					node);
-			urb->bandwidth = eurbp->urb->bandwidth;
-			ret = uhci_submit_interrupt(uhci, urb, qh);
-		}
+		ret = uhci_submit_interrupt(uhci, urb, qh);
 		break;
 		break;
 	case USB_ENDPOINT_XFER_ISOC:
 	case USB_ENDPOINT_XFER_ISOC:
 		urb->error_count = 0;
 		urb->error_count = 0;
-		bustime = usb_check_bandwidth(urb->dev, urb);
-		if (bustime < 0) {
-			ret = bustime;
-			break;
-		}
-
 		ret = uhci_submit_isochronous(uhci, urb, qh);
 		ret = uhci_submit_isochronous(uhci, urb, qh);
-		if (ret == 0)
-			usb_claim_bandwidth(urb->dev, urb, bustime, 1);
 		break;
 		break;
 	}
 	}
 	if (ret != 0)
 	if (ret != 0)
@@ -1274,24 +1405,6 @@ __acquires(uhci->lock)
 
 
 	uhci_free_urb_priv(uhci, urbp);
 	uhci_free_urb_priv(uhci, urbp);
 
 
-	switch (qh->type) {
-	case USB_ENDPOINT_XFER_ISOC:
-		/* Release bandwidth for Interrupt or Isoc. transfers */
-		if (urb->bandwidth)
-			usb_release_bandwidth(urb->dev, urb, 1);
-		break;
-	case USB_ENDPOINT_XFER_INT:
-		/* Release bandwidth for Interrupt or Isoc. transfers */
-		/* Make sure we don't release if we have a queued URB */
-		if (list_empty(&qh->queue) && urb->bandwidth)
-			usb_release_bandwidth(urb->dev, urb, 0);
-		else
-			/* bandwidth was passed on to queued URB, */
-			/* so don't let usb_unlink_urb() release it */
-			urb->bandwidth = 0;
-		break;
-	}
-
 	spin_unlock(&uhci->lock);
 	spin_unlock(&uhci->lock);
 	usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
 	usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
 	spin_lock(&uhci->lock);
 	spin_lock(&uhci->lock);
@@ -1300,9 +1413,8 @@ __acquires(uhci->lock)
 	 * reserved bandwidth. */
 	 * reserved bandwidth. */
 	if (list_empty(&qh->queue)) {
 	if (list_empty(&qh->queue)) {
 		uhci_unlink_qh(uhci, qh);
 		uhci_unlink_qh(uhci, qh);
-
-		/* Bandwidth stuff not yet implemented */
-		qh->period = 0;
+		if (qh->bandwidth_reserved)
+			uhci_release_bandwidth(uhci, qh);
 	}
 	}
 }
 }
 
 

+ 4 - 0
drivers/usb/image/mdc800.c

@@ -565,11 +565,15 @@ static void mdc800_usb_disconnect (struct usb_interface *intf)
 
 
 		usb_deregister_dev(intf, &mdc800_class);
 		usb_deregister_dev(intf, &mdc800_class);
 
 
+		/* must be under lock to make sure no URB
+		   is submitted after usb_kill_urb() */
+		mutex_lock(&mdc800->io_lock);
 		mdc800->state=NOT_CONNECTED;
 		mdc800->state=NOT_CONNECTED;
 
 
 		usb_kill_urb(mdc800->irq_urb);
 		usb_kill_urb(mdc800->irq_urb);
 		usb_kill_urb(mdc800->write_urb);
 		usb_kill_urb(mdc800->write_urb);
 		usb_kill_urb(mdc800->download_urb);
 		usb_kill_urb(mdc800->download_urb);
+		mutex_unlock(&mdc800->io_lock);
 
 
 		mdc800->dev = NULL;
 		mdc800->dev = NULL;
 		usb_set_intfdata(intf, NULL);
 		usb_set_intfdata(intf, NULL);

+ 12 - 0
drivers/usb/input/Kconfig

@@ -352,3 +352,15 @@ config USB_APPLETOUCH
 
 
 	  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 appletouch.
 	  module will be called appletouch.
+
+config USB_GTCO
+        tristate "GTCO CalComp/InterWrite USB Support"
+        depends on USB && INPUT
+        ---help---
+          Say Y here if you want to use the USB version of the GTCO
+          CalComp/InterWrite Tablet.  Make sure to say Y to "Mouse support"
+          (CONFIG_INPUT_MOUSEDEV) and/or "Event interface support"
+          (CONFIG_INPUT_EVDEV) as well.
+
+          To compile this driver as a module, choose M here: the
+          module will be called gtco.

+ 1 - 0
drivers/usb/input/Makefile

@@ -48,6 +48,7 @@ obj-$(CONFIG_USB_ACECAD)	+= acecad.o
 obj-$(CONFIG_USB_YEALINK)	+= yealink.o
 obj-$(CONFIG_USB_YEALINK)	+= yealink.o
 obj-$(CONFIG_USB_XPAD)		+= xpad.o
 obj-$(CONFIG_USB_XPAD)		+= xpad.o
 obj-$(CONFIG_USB_APPLETOUCH)	+= appletouch.o
 obj-$(CONFIG_USB_APPLETOUCH)	+= appletouch.o
+obj-$(CONFIG_USB_GTCO)         += gtco.o
 
 
 ifeq ($(CONFIG_USB_DEBUG),y)
 ifeq ($(CONFIG_USB_DEBUG),y)
 EXTRA_CFLAGS += -DDEBUG
 EXTRA_CFLAGS += -DDEBUG

+ 1104 - 0
drivers/usb/input/gtco.c

@@ -0,0 +1,1104 @@
+/*    -*- linux-c -*-
+
+GTCO digitizer USB driver
+
+Use the err(), dbg() and info() macros from usb.h for system logging
+
+TO CHECK:  Is pressure done right on report 5?
+
+Copyright (C) 2006  GTCO CalComp
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; version 2
+of the License.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation, and that the name of GTCO-CalComp not be used in advertising
+or publicity pertaining to distribution of the software without specific,
+written prior permission. GTCO-CalComp makes no representations about the
+suitability of this software for any purpose.  It is provided "as is"
+without express or implied warranty.
+
+GTCO-CALCOMP DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+EVENT SHALL GTCO-CALCOMP BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTIONS, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+PERFORMANCE OF THIS SOFTWARE.
+
+GTCO CalComp, Inc.
+7125 Riverwood Drive
+Columbia, MD 21046
+
+Jeremy Roberson jroberson@gtcocalcomp.com
+Scott Hill shill@gtcocalcomp.com
+*/
+
+
+
+/*#define DEBUG*/
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <asm/uaccess.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+
+
+#include <linux/version.h>
+#include <linux/usb/input.h>
+
+/* Version with a Major number of 2 is for kernel inclusion only. */
+#define  GTCO_VERSION   "2.00.0006"
+
+
+/*   MACROS  */
+
+#define VENDOR_ID_GTCO	      0x078C
+#define PID_400               0x400
+#define PID_401               0x401
+#define PID_1000              0x1000
+#define PID_1001              0x1001
+#define PID_1002              0x1002
+
+/* Max size of a single report */
+#define REPORT_MAX_SIZE       10
+
+
+/* Bitmask whether pen is in range */
+#define MASK_INRANGE 0x20
+#define MASK_BUTTON  0x01F
+
+#define  PATHLENGTH     64
+
+/* DATA STRUCTURES */
+
+/* Device table */
+static struct usb_device_id gtco_usbid_table [] = {
+	{ USB_DEVICE(VENDOR_ID_GTCO, PID_400) },
+	{ USB_DEVICE(VENDOR_ID_GTCO, PID_401) },
+	{ USB_DEVICE(VENDOR_ID_GTCO, PID_1000) },
+	{ USB_DEVICE(VENDOR_ID_GTCO, PID_1001) },
+	{ USB_DEVICE(VENDOR_ID_GTCO, PID_1002) },
+	{ }
+};
+MODULE_DEVICE_TABLE (usb, gtco_usbid_table);
+
+
+/* Structure to hold all of our device specific stuff */
+struct gtco {
+
+	struct input_dev  *inputdevice; /* input device struct pointer  */
+	struct usb_device *usbdev; /* the usb device for this device */
+	struct urb        *urbinfo;	 /* urb for incoming reports      */
+	dma_addr_t        buf_dma;  /* dma addr of the data buffer*/
+	unsigned char *   buffer;   /* databuffer for reports */
+
+	char  usbpath[PATHLENGTH];
+	int   openCount;
+
+	/* Information pulled from Report Descriptor */
+	u32  usage;
+	u32  min_X;
+	u32  max_X;
+	u32  min_Y;
+	u32  max_Y;
+	s8   mintilt_X;
+	s8   maxtilt_X;
+	s8   mintilt_Y;
+	s8   maxtilt_Y;
+	u32  maxpressure;
+	u32  minpressure;
+};
+
+
+
+/*   Code for parsing the HID REPORT DESCRIPTOR          */
+
+/* From HID1.11 spec */
+struct hid_descriptor
+{
+	struct usb_descriptor_header header;
+	__le16   bcdHID;
+	u8       bCountryCode;
+	u8       bNumDescriptors;
+	u8       bDescriptorType;
+	__le16   wDescriptorLength;
+} __attribute__ ((packed));
+
+
+#define HID_DESCRIPTOR_SIZE   9
+#define HID_DEVICE_TYPE       33
+#define REPORT_DEVICE_TYPE    34
+
+
+#define PREF_TAG(x)     ((x)>>4)
+#define PREF_TYPE(x)    ((x>>2)&0x03)
+#define PREF_SIZE(x)    ((x)&0x03)
+
+#define TYPE_MAIN       0
+#define TYPE_GLOBAL     1
+#define TYPE_LOCAL      2
+#define TYPE_RESERVED   3
+
+#define TAG_MAIN_INPUT        0x8
+#define TAG_MAIN_OUTPUT       0x9
+#define TAG_MAIN_FEATURE      0xB
+#define TAG_MAIN_COL_START    0xA
+#define TAG_MAIN_COL_END      0xC
+
+#define TAG_GLOB_USAGE        0
+#define TAG_GLOB_LOG_MIN      1
+#define TAG_GLOB_LOG_MAX      2
+#define TAG_GLOB_PHYS_MIN     3
+#define TAG_GLOB_PHYS_MAX     4
+#define TAG_GLOB_UNIT_EXP     5
+#define TAG_GLOB_UNIT         6
+#define TAG_GLOB_REPORT_SZ    7
+#define TAG_GLOB_REPORT_ID    8
+#define TAG_GLOB_REPORT_CNT   9
+#define TAG_GLOB_PUSH         10
+#define TAG_GLOB_POP          11
+
+#define TAG_GLOB_MAX          12
+
+#define DIGITIZER_USAGE_TIP_PRESSURE   0x30
+#define DIGITIZER_USAGE_TILT_X         0x3D
+#define DIGITIZER_USAGE_TILT_Y         0x3E
+
+
+/*
+ *
+ *   This is an abbreviated parser for the HID Report Descriptor.  We
+ *   know what devices we are talking to, so this is by no means meant
+ *   to be generic.  We can make some safe assumptions:
+ *
+ *   - We know there are no LONG tags, all short
+ *   - We know that we have no MAIN Feature and MAIN Output items
+ *   - We know what the IRQ reports are supposed to look like.
+ *
+ *   The main purpose of this is to use the HID report desc to figure
+ *   out the mins and maxs of the fields in the IRQ reports.  The IRQ
+ *   reports for 400/401 change slightly if the max X is bigger than 64K.
+ *
+ */
+static void parse_hid_report_descriptor(struct gtco *device, char * report,
+					int length)
+{
+	int   x,i=0;
+
+	/* Tag primitive vars */
+	__u8   prefix;
+	__u8   size;
+	__u8   tag;
+	__u8   type;
+	__u8   data   = 0;
+	__u16  data16 = 0;
+	__u32  data32 = 0;
+
+
+	/* For parsing logic */
+	int   inputnum = 0;
+	__u32 usage = 0;
+
+	/* Global Values, indexed by TAG */
+	__u32 globalval[TAG_GLOB_MAX];
+	__u32 oldval[TAG_GLOB_MAX];
+
+	/* Debug stuff */
+	char  maintype='x';
+	char  globtype[12];
+	int   indent=0;
+	char  indentstr[10]="";
+
+
+
+	dbg("======>>>>>>PARSE<<<<<<======");
+
+	/* Walk  this report and pull out the info we need */
+	while (i<length){
+		prefix=report[i];
+
+		/* Skip over prefix */
+		i++;
+
+		/* Determine data size and save the data in the proper variable */
+		size = PREF_SIZE(prefix);
+		switch(size){
+		case 1:
+			data = report[i];
+			break;
+		case 2:
+			data16 = le16_to_cpu(get_unaligned((__le16*)(&(report[i]))));
+			break;
+		case 3:
+			size = 4;
+			data32 = le32_to_cpu(get_unaligned((__le32*)(&(report[i]))));
+		}
+
+		/* Skip size of data */
+		i+=size;
+
+		/* What we do depends on the tag type */
+		tag  = PREF_TAG(prefix);
+		type = PREF_TYPE(prefix);
+		switch(type){
+		case TYPE_MAIN:
+			strcpy(globtype,"");
+			switch(tag){
+
+			case TAG_MAIN_INPUT:
+				/*
+				 * The INPUT MAIN tag signifies this is
+				 * information from a report.  We need to
+				 * figure out what it is and store the
+				 * min/max values
+				 */
+
+				maintype='I';
+				if (data==2){
+					strcpy(globtype,"Variable");
+				}
+				if (data==3){
+					strcpy(globtype,"Var|Const");
+				}
+
+				dbg("::::: Saving Report: %d input #%d Max: 0x%X(%d) Min:0x%X(%d) of %d bits",
+				    globalval[TAG_GLOB_REPORT_ID],inputnum,
+				    globalval[TAG_GLOB_LOG_MAX],globalval[TAG_GLOB_LOG_MAX],
+				    globalval[TAG_GLOB_LOG_MIN],globalval[TAG_GLOB_LOG_MIN],
+				    (globalval[TAG_GLOB_REPORT_SZ] * globalval[TAG_GLOB_REPORT_CNT]));
+
+
+				/*
+				  We can assume that the first two input items
+				  are always the X and Y coordinates.  After
+				  that, we look for everything else by
+				  local usage value
+				 */
+				switch (inputnum){
+				case 0:  /* X coord */
+					dbg("GER: X Usage: 0x%x",usage);
+					if (device->max_X == 0){
+						device->max_X = globalval[TAG_GLOB_LOG_MAX];
+						device->min_X = globalval[TAG_GLOB_LOG_MIN];
+					}
+
+					break;
+				case 1:  /* Y coord */
+					dbg("GER: Y Usage: 0x%x",usage);
+					if (device->max_Y == 0){
+						device->max_Y = globalval[TAG_GLOB_LOG_MAX];
+						device->min_Y = globalval[TAG_GLOB_LOG_MIN];
+					}
+					break;
+				default:
+					/* Tilt X */
+					if (usage == DIGITIZER_USAGE_TILT_X){
+						if (device->maxtilt_X == 0){
+							device->maxtilt_X = globalval[TAG_GLOB_LOG_MAX];
+							device->mintilt_X = globalval[TAG_GLOB_LOG_MIN];
+						}
+					}
+
+					/* Tilt Y */
+					if (usage == DIGITIZER_USAGE_TILT_Y){
+						if (device->maxtilt_Y == 0){
+							device->maxtilt_Y = globalval[TAG_GLOB_LOG_MAX];
+							device->mintilt_Y = globalval[TAG_GLOB_LOG_MIN];
+						}
+					}
+
+
+					/* Pressure */
+					if (usage == DIGITIZER_USAGE_TIP_PRESSURE){
+						if (device->maxpressure == 0){
+							device->maxpressure = globalval[TAG_GLOB_LOG_MAX];
+							device->minpressure = globalval[TAG_GLOB_LOG_MIN];
+						}
+					}
+
+					break;
+				}
+
+				inputnum++;
+
+
+				break;
+			case TAG_MAIN_OUTPUT:
+				maintype='O';
+				break;
+			case TAG_MAIN_FEATURE:
+				maintype='F';
+				break;
+			case TAG_MAIN_COL_START:
+				maintype='S';
+
+				if (data==0){
+					dbg("======>>>>>> Physical");
+					strcpy(globtype,"Physical");
+				}else{
+					dbg("======>>>>>>");
+				}
+
+				/* Indent the debug output */
+				indent++;
+				for (x=0;x<indent;x++){
+					indentstr[x]='-';
+				}
+				indentstr[x]=0;
+
+				/* Save global tags */
+				for (x=0;x<TAG_GLOB_MAX;x++){
+					oldval[x] = globalval[x];
+				}
+
+				break;
+			case TAG_MAIN_COL_END:
+				dbg("<<<<<<======");
+				maintype='E';
+				indent--;
+				for (x=0;x<indent;x++){
+					indentstr[x]='-';
+				}
+				indentstr[x]=0;
+
+				/* Copy global tags back */
+				for (x=0;x<TAG_GLOB_MAX;x++){
+					globalval[x] = oldval[x];
+				}
+
+				break;
+			}
+
+			switch (size){
+			case 1:
+				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+				    indentstr,tag,maintype,size,globtype,data);
+				break;
+			case 2:
+				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+				    indentstr,tag,maintype,size,globtype, data16);
+				break;
+			case 4:
+				dbg("%sMAINTAG:(%d) %c SIZE: %d Data: %s 0x%x",
+				    indentstr,tag,maintype,size,globtype,data32);
+				break;
+			}
+			break;
+		case TYPE_GLOBAL:
+			switch(tag){
+			case TAG_GLOB_USAGE:
+				/*
+				 * First time we hit the global usage tag,
+				 * it should tell us the type of device
+				 */
+				if (device->usage == 0){
+					device->usage = data;
+				}
+				strcpy(globtype,"USAGE");
+				break;
+			case TAG_GLOB_LOG_MIN   :
+				strcpy(globtype,"LOG_MIN");
+				break;
+			case TAG_GLOB_LOG_MAX   :
+				strcpy(globtype,"LOG_MAX");
+				break;
+			case TAG_GLOB_PHYS_MIN  :
+				strcpy(globtype,"PHYS_MIN");
+				break;
+			case TAG_GLOB_PHYS_MAX  :
+				strcpy(globtype,"PHYS_MAX");
+				break;
+			case TAG_GLOB_UNIT_EXP  :
+				strcpy(globtype,"EXP");
+				break;
+			case TAG_GLOB_UNIT      :
+				strcpy(globtype,"UNIT");
+				break;
+			case TAG_GLOB_REPORT_SZ :
+				strcpy(globtype,"REPORT_SZ");
+				break;
+			case TAG_GLOB_REPORT_ID :
+				strcpy(globtype,"REPORT_ID");
+				/* New report, restart numbering */
+				inputnum=0;
+				break;
+			case TAG_GLOB_REPORT_CNT:
+				strcpy(globtype,"REPORT_CNT");
+				break;
+			case TAG_GLOB_PUSH :
+				strcpy(globtype,"PUSH");
+				break;
+			case TAG_GLOB_POP:
+				strcpy(globtype,"POP");
+				break;
+			}
+
+
+			/* Check to make sure we have a good tag number
+			   so we don't overflow array */
+			if (tag < TAG_GLOB_MAX){
+				switch (size){
+				case 1:
+					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data);
+					globalval[tag]=data;
+					break;
+				case 2:
+					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data16);
+					globalval[tag]=data16;
+					break;
+				case 4:
+					dbg("%sGLOBALTAG:%s(%d) SIZE: %d Data: 0x%x",indentstr,globtype,tag,size,data32);
+					globalval[tag]=data32;
+					break;
+				}
+			}else{
+				dbg("%sGLOBALTAG: ILLEGAL TAG:%d SIZE: %d ",
+				    indentstr,tag,size);
+			}
+
+
+			break;
+
+		case TYPE_LOCAL:
+			switch(tag){
+			case TAG_GLOB_USAGE:
+				strcpy(globtype,"USAGE");
+				/* Always 1 byte */
+				usage = data;
+				break;
+			case TAG_GLOB_LOG_MIN   :
+				strcpy(globtype,"MIN");
+				break;
+			case TAG_GLOB_LOG_MAX   :
+				strcpy(globtype,"MAX");
+				break;
+			default:
+				strcpy(globtype,"UNKNOWN");
+			}
+
+			switch (size){
+			case 1:
+				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+				    indentstr,tag,globtype,size,data);
+				break;
+			case 2:
+				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+				    indentstr,tag,globtype,size,data16);
+				break;
+			case 4:
+				dbg("%sLOCALTAG:(%d) %s SIZE: %d Data: 0x%x",
+				    indentstr,tag,globtype,size,data32);
+				break;
+			}
+
+			break;
+		}
+
+	}
+
+}
+
+
+
+/*   INPUT DRIVER Routines                               */
+
+
+/*
+ *    Called when opening the input device.  This will submit the URB to
+ *    the usb system so we start getting reports
+ */
+static int gtco_input_open(struct input_dev *inputdev)
+{
+	struct gtco *device;
+	device = inputdev->private;
+
+	device->urbinfo->dev = device->usbdev;
+	if (usb_submit_urb(device->urbinfo, GFP_KERNEL)) {
+		return -EIO;
+	}
+	return 0;
+}
+
+/**
+    Called when closing the input device.  This will unlink the URB
+*/
+static void gtco_input_close(struct input_dev *inputdev)
+{
+	struct gtco *device = inputdev->private;
+
+	usb_kill_urb(device->urbinfo);
+
+}
+
+
+/*
+ *  Setup input device capabilities.  Tell the input system what this
+ *  device is capable of generating.
+ *
+ *  This information is based on what is read from the HID report and
+ *  placed in the struct gtco structure
+ *
+ */
+static void  gtco_setup_caps(struct input_dev  *inputdev)
+{
+	struct gtco *device = inputdev->private;
+
+
+	/* Which events */
+	inputdev->evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_MSC);
+
+
+	/* Misc event menu block */
+	inputdev->mscbit[0] = BIT(MSC_SCAN)|BIT(MSC_SERIAL)|BIT(MSC_RAW) ;
+
+
+	/* Absolute values based on HID report info */
+	input_set_abs_params(inputdev, ABS_X, device->min_X, device->max_X,
+			     0, 0);
+	input_set_abs_params(inputdev, ABS_Y, device->min_Y, device->max_Y,
+			     0, 0);
+
+	/* Proximity */
+	input_set_abs_params(inputdev, ABS_DISTANCE, 0, 1, 0, 0);
+
+	/* Tilt & pressure */
+	input_set_abs_params(inputdev, ABS_TILT_X, device->mintilt_X,
+			     device->maxtilt_X, 0, 0);
+	input_set_abs_params(inputdev, ABS_TILT_Y, device->mintilt_Y,
+			     device->maxtilt_Y, 0, 0);
+	input_set_abs_params(inputdev, ABS_PRESSURE, device->minpressure,
+			     device->maxpressure, 0, 0);
+
+
+	/* Transducer */
+	input_set_abs_params(inputdev, ABS_MISC, 0,0xFF, 0, 0);
+
+}
+
+
+
+/*   USB Routines  */
+
+
+/*
+ * URB callback routine.  Called when we get IRQ reports from the
+ *  digitizer.
+ *
+ *  This bridges the USB and input device worlds.  It generates events
+ *  on the input device based on the USB reports.
+ */
+static void gtco_urb_callback(struct urb *urbinfo)
+{
+
+
+	struct gtco     *device = urbinfo->context;
+	struct input_dev  *inputdev;
+	int               rc;
+	u32               val = 0;
+	s8                valsigned = 0;
+	char              le_buffer[2];
+
+	inputdev = device->inputdevice;
+
+
+	/* Was callback OK? */
+	if ((urbinfo->status == -ECONNRESET ) ||
+	    (urbinfo->status == -ENOENT ) ||
+	    (urbinfo->status == -ESHUTDOWN )){
+
+		/* Shutdown is occurring. Return and don't queue up any more */
+		return;
+	}
+
+	if (urbinfo->status != 0 ) {
+		/* Some unknown error.  Hopefully temporary.  Just go and */
+		/* requeue an URB */
+		goto resubmit;
+	}
+
+	/*
+	 * Good URB, now process
+	 */
+
+	/* PID dependent when we interpret the report */
+	if ((inputdev->id.product == PID_1000 )||
+	    (inputdev->id.product == PID_1001 )||
+	    (inputdev->id.product == PID_1002 ))
+	{
+
+		/*
+		 * Switch on the report ID
+		 * Conveniently, the reports have more information, the higher
+		 * the report number.  We can just fall through the case
+		 * statements if we start with the highest number report
+		 */
+		switch(device->buffer[0]){
+		case 5:
+			/* Pressure is 9 bits */
+			val =  ((u16)(device->buffer[8]) << 1);
+			val |= (u16)(device->buffer[7] >> 7);
+			input_report_abs(inputdev, ABS_PRESSURE,
+					 device->buffer[8]);
+
+			/* Mask out the Y tilt value used for pressure */
+			device->buffer[7] = (u8)((device->buffer[7]) & 0x7F);
+
+
+			/* Fall thru */
+		case 4:
+			/* Tilt */
+
+			/* Sign extend these 7 bit numbers.  */
+			if (device->buffer[6] & 0x40)
+				device->buffer[6] |= 0x80;
+
+			if (device->buffer[7] & 0x40)
+				device->buffer[7] |= 0x80;
+
+
+			valsigned = (device->buffer[6]);
+			input_report_abs(inputdev, ABS_TILT_X, (s32)valsigned);
+
+			valsigned = (device->buffer[7]);
+			input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned);
+
+			/* Fall thru */
+
+		case 2:
+		case 3:
+			/* Convert buttons, only 5 bits possible */
+			val = (device->buffer[5])&MASK_BUTTON;
+
+			/* We don't apply any meaning to the bitmask,
+			   just report */
+			input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+
+			/*  Fall thru */
+		case 1:
+
+			/* All reports have X and Y coords in the same place */
+			val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[1])));
+			input_report_abs(inputdev, ABS_X, val);
+
+			val = le16_to_cpu(get_unaligned((__le16 *) &(device->buffer[3])));
+			input_report_abs(inputdev, ABS_Y, val);
+
+
+			/* Ditto for proximity bit */
+			if (device->buffer[5]& MASK_INRANGE){
+				val = 1;
+			}else{
+				val=0;
+			}
+			input_report_abs(inputdev, ABS_DISTANCE, val);
+
+
+			/* Report 1 is an exception to how we handle buttons */
+			/* Buttons are an index, not a bitmask */
+			if (device->buffer[0] == 1){
+
+				/* Convert buttons, 5 bit index */
+				/* Report value of index set as one,
+				   the rest as 0 */
+				val = device->buffer[5]& MASK_BUTTON;
+				dbg("======>>>>>>REPORT 1: val 0x%X(%d)",
+				    val,val);
+
+				/*
+				 * We don't apply any meaning to the button
+				 * index, just report it
+				 */
+				input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+
+
+			}
+
+			break;
+		case 7:
+			/* Menu blocks */
+			input_event(inputdev, EV_MSC, MSC_SCAN,
+				    device->buffer[1]);
+
+
+			break;
+
+		}
+
+
+	}
+	/* Other pid class */
+	if ((inputdev->id.product == PID_400 )||
+	    (inputdev->id.product == PID_401 ))
+	{
+
+		/* Report 2 */
+		if (device->buffer[0] == 2){
+			/* Menu blocks */
+			input_event(inputdev, EV_MSC, MSC_SCAN,
+				    device->buffer[1]);
+		}
+
+		/*  Report 1 */
+		if (device->buffer[0] == 1){
+			char buttonbyte;
+
+
+			/*  IF X max > 64K, we still a bit from the y report */
+			if (device->max_X > 0x10000){
+
+				val = (u16)(((u16)(device->buffer[2]<<8))|((u8)(device->buffer[1])));
+				val |= (u32)(((u8)device->buffer[3]&0x1)<< 16);
+
+				input_report_abs(inputdev, ABS_X, val);
+
+				le_buffer[0]  = (u8)((u8)(device->buffer[3])>>1);
+				le_buffer[0] |= (u8)((device->buffer[3]&0x1)<<7);
+
+				le_buffer[1]  = (u8)(device->buffer[4]>>1);
+				le_buffer[1] |= (u8)((device->buffer[5]&0x1)<<7);
+
+				val = le16_to_cpu(get_unaligned((__le16 *)(le_buffer)));
+
+				input_report_abs(inputdev, ABS_Y, val);
+
+
+				/*
+				 * Shift the button byte right by one to
+				 * make it look like the standard report
+				 */
+				buttonbyte = (device->buffer[5])>>1;
+			}else{
+
+				val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[1]))));
+				input_report_abs(inputdev, ABS_X, val);
+
+				val = le16_to_cpu(get_unaligned((__le16 *) (&(device->buffer[3]))));
+				input_report_abs(inputdev, ABS_Y, val);
+
+				buttonbyte = device->buffer[5];
+
+			}
+
+
+			/* BUTTONS and PROXIMITY */
+			if (buttonbyte& MASK_INRANGE){
+				val = 1;
+			}else{
+				val=0;
+			}
+			input_report_abs(inputdev, ABS_DISTANCE, val);
+
+			/* Convert buttons, only 4 bits possible */
+			val = buttonbyte&0x0F;
+#ifdef USE_BUTTONS
+			for ( i=0;i<5;i++){
+				input_report_key(inputdev, BTN_DIGI+i,val&(1<<i));
+			}
+#else
+			/* We don't apply any meaning to the bitmask, just report */
+			input_event(inputdev, EV_MSC, MSC_SERIAL, val);
+#endif
+			/* TRANSDUCER */
+			input_report_abs(inputdev, ABS_MISC, device->buffer[6]);
+
+		}
+	}
+
+	/* Everybody gets report ID's */
+	input_event(inputdev, EV_MSC, MSC_RAW,  device->buffer[0]);
+
+	/* Sync it up */
+	input_sync(inputdev);
+
+ resubmit:
+	rc = usb_submit_urb(urbinfo, GFP_ATOMIC);
+	if (rc != 0) {
+		err("usb_submit_urb failed rc=0x%x",rc);
+	}
+
+}
+
+/*
+ *  The probe routine.  This is called when the kernel find the matching USB
+ *   vendor/product.  We do the following:
+ *
+ *    - Allocate mem for a local structure to manage the device
+ *    - Request a HID Report Descriptor from the device and parse it to
+ *      find out the device parameters
+ *    - Create an input device and assign it attributes
+ *   - Allocate an URB so the device can talk to us when the input
+ *      queue is open
+ */
+static int gtco_probe(struct usb_interface *usbinterface,
+		      const struct usb_device_id *id)
+{
+
+	struct gtco             *device = NULL;
+	char                    path[PATHLENGTH];
+	struct input_dev        *inputdev;
+	struct hid_descriptor   *hid_desc;
+	char                    *report;
+	int                     result=0, retry;
+	struct usb_endpoint_descriptor *endpoint;
+
+	/* Allocate memory for device structure */
+	device = kzalloc(sizeof(struct gtco), GFP_KERNEL);
+	if (device == NULL) {
+		err("No more memory");
+		return -ENOMEM;
+	}
+
+
+	device->inputdevice = input_allocate_device();
+	if (!device->inputdevice){
+		kfree(device);
+		err("No more memory");
+		return -ENOMEM;
+	}
+
+	/* Get pointer to the input device */
+	inputdev = device->inputdevice;
+
+	/* Save interface information */
+	device->usbdev     = usb_get_dev(interface_to_usbdev(usbinterface));
+
+
+	/* Allocate some data for incoming reports */
+	device->buffer = usb_buffer_alloc(device->usbdev, REPORT_MAX_SIZE,
+					   GFP_KERNEL, &(device->buf_dma));
+	if (!device->buffer){
+		input_free_device(device->inputdevice);
+		kfree(device);
+		err("No more memory");
+		return -ENOMEM;
+	}
+
+	/* Allocate URB for reports */
+	device->urbinfo = usb_alloc_urb(0, GFP_KERNEL);
+	if (!device->urbinfo) {
+		usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+				device->buffer, device->buf_dma);
+		input_free_device(device->inputdevice);
+		kfree(device);
+		err("No more memory");
+		return -ENOMEM;
+	}
+
+
+	/*
+	 * The endpoint is always altsetting 0, we know this since we know
+	 * this device only has one interrupt endpoint
+	 */
+	endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+
+	/* Some debug */
+	dbg("gtco # interfaces: %d",usbinterface->num_altsetting);
+	dbg("num endpoints:     %d",usbinterface->cur_altsetting->desc.bNumEndpoints);
+	dbg("interface class:   %d",usbinterface->cur_altsetting->desc.bInterfaceClass);
+	dbg("endpoint: attribute:0x%x type:0x%x",endpoint->bmAttributes,endpoint->bDescriptorType);
+	if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
+		dbg("endpoint: we have interrupt endpoint\n");
+
+	dbg("endpoint extra len:%d ",usbinterface->altsetting[0].extralen);
+
+
+
+	/*
+	 * Find the HID descriptor so we can find out the size of the
+	 * HID report descriptor
+	 */
+	if (usb_get_extra_descriptor(usbinterface->cur_altsetting,
+				     HID_DEVICE_TYPE,&hid_desc) != 0){
+		err("Can't retrieve exta USB descriptor to get hid report descriptor length");
+		usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+				device->buffer, device->buf_dma);
+		input_free_device(device->inputdevice);
+		kfree(device);
+		return -EIO;
+	}
+
+	dbg("Extra descriptor success: type:%d  len:%d",
+	    hid_desc->bDescriptorType,  hid_desc->wDescriptorLength);
+
+	if (!(report = kzalloc(hid_desc->wDescriptorLength, GFP_KERNEL))) {
+		usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+				device->buffer, device->buf_dma);
+
+		input_free_device(device->inputdevice);
+		kfree(device);
+		err("No more memory");
+		return -ENOMEM;
+	}
+
+	/* Couple of tries to get reply */
+	for (retry=0;retry<3;retry++) {
+		result = usb_control_msg(device->usbdev,
+					 usb_rcvctrlpipe(device->usbdev, 0),
+					 USB_REQ_GET_DESCRIPTOR,
+					 USB_RECIP_INTERFACE | USB_DIR_IN,
+					 (REPORT_DEVICE_TYPE << 8),
+					 0, /* interface */
+					 report,
+					 hid_desc->wDescriptorLength,
+					 5000); /* 5 secs */
+
+		if (result == hid_desc->wDescriptorLength)
+			break;
+	}
+
+	/* If we didn't get the report, fail */
+	dbg("usb_control_msg result: :%d", result);
+	if (result != hid_desc->wDescriptorLength){
+		kfree(report);
+		usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+				device->buffer, device->buf_dma);
+		input_free_device(device->inputdevice);
+		kfree(device);
+		err("Failed to get HID Report Descriptor of size: %d",
+		    hid_desc->wDescriptorLength);
+		return -EIO;
+	}
+
+
+	/* Now we parse the report */
+	parse_hid_report_descriptor(device,report,result);
+
+	/* Now we delete it */
+	kfree(report);
+
+	/* Create a device file node */
+	usb_make_path(device->usbdev, path, PATHLENGTH);
+	sprintf(device->usbpath, "%s/input0", path);
+
+
+	/* Set Input device functions */
+	inputdev->open     = gtco_input_open;
+	inputdev->close    = gtco_input_close;
+
+	/* Set input device information */
+	inputdev->name     = "GTCO_CalComp";
+	inputdev->phys     = device->usbpath;
+	inputdev->private  = device;
+
+
+	/* Now set up all the input device capabilities */
+	gtco_setup_caps(inputdev);
+
+	/* Set input device required ID information */
+	usb_to_input_id(device->usbdev, &device->inputdevice->id);
+	inputdev->cdev.dev = &usbinterface->dev;
+
+	/* Setup the URB, it will be posted later on open of input device */
+	endpoint = &usbinterface->altsetting[0].endpoint[0].desc;
+
+	usb_fill_int_urb(device->urbinfo,
+			 device->usbdev,
+			 usb_rcvintpipe(device->usbdev,
+					endpoint->bEndpointAddress),
+			 device->buffer,
+			 REPORT_MAX_SIZE,
+			 gtco_urb_callback,
+			 device,
+			 endpoint->bInterval);
+
+	device->urbinfo->transfer_dma = device->buf_dma;
+	device->urbinfo->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+
+	/* Save device pointer in USB interface device */
+	usb_set_intfdata(usbinterface, device);
+
+	/* All done, now register the input device */
+	input_register_device(inputdev);
+
+	info( "gtco driver created usb:  %s\n",  path);
+	return 0;
+
+}
+
+/*
+ *  This function is a standard USB function called when the USB device
+ *  is disconnected.  We will get rid of the URV, de-register the input
+ *  device, and free up allocated memory
+ */
+static void gtco_disconnect(struct usb_interface *interface)
+{
+
+	/* Grab private device ptr */
+	struct gtco    *device = usb_get_intfdata (interface);
+	struct input_dev *inputdev;
+
+	inputdev = device->inputdevice;
+
+	/* Now reverse all the registration stuff */
+	if (device) {
+		input_unregister_device(inputdev);
+		usb_kill_urb(device->urbinfo);
+		usb_free_urb(device->urbinfo);
+		usb_buffer_free(device->usbdev, REPORT_MAX_SIZE,
+				device->buffer, device->buf_dma);
+		kfree(device);
+	}
+
+	info("gtco driver disconnected");
+}
+
+
+/*   STANDARD MODULE LOAD ROUTINES  */
+
+static struct usb_driver gtco_driverinfo_table = {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,16))
+	.owner      = THIS_MODULE,
+#endif
+	.name       = "gtco",
+	.id_table   = gtco_usbid_table,
+	.probe      = gtco_probe,
+	.disconnect = gtco_disconnect,
+};
+/*
+ *  Register this module with the USB subsystem
+ */
+static int __init gtco_init(void)
+{
+	int rc;
+	rc = usb_register(&gtco_driverinfo_table);
+	if (rc) {
+		err("usb_register() failed rc=0x%x", rc);
+	}
+	printk("GTCO usb driver version: %s",GTCO_VERSION);
+	return rc;
+}
+
+/*
+ *   Deregister this module with the USB subsystem
+ */
+static void __exit gtco_exit(void)
+{
+	usb_deregister(&gtco_driverinfo_table);
+}
+
+module_init (gtco_init);
+module_exit (gtco_exit);
+
+MODULE_LICENSE("GPL");

+ 35 - 0
drivers/usb/input/hid-core.c

@@ -768,6 +768,9 @@ void usbhid_init_reports(struct hid_device *hid)
 #define USB_VENDOR_ID_PANTHERLORD	0x0810
 #define USB_VENDOR_ID_PANTHERLORD	0x0810
 #define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK	0x0001
 #define USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK	0x0001
 
 
+#define USB_VENDOR_ID_SONY			0x054c
+#define USB_DEVICE_ID_SONY_PS3_CONTROLLER	0x0268
+
 /*
 /*
  * Alphabetically sorted blacklist by quirk type.
  * Alphabetically sorted blacklist by quirk type.
  */
  */
@@ -949,6 +952,8 @@ static const struct hid_blacklist {
 
 
 	{ USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
 	{ USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
 
 
+	{ USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER, HID_QUIRK_SONY_PS3_CONTROLLER },
+
 	{ 0, 0 }
 	{ 0, 0 }
 };
 };
 
 
@@ -1013,6 +1018,32 @@ static void hid_fixup_cymotion_descriptor(char *rdesc, int rsize)
 	}
 	}
 }
 }
 
 
+/*
+ * Sending HID_REQ_GET_REPORT changes the operation mode of the ps3 controller
+ * to "operational".  Without this, the ps3 controller will not report any
+ * events.
+ */
+static void hid_fixup_sony_ps3_controller(struct usb_device *dev, int ifnum)
+{
+	int result;
+	char *buf = kmalloc(18, GFP_KERNEL);
+
+	if (!buf)
+		return;
+
+	result = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+				 HID_REQ_GET_REPORT,
+				 USB_DIR_IN | USB_TYPE_CLASS |
+				 USB_RECIP_INTERFACE,
+				 (3 << 8) | 0xf2, ifnum, buf, 17,
+				 USB_CTRL_GET_TIMEOUT);
+
+	if (result < 0)
+		err("%s failed: %d\n", __func__, result);
+
+	kfree(buf);
+}
+
 static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 static struct hid_device *usb_hid_configure(struct usb_interface *intf)
 {
 {
 	struct usb_host_interface *interface = intf->cur_altsetting;
 	struct usb_host_interface *interface = intf->cur_altsetting;
@@ -1303,6 +1334,10 @@ static int hid_probe(struct usb_interface *intf, const struct usb_device_id *id)
 	if ((hid->claimed & HID_CLAIMED_INPUT))
 	if ((hid->claimed & HID_CLAIMED_INPUT))
 		hid_ff_init(hid);
 		hid_ff_init(hid);
 
 
+	if (hid->quirks & HID_QUIRK_SONY_PS3_CONTROLLER)
+		hid_fixup_sony_ps3_controller(interface_to_usbdev(intf),
+			intf->cur_altsetting->desc.bInterfaceNumber);
+
 	printk(KERN_INFO);
 	printk(KERN_INFO);
 
 
 	if (hid->claimed & HID_CLAIMED_INPUT)
 	if (hid->claimed & HID_CLAIMED_INPUT)

+ 4 - 6
drivers/usb/misc/idmouse.c

@@ -269,7 +269,7 @@ static int idmouse_release(struct inode *inode, struct file *file)
 	/* prevent a race condition with open() */
 	/* prevent a race condition with open() */
 	mutex_lock(&disconnect_mutex);
 	mutex_lock(&disconnect_mutex);
 
 
-	dev = (struct usb_idmouse *) file->private_data;
+	dev = file->private_data;
 
 
 	if (dev == NULL) {
 	if (dev == NULL) {
 		mutex_unlock(&disconnect_mutex);
 		mutex_unlock(&disconnect_mutex);
@@ -304,17 +304,15 @@ static int idmouse_release(struct inode *inode, struct file *file)
 static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count,
 static ssize_t idmouse_read(struct file *file, char __user *buffer, size_t count,
 				loff_t * ppos)
 				loff_t * ppos)
 {
 {
-	struct usb_idmouse *dev;
+	struct usb_idmouse *dev = file->private_data;
 	int result;
 	int result;
 
 
-	dev = (struct usb_idmouse *) file->private_data;
-
 	/* lock this object */
 	/* lock this object */
-	down (&dev->sem);
+	down(&dev->sem);
 
 
 	/* verify that the device wasn't unplugged */
 	/* verify that the device wasn't unplugged */
 	if (!dev->present) {
 	if (!dev->present) {
-		up (&dev->sem);
+		up(&dev->sem);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 

+ 30 - 24
drivers/usb/misc/rio500.c

@@ -69,7 +69,7 @@ struct rio_usb_data {
         char *obuf, *ibuf;              /* transfer buffers */
         char *obuf, *ibuf;              /* transfer buffers */
         char bulk_in_ep, bulk_out_ep;   /* Endpoint assignments */
         char bulk_in_ep, bulk_out_ep;   /* Endpoint assignments */
         wait_queue_head_t wait_q;       /* for timeouts */
         wait_queue_head_t wait_q;       /* for timeouts */
-	struct semaphore lock;          /* general race avoidance */
+	struct mutex lock;          /* general race avoidance */
 };
 };
 
 
 static struct rio_usb_data rio_instance;
 static struct rio_usb_data rio_instance;
@@ -78,17 +78,17 @@ static int open_rio(struct inode *inode, struct file *file)
 {
 {
 	struct rio_usb_data *rio = &rio_instance;
 	struct rio_usb_data *rio = &rio_instance;
 
 
-	down(&(rio->lock));
+	mutex_lock(&(rio->lock));
 
 
 	if (rio->isopen || !rio->present) {
 	if (rio->isopen || !rio->present) {
-		up(&(rio->lock));
+		mutex_unlock(&(rio->lock));
 		return -EBUSY;
 		return -EBUSY;
 	}
 	}
 	rio->isopen = 1;
 	rio->isopen = 1;
 
 
 	init_waitqueue_head(&rio->wait_q);
 	init_waitqueue_head(&rio->wait_q);
 
 
-	up(&(rio->lock));
+	mutex_unlock(&(rio->lock));
 
 
 	info("Rio opened.");
 	info("Rio opened.");
 
 
@@ -117,7 +117,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
 	int retries;
 	int retries;
 	int retval=0;
 	int retval=0;
 
 
-	down(&(rio->lock));
+	mutex_lock(&(rio->lock));
         /* Sanity check to make sure rio is connected, powered, etc */
         /* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
         if ( rio == NULL ||
              rio->present == 0 ||
              rio->present == 0 ||
@@ -257,7 +257,7 @@ ioctl_rio(struct inode *inode, struct file *file, unsigned int cmd,
 
 
 
 
 err_out:
 err_out:
-	up(&(rio->lock));
+	mutex_unlock(&(rio->lock));
 	return retval;
 	return retval;
 }
 }
 
 
@@ -275,14 +275,17 @@ write_rio(struct file *file, const char __user *buffer,
 	int result = 0;
 	int result = 0;
 	int maxretry;
 	int maxretry;
 	int errn = 0;
 	int errn = 0;
+	int intr;
 
 
-	down(&(rio->lock));
+	intr = mutex_lock_interruptible(&(rio->lock));
+	if (intr)
+		return -EINTR;
         /* Sanity check to make sure rio is connected, powered, etc */
         /* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
         if ( rio == NULL ||
              rio->present == 0 ||
              rio->present == 0 ||
              rio->rio_dev == NULL )
              rio->rio_dev == NULL )
 	{
 	{
-		up(&(rio->lock));
+		mutex_unlock(&(rio->lock));
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
@@ -305,7 +308,7 @@ write_rio(struct file *file, const char __user *buffer,
 				goto error;
 				goto error;
 			}
 			}
 			if (signal_pending(current)) {
 			if (signal_pending(current)) {
-				up(&(rio->lock));
+				mutex_unlock(&(rio->lock));
 				return bytes_written ? bytes_written : -EINTR;
 				return bytes_written ? bytes_written : -EINTR;
 			}
 			}
 
 
@@ -341,12 +344,12 @@ write_rio(struct file *file, const char __user *buffer,
 		buffer += copy_size;
 		buffer += copy_size;
 	} while (count > 0);
 	} while (count > 0);
 
 
-	up(&(rio->lock));
+	mutex_unlock(&(rio->lock));
 
 
 	return bytes_written ? bytes_written : -EIO;
 	return bytes_written ? bytes_written : -EIO;
 
 
 error:
 error:
-	up(&(rio->lock));
+	mutex_unlock(&(rio->lock));
 	return errn;
 	return errn;
 }
 }
 
 
@@ -361,14 +364,17 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
 	int result;
 	int result;
 	int maxretry = 10;
 	int maxretry = 10;
 	char *ibuf;
 	char *ibuf;
+	int intr;
 
 
-	down(&(rio->lock));
+	intr = mutex_lock_interruptible(&(rio->lock));
+	if (intr)
+		return -EINTR;
 	/* Sanity check to make sure rio is connected, powered, etc */
 	/* Sanity check to make sure rio is connected, powered, etc */
         if ( rio == NULL ||
         if ( rio == NULL ||
              rio->present == 0 ||
              rio->present == 0 ||
              rio->rio_dev == NULL )
              rio->rio_dev == NULL )
 	{
 	{
-		up(&(rio->lock));
+		mutex_unlock(&(rio->lock));
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
@@ -379,11 +385,11 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
 
 
 	while (count > 0) {
 	while (count > 0) {
 		if (signal_pending(current)) {
 		if (signal_pending(current)) {
-			up(&(rio->lock));
+			mutex_unlock(&(rio->lock));
 			return read_count ? read_count : -EINTR;
 			return read_count ? read_count : -EINTR;
 		}
 		}
 		if (!rio->rio_dev) {
 		if (!rio->rio_dev) {
-			up(&(rio->lock));
+			mutex_unlock(&(rio->lock));
 			return -ENODEV;
 			return -ENODEV;
 		}
 		}
 		this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
 		this_read = (count >= IBUF_SIZE) ? IBUF_SIZE : count;
@@ -400,7 +406,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
 			count = this_read = partial;
 			count = this_read = partial;
 		} else if (result == -ETIMEDOUT || result == 15) {	/* FIXME: 15 ??? */
 		} else if (result == -ETIMEDOUT || result == 15) {	/* FIXME: 15 ??? */
 			if (!maxretry--) {
 			if (!maxretry--) {
-				up(&(rio->lock));
+				mutex_unlock(&(rio->lock));
 				err("read_rio: maxretry timeout");
 				err("read_rio: maxretry timeout");
 				return -ETIME;
 				return -ETIME;
 			}
 			}
@@ -409,18 +415,18 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
 			finish_wait(&rio->wait_q, &wait);
 			finish_wait(&rio->wait_q, &wait);
 			continue;
 			continue;
 		} else if (result != -EREMOTEIO) {
 		} else if (result != -EREMOTEIO) {
-			up(&(rio->lock));
+			mutex_unlock(&(rio->lock));
 			err("Read Whoops - result:%u partial:%u this_read:%u",
 			err("Read Whoops - result:%u partial:%u this_read:%u",
 			     result, partial, this_read);
 			     result, partial, this_read);
 			return -EIO;
 			return -EIO;
 		} else {
 		} else {
-			up(&(rio->lock));
+			mutex_unlock(&(rio->lock));
 			return (0);
 			return (0);
 		}
 		}
 
 
 		if (this_read) {
 		if (this_read) {
 			if (copy_to_user(buffer, ibuf, this_read)) {
 			if (copy_to_user(buffer, ibuf, this_read)) {
-				up(&(rio->lock));
+				mutex_unlock(&(rio->lock));
 				return -EFAULT;
 				return -EFAULT;
 			}
 			}
 			count -= this_read;
 			count -= this_read;
@@ -428,7 +434,7 @@ read_rio(struct file *file, char __user *buffer, size_t count, loff_t * ppos)
 			buffer += this_read;
 			buffer += this_read;
 		}
 		}
 	}
 	}
-	up(&(rio->lock));
+	mutex_unlock(&(rio->lock));
 	return read_count;
 	return read_count;
 }
 }
 
 
@@ -480,7 +486,7 @@ static int probe_rio(struct usb_interface *intf,
 	}
 	}
 	dbg("probe_rio: ibuf address:%p", rio->ibuf);
 	dbg("probe_rio: ibuf address:%p", rio->ibuf);
 
 
-	init_MUTEX(&(rio->lock));
+	mutex_init(&(rio->lock));
 
 
 	usb_set_intfdata (intf, rio);
 	usb_set_intfdata (intf, rio);
 	rio->present = 1;
 	rio->present = 1;
@@ -496,12 +502,12 @@ static void disconnect_rio(struct usb_interface *intf)
 	if (rio) {
 	if (rio) {
 		usb_deregister_dev(intf, &usb_rio_class);
 		usb_deregister_dev(intf, &usb_rio_class);
 
 
-		down(&(rio->lock));
+		mutex_lock(&(rio->lock));
 		if (rio->isopen) {
 		if (rio->isopen) {
 			rio->isopen = 0;
 			rio->isopen = 0;
 			/* better let it finish - the release will do whats needed */
 			/* better let it finish - the release will do whats needed */
 			rio->rio_dev = NULL;
 			rio->rio_dev = NULL;
-			up(&(rio->lock));
+			mutex_unlock(&(rio->lock));
 			return;
 			return;
 		}
 		}
 		kfree(rio->ibuf);
 		kfree(rio->ibuf);
@@ -510,7 +516,7 @@ static void disconnect_rio(struct usb_interface *intf)
 		info("USB Rio disconnected.");
 		info("USB Rio disconnected.");
 
 
 		rio->present = 0;
 		rio->present = 0;
-		up(&(rio->lock));
+		mutex_unlock(&(rio->lock));
 	}
 	}
 }
 }
 
 

+ 1 - 1
drivers/usb/mon/Makefile

@@ -2,7 +2,7 @@
 # Makefile for USB Core files and filesystem
 # Makefile for USB Core files and filesystem
 #
 #
 
 
-usbmon-objs	:= mon_main.o mon_stat.o mon_text.o mon_dma.o
+usbmon-objs	:= mon_main.o mon_stat.o mon_text.o mon_bin.o mon_dma.o
 
 
 # This does not use CONFIG_USB_MON because we want this to use a tristate.
 # This does not use CONFIG_USB_MON because we want this to use a tristate.
 obj-$(CONFIG_USB)	+= usbmon.o
 obj-$(CONFIG_USB)	+= usbmon.o

+ 1172 - 0
drivers/usb/mon/mon_bin.c

@@ -0,0 +1,1172 @@
+/*
+ * The USB Monitor, inspired by Dave Harding's USBMon.
+ *
+ * This is a binary format reader.
+ *
+ * Copyright (C) 2006 Paolo Abeni (paolo.abeni@email.it)
+ * Copyright (C) 2006 Pete Zaitcev (zaitcev@redhat.com)
+ */
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/usb.h>
+#include <linux/poll.h>
+#include <linux/compat.h>
+#include <linux/mm.h>
+
+#include <asm/uaccess.h>
+
+#include "usb_mon.h"
+
+/*
+ * Defined by USB 2.0 clause 9.3, table 9.2.
+ */
+#define SETUP_LEN  8
+
+/* ioctl macros */
+#define MON_IOC_MAGIC 0x92
+
+#define MON_IOCQ_URB_LEN _IO(MON_IOC_MAGIC, 1)
+/* #2 used to be MON_IOCX_URB, removed before it got into Linus tree */
+#define MON_IOCG_STATS _IOR(MON_IOC_MAGIC, 3, struct mon_bin_stats)
+#define MON_IOCT_RING_SIZE _IO(MON_IOC_MAGIC, 4)
+#define MON_IOCQ_RING_SIZE _IO(MON_IOC_MAGIC, 5)
+#define MON_IOCX_GET   _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get)
+#define MON_IOCX_MFETCH _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch)
+#define MON_IOCH_MFLUSH _IO(MON_IOC_MAGIC, 8)
+#ifdef CONFIG_COMPAT
+#define MON_IOCX_GET32 _IOW(MON_IOC_MAGIC, 6, struct mon_bin_get32)
+#define MON_IOCX_MFETCH32 _IOWR(MON_IOC_MAGIC, 7, struct mon_bin_mfetch32)
+#endif
+
+/*
+ * Some architectures have enormous basic pages (16KB for ia64, 64KB for ppc).
+ * But it's all right. Just use a simple way to make sure the chunk is never
+ * smaller than a page.
+ *
+ * N.B. An application does not know our chunk size.
+ *
+ * Woops, get_zeroed_page() returns a single page. I guess we're stuck with
+ * page-sized chunks for the time being.
+ */
+#define CHUNK_SIZE   PAGE_SIZE
+#define CHUNK_ALIGN(x)   (((x)+CHUNK_SIZE-1) & ~(CHUNK_SIZE-1))
+
+/*
+ * The magic limit was calculated so that it allows the monitoring
+ * application to pick data once in two ticks. This way, another application,
+ * which presumably drives the bus, gets to hog CPU, yet we collect our data.
+ * If HZ is 100, a 480 mbit/s bus drives 614 KB every jiffy. USB has an
+ * enormous overhead built into the bus protocol, so we need about 1000 KB.
+ *
+ * This is still too much for most cases, where we just snoop a few
+ * descriptor fetches for enumeration. So, the default is a "reasonable"
+ * amount for systems with HZ=250 and incomplete bus saturation.
+ *
+ * XXX What about multi-megabyte URBs which take minutes to transfer?
+ */
+#define BUFF_MAX  CHUNK_ALIGN(1200*1024)
+#define BUFF_DFL   CHUNK_ALIGN(300*1024)
+#define BUFF_MIN     CHUNK_ALIGN(8*1024)
+
+/*
+ * The per-event API header (2 per URB).
+ *
+ * This structure is seen in userland as defined by the documentation.
+ */
+struct mon_bin_hdr {
+	u64 id;			/* URB ID - from submission to callback */
+	unsigned char type;	/* Same as in text API; extensible. */
+	unsigned char xfer_type;	/* ISO, Intr, Control, Bulk */
+	unsigned char epnum;	/* Endpoint number and transfer direction */
+	unsigned char devnum;	/* Device address */
+	unsigned short busnum;	/* Bus number */
+	char flag_setup;
+	char flag_data;
+	s64 ts_sec;		/* gettimeofday */
+	s32 ts_usec;		/* gettimeofday */
+	int status;
+	unsigned int len_urb;	/* Length of data (submitted or actual) */
+	unsigned int len_cap;	/* Delivered length */
+	unsigned char setup[SETUP_LEN];	/* Only for Control S-type */
+};
+
+/* per file statistic */
+struct mon_bin_stats {
+	u32 queued;
+	u32 dropped;
+};
+
+struct mon_bin_get {
+	struct mon_bin_hdr __user *hdr;	/* Only 48 bytes, not 64. */
+	void __user *data;
+	size_t alloc;		/* Length of data (can be zero) */
+};
+
+struct mon_bin_mfetch {
+	u32 __user *offvec;	/* Vector of events fetched */
+	u32 nfetch;		/* Number of events to fetch (out: fetched) */
+	u32 nflush;		/* Number of events to flush */
+};
+
+#ifdef CONFIG_COMPAT
+struct mon_bin_get32 {
+	u32 hdr32;
+	u32 data32;
+	u32 alloc32;
+};
+
+struct mon_bin_mfetch32 {
+        u32 offvec32;
+        u32 nfetch32;
+        u32 nflush32;
+};
+#endif
+
+/* Having these two values same prevents wrapping of the mon_bin_hdr */
+#define PKT_ALIGN   64
+#define PKT_SIZE    64
+
+/* max number of USB bus supported */
+#define MON_BIN_MAX_MINOR 128
+
+/*
+ * The buffer: map of used pages.
+ */
+struct mon_pgmap {
+	struct page *pg;
+	unsigned char *ptr;	/* XXX just use page_to_virt everywhere? */
+};
+
+/*
+ * This gets associated with an open file struct.
+ */
+struct mon_reader_bin {
+	/* The buffer: one per open. */
+	spinlock_t b_lock;		/* Protect b_cnt, b_in */
+	unsigned int b_size;		/* Current size of the buffer - bytes */
+	unsigned int b_cnt;		/* Bytes used */
+	unsigned int b_in, b_out;	/* Offsets into buffer - bytes */
+	unsigned int b_read;		/* Amount of read data in curr. pkt. */
+	struct mon_pgmap *b_vec;	/* The map array */
+	wait_queue_head_t b_wait;	/* Wait for data here */
+
+	struct mutex fetch_lock;	/* Protect b_read, b_out */
+	int mmap_active;
+
+	/* A list of these is needed for "bus 0". Some time later. */
+	struct mon_reader r;
+
+	/* Stats */
+	unsigned int cnt_lost;
+};
+
+static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp,
+    unsigned int offset)
+{
+	return (struct mon_bin_hdr *)
+	    (rp->b_vec[offset / CHUNK_SIZE].ptr + offset % CHUNK_SIZE);
+}
+
+#define MON_RING_EMPTY(rp)	((rp)->b_cnt == 0)
+
+static dev_t mon_bin_dev0;
+static struct cdev mon_bin_cdev;
+
+static void mon_buff_area_fill(const struct mon_reader_bin *rp,
+    unsigned int offset, unsigned int size);
+static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp);
+static int mon_alloc_buff(struct mon_pgmap *map, int npages);
+static void mon_free_buff(struct mon_pgmap *map, int npages);
+
+/*
+ * This is a "chunked memcpy". It does not manipulate any counters.
+ * But it returns the new offset for repeated application.
+ */
+unsigned int mon_copy_to_buff(const struct mon_reader_bin *this,
+    unsigned int off, const unsigned char *from, unsigned int length)
+{
+	unsigned int step_len;
+	unsigned char *buf;
+	unsigned int in_page;
+
+	while (length) {
+		/*
+		 * Determine step_len.
+		 */
+		step_len = length;
+		in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1));
+		if (in_page < step_len)
+			step_len = in_page;
+
+		/*
+		 * Copy data and advance pointers.
+		 */
+		buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE;
+		memcpy(buf, from, step_len);
+		if ((off += step_len) >= this->b_size) off = 0;
+		from += step_len;
+		length -= step_len;
+	}
+	return off;
+}
+
+/*
+ * This is a little worse than the above because it's "chunked copy_to_user".
+ * The return value is an error code, not an offset.
+ */
+static int copy_from_buf(const struct mon_reader_bin *this, unsigned int off,
+    char __user *to, int length)
+{
+	unsigned int step_len;
+	unsigned char *buf;
+	unsigned int in_page;
+
+	while (length) {
+		/*
+		 * Determine step_len.
+		 */
+		step_len = length;
+		in_page = CHUNK_SIZE - (off & (CHUNK_SIZE-1));
+		if (in_page < step_len)
+			step_len = in_page;
+
+		/*
+		 * Copy data and advance pointers.
+		 */
+		buf = this->b_vec[off / CHUNK_SIZE].ptr + off % CHUNK_SIZE;
+		if (copy_to_user(to, buf, step_len))
+			return -EINVAL;
+		if ((off += step_len) >= this->b_size) off = 0;
+		to += step_len;
+		length -= step_len;
+	}
+	return 0;
+}
+
+/*
+ * Allocate an (aligned) area in the buffer.
+ * This is called under b_lock.
+ * Returns ~0 on failure.
+ */
+static unsigned int mon_buff_area_alloc(struct mon_reader_bin *rp,
+    unsigned int size)
+{
+	unsigned int offset;
+
+	size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+	if (rp->b_cnt + size > rp->b_size)
+		return ~0;
+	offset = rp->b_in;
+	rp->b_cnt += size;
+	if ((rp->b_in += size) >= rp->b_size)
+		rp->b_in -= rp->b_size;
+	return offset;
+}
+
+/*
+ * This is the same thing as mon_buff_area_alloc, only it does not allow
+ * buffers to wrap. This is needed by applications which pass references
+ * into mmap-ed buffers up their stacks (libpcap can do that).
+ *
+ * Currently, we always have the header stuck with the data, although
+ * it is not strictly speaking necessary.
+ *
+ * When a buffer would wrap, we place a filler packet to mark the space.
+ */
+static unsigned int mon_buff_area_alloc_contiguous(struct mon_reader_bin *rp,
+    unsigned int size)
+{
+	unsigned int offset;
+	unsigned int fill_size;
+
+	size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+	if (rp->b_cnt + size > rp->b_size)
+		return ~0;
+	if (rp->b_in + size > rp->b_size) {
+		/*
+		 * This would wrap. Find if we still have space after
+		 * skipping to the end of the buffer. If we do, place
+		 * a filler packet and allocate a new packet.
+		 */
+		fill_size = rp->b_size - rp->b_in;
+		if (rp->b_cnt + size + fill_size > rp->b_size)
+			return ~0;
+		mon_buff_area_fill(rp, rp->b_in, fill_size);
+
+		offset = 0;
+		rp->b_in = size;
+		rp->b_cnt += size + fill_size;
+	} else if (rp->b_in + size == rp->b_size) {
+		offset = rp->b_in;
+		rp->b_in = 0;
+		rp->b_cnt += size;
+	} else {
+		offset = rp->b_in;
+		rp->b_in += size;
+		rp->b_cnt += size;
+	}
+	return offset;
+}
+
+/*
+ * Return a few (kilo-)bytes to the head of the buffer.
+ * This is used if a DMA fetch fails.
+ */
+static void mon_buff_area_shrink(struct mon_reader_bin *rp, unsigned int size)
+{
+
+	size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+	rp->b_cnt -= size;
+	if (rp->b_in < size)
+		rp->b_in += rp->b_size;
+	rp->b_in -= size;
+}
+
+/*
+ * This has to be called under both b_lock and fetch_lock, because
+ * it accesses both b_cnt and b_out.
+ */
+static void mon_buff_area_free(struct mon_reader_bin *rp, unsigned int size)
+{
+
+	size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+	rp->b_cnt -= size;
+	if ((rp->b_out += size) >= rp->b_size)
+		rp->b_out -= rp->b_size;
+}
+
+static void mon_buff_area_fill(const struct mon_reader_bin *rp,
+    unsigned int offset, unsigned int size)
+{
+	struct mon_bin_hdr *ep;
+
+	ep = MON_OFF2HDR(rp, offset);
+	memset(ep, 0, PKT_SIZE);
+	ep->type = '@';
+	ep->len_cap = size - PKT_SIZE;
+}
+
+static inline char mon_bin_get_setup(unsigned char *setupb,
+    const struct urb *urb, char ev_type)
+{
+
+	if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+		return '-';
+
+	if (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)
+		return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN);
+	if (urb->setup_packet == NULL)
+		return 'Z';
+
+	memcpy(setupb, urb->setup_packet, SETUP_LEN);
+	return 0;
+}
+
+static char mon_bin_get_data(const struct mon_reader_bin *rp,
+    unsigned int offset, struct urb *urb, unsigned int length)
+{
+
+	if (urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP) {
+		mon_dmapeek_vec(rp, offset, urb->transfer_dma, length);
+		return 0;
+	}
+
+	if (urb->transfer_buffer == NULL)
+		return 'Z';
+
+	mon_copy_to_buff(rp, offset, urb->transfer_buffer, length);
+	return 0;
+}
+
+static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
+    char ev_type)
+{
+	unsigned long flags;
+	struct timeval ts;
+	unsigned int urb_length;
+	unsigned int offset;
+	unsigned int length;
+	struct mon_bin_hdr *ep;
+	char data_tag = 0;
+
+	do_gettimeofday(&ts);
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+
+	/*
+	 * Find the maximum allowable length, then allocate space.
+	 */
+	urb_length = (ev_type == 'S') ?
+	    urb->transfer_buffer_length : urb->actual_length;
+	length = urb_length;
+
+	if (length >= rp->b_size/5)
+		length = rp->b_size/5;
+
+	if (usb_pipein(urb->pipe)) {
+		if (ev_type == 'S') {
+			length = 0;
+			data_tag = '<';
+		}
+	} else {
+		if (ev_type == 'C') {
+			length = 0;
+			data_tag = '>';
+		}
+	}
+
+	if (rp->mmap_active)
+		offset = mon_buff_area_alloc_contiguous(rp, length + PKT_SIZE);
+	else
+		offset = mon_buff_area_alloc(rp, length + PKT_SIZE);
+	if (offset == ~0) {
+		rp->cnt_lost++;
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+		return;
+	}
+
+	ep = MON_OFF2HDR(rp, offset);
+	if ((offset += PKT_SIZE) >= rp->b_size) offset = 0;
+
+	/*
+	 * Fill the allocated area.
+	 */
+	memset(ep, 0, PKT_SIZE);
+	ep->type = ev_type;
+	ep->xfer_type = usb_pipetype(urb->pipe);
+	/* We use the fact that usb_pipein() returns 0x80 */
+	ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
+	ep->devnum = usb_pipedevice(urb->pipe);
+	ep->busnum = rp->r.m_bus->u_bus->busnum;
+	ep->id = (unsigned long) urb;
+	ep->ts_sec = ts.tv_sec;
+	ep->ts_usec = ts.tv_usec;
+	ep->status = urb->status;
+	ep->len_urb = urb_length;
+	ep->len_cap = length;
+
+	ep->flag_setup = mon_bin_get_setup(ep->setup, urb, ev_type);
+	if (length != 0) {
+		ep->flag_data = mon_bin_get_data(rp, offset, urb, length);
+		if (ep->flag_data != 0) {	/* Yes, it's 0x00, not '0' */
+			ep->len_cap = 0;
+			mon_buff_area_shrink(rp, length);
+		}
+	} else {
+		ep->flag_data = data_tag;
+	}
+
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+
+	wake_up(&rp->b_wait);
+}
+
+static void mon_bin_submit(void *data, struct urb *urb)
+{
+	struct mon_reader_bin *rp = data;
+	mon_bin_event(rp, urb, 'S');
+}
+
+static void mon_bin_complete(void *data, struct urb *urb)
+{
+	struct mon_reader_bin *rp = data;
+	mon_bin_event(rp, urb, 'C');
+}
+
+static void mon_bin_error(void *data, struct urb *urb, int error)
+{
+	struct mon_reader_bin *rp = data;
+	unsigned long flags;
+	unsigned int offset;
+	struct mon_bin_hdr *ep;
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+
+	offset = mon_buff_area_alloc(rp, PKT_SIZE);
+	if (offset == ~0) {
+		/* Not incrementing cnt_lost. Just because. */
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+		return;
+	}
+
+	ep = MON_OFF2HDR(rp, offset);
+
+	memset(ep, 0, PKT_SIZE);
+	ep->type = 'E';
+	ep->xfer_type = usb_pipetype(urb->pipe);
+	/* We use the fact that usb_pipein() returns 0x80 */
+	ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
+	ep->devnum = usb_pipedevice(urb->pipe);
+	ep->busnum = rp->r.m_bus->u_bus->busnum;
+	ep->id = (unsigned long) urb;
+	ep->status = error;
+
+	ep->flag_setup = '-';
+	ep->flag_data = 'E';
+
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+
+	wake_up(&rp->b_wait);
+}
+
+static int mon_bin_open(struct inode *inode, struct file *file)
+{
+	struct mon_bus *mbus;
+	struct usb_bus *ubus;
+	struct mon_reader_bin *rp;
+	size_t size;
+	int rc;
+
+	mutex_lock(&mon_lock);
+	if ((mbus = mon_bus_lookup(iminor(inode))) == NULL) {
+		mutex_unlock(&mon_lock);
+		return -ENODEV;
+	}
+	if ((ubus = mbus->u_bus) == NULL) {
+		printk(KERN_ERR TAG ": consistency error on open\n");
+		mutex_unlock(&mon_lock);
+		return -ENODEV;
+	}
+
+	rp = kzalloc(sizeof(struct mon_reader_bin), GFP_KERNEL);
+	if (rp == NULL) {
+		rc = -ENOMEM;
+		goto err_alloc;
+	}
+	spin_lock_init(&rp->b_lock);
+	init_waitqueue_head(&rp->b_wait);
+	mutex_init(&rp->fetch_lock);
+
+	rp->b_size = BUFF_DFL;
+
+	size = sizeof(struct mon_pgmap) * (rp->b_size/CHUNK_SIZE);
+	if ((rp->b_vec = kzalloc(size, GFP_KERNEL)) == NULL) {
+		rc = -ENOMEM;
+		goto err_allocvec;
+	}
+
+	if ((rc = mon_alloc_buff(rp->b_vec, rp->b_size/CHUNK_SIZE)) < 0)
+		goto err_allocbuff;
+
+	rp->r.m_bus = mbus;
+	rp->r.r_data = rp;
+	rp->r.rnf_submit = mon_bin_submit;
+	rp->r.rnf_error = mon_bin_error;
+	rp->r.rnf_complete = mon_bin_complete;
+
+	mon_reader_add(mbus, &rp->r);
+
+	file->private_data = rp;
+	mutex_unlock(&mon_lock);
+	return 0;
+
+err_allocbuff:
+	kfree(rp->b_vec);
+err_allocvec:
+	kfree(rp);
+err_alloc:
+	mutex_unlock(&mon_lock);
+	return rc;
+}
+
+/*
+ * Extract an event from buffer and copy it to user space.
+ * Wait if there is no event ready.
+ * Returns zero or error.
+ */
+static int mon_bin_get_event(struct file *file, struct mon_reader_bin *rp,
+    struct mon_bin_hdr __user *hdr, void __user *data, unsigned int nbytes)
+{
+	unsigned long flags;
+	struct mon_bin_hdr *ep;
+	size_t step_len;
+	unsigned int offset;
+	int rc;
+
+	mutex_lock(&rp->fetch_lock);
+
+	if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+		mutex_unlock(&rp->fetch_lock);
+		return rc;
+	}
+
+	ep = MON_OFF2HDR(rp, rp->b_out);
+
+	if (copy_to_user(hdr, ep, sizeof(struct mon_bin_hdr))) {
+		mutex_unlock(&rp->fetch_lock);
+		return -EFAULT;
+	}
+
+	step_len = min(ep->len_cap, nbytes);
+	if ((offset = rp->b_out + PKT_SIZE) >= rp->b_size) offset = 0;
+
+	if (copy_from_buf(rp, offset, data, step_len)) {
+		mutex_unlock(&rp->fetch_lock);
+		return -EFAULT;
+	}
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+	mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+	rp->b_read = 0;
+
+	mutex_unlock(&rp->fetch_lock);
+	return 0;
+}
+
+static int mon_bin_release(struct inode *inode, struct file *file)
+{
+	struct mon_reader_bin *rp = file->private_data;
+	struct mon_bus* mbus = rp->r.m_bus;
+
+	mutex_lock(&mon_lock);
+
+	if (mbus->nreaders <= 0) {
+		printk(KERN_ERR TAG ": consistency error on close\n");
+		mutex_unlock(&mon_lock);
+		return 0;
+	}
+	mon_reader_del(mbus, &rp->r);
+
+	mon_free_buff(rp->b_vec, rp->b_size/CHUNK_SIZE);
+	kfree(rp->b_vec);
+	kfree(rp);
+
+	mutex_unlock(&mon_lock);
+	return 0;
+}
+
+static ssize_t mon_bin_read(struct file *file, char __user *buf,
+    size_t nbytes, loff_t *ppos)
+{
+	struct mon_reader_bin *rp = file->private_data;
+	unsigned long flags;
+	struct mon_bin_hdr *ep;
+	unsigned int offset;
+	size_t step_len;
+	char *ptr;
+	ssize_t done = 0;
+	int rc;
+
+	mutex_lock(&rp->fetch_lock);
+
+	if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+		mutex_unlock(&rp->fetch_lock);
+		return rc;
+	}
+
+	ep = MON_OFF2HDR(rp, rp->b_out);
+
+	if (rp->b_read < sizeof(struct mon_bin_hdr)) {
+		step_len = min(nbytes, sizeof(struct mon_bin_hdr) - rp->b_read);
+		ptr = ((char *)ep) + rp->b_read;
+		if (step_len && copy_to_user(buf, ptr, step_len)) {
+			mutex_unlock(&rp->fetch_lock);
+			return -EFAULT;
+		}
+		nbytes -= step_len;
+		buf += step_len;
+		rp->b_read += step_len;
+		done += step_len;
+	}
+
+	if (rp->b_read >= sizeof(struct mon_bin_hdr)) {
+		step_len = min(nbytes, (size_t)ep->len_cap);
+		offset = rp->b_out + PKT_SIZE;
+		offset += rp->b_read - sizeof(struct mon_bin_hdr);
+		if (offset >= rp->b_size)
+			offset -= rp->b_size;
+		if (copy_from_buf(rp, offset, buf, step_len)) {
+			mutex_unlock(&rp->fetch_lock);
+			return -EFAULT;
+		}
+		nbytes -= step_len;
+		buf += step_len;
+		rp->b_read += step_len;
+		done += step_len;
+	}
+
+	/*
+	 * Check if whole packet was read, and if so, jump to the next one.
+	 */
+	if (rp->b_read >= sizeof(struct mon_bin_hdr) + ep->len_cap) {
+		spin_lock_irqsave(&rp->b_lock, flags);
+		mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+		rp->b_read = 0;
+	}
+
+	mutex_unlock(&rp->fetch_lock);
+	return done;
+}
+
+/*
+ * Remove at most nevents from chunked buffer.
+ * Returns the number of removed events.
+ */
+static int mon_bin_flush(struct mon_reader_bin *rp, unsigned nevents)
+{
+	unsigned long flags;
+	struct mon_bin_hdr *ep;
+	int i;
+
+	mutex_lock(&rp->fetch_lock);
+	spin_lock_irqsave(&rp->b_lock, flags);
+	for (i = 0; i < nevents; ++i) {
+		if (MON_RING_EMPTY(rp))
+			break;
+
+		ep = MON_OFF2HDR(rp, rp->b_out);
+		mon_buff_area_free(rp, PKT_SIZE + ep->len_cap);
+	}
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+	rp->b_read = 0;
+	mutex_unlock(&rp->fetch_lock);
+	return i;
+}
+
+/*
+ * Fetch at most max event offsets into the buffer and put them into vec.
+ * The events are usually freed later with mon_bin_flush.
+ * Return the effective number of events fetched.
+ */
+static int mon_bin_fetch(struct file *file, struct mon_reader_bin *rp,
+    u32 __user *vec, unsigned int max)
+{
+	unsigned int cur_out;
+	unsigned int bytes, avail;
+	unsigned int size;
+	unsigned int nevents;
+	struct mon_bin_hdr *ep;
+	unsigned long flags;
+	int rc;
+
+	mutex_lock(&rp->fetch_lock);
+
+	if ((rc = mon_bin_wait_event(file, rp)) < 0) {
+		mutex_unlock(&rp->fetch_lock);
+		return rc;
+	}
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+	avail = rp->b_cnt;
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+
+	cur_out = rp->b_out;
+	nevents = 0;
+	bytes = 0;
+	while (bytes < avail) {
+		if (nevents >= max)
+			break;
+
+		ep = MON_OFF2HDR(rp, cur_out);
+		if (put_user(cur_out, &vec[nevents])) {
+			mutex_unlock(&rp->fetch_lock);
+			return -EFAULT;
+		}
+
+		nevents++;
+		size = ep->len_cap + PKT_SIZE;
+		size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+		if ((cur_out += size) >= rp->b_size)
+			cur_out -= rp->b_size;
+		bytes += size;
+	}
+
+	mutex_unlock(&rp->fetch_lock);
+	return nevents;
+}
+
+/*
+ * Count events. This is almost the same as the above mon_bin_fetch,
+ * only we do not store offsets into user vector, and we have no limit.
+ */
+static int mon_bin_queued(struct mon_reader_bin *rp)
+{
+	unsigned int cur_out;
+	unsigned int bytes, avail;
+	unsigned int size;
+	unsigned int nevents;
+	struct mon_bin_hdr *ep;
+	unsigned long flags;
+
+	mutex_lock(&rp->fetch_lock);
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+	avail = rp->b_cnt;
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+
+	cur_out = rp->b_out;
+	nevents = 0;
+	bytes = 0;
+	while (bytes < avail) {
+		ep = MON_OFF2HDR(rp, cur_out);
+
+		nevents++;
+		size = ep->len_cap + PKT_SIZE;
+		size = (size + PKT_ALIGN-1) & ~(PKT_ALIGN-1);
+		if ((cur_out += size) >= rp->b_size)
+			cur_out -= rp->b_size;
+		bytes += size;
+	}
+
+	mutex_unlock(&rp->fetch_lock);
+	return nevents;
+}
+
+/*
+ */
+static int mon_bin_ioctl(struct inode *inode, struct file *file,
+    unsigned int cmd, unsigned long arg)
+{
+	struct mon_reader_bin *rp = file->private_data;
+	// struct mon_bus* mbus = rp->r.m_bus;
+	int ret = 0;
+	struct mon_bin_hdr *ep;
+	unsigned long flags;
+
+	switch (cmd) {
+
+	case MON_IOCQ_URB_LEN:
+		/*
+		 * N.B. This only returns the size of data, without the header.
+		 */
+		spin_lock_irqsave(&rp->b_lock, flags);
+		if (!MON_RING_EMPTY(rp)) {
+			ep = MON_OFF2HDR(rp, rp->b_out);
+			ret = ep->len_cap;
+		}
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+		break;
+
+	case MON_IOCQ_RING_SIZE:
+		ret = rp->b_size;
+		break;
+
+	case MON_IOCT_RING_SIZE:
+		/*
+		 * Changing the buffer size will flush it's contents; the new
+		 * buffer is allocated before releasing the old one to be sure
+		 * the device will stay functional also in case of memory
+		 * pressure.
+		 */
+		{
+		int size;
+		struct mon_pgmap *vec;
+
+		if (arg < BUFF_MIN || arg > BUFF_MAX)
+			return -EINVAL;
+
+		size = CHUNK_ALIGN(arg);
+		if ((vec = kzalloc(sizeof(struct mon_pgmap) * (size/CHUNK_SIZE),
+		    GFP_KERNEL)) == NULL) {
+			ret = -ENOMEM;
+			break;
+		}
+
+		ret = mon_alloc_buff(vec, size/CHUNK_SIZE);
+		if (ret < 0) {
+			kfree(vec);
+			break;
+		}
+
+		mutex_lock(&rp->fetch_lock);
+		spin_lock_irqsave(&rp->b_lock, flags);
+		mon_free_buff(rp->b_vec, size/CHUNK_SIZE);
+		kfree(rp->b_vec);
+		rp->b_vec  = vec;
+		rp->b_size = size;
+		rp->b_read = rp->b_in = rp->b_out = rp->b_cnt = 0;
+		rp->cnt_lost = 0;
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+		mutex_unlock(&rp->fetch_lock);
+		}
+		break;
+
+	case MON_IOCH_MFLUSH:
+		ret = mon_bin_flush(rp, arg);
+		break;
+
+	case MON_IOCX_GET:
+		{
+		struct mon_bin_get getb;
+
+		if (copy_from_user(&getb, (void __user *)arg,
+					    sizeof(struct mon_bin_get)))
+			return -EFAULT;
+
+		if (getb.alloc > 0x10000000)	/* Want to cast to u32 */
+			return -EINVAL;
+		ret = mon_bin_get_event(file, rp,
+			  getb.hdr, getb.data, (unsigned int)getb.alloc);
+		}
+		break;
+
+#ifdef CONFIG_COMPAT
+	case MON_IOCX_GET32: {
+		struct mon_bin_get32 getb;
+
+		if (copy_from_user(&getb, (void __user *)arg,
+					    sizeof(struct mon_bin_get32)))
+			return -EFAULT;
+
+		ret = mon_bin_get_event(file, rp,
+		    compat_ptr(getb.hdr32), compat_ptr(getb.data32),
+		    getb.alloc32);
+		}
+		break;
+#endif
+
+	case MON_IOCX_MFETCH:
+		{
+		struct mon_bin_mfetch mfetch;
+		struct mon_bin_mfetch __user *uptr;
+
+		uptr = (struct mon_bin_mfetch __user *)arg;
+
+		if (copy_from_user(&mfetch, uptr, sizeof(mfetch)))
+			return -EFAULT;
+
+		if (mfetch.nflush) {
+			ret = mon_bin_flush(rp, mfetch.nflush);
+			if (ret < 0)
+				return ret;
+			if (put_user(ret, &uptr->nflush))
+				return -EFAULT;
+		}
+		ret = mon_bin_fetch(file, rp, mfetch.offvec, mfetch.nfetch);
+		if (ret < 0)
+			return ret;
+		if (put_user(ret, &uptr->nfetch))
+			return -EFAULT;
+		ret = 0;
+		}
+		break;
+
+#ifdef CONFIG_COMPAT
+	case MON_IOCX_MFETCH32:
+		{
+		struct mon_bin_mfetch32 mfetch;
+		struct mon_bin_mfetch32 __user *uptr;
+
+		uptr = (struct mon_bin_mfetch32 __user *) compat_ptr(arg);
+
+		if (copy_from_user(&mfetch, uptr, sizeof(mfetch)))
+			return -EFAULT;
+
+		if (mfetch.nflush32) {
+			ret = mon_bin_flush(rp, mfetch.nflush32);
+			if (ret < 0)
+				return ret;
+			if (put_user(ret, &uptr->nflush32))
+				return -EFAULT;
+		}
+		ret = mon_bin_fetch(file, rp, compat_ptr(mfetch.offvec32),
+		    mfetch.nfetch32);
+		if (ret < 0)
+			return ret;
+		if (put_user(ret, &uptr->nfetch32))
+			return -EFAULT;
+		ret = 0;
+		}
+		break;
+#endif
+
+	case MON_IOCG_STATS: {
+		struct mon_bin_stats __user *sp;
+		unsigned int nevents;
+		unsigned int ndropped;
+
+		spin_lock_irqsave(&rp->b_lock, flags);
+		ndropped = rp->cnt_lost;
+		rp->cnt_lost = 0;
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+		nevents = mon_bin_queued(rp);
+
+		sp = (struct mon_bin_stats __user *)arg;
+		if (put_user(rp->cnt_lost, &sp->dropped))
+			return -EFAULT;
+		if (put_user(nevents, &sp->queued))
+			return -EFAULT;
+
+		}
+		break;
+
+	default:
+		return -ENOTTY;
+	}
+
+	return ret;
+}
+
+static unsigned int
+mon_bin_poll(struct file *file, struct poll_table_struct *wait)
+{
+	struct mon_reader_bin *rp = file->private_data;
+	unsigned int mask = 0;
+	unsigned long flags;
+
+	if (file->f_mode & FMODE_READ)
+		poll_wait(file, &rp->b_wait, wait);
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+	if (!MON_RING_EMPTY(rp))
+		mask |= POLLIN | POLLRDNORM;    /* readable */
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+	return mask;
+}
+
+/*
+ * open and close: just keep track of how many times the device is
+ * mapped, to use the proper memory allocation function.
+ */
+static void mon_bin_vma_open(struct vm_area_struct *vma)
+{
+	struct mon_reader_bin *rp = vma->vm_private_data;
+	rp->mmap_active++;
+}
+
+static void mon_bin_vma_close(struct vm_area_struct *vma)
+{
+	struct mon_reader_bin *rp = vma->vm_private_data;
+	rp->mmap_active--;
+}
+
+/*
+ * Map ring pages to user space.
+ */
+struct page *mon_bin_vma_nopage(struct vm_area_struct *vma,
+                                unsigned long address, int *type)
+{
+	struct mon_reader_bin *rp = vma->vm_private_data;
+	unsigned long offset, chunk_idx;
+	struct page *pageptr;
+
+	offset = (address - vma->vm_start) + (vma->vm_pgoff << PAGE_SHIFT);
+	if (offset >= rp->b_size)
+		return NOPAGE_SIGBUS;
+	chunk_idx = offset / CHUNK_SIZE;
+	pageptr = rp->b_vec[chunk_idx].pg;
+	get_page(pageptr);
+	if (type)
+		*type = VM_FAULT_MINOR;
+	return pageptr;
+}
+
+struct vm_operations_struct mon_bin_vm_ops = {
+	.open =     mon_bin_vma_open,
+	.close =    mon_bin_vma_close,
+	.nopage =   mon_bin_vma_nopage,
+};
+
+int mon_bin_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+	/* don't do anything here: "nopage" will set up page table entries */
+	vma->vm_ops = &mon_bin_vm_ops;
+	vma->vm_flags |= VM_RESERVED;
+	vma->vm_private_data = filp->private_data;
+	mon_bin_vma_open(vma);
+	return 0;
+}
+
+struct file_operations mon_fops_binary = {
+	.owner =	THIS_MODULE,
+	.open =		mon_bin_open,
+	.llseek =	no_llseek,
+	.read =		mon_bin_read,
+	/* .write =	mon_text_write, */
+	.poll =		mon_bin_poll,
+	.ioctl =	mon_bin_ioctl,
+	.release =	mon_bin_release,
+};
+
+static int mon_bin_wait_event(struct file *file, struct mon_reader_bin *rp)
+{
+	DECLARE_WAITQUEUE(waita, current);
+	unsigned long flags;
+
+	add_wait_queue(&rp->b_wait, &waita);
+	set_current_state(TASK_INTERRUPTIBLE);
+
+	spin_lock_irqsave(&rp->b_lock, flags);
+	while (MON_RING_EMPTY(rp)) {
+		spin_unlock_irqrestore(&rp->b_lock, flags);
+
+		if (file->f_flags & O_NONBLOCK) {
+			set_current_state(TASK_RUNNING);
+			remove_wait_queue(&rp->b_wait, &waita);
+			return -EWOULDBLOCK; /* Same as EAGAIN in Linux */
+		}
+		schedule();
+		if (signal_pending(current)) {
+			remove_wait_queue(&rp->b_wait, &waita);
+			return -EINTR;
+		}
+		set_current_state(TASK_INTERRUPTIBLE);
+
+		spin_lock_irqsave(&rp->b_lock, flags);
+	}
+	spin_unlock_irqrestore(&rp->b_lock, flags);
+
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&rp->b_wait, &waita);
+	return 0;
+}
+
+static int mon_alloc_buff(struct mon_pgmap *map, int npages)
+{
+	int n;
+	unsigned long vaddr;
+
+	for (n = 0; n < npages; n++) {
+		vaddr = get_zeroed_page(GFP_KERNEL);
+		if (vaddr == 0) {
+			while (n-- != 0)
+				free_page((unsigned long) map[n].ptr);
+			return -ENOMEM;
+		}
+		map[n].ptr = (unsigned char *) vaddr;
+		map[n].pg = virt_to_page(vaddr);
+	}
+	return 0;
+}
+
+static void mon_free_buff(struct mon_pgmap *map, int npages)
+{
+	int n;
+
+	for (n = 0; n < npages; n++)
+		free_page((unsigned long) map[n].ptr);
+}
+
+int __init mon_bin_init(void)
+{
+	int rc;
+
+	rc = alloc_chrdev_region(&mon_bin_dev0, 0, MON_BIN_MAX_MINOR, "usbmon");
+	if (rc < 0)
+		goto err_dev;
+
+	cdev_init(&mon_bin_cdev, &mon_fops_binary);
+	mon_bin_cdev.owner = THIS_MODULE;
+
+	rc = cdev_add(&mon_bin_cdev, mon_bin_dev0, MON_BIN_MAX_MINOR);
+	if (rc < 0)
+		goto err_add;
+
+	return 0;
+
+err_add:
+	unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
+err_dev:
+	return rc;
+}
+
+void __exit mon_bin_exit(void)
+{
+	cdev_del(&mon_bin_cdev);
+	unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
+}

+ 38 - 1
drivers/usb/mon/mon_dma.c

@@ -48,6 +48,36 @@ char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
 	local_irq_restore(flags);
 	local_irq_restore(flags);
 	return 0;
 	return 0;
 }
 }
+
+void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+    unsigned int offset, dma_addr_t dma_addr, unsigned int length)
+{
+	unsigned long flags;
+	unsigned int step_len;
+	struct page *pg;
+	unsigned char *map;
+	unsigned long page_off, page_len;
+
+	local_irq_save(flags);
+	while (length) {
+		/* compute number of bytes we are going to copy in this page */
+		step_len = length;
+		page_off = dma_addr & (PAGE_SIZE-1);
+		page_len = PAGE_SIZE - page_off;
+		if (page_len < step_len)
+			step_len = page_len;
+
+		/* copy data and advance pointers */
+		pg = phys_to_page(dma_addr);
+		map = kmap_atomic(pg, KM_IRQ0);
+		offset = mon_copy_to_buff(rp, offset, map + page_off, step_len);
+		kunmap_atomic(map, KM_IRQ0);
+		dma_addr += step_len;
+		length -= step_len;
+	}
+	local_irq_restore(flags);
+}
+
 #endif /* __i386__ */
 #endif /* __i386__ */
 
 
 #ifndef MON_HAS_UNMAP
 #ifndef MON_HAS_UNMAP
@@ -55,4 +85,11 @@ char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len)
 {
 {
 	return 'D';
 	return 'D';
 }
 }
-#endif
+
+void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+    unsigned int offset, dma_addr_t dma_addr, unsigned int length)
+{
+	;
+}
+
+#endif /* MON_HAS_UNMAP */

+ 48 - 49
drivers/usb/mon/mon_main.c

@@ -9,7 +9,6 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
-#include <linux/debugfs.h>
 #include <linux/smp_lock.h>
 #include <linux/smp_lock.h>
 #include <linux/notifier.h>
 #include <linux/notifier.h>
 #include <linux/mutex.h>
 #include <linux/mutex.h>
@@ -22,11 +21,10 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb);
 static void mon_stop(struct mon_bus *mbus);
 static void mon_stop(struct mon_bus *mbus);
 static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
 static void mon_dissolve(struct mon_bus *mbus, struct usb_bus *ubus);
 static void mon_bus_drop(struct kref *r);
 static void mon_bus_drop(struct kref *r);
-static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus);
+static void mon_bus_init(struct usb_bus *ubus);
 
 
 DEFINE_MUTEX(mon_lock);
 DEFINE_MUTEX(mon_lock);
 
 
-static struct dentry *mon_dir;		/* /dbg/usbmon */
 static LIST_HEAD(mon_buses);		/* All buses we know: struct mon_bus */
 static LIST_HEAD(mon_buses);		/* All buses we know: struct mon_bus */
 
 
 /*
 /*
@@ -200,7 +198,7 @@ static void mon_stop(struct mon_bus *mbus)
  */
  */
 static void mon_bus_add(struct usb_bus *ubus)
 static void mon_bus_add(struct usb_bus *ubus)
 {
 {
-	mon_bus_init(mon_dir, ubus);
+	mon_bus_init(ubus);
 }
 }
 
 
 /*
 /*
@@ -212,8 +210,8 @@ static void mon_bus_remove(struct usb_bus *ubus)
 
 
 	mutex_lock(&mon_lock);
 	mutex_lock(&mon_lock);
 	list_del(&mbus->bus_link);
 	list_del(&mbus->bus_link);
-	debugfs_remove(mbus->dent_t);
-	debugfs_remove(mbus->dent_s);
+	if (mbus->text_inited)
+		mon_text_del(mbus);
 
 
 	mon_dissolve(mbus, ubus);
 	mon_dissolve(mbus, ubus);
 	kref_put(&mbus->ref, mon_bus_drop);
 	kref_put(&mbus->ref, mon_bus_drop);
@@ -281,13 +279,9 @@ static void mon_bus_drop(struct kref *r)
  *  - refcount USB bus struct
  *  - refcount USB bus struct
  *  - link
  *  - link
  */
  */
-static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
+static void mon_bus_init(struct usb_bus *ubus)
 {
 {
-	struct dentry *d;
 	struct mon_bus *mbus;
 	struct mon_bus *mbus;
-	enum { NAMESZ = 10 };
-	char name[NAMESZ];
-	int rc;
 
 
 	if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
 	if ((mbus = kzalloc(sizeof(struct mon_bus), GFP_KERNEL)) == NULL)
 		goto err_alloc;
 		goto err_alloc;
@@ -303,57 +297,54 @@ static void mon_bus_init(struct dentry *mondir, struct usb_bus *ubus)
 	ubus->mon_bus = mbus;
 	ubus->mon_bus = mbus;
 	mbus->uses_dma = ubus->uses_dma;
 	mbus->uses_dma = ubus->uses_dma;
 
 
-	rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
-	if (rc <= 0 || rc >= NAMESZ)
-		goto err_print_t;
-	d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_text);
-	if (d == NULL)
-		goto err_create_t;
-	mbus->dent_t = d;
-
-	rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
-	if (rc <= 0 || rc >= NAMESZ)
-		goto err_print_s;
-	d = debugfs_create_file(name, 0600, mondir, mbus, &mon_fops_stat);
-	if (d == NULL)
-		goto err_create_s;
-	mbus->dent_s = d;
+	mbus->text_inited = mon_text_add(mbus, ubus);
+	// mon_bin_add(...)
 
 
 	mutex_lock(&mon_lock);
 	mutex_lock(&mon_lock);
 	list_add_tail(&mbus->bus_link, &mon_buses);
 	list_add_tail(&mbus->bus_link, &mon_buses);
 	mutex_unlock(&mon_lock);
 	mutex_unlock(&mon_lock);
 	return;
 	return;
 
 
-err_create_s:
-err_print_s:
-	debugfs_remove(mbus->dent_t);
-err_create_t:
-err_print_t:
-	kfree(mbus);
 err_alloc:
 err_alloc:
 	return;
 	return;
 }
 }
 
 
+/*
+ * Search a USB bus by number. Notice that USB bus numbers start from one,
+ * which we may later use to identify "all" with zero.
+ *
+ * This function must be called with mon_lock held.
+ *
+ * This is obviously inefficient and may be revised in the future.
+ */
+struct mon_bus *mon_bus_lookup(unsigned int num)
+{
+	struct list_head *p;
+	struct mon_bus *mbus;
+
+	list_for_each (p, &mon_buses) {
+		mbus = list_entry(p, struct mon_bus, bus_link);
+		if (mbus->u_bus->busnum == num) {
+			return mbus;
+		}
+	}
+	return NULL;
+}
+
 static int __init mon_init(void)
 static int __init mon_init(void)
 {
 {
 	struct usb_bus *ubus;
 	struct usb_bus *ubus;
-	struct dentry *mondir;
+	int rc;
 
 
-	mondir = debugfs_create_dir("usbmon", NULL);
-	if (IS_ERR(mondir)) {
-		printk(KERN_NOTICE TAG ": debugfs is not available\n");
-		return -ENODEV;
-	}
-	if (mondir == NULL) {
-		printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
-		return -ENODEV;
-	}
-	mon_dir = mondir;
+	if ((rc = mon_text_init()) != 0)
+		goto err_text;
+	if ((rc = mon_bin_init()) != 0)
+		goto err_bin;
 
 
 	if (usb_mon_register(&mon_ops_0) != 0) {
 	if (usb_mon_register(&mon_ops_0) != 0) {
 		printk(KERN_NOTICE TAG ": unable to register with the core\n");
 		printk(KERN_NOTICE TAG ": unable to register with the core\n");
-		debugfs_remove(mondir);
-		return -ENODEV;
+		rc = -ENODEV;
+		goto err_reg;
 	}
 	}
 	// MOD_INC_USE_COUNT(which_module?);
 	// MOD_INC_USE_COUNT(which_module?);
 
 
@@ -361,10 +352,17 @@ static int __init mon_init(void)
 
 
 	mutex_lock(&usb_bus_list_lock);
 	mutex_lock(&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(ubus);
 	}
 	}
 	mutex_unlock(&usb_bus_list_lock);
 	mutex_unlock(&usb_bus_list_lock);
 	return 0;
 	return 0;
+
+err_reg:
+	mon_bin_exit();
+err_bin:
+	mon_text_exit();
+err_text:
+	return rc;
 }
 }
 
 
 static void __exit mon_exit(void)
 static void __exit mon_exit(void)
@@ -381,8 +379,8 @@ static void __exit mon_exit(void)
 		mbus = list_entry(p, struct mon_bus, bus_link);
 		mbus = list_entry(p, struct mon_bus, bus_link);
 		list_del(p);
 		list_del(p);
 
 
-		debugfs_remove(mbus->dent_t);
-		debugfs_remove(mbus->dent_s);
+		if (mbus->text_inited)
+			mon_text_del(mbus);
 
 
 		/*
 		/*
 		 * This never happens, because the open/close paths in
 		 * This never happens, because the open/close paths in
@@ -401,7 +399,8 @@ static void __exit mon_exit(void)
 	}
 	}
 	mutex_unlock(&mon_lock);
 	mutex_unlock(&mon_lock);
 
 
-	debugfs_remove(mon_dir);
+	mon_text_exit();
+	mon_bin_exit();
 }
 }
 
 
 module_init(mon_init);
 module_init(mon_init);

+ 66 - 1
drivers/usb/mon/mon_text.c

@@ -9,6 +9,7 @@
 #include <linux/usb.h>
 #include <linux/usb.h>
 #include <linux/time.h>
 #include <linux/time.h>
 #include <linux/mutex.h>
 #include <linux/mutex.h>
+#include <linux/debugfs.h>
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 
 
 #include "usb_mon.h"
 #include "usb_mon.h"
@@ -63,6 +64,8 @@ struct mon_reader_text {
 	char slab_name[SLAB_NAME_SZ];
 	char slab_name[SLAB_NAME_SZ];
 };
 };
 
 
+static struct dentry *mon_dir;		/* Usually /sys/kernel/debug/usbmon */
+
 static void mon_text_ctor(void *, struct kmem_cache *, unsigned long);
 static void mon_text_ctor(void *, struct kmem_cache *, unsigned long);
 
 
 /*
 /*
@@ -436,7 +439,7 @@ static int mon_text_release(struct inode *inode, struct file *file)
 	return 0;
 	return 0;
 }
 }
 
 
-const struct file_operations mon_fops_text = {
+static const struct file_operations mon_fops_text = {
 	.owner =	THIS_MODULE,
 	.owner =	THIS_MODULE,
 	.open =		mon_text_open,
 	.open =		mon_text_open,
 	.llseek =	no_llseek,
 	.llseek =	no_llseek,
@@ -447,6 +450,47 @@ const struct file_operations mon_fops_text = {
 	.release =	mon_text_release,
 	.release =	mon_text_release,
 };
 };
 
 
+int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
+{
+	struct dentry *d;
+	enum { NAMESZ = 10 };
+	char name[NAMESZ];
+	int rc;
+
+	rc = snprintf(name, NAMESZ, "%dt", ubus->busnum);
+	if (rc <= 0 || rc >= NAMESZ)
+		goto err_print_t;
+	d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text);
+	if (d == NULL)
+		goto err_create_t;
+	mbus->dent_t = d;
+
+	/* XXX The stats do not belong to here (text API), but oh well... */
+	rc = snprintf(name, NAMESZ, "%ds", ubus->busnum);
+	if (rc <= 0 || rc >= NAMESZ)
+		goto err_print_s;
+	d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_stat);
+	if (d == NULL)
+		goto err_create_s;
+	mbus->dent_s = d;
+
+	return 1;
+
+err_create_s:
+err_print_s:
+	debugfs_remove(mbus->dent_t);
+	mbus->dent_t = NULL;
+err_create_t:
+err_print_t:
+	return 0;
+}
+
+void mon_text_del(struct mon_bus *mbus)
+{
+	debugfs_remove(mbus->dent_t);
+	debugfs_remove(mbus->dent_s);
+}
+
 /*
 /*
  * Slab interface: constructor.
  * Slab interface: constructor.
  */
  */
@@ -459,3 +503,24 @@ static void mon_text_ctor(void *mem, struct kmem_cache *slab, unsigned long sfla
 	memset(mem, 0xe5, sizeof(struct mon_event_text));
 	memset(mem, 0xe5, sizeof(struct mon_event_text));
 }
 }
 
 
+int __init mon_text_init(void)
+{
+	struct dentry *mondir;
+
+	mondir = debugfs_create_dir("usbmon", NULL);
+	if (IS_ERR(mondir)) {
+		printk(KERN_NOTICE TAG ": debugfs is not available\n");
+		return -ENODEV;
+	}
+	if (mondir == NULL) {
+		printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
+		return -ENODEV;
+	}
+	mon_dir = mondir;
+	return 0;
+}
+
+void __exit mon_text_exit(void)
+{
+	debugfs_remove(mon_dir);
+}

+ 27 - 3
drivers/usb/mon/usb_mon.h

@@ -17,9 +17,11 @@
 struct mon_bus {
 struct mon_bus {
 	struct list_head bus_link;
 	struct list_head bus_link;
 	spinlock_t lock;
 	spinlock_t lock;
+	struct usb_bus *u_bus;
+
+	int text_inited;
 	struct dentry *dent_s;		/* Debugging file */
 	struct dentry *dent_s;		/* Debugging file */
 	struct dentry *dent_t;		/* Text interface file */
 	struct dentry *dent_t;		/* Text interface file */
-	struct usb_bus *u_bus;
 	int uses_dma;
 	int uses_dma;
 
 
 	/* Ref */
 	/* Ref */
@@ -48,13 +50,35 @@ struct mon_reader {
 void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
 void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);
 void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
 void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
 
 
+struct mon_bus *mon_bus_lookup(unsigned int num);
+
+int /*bool*/ mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus);
+void mon_text_del(struct mon_bus *mbus);
+// void mon_bin_add(struct mon_bus *);
+
+int __init mon_text_init(void);
+void __exit mon_text_exit(void);
+int __init mon_bin_init(void);
+void __exit mon_bin_exit(void);
+
 /*
 /*
- */
+ * DMA interface.
+ *
+ * XXX The vectored side needs a serious re-thinking. Abstracting vectors,
+ * like in Paolo's original patch, produces a double pkmap. We need an idea.
+*/
 extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len);
 extern char mon_dmapeek(unsigned char *dst, dma_addr_t dma_addr, int len);
 
 
+struct mon_reader_bin;
+extern void mon_dmapeek_vec(const struct mon_reader_bin *rp,
+    unsigned int offset, dma_addr_t dma_addr, unsigned int len);
+extern unsigned int mon_copy_to_buff(const struct mon_reader_bin *rp,
+    unsigned int offset, const unsigned char *from, unsigned int len);
+
+/*
+ */
 extern struct mutex mon_lock;
 extern struct mutex mon_lock;
 
 
-extern const struct file_operations mon_fops_text;
 extern const struct file_operations mon_fops_stat;
 extern const struct file_operations mon_fops_stat;
 
 
 #endif /* __USB_MON_H */
 #endif /* __USB_MON_H */

+ 4 - 2
drivers/usb/net/Kconfig

@@ -222,13 +222,15 @@ config USB_NET_MCS7830
 	  adapters marketed under the DeLOCK brand.
 	  adapters marketed under the DeLOCK brand.
 
 
 config USB_NET_RNDIS_HOST
 config USB_NET_RNDIS_HOST
-	tristate "Host for RNDIS devices (EXPERIMENTAL)"
+	tristate "Host for RNDIS and ActiveSync devices (EXPERIMENTAL)"
 	depends on USB_USBNET && EXPERIMENTAL
 	depends on USB_USBNET && EXPERIMENTAL
 	select USB_NET_CDCETHER
 	select USB_NET_CDCETHER
 	help
 	help
 	  This option enables hosting "Remote NDIS" USB networking links,
 	  This option enables hosting "Remote NDIS" USB networking links,
 	  as encouraged by Microsoft (instead of CDC Ethernet!) for use in
 	  as encouraged by Microsoft (instead of CDC Ethernet!) for use in
-	  various devices that may only support this protocol.
+	  various devices that may only support this protocol.  A variant
+	  of this protocol (with even less public documentation) seems to
+	  be at the root of Microsoft's "ActiveSync" too.
 
 
 	  Avoid using this protocol unless you have no better options.
 	  Avoid using this protocol unless you have no better options.
 	  The protocol specification is incomplete, and is controlled by
 	  The protocol specification is incomplete, and is controlled by

+ 58 - 2
drivers/usb/net/cdc_ether.c

@@ -1,6 +1,7 @@
 /*
 /*
  * CDC Ethernet based networking peripherals
  * CDC Ethernet based networking peripherals
  * Copyright (C) 2003-2005 by David Brownell
  * Copyright (C) 2003-2005 by David Brownell
+ * Copyright (C) 2006 by Ole Andre Vadla Ravnas (ActiveSync)
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by
@@ -35,6 +36,29 @@
 #include "usbnet.h"
 #include "usbnet.h"
 
 
 
 
+#if defined(CONFIG_USB_NET_RNDIS_HOST) || defined(CONFIG_USB_NET_RNDIS_HOST_MODULE)
+
+static int is_rndis(struct usb_interface_descriptor *desc)
+{
+	return desc->bInterfaceClass == USB_CLASS_COMM
+		&& desc->bInterfaceSubClass == 2
+		&& desc->bInterfaceProtocol == 0xff;
+}
+
+static int is_activesync(struct usb_interface_descriptor *desc)
+{
+	return desc->bInterfaceClass == USB_CLASS_MISC
+		&& desc->bInterfaceSubClass == 1
+		&& desc->bInterfaceProtocol == 1;
+}
+
+#else
+
+#define is_rndis(desc)		0
+#define is_activesync(desc)	0
+
+#endif
+
 /*
 /*
  * probes control interface, claims data interface, collects the bulk
  * probes control interface, claims data interface, collects the bulk
  * endpoints, activates data interface (if needed), maybe sets MTU.
  * endpoints, activates data interface (if needed), maybe sets MTU.
@@ -71,7 +95,8 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
 	/* this assumes that if there's a non-RNDIS vendor variant
 	/* this assumes that if there's a non-RNDIS vendor variant
 	 * of cdc-acm, it'll fail RNDIS requests cleanly.
 	 * of cdc-acm, it'll fail RNDIS requests cleanly.
 	 */
 	 */
-	rndis = (intf->cur_altsetting->desc.bInterfaceProtocol == 0xff);
+	rndis = is_rndis(&intf->cur_altsetting->desc)
+		|| is_activesync(&intf->cur_altsetting->desc);
 
 
 	memset(info, 0, sizeof *info);
 	memset(info, 0, sizeof *info);
 	info->control = intf;
 	info->control = intf;
@@ -99,6 +124,23 @@ int usbnet_generic_cdc_bind(struct usbnet *dev, struct usb_interface *intf)
 				goto bad_desc;
 				goto bad_desc;
 			}
 			}
 			break;
 			break;
+		case USB_CDC_ACM_TYPE:
+			/* paranoia:  disambiguate a "real" vendor-specific
+			 * modem interface from an RNDIS non-modem.
+			 */
+			if (rndis) {
+				struct usb_cdc_acm_descriptor *d;
+
+				d = (void *) buf;
+				if (d->bmCapabilities) {
+					dev_dbg(&intf->dev,
+						"ACM capabilities %02x, "
+						"not really RNDIS?\n",
+						d->bmCapabilities);
+					goto bad_desc;
+				}
+			}
+			break;
 		case USB_CDC_UNION_TYPE:
 		case USB_CDC_UNION_TYPE:
 			if (info->u) {
 			if (info->u) {
 				dev_dbg(&intf->dev, "extra CDC union\n");
 				dev_dbg(&intf->dev, "extra CDC union\n");
@@ -171,7 +213,21 @@ next_desc:
 		buf += buf [0];
 		buf += buf [0];
 	}
 	}
 
 
-	if (!info->header || !info->u || (!rndis && !info->ether)) {
+	/* Microsoft ActiveSync based RNDIS devices lack the CDC descriptors,
+	 * so we'll hard-wire the interfaces and not check for descriptors.
+	 */
+	if (is_activesync(&intf->cur_altsetting->desc) && !info->u) {
+		info->control = usb_ifnum_to_if(dev->udev, 0);
+		info->data = usb_ifnum_to_if(dev->udev, 1);
+		if (!info->control || !info->data) {
+			dev_dbg(&intf->dev,
+				"activesync: master #0/%p slave #1/%p\n",
+				info->control,
+				info->data);
+			goto bad_desc;
+		}
+
+	} else if (!info->header || !info->u || (!rndis && !info->ether)) {
 		dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
 		dev_dbg(&intf->dev, "missing cdc %s%s%sdescriptor\n",
 			info->header ? "" : "header ",
 			info->header ? "" : "header ",
 			info->u ? "" : "union ",
 			info->u ? "" : "union ",

+ 32 - 5
drivers/usb/net/kaweth.c

@@ -179,6 +179,7 @@ static struct usb_driver kaweth_driver = {
 	.suspend =	kaweth_suspend,
 	.suspend =	kaweth_suspend,
 	.resume =	kaweth_resume,
 	.resume =	kaweth_resume,
 	.id_table =     usb_klsi_table,
 	.id_table =     usb_klsi_table,
+	.supports_autosuspend =	1,
 };
 };
 
 
 typedef __u8 eth_addr_t[6];
 typedef __u8 eth_addr_t[6];
@@ -225,6 +226,7 @@ struct kaweth_device
 	struct delayed_work lowmem_work;
 	struct delayed_work lowmem_work;
 
 
 	struct usb_device *dev;
 	struct usb_device *dev;
+	struct usb_interface *intf;
 	struct net_device *net;
 	struct net_device *net;
 	wait_queue_head_t term_wait;
 	wait_queue_head_t term_wait;
 
 
@@ -662,9 +664,14 @@ static int kaweth_open(struct net_device *net)
 
 
 	dbg("Opening network device.");
 	dbg("Opening network device.");
 
 
+	res = usb_autopm_get_interface(kaweth->intf);
+	if (res) {
+		err("Interface cannot be resumed.");
+		return -EIO;
+	}
 	res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
 	res = kaweth_resubmit_rx_urb(kaweth, GFP_KERNEL);
 	if (res)
 	if (res)
-		return -EIO;
+		goto err_out;
 
 
 	usb_fill_int_urb(
 	usb_fill_int_urb(
 		kaweth->irq_urb,
 		kaweth->irq_urb,
@@ -681,7 +688,7 @@ static int kaweth_open(struct net_device *net)
 	res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL);
 	res = usb_submit_urb(kaweth->irq_urb, GFP_KERNEL);
 	if (res) {
 	if (res) {
 		usb_kill_urb(kaweth->rx_urb);
 		usb_kill_urb(kaweth->rx_urb);
-		return -EIO;
+		goto err_out;
 	}
 	}
 	kaweth->opened = 1;
 	kaweth->opened = 1;
 
 
@@ -689,10 +696,14 @@ static int kaweth_open(struct net_device *net)
 
 
 	kaweth_async_set_rx_mode(kaweth);
 	kaweth_async_set_rx_mode(kaweth);
 	return 0;
 	return 0;
+
+err_out:
+	usb_autopm_enable(kaweth->intf);
+	return -EIO;
 }
 }
 
 
 /****************************************************************
 /****************************************************************
- *     kaweth_close
+ *     kaweth_kill_urbs
  ****************************************************************/
  ****************************************************************/
 static void kaweth_kill_urbs(struct kaweth_device *kaweth)
 static void kaweth_kill_urbs(struct kaweth_device *kaweth)
 {
 {
@@ -724,17 +735,29 @@ static int kaweth_close(struct net_device *net)
 
 
 	kaweth->status &= ~KAWETH_STATUS_CLOSING;
 	kaweth->status &= ~KAWETH_STATUS_CLOSING;
 
 
+	usb_autopm_enable(kaweth->intf);
+
 	return 0;
 	return 0;
 }
 }
 
 
 static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 static void kaweth_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
 {
 {
+	struct kaweth_device *kaweth = netdev_priv(dev);
 
 
 	strlcpy(info->driver, driver_name, sizeof(info->driver));
 	strlcpy(info->driver, driver_name, sizeof(info->driver));
+	usb_make_path(kaweth->dev, info->bus_info, sizeof (info->bus_info));
+}
+
+static u32 kaweth_get_link(struct net_device *dev)
+{
+	struct kaweth_device *kaweth = netdev_priv(dev);
+
+	return kaweth->linkstate;
 }
 }
 
 
 static struct ethtool_ops ops = {
 static struct ethtool_ops ops = {
-	.get_drvinfo = kaweth_get_drvinfo
+	.get_drvinfo	= kaweth_get_drvinfo,
+	.get_link	= kaweth_get_link
 };
 };
 
 
 /****************************************************************
 /****************************************************************
@@ -908,6 +931,7 @@ static int kaweth_suspend(struct usb_interface *intf, pm_message_t message)
 	struct kaweth_device *kaweth = usb_get_intfdata(intf);
 	struct kaweth_device *kaweth = usb_get_intfdata(intf);
 	unsigned long flags;
 	unsigned long flags;
 
 
+	dbg("Suspending device");
 	spin_lock_irqsave(&kaweth->device_lock, flags);
 	spin_lock_irqsave(&kaweth->device_lock, flags);
 	kaweth->status |= KAWETH_STATUS_SUSPENDING;
 	kaweth->status |= KAWETH_STATUS_SUSPENDING;
 	spin_unlock_irqrestore(&kaweth->device_lock, flags);
 	spin_unlock_irqrestore(&kaweth->device_lock, flags);
@@ -924,6 +948,7 @@ static int kaweth_resume(struct usb_interface *intf)
 	struct kaweth_device *kaweth = usb_get_intfdata(intf);
 	struct kaweth_device *kaweth = usb_get_intfdata(intf);
 	unsigned long flags;
 	unsigned long flags;
 
 
+	dbg("Resuming device");
 	spin_lock_irqsave(&kaweth->device_lock, flags);
 	spin_lock_irqsave(&kaweth->device_lock, flags);
 	kaweth->status &= ~KAWETH_STATUS_SUSPENDING;
 	kaweth->status &= ~KAWETH_STATUS_SUSPENDING;
 	spin_unlock_irqrestore(&kaweth->device_lock, flags);
 	spin_unlock_irqrestore(&kaweth->device_lock, flags);
@@ -1086,6 +1111,8 @@ err_fw:
 
 
 	dbg("Initializing net device.");
 	dbg("Initializing net device.");
 
 
+	kaweth->intf = intf;
+
 	kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
 	kaweth->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
 	if (!kaweth->tx_urb)
 	if (!kaweth->tx_urb)
 		goto err_free_netdev;
 		goto err_free_netdev;
@@ -1265,7 +1292,7 @@ static int kaweth_internal_control_msg(struct usb_device *usb_dev,
 {
 {
         struct urb *urb;
         struct urb *urb;
         int retv;
         int retv;
-        int length;
+        int length = 0; /* shut up GCC */
 
 
         urb = usb_alloc_urb(0, GFP_NOIO);
         urb = usb_alloc_urb(0, GFP_NOIO);
         if (!urb)
         if (!urb)

+ 62 - 19
drivers/usb/net/rndis_host.c

@@ -49,6 +49,8 @@
  *    - In some cases, MS-Windows will emit undocumented requests; this
  *    - In some cases, MS-Windows will emit undocumented requests; this
  *	matters more to peripheral implementations than host ones.
  *	matters more to peripheral implementations than host ones.
  *
  *
+ * Moreover there's a no-open-specs variant of RNDIS called "ActiveSync".
+ *
  * For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in
  * For these reasons and others, ** USE OF RNDIS IS STRONGLY DISCOURAGED ** in
  * favor of such non-proprietary alternatives as CDC Ethernet or the newer (and
  * favor of such non-proprietary alternatives as CDC Ethernet or the newer (and
  * currently rare) "Ethernet Emulation Model" (EEM).
  * currently rare) "Ethernet Emulation Model" (EEM).
@@ -61,6 +63,9 @@
  *  - control-in:  GET_ENCAPSULATED
  *  - control-in:  GET_ENCAPSULATED
  *
  *
  * We'll try to ignore the RESPONSE_AVAILABLE notifications.
  * We'll try to ignore the RESPONSE_AVAILABLE notifications.
+ *
+ * REVISIT some RNDIS implementations seem to have curious issues still
+ * to be resolved.
  */
  */
 struct rndis_msg_hdr {
 struct rndis_msg_hdr {
 	__le32	msg_type;			/* RNDIS_MSG_* */
 	__le32	msg_type;			/* RNDIS_MSG_* */
@@ -71,8 +76,14 @@ struct rndis_msg_hdr {
 	// ... and more
 	// ... and more
 } __attribute__ ((packed));
 } __attribute__ ((packed));
 
 
-/* RNDIS defines this (absurdly huge) control timeout */
-#define	RNDIS_CONTROL_TIMEOUT_MS	(10 * 1000)
+/* MS-Windows uses this strange size, but RNDIS spec says 1024 minimum */
+#define	CONTROL_BUFFER_SIZE		1025
+
+/* RNDIS defines an (absurdly huge) 10 second control timeout,
+ * but ActiveSync seems to use a more usual 5 second timeout
+ * (which matches the USB 2.0 spec).
+ */
+#define	RNDIS_CONTROL_TIMEOUT_MS	(5 * 1000)
 
 
 
 
 #define ccpu2 __constant_cpu_to_le32
 #define ccpu2 __constant_cpu_to_le32
@@ -270,6 +281,7 @@ static void rndis_status(struct usbnet *dev, struct urb *urb)
 static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
 static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
 {
 {
 	struct cdc_state	*info = (void *) &dev->data;
 	struct cdc_state	*info = (void *) &dev->data;
+	int			master_ifnum;
 	int			retval;
 	int			retval;
 	unsigned		count;
 	unsigned		count;
 	__le32			rsp;
 	__le32			rsp;
@@ -279,7 +291,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
 	 * disconnect(): either serialize, or dispatch responses on xid
 	 * disconnect(): either serialize, or dispatch responses on xid
 	 */
 	 */
 
 
-	/* Issue the request; don't bother byteswapping our xid */
+	/* Issue the request; xid is unique, don't bother byteswapping it */
 	if (likely(buf->msg_type != RNDIS_MSG_HALT
 	if (likely(buf->msg_type != RNDIS_MSG_HALT
 			&& buf->msg_type != RNDIS_MSG_RESET)) {
 			&& buf->msg_type != RNDIS_MSG_RESET)) {
 		xid = dev->xid++;
 		xid = dev->xid++;
@@ -287,11 +299,12 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
 			xid = dev->xid++;
 			xid = dev->xid++;
 		buf->request_id = (__force __le32) xid;
 		buf->request_id = (__force __le32) xid;
 	}
 	}
+	master_ifnum = info->control->cur_altsetting->desc.bInterfaceNumber;
 	retval = usb_control_msg(dev->udev,
 	retval = usb_control_msg(dev->udev,
 		usb_sndctrlpipe(dev->udev, 0),
 		usb_sndctrlpipe(dev->udev, 0),
 		USB_CDC_SEND_ENCAPSULATED_COMMAND,
 		USB_CDC_SEND_ENCAPSULATED_COMMAND,
 		USB_TYPE_CLASS | USB_RECIP_INTERFACE,
 		USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-		0, info->u->bMasterInterface0,
+		0, master_ifnum,
 		buf, le32_to_cpu(buf->msg_len),
 		buf, le32_to_cpu(buf->msg_len),
 		RNDIS_CONTROL_TIMEOUT_MS);
 		RNDIS_CONTROL_TIMEOUT_MS);
 	if (unlikely(retval < 0 || xid == 0))
 	if (unlikely(retval < 0 || xid == 0))
@@ -306,13 +319,13 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
 	 */
 	 */
 	rsp = buf->msg_type | RNDIS_MSG_COMPLETION;
 	rsp = buf->msg_type | RNDIS_MSG_COMPLETION;
 	for (count = 0; count < 10; count++) {
 	for (count = 0; count < 10; count++) {
-		memset(buf, 0, 1024);
+		memset(buf, 0, CONTROL_BUFFER_SIZE);
 		retval = usb_control_msg(dev->udev,
 		retval = usb_control_msg(dev->udev,
 			usb_rcvctrlpipe(dev->udev, 0),
 			usb_rcvctrlpipe(dev->udev, 0),
 			USB_CDC_GET_ENCAPSULATED_RESPONSE,
 			USB_CDC_GET_ENCAPSULATED_RESPONSE,
 			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
 			USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-			0, info->u->bMasterInterface0,
-			buf, 1024,
+			0, master_ifnum,
+			buf, CONTROL_BUFFER_SIZE,
 			RNDIS_CONTROL_TIMEOUT_MS);
 			RNDIS_CONTROL_TIMEOUT_MS);
 		if (likely(retval >= 8)) {
 		if (likely(retval >= 8)) {
 			msg_len = le32_to_cpu(buf->msg_len);
 			msg_len = le32_to_cpu(buf->msg_len);
@@ -350,7 +363,7 @@ static int rndis_command(struct usbnet *dev, struct rndis_msg_hdr *buf)
 					usb_sndctrlpipe(dev->udev, 0),
 					usb_sndctrlpipe(dev->udev, 0),
 					USB_CDC_SEND_ENCAPSULATED_COMMAND,
 					USB_CDC_SEND_ENCAPSULATED_COMMAND,
 					USB_TYPE_CLASS | USB_RECIP_INTERFACE,
 					USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-					0, info->u->bMasterInterface0,
+					0, master_ifnum,
 					msg, sizeof *msg,
 					msg, sizeof *msg,
 					RNDIS_CONTROL_TIMEOUT_MS);
 					RNDIS_CONTROL_TIMEOUT_MS);
 				if (unlikely(retval < 0))
 				if (unlikely(retval < 0))
@@ -393,38 +406,64 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
 	u32			tmp;
 	u32			tmp;
 
 
 	/* we can't rely on i/o from stack working, or stack allocation */
 	/* we can't rely on i/o from stack working, or stack allocation */
-	u.buf = kmalloc(1024, GFP_KERNEL);
+	u.buf = kmalloc(CONTROL_BUFFER_SIZE, GFP_KERNEL);
 	if (!u.buf)
 	if (!u.buf)
 		return -ENOMEM;
 		return -ENOMEM;
 	retval = usbnet_generic_cdc_bind(dev, intf);
 	retval = usbnet_generic_cdc_bind(dev, intf);
 	if (retval < 0)
 	if (retval < 0)
 		goto fail;
 		goto fail;
 
 
-	net->hard_header_len += sizeof (struct rndis_data_hdr);
-
-	/* initialize; max transfer is 16KB at full speed */
 	u.init->msg_type = RNDIS_MSG_INIT;
 	u.init->msg_type = RNDIS_MSG_INIT;
 	u.init->msg_len = ccpu2(sizeof *u.init);
 	u.init->msg_len = ccpu2(sizeof *u.init);
 	u.init->major_version = ccpu2(1);
 	u.init->major_version = ccpu2(1);
 	u.init->minor_version = ccpu2(0);
 	u.init->minor_version = ccpu2(0);
-	u.init->max_transfer_size = ccpu2(net->mtu + net->hard_header_len);
 
 
+	/* max transfer (in spec) is 0x4000 at full speed, but for
+	 * TX we'll stick to one Ethernet packet plus RNDIS framing.
+	 * For RX we handle drivers that zero-pad to end-of-packet.
+	 * Don't let userspace change these settings.
+	 */
+	net->hard_header_len += sizeof (struct rndis_data_hdr);
+	dev->hard_mtu = net->mtu + net->hard_header_len;
+
+	dev->rx_urb_size = dev->hard_mtu + (dev->maxpacket + 1);
+	dev->rx_urb_size &= ~(dev->maxpacket - 1);
+	u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size);
+
+	net->change_mtu = NULL;
 	retval = rndis_command(dev, u.header);
 	retval = rndis_command(dev, u.header);
 	if (unlikely(retval < 0)) {
 	if (unlikely(retval < 0)) {
 		/* it might not even be an RNDIS device!! */
 		/* it might not even be an RNDIS device!! */
 		dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
 		dev_err(&intf->dev, "RNDIS init failed, %d\n", retval);
+ 		goto fail_and_release;
+	}
+	tmp = le32_to_cpu(u.init_c->max_transfer_size);
+	if (tmp < dev->hard_mtu) {
+		dev_err(&intf->dev,
+			"dev can't take %u byte packets (max %u)\n",
+			dev->hard_mtu, tmp);
 		goto fail_and_release;
 		goto fail_and_release;
 	}
 	}
-	dev->hard_mtu = le32_to_cpu(u.init_c->max_transfer_size);
+
 	/* REVISIT:  peripheral "alignment" request is ignored ... */
 	/* REVISIT:  peripheral "alignment" request is ignored ... */
-	dev_dbg(&intf->dev, "hard mtu %u, align %d\n", dev->hard_mtu,
+	dev_dbg(&intf->dev,
+		"hard mtu %u (%u from dev), rx buflen %Zu, align %d\n",
+		dev->hard_mtu, tmp, dev->rx_urb_size,
 		1 << le32_to_cpu(u.init_c->packet_alignment));
 		1 << le32_to_cpu(u.init_c->packet_alignment));
 
 
-	/* get designated host ethernet address */
-	memset(u.get, 0, sizeof *u.get);
+	/* Get designated host ethernet address.
+	 *
+	 * Adding a payload exactly the same size as the expected response
+	 * payload is an evident requirement MSFT added for ActiveSync.
+	 * This undocumented (and nonsensical) issue was found by sniffing
+	 * protocol requests from the ActiveSync 4.1 Windows driver.
+	 */
+	memset(u.get, 0, sizeof *u.get + 48);
 	u.get->msg_type = RNDIS_MSG_QUERY;
 	u.get->msg_type = RNDIS_MSG_QUERY;
-	u.get->msg_len = ccpu2(sizeof *u.get);
+	u.get->msg_len = ccpu2(sizeof *u.get + 48);
 	u.get->oid = OID_802_3_PERMANENT_ADDRESS;
 	u.get->oid = OID_802_3_PERMANENT_ADDRESS;
+	u.get->len = ccpu2(48);
+	u.get->offset = ccpu2(20);
 
 
 	retval = rndis_command(dev, u.header);
 	retval = rndis_command(dev, u.header);
 	if (unlikely(retval < 0)) {
 	if (unlikely(retval < 0)) {
@@ -432,7 +471,7 @@ static int rndis_bind(struct usbnet *dev, struct usb_interface *intf)
 		goto fail_and_release;
 		goto fail_and_release;
 	}
 	}
 	tmp = le32_to_cpu(u.get_c->offset);
 	tmp = le32_to_cpu(u.get_c->offset);
-	if (unlikely((tmp + 8) > (1024 - ETH_ALEN)
+	if (unlikely((tmp + 8) > (CONTROL_BUFFER_SIZE - ETH_ALEN)
 			|| u.get_c->len != ccpu2(ETH_ALEN))) {
 			|| u.get_c->len != ccpu2(ETH_ALEN))) {
 		dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n",
 		dev_err(&intf->dev, "rndis ethaddr off %d len %d ?\n",
 			tmp, le32_to_cpu(u.get_c->len));
 			tmp, le32_to_cpu(u.get_c->len));
@@ -598,6 +637,10 @@ static const struct usb_device_id	products [] = {
 	/* RNDIS is MSFT's un-official variant of CDC ACM */
 	/* RNDIS is MSFT's un-official variant of CDC ACM */
 	USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
 	USB_INTERFACE_INFO(USB_CLASS_COMM, 2 /* ACM */, 0x0ff),
 	.driver_info = (unsigned long) &rndis_info,
 	.driver_info = (unsigned long) &rndis_info,
+}, {
+	/* "ActiveSync" is an undocumented variant of RNDIS, used in WM5 */
+	USB_INTERFACE_INFO(USB_CLASS_MISC, 1, 1),
+	.driver_info = (unsigned long) &rndis_info,
 },
 },
 	{ },		// END
 	{ },		// END
 };
 };

+ 13 - 8
drivers/usb/serial/aircable.c

@@ -572,8 +572,20 @@ static void aircable_unthrottle(struct usb_serial_port *port)
 		schedule_work(&priv->rx_work);
 		schedule_work(&priv->rx_work);
 }
 }
 
 
+static struct usb_driver aircable_driver = {
+	.name =		"aircable",
+	.probe =	usb_serial_probe,
+	.disconnect =	usb_serial_disconnect,
+	.id_table =	id_table,
+	.no_dynamic_id =	1,
+};
+
 static struct usb_serial_driver aircable_device = {
 static struct usb_serial_driver aircable_device = {
-	.description =		"aircable",
+	.driver = {
+		.owner =	THIS_MODULE,
+		.name =		"aircable",
+	},
+	.usb_driver = 		&aircable_driver,
 	.id_table = 		id_table,
 	.id_table = 		id_table,
 	.num_ports =		1,
 	.num_ports =		1,
 	.attach =		aircable_attach,
 	.attach =		aircable_attach,
@@ -587,13 +599,6 @@ static struct usb_serial_driver aircable_device = {
 	.unthrottle =		aircable_unthrottle,
 	.unthrottle =		aircable_unthrottle,
 };
 };
 
 
-static struct usb_driver aircable_driver = {
-	.name =		"aircable",
-	.probe =	usb_serial_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	id_table,
-};
-
 static int __init aircable_init (void)
 static int __init aircable_init (void)
 {
 {
 	int retval;
 	int retval;

+ 1 - 0
drivers/usb/serial/airprime.c

@@ -277,6 +277,7 @@ static struct usb_serial_driver airprime_device = {
 		.owner =	THIS_MODULE,
 		.owner =	THIS_MODULE,
 		.name =		"airprime",
 		.name =		"airprime",
 	},
 	},
+	.usb_driver =		&airprime_driver,
 	.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,

+ 2 - 0
drivers/usb/serial/ark3116.c

@@ -444,6 +444,7 @@ static struct usb_driver ark3116_driver = {
 	.probe =	usb_serial_probe,
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
 	.disconnect =	usb_serial_disconnect,
 	.id_table =	id_table,
 	.id_table =	id_table,
+	.no_dynamic_id =	1,
 };
 };
 
 
 static struct usb_serial_driver ark3116_device = {
 static struct usb_serial_driver ark3116_device = {
@@ -452,6 +453,7 @@ static struct usb_serial_driver ark3116_device = {
 		.name =		"ark3116",
 		.name =		"ark3116",
 	},
 	},
 	.id_table =		id_table,
 	.id_table =		id_table,
+	.usb_driver =		&ark3116_driver,
 	.num_interrupt_in =	1,
 	.num_interrupt_in =	1,
 	.num_bulk_in =		1,
 	.num_bulk_in =		1,
 	.num_bulk_out =		1,
 	.num_bulk_out =		1,

+ 1 - 0
drivers/usb/serial/belkin_sa.c

@@ -126,6 +126,7 @@ static struct usb_serial_driver belkin_device = {
 		.name =		"belkin",
 		.name =		"belkin",
 	},
 	},
 	.description =		"Belkin / Peracom / GoHubs USB Serial Adapter",
 	.description =		"Belkin / Peracom / GoHubs USB Serial Adapter",
+	.usb_driver =		&belkin_driver,
 	.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,

+ 45 - 0
drivers/usb/serial/bus.c

@@ -103,11 +103,52 @@ exit:
 	return retval;
 	return retval;
 }
 }
 
 
+#ifdef CONFIG_HOTPLUG
+static ssize_t store_new_id(struct device_driver *driver,
+			    const char *buf, size_t count)
+{
+	struct usb_serial_driver *usb_drv = to_usb_serial_driver(driver);
+	ssize_t retval = usb_store_new_id(&usb_drv->dynids, driver, buf, count);
+
+	if (retval >= 0 && usb_drv->usb_driver != NULL)
+		retval = usb_store_new_id(&usb_drv->usb_driver->dynids,
+					  &usb_drv->usb_driver->drvwrap.driver,
+					  buf, count);
+	return retval;
+}
+
+static struct driver_attribute drv_attrs[] = {
+	__ATTR(new_id, S_IWUSR, NULL, store_new_id),
+	__ATTR_NULL,
+};
+
+static void free_dynids(struct usb_serial_driver *drv)
+{
+	struct usb_dynid *dynid, *n;
+
+	spin_lock(&drv->dynids.lock);
+	list_for_each_entry_safe(dynid, n, &drv->dynids.list, node) {
+		list_del(&dynid->node);
+		kfree(dynid);
+	}
+	spin_unlock(&drv->dynids.lock);
+}
+
+#else
+static struct driver_attribute drv_attrs[] = {
+	__ATTR_NULL,
+};
+static inline void free_dynids(struct usb_driver *drv)
+{
+}
+#endif
+
 struct bus_type usb_serial_bus_type = {
 struct bus_type usb_serial_bus_type = {
 	.name =		"usb-serial",
 	.name =		"usb-serial",
 	.match =	usb_serial_device_match,
 	.match =	usb_serial_device_match,
 	.probe =	usb_serial_device_probe,
 	.probe =	usb_serial_device_probe,
 	.remove =	usb_serial_device_remove,
 	.remove =	usb_serial_device_remove,
+	.drv_attrs = 	drv_attrs,
 };
 };
 
 
 int usb_serial_bus_register(struct usb_serial_driver *driver)
 int usb_serial_bus_register(struct usb_serial_driver *driver)
@@ -115,6 +156,9 @@ int usb_serial_bus_register(struct usb_serial_driver *driver)
 	int retval;
 	int retval;
 
 
 	driver->driver.bus = &usb_serial_bus_type;
 	driver->driver.bus = &usb_serial_bus_type;
+	spin_lock_init(&driver->dynids.lock);
+	INIT_LIST_HEAD(&driver->dynids.list);
+
 	retval = driver_register(&driver->driver);
 	retval = driver_register(&driver->driver);
 
 
 	return retval;
 	return retval;
@@ -122,6 +166,7 @@ int usb_serial_bus_register(struct usb_serial_driver *driver)
 
 
 void usb_serial_bus_deregister(struct usb_serial_driver *driver)
 void usb_serial_bus_deregister(struct usb_serial_driver *driver)
 {
 {
+	free_dynids(driver);
 	driver_unregister(&driver->driver);
 	driver_unregister(&driver->driver);
 }
 }
 
 

+ 1 - 0
drivers/usb/serial/cp2101.c

@@ -89,6 +89,7 @@ static struct usb_serial_driver cp2101_device = {
 		.owner =	THIS_MODULE,
 		.owner =	THIS_MODULE,
 		.name = 	"cp2101",
 		.name = 	"cp2101",
 	},
 	},
+	.usb_driver		= &cp2101_driver,
 	.id_table		= id_table,
 	.id_table		= id_table,
 	.num_interrupt_in	= 0,
 	.num_interrupt_in	= 0,
 	.num_bulk_in		= 0,
 	.num_bulk_in		= 0,

+ 2 - 1
drivers/usb/serial/cyberjack.c

@@ -88,6 +88,7 @@ static struct usb_serial_driver cyberjack_device = {
 		.name =		"cyberjack",
 		.name =		"cyberjack",
 	},
 	},
 	.description =		"Reiner SCT Cyberjack USB card reader",
 	.description =		"Reiner SCT Cyberjack USB card reader",
+	.usb_driver = 		&cyberjack_driver,
 	.id_table =		id_table,
 	.id_table =		id_table,
 	.num_interrupt_in =	1,
 	.num_interrupt_in =	1,
 	.num_bulk_in =		1,
 	.num_bulk_in =		1,
@@ -98,7 +99,7 @@ static struct usb_serial_driver cyberjack_device = {
 	.open =			cyberjack_open,
 	.open =			cyberjack_open,
 	.close =		cyberjack_close,
 	.close =		cyberjack_close,
 	.write =		cyberjack_write,
 	.write =		cyberjack_write,
-	.write_room =	cyberjack_write_room,
+	.write_room =		cyberjack_write_room,
 	.read_int_callback =	cyberjack_read_int_callback,
 	.read_int_callback =	cyberjack_read_int_callback,
 	.read_bulk_callback =	cyberjack_read_bulk_callback,
 	.read_bulk_callback =	cyberjack_read_bulk_callback,
 	.write_bulk_callback =	cyberjack_write_bulk_callback,
 	.write_bulk_callback =	cyberjack_write_bulk_callback,

+ 3 - 0
drivers/usb/serial/cypress_m8.c

@@ -193,6 +193,7 @@ static struct usb_serial_driver cypress_earthmate_device = {
 		.name =			"earthmate",
 		.name =			"earthmate",
 	},
 	},
 	.description =			"DeLorme Earthmate USB",
 	.description =			"DeLorme Earthmate USB",
+	.usb_driver = 			&cypress_driver,
 	.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,
@@ -222,6 +223,7 @@ static struct usb_serial_driver cypress_hidcom_device = {
 		.name =			"cyphidcom",
 		.name =			"cyphidcom",
 	},
 	},
 	.description =			"HID->COM RS232 Adapter",
 	.description =			"HID->COM RS232 Adapter",
+	.usb_driver = 			&cypress_driver,
 	.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,
@@ -251,6 +253,7 @@ static struct usb_serial_driver cypress_ca42v2_device = {
                 .name =			"nokiaca42v2",
                 .name =			"nokiaca42v2",
 	},
 	},
 	.description =			"Nokia CA-42 V2 Adapter",
 	.description =			"Nokia CA-42 V2 Adapter",
+	.usb_driver = 			&cypress_driver,
 	.id_table =			id_table_nokiaca42v2,
 	.id_table =			id_table_nokiaca42v2,
 	.num_interrupt_in =		1,
 	.num_interrupt_in =		1,
 	.num_interrupt_out =		1,
 	.num_interrupt_out =		1,

+ 2 - 0
drivers/usb/serial/digi_acceleport.c

@@ -509,6 +509,7 @@ static struct usb_serial_driver digi_acceleport_2_device = {
 		.name =			"digi_2",
 		.name =			"digi_2",
 	},
 	},
 	.description =			"Digi 2 port USB adapter",
 	.description =			"Digi 2 port USB adapter",
+	.usb_driver = 			&digi_driver,
 	.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,
@@ -538,6 +539,7 @@ static struct usb_serial_driver digi_acceleport_4_device = {
 		.name =			"digi_4",
 		.name =			"digi_4",
 	},
 	},
 	.description =			"Digi 4 port USB adapter",
 	.description =			"Digi 4 port USB adapter",
+	.usb_driver = 			&digi_driver,
 	.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,

+ 1 - 0
drivers/usb/serial/empeg.c

@@ -117,6 +117,7 @@ static struct usb_serial_driver empeg_device = {
 		.name =		"empeg",
 		.name =		"empeg",
 	},
 	},
 	.id_table =		id_table,
 	.id_table =		id_table,
+	.usb_driver = 		&empeg_driver,
 	.num_interrupt_in =	0,
 	.num_interrupt_in =	0,
 	.num_bulk_in =		1,
 	.num_bulk_in =		1,
 	.num_bulk_out =		1,
 	.num_bulk_out =		1,

+ 1 - 1
drivers/usb/serial/ftdi_sio.c

@@ -464,7 +464,6 @@ static struct usb_device_id id_table_combined [] = {
 	{ USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
 	{ USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
 	{ USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
 	{ USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
 	{ USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) },
 	{ USB_DEVICE(FTDI_VID, EVER_ECO_PRO_CDS) },
-	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_0_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_1_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
 	{ USB_DEVICE(FTDI_VID, FTDI_4N_GALAXY_DE_2_PID) },
 	{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) },
 	{ USB_DEVICE(FTDI_VID, XSENS_CONVERTER_0_PID) },
@@ -615,6 +614,7 @@ static struct usb_serial_driver ftdi_sio_device = {
 		.name =		"ftdi_sio",
 		.name =		"ftdi_sio",
 	},
 	},
 	.description =		"FTDI USB Serial Device",
 	.description =		"FTDI USB Serial Device",
+	.usb_driver = 		&ftdi_driver ,
 	.id_table =		id_table_combined,
 	.id_table =		id_table_combined,
 	.num_interrupt_in =	0,
 	.num_interrupt_in =	0,
 	.num_bulk_in =		1,
 	.num_bulk_in =		1,

+ 0 - 1
drivers/usb/serial/ftdi_sio.h

@@ -364,7 +364,6 @@
  * USB-TTY activ, USB-TTY passiv.  Some PIDs are used by several devices
  * USB-TTY activ, USB-TTY passiv.  Some PIDs are used by several devices
  * and I'm not entirely sure which are used by which.
  * and I'm not entirely sure which are used by which.
  */
  */
-#define FTDI_4N_GALAXY_DE_0_PID	0x8372
 #define FTDI_4N_GALAXY_DE_1_PID	0xF3C0
 #define FTDI_4N_GALAXY_DE_1_PID	0xF3C0
 #define FTDI_4N_GALAXY_DE_2_PID	0xF3C1
 #define FTDI_4N_GALAXY_DE_2_PID	0xF3C1
 
 

+ 1 - 0
drivers/usb/serial/funsoft.c

@@ -58,6 +58,7 @@ static struct usb_serial_driver funsoft_device = {
 		.name =		"funsoft",
 		.name =		"funsoft",
 	},
 	},
 	.id_table =		id_table,
 	.id_table =		id_table,
+	.usb_driver = 		&funsoft_driver,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,

+ 1 - 0
drivers/usb/serial/garmin_gps.c

@@ -1566,6 +1566,7 @@ static struct usb_serial_driver garmin_device = {
 		.name        = "garmin_gps",
 		.name        = "garmin_gps",
 	},
 	},
 	.description         = "Garmin GPS usb/tty",
 	.description         = "Garmin GPS usb/tty",
+	.usb_driver          = &garmin_driver,
 	.id_table            = id_table,
 	.id_table            = id_table,
 	.num_interrupt_in    = 1,
 	.num_interrupt_in    = 1,
 	.num_bulk_in         = 1,
 	.num_bulk_in         = 1,

+ 20 - 15
drivers/usb/serial/generic.c

@@ -20,6 +20,10 @@
 #include <linux/usb/serial.h>
 #include <linux/usb/serial.h>
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 
 
+static int generic_probe(struct usb_interface *interface,
+			 const struct usb_device_id *id);
+
+
 static int debug;
 static int debug;
 
 
 #ifdef CONFIG_USB_SERIAL_GENERIC
 #ifdef CONFIG_USB_SERIAL_GENERIC
@@ -34,6 +38,21 @@ MODULE_PARM_DESC(product, "User specified USB idProduct");
 
 
 static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */
 static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */
 
 
+/* we want to look at all devices, as the vendor/product id can change
+ * depending on the command line argument */
+static struct usb_device_id generic_serial_ids[] = {
+	{.driver_info = 42},
+	{}
+};
+
+static struct usb_driver generic_driver = {
+	.name =		"usbserial_generic",
+	.probe =	generic_probe,
+	.disconnect =	usb_serial_disconnect,
+	.id_table =	generic_serial_ids,
+	.no_dynamic_id =	1,
+};
+
 /* All of the device info needed for the Generic Serial Converter */
 /* All of the device info needed for the Generic Serial Converter */
 struct usb_serial_driver usb_serial_generic_device = {
 struct usb_serial_driver usb_serial_generic_device = {
 	.driver = {
 	.driver = {
@@ -41,6 +60,7 @@ struct usb_serial_driver usb_serial_generic_device = {
 		.name =		"generic",
 		.name =		"generic",
 	},
 	},
 	.id_table =		generic_device_ids,
 	.id_table =		generic_device_ids,
+	.usb_driver = 		&generic_driver,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_interrupt_in =	NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,
@@ -48,13 +68,6 @@ struct usb_serial_driver usb_serial_generic_device = {
 	.shutdown =		usb_serial_generic_shutdown,
 	.shutdown =		usb_serial_generic_shutdown,
 };
 };
 
 
-/* we want to look at all devices, as the vendor/product id can change
- * depending on the command line argument */
-static struct usb_device_id generic_serial_ids[] = {
-	{.driver_info = 42},
-	{}
-};
-
 static int generic_probe(struct usb_interface *interface,
 static int generic_probe(struct usb_interface *interface,
 			       const struct usb_device_id *id)
 			       const struct usb_device_id *id)
 {
 {
@@ -65,14 +78,6 @@ static int generic_probe(struct usb_interface *interface,
 		return usb_serial_probe(interface, id);
 		return usb_serial_probe(interface, id);
 	return -ENODEV;
 	return -ENODEV;
 }
 }
-
-static struct usb_driver generic_driver = {
-	.name =		"usbserial_generic",
-	.probe =	generic_probe,
-	.disconnect =	usb_serial_disconnect,
-	.id_table =	generic_serial_ids,
-	.no_dynamic_id = 	1,
-};
 #endif
 #endif
 
 
 int usb_serial_generic_register (int _debug)
 int usb_serial_generic_register (int _debug)

Неке датотеке нису приказане због велике количине промена