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

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: (149 commits)
  USB: ohci-pnx4008: Remove unnecessary cast of return value of kzalloc
  USB: additions to the quirk list
  usb-storage: implement autosuspend
  USB: cdc-acm: add new device id to option driver
  USB: goku_udc trivial cleanups
  USB: usb gadget stack can now -DDEBUG with Kconfig
  usb gadget stack: remove usb_ep_*_buffer(), part 2
  usb gadget stack: remove usb_ep_*_buffer(), part 1
  USB: pxa2xx_udc -- cleanups, mostly removing dma hooks
  USB: pxa2xx_udc: use generic gpio layer
  USB: quirk for samsung printer
  USB: usb/dma doc updates
  USB: drivers/usb/storage/unusual_devs.h whitespace cleanup
  USB: remove Makefile reference to obsolete OHCI_AT91
  USB: io_*: remove bogus termios no change checks
  USB: mos7720: remove bogus no termios change check
  USB: visor and whiteheat: remove bogus termios change checks
  USB: pl2303: remove bogus checks and fix speed support to use tty_get_baud_rate()
  USB: mos7840.c: turn this into a serial driver
  USB: make the usb_device numa_node get assigned from controller
  ...
Linus Torvalds 18 жил өмнө
parent
commit
9374430a52
100 өөрчлөгдсөн 10688 нэмэгдсэн , 2582 устгасан
  1. 13 0
      Documentation/ABI/testing/sysfs-bus-usb
  2. 3 0
      Documentation/power/swsusp.txt
  3. 37 15
      Documentation/usb/dma.txt
  4. 156 0
      Documentation/usb/persist.txt
  5. 4 4
      MAINTAINERS
  6. 3 9
      drivers/block/ub.c
  7. 6 3
      drivers/hid/usbhid/hid-core.c
  8. 6 3
      drivers/usb/Kconfig
  9. 1 1
      drivers/usb/Makefile
  10. 31 42
      drivers/usb/atm/cxacru.c
  11. 3 0
      drivers/usb/class/cdc-acm.c
  12. 376 242
      drivers/usb/class/usblp.c
  13. 25 0
      drivers/usb/core/Kconfig
  14. 39 3
      drivers/usb/core/config.c
  15. 26 0
      drivers/usb/core/devices.c
  16. 105 57
      drivers/usb/core/driver.c
  17. 13 16
      drivers/usb/core/file.c
  18. 24 5
      drivers/usb/core/generic.c
  19. 2 1
      drivers/usb/core/hcd-pci.c
  20. 65 61
      drivers/usb/core/hcd.c
  21. 2 12
      drivers/usb/core/hcd.h
  22. 283 360
      drivers/usb/core/hub.c
  23. 34 4
      drivers/usb/core/message.c
  24. 18 0
      drivers/usb/core/quirks.c
  25. 107 2
      drivers/usb/core/sysfs.c
  26. 102 3
      drivers/usb/core/urb.c
  27. 7 5
      drivers/usb/core/usb.c
  28. 12 2
      drivers/usb/core/usb.h
  29. 53 0
      drivers/usb/gadget/Kconfig
  30. 6 0
      drivers/usb/gadget/Makefile
  31. 0 21
      drivers/usb/gadget/at91_udc.c
  32. 1 38
      drivers/usb/gadget/dummy_hcd.c
  33. 6 2
      drivers/usb/gadget/ether.c
  34. 6 16
      drivers/usb/gadget/file_storage.c
  35. 36 63
      drivers/usb/gadget/fsl_usb2_udc.c
  36. 4 0
      drivers/usb/gadget/fsl_usb2_udc.h
  37. 23 4
      drivers/usb/gadget/gadget_chips.h
  38. 1 7
      drivers/usb/gadget/gmidi.c
  39. 17 67
      drivers/usb/gadget/goku_udc.c
  40. 6 4
      drivers/usb/gadget/goku_udc.h
  41. 4 4
      drivers/usb/gadget/inode.c
  42. 0 27
      drivers/usb/gadget/lh7a40x_udc.c
  43. 1653 0
      drivers/usb/gadget/m66592-udc.c
  44. 577 0
      drivers/usb/gadget/m66592-udc.h
  45. 0 97
      drivers/usb/gadget/net2280.c
  46. 0 108
      drivers/usb/gadget/omap_udc.c
  47. 72 401
      drivers/usb/gadget/pxa2xx_udc.c
  48. 5 43
      drivers/usb/gadget/pxa2xx_udc.h
  49. 82 82
      drivers/usb/gadget/rndis.c
  50. 2045 0
      drivers/usb/gadget/s3c2410_udc.c
  51. 110 0
      drivers/usb/gadget/s3c2410_udc.h
  52. 8 6
      drivers/usb/gadget/serial.c
  53. 3 6
      drivers/usb/gadget/zero.c
  54. 26 2
      drivers/usb/host/Kconfig
  55. 2 0
      drivers/usb/host/Makefile
  56. 96 87
      drivers/usb/host/ehci-dbg.c
  57. 7 3
      drivers/usb/host/ehci-fsl.c
  58. 95 23
      drivers/usb/host/ehci-hcd.c
  59. 116 6
      drivers/usb/host/ehci-hub.c
  60. 16 11
      drivers/usb/host/ehci-mem.c
  61. 4 3
      drivers/usb/host/ehci-pci.c
  62. 182 0
      drivers/usb/host/ehci-ppc-soc.c
  63. 74 12
      drivers/usb/host/ehci-ps3.c
  64. 51 45
      drivers/usb/host/ehci-q.c
  65. 240 99
      drivers/usb/host/ehci-sched.c
  66. 181 53
      drivers/usb/host/ehci.h
  67. 2 2
      drivers/usb/host/ohci-dbg.c
  68. 47 45
      drivers/usb/host/ohci-hcd.c
  69. 3 2
      drivers/usb/host/ohci-hub.c
  70. 1 0
      drivers/usb/host/ohci-mem.c
  71. 56 1
      drivers/usb/host/ohci-pci.c
  72. 1 1
      drivers/usb/host/ohci-pnx4008.c
  73. 75 12
      drivers/usb/host/ohci-ps3.c
  74. 2 0
      drivers/usb/host/ohci.h
  75. 2244 0
      drivers/usb/host/r8a66597-hcd.c
  76. 634 0
      drivers/usb/host/r8a66597.h
  77. 2 3
      drivers/usb/host/uhci-hcd.c
  78. 11 20
      drivers/usb/misc/adutux.c
  79. 3 3
      drivers/usb/misc/auerswald.c
  80. 35 0
      drivers/usb/misc/berry_charge.c
  81. 15 39
      drivers/usb/misc/idmouse.c
  82. 8 18
      drivers/usb/misc/iowarrior.c
  83. 8 25
      drivers/usb/misc/ldusb.c
  84. 6 18
      drivers/usb/misc/legousbtower.c
  85. 5 33
      drivers/usb/misc/sisusbvga/sisusb.c
  86. 2 23
      drivers/usb/misc/sisusbvga/sisusb_con.c
  87. 0 2
      drivers/usb/misc/sisusbvga/sisusb_init.h
  88. 47 20
      drivers/usb/misc/usblcd.c
  89. 33 1
      drivers/usb/mon/mon_bin.c
  90. 10 4
      drivers/usb/mon/mon_main.c
  91. 18 11
      drivers/usb/mon/mon_text.c
  92. 5 2
      drivers/usb/mon/usb_mon.h
  93. 10 0
      drivers/usb/serial/Kconfig
  94. 1 0
      drivers/usb/serial/Makefile
  95. 9 7
      drivers/usb/serial/aircable.c
  96. 6 4
      drivers/usb/serial/airprime.c
  97. 23 38
      drivers/usb/serial/ark3116.c
  98. 33 45
      drivers/usb/serial/belkin_sa.c
  99. 11 6
      drivers/usb/serial/cyberjack.c
  100. 11 7
      drivers/usb/serial/cypress_m8.c

+ 13 - 0
Documentation/ABI/testing/sysfs-bus-usb

@@ -39,3 +39,16 @@ Description:
 		If you want to suspend a device immediately but leave it
 		If you want to suspend a device immediately but leave it
 		free to wake up in response to I/O requests, you should
 		free to wake up in response to I/O requests, you should
 		write "0" to power/autosuspend.
 		write "0" to power/autosuspend.
+
+What:		/sys/bus/usb/devices/.../power/persist
+Date:		May 2007
+KernelVersion:	2.6.23
+Contact:	Alan Stern <stern@rowland.harvard.edu>
+Description:
+		If CONFIG_USB_PERSIST is set, then each USB device directory
+		will contain a file named power/persist.  The file holds a
+		boolean value (0 or 1) indicating whether or not the
+		"USB-Persist" facility is enabled for the device.  Since the
+		facility is inherently dangerous, it is disabled by default
+		for all devices except hubs.  For more information, see
+		Documentation/usb/persist.txt.

+ 3 - 0
Documentation/power/swsusp.txt

@@ -393,6 +393,9 @@ safest thing is to unmount all filesystems on removable media (such USB,
 Firewire, CompactFlash, MMC, external SATA, or even IDE hotplug bays)
 Firewire, CompactFlash, MMC, external SATA, or even IDE hotplug bays)
 before suspending; then remount them after resuming.
 before suspending; then remount them after resuming.
 
 
+There is a work-around for this problem.  For more information, see
+Documentation/usb/persist.txt.
+
 Q: I upgraded the kernel from 2.6.15 to 2.6.16. Both kernels were
 Q: I upgraded the kernel from 2.6.15 to 2.6.16. Both kernels were
 compiled with the similar configuration files. Anyway I found that
 compiled with the similar configuration files. Anyway I found that
 suspend to disk (and resume) is much slower on 2.6.16 compared to
 suspend to disk (and resume) is much slower on 2.6.16 compared to

+ 37 - 15
Documentation/usb/dma.txt

@@ -32,12 +32,15 @@ ELIMINATING COPIES
 It's good to avoid making CPUs copy data needlessly.  The costs can add up,
 It's good to avoid making CPUs copy data needlessly.  The costs can add up,
 and effects like cache-trashing can impose subtle penalties.
 and effects like cache-trashing can impose subtle penalties.
 
 
-- When you're allocating a buffer for DMA purposes anyway, use the buffer
-  primitives.  Think of them as kmalloc and kfree that give you the right
-  kind of addresses to store in urb->transfer_buffer and urb->transfer_dma,
-  while guaranteeing that no hidden copies through DMA "bounce" buffers will
-  slow things down.  You'd also set URB_NO_TRANSFER_DMA_MAP in
-  urb->transfer_flags:
+- If you're doing lots of small data transfers from the same buffer all
+  the time, that can really burn up resources on systems which use an
+  IOMMU to manage the DMA mappings.  It can cost MUCH more to set up and
+  tear down the IOMMU mappings with each request than perform the I/O!
+
+  For those specific cases, USB has primitives to allocate less expensive
+  memory.  They work like kmalloc and kfree versions that give you the right
+  kind of addresses to store in urb->transfer_buffer and urb->transfer_dma.
+  You'd also set URB_NO_TRANSFER_DMA_MAP in urb->transfer_flags:
 
 
 	void *usb_buffer_alloc (struct usb_device *dev, size_t size,
 	void *usb_buffer_alloc (struct usb_device *dev, size_t size,
 		int mem_flags, dma_addr_t *dma);
 		int mem_flags, dma_addr_t *dma);
@@ -45,6 +48,10 @@ and effects like cache-trashing can impose subtle penalties.
 	void usb_buffer_free (struct usb_device *dev, size_t size,
 	void usb_buffer_free (struct usb_device *dev, size_t size,
 		void *addr, dma_addr_t dma);
 		void *addr, dma_addr_t dma);
 
 
+  Most drivers should *NOT* be using these primitives; they don't need
+  to use this type of memory ("dma-coherent"), and memory returned from
+  kmalloc() will work just fine.
+
   For control transfers you can use the buffer primitives or not for each
   For control transfers you can use the buffer primitives or not for each
   of the transfer buffer and setup buffer independently.  Set the flag bits
   of the transfer buffer and setup buffer independently.  Set the flag bits
   URB_NO_TRANSFER_DMA_MAP and URB_NO_SETUP_DMA_MAP to indicate which
   URB_NO_TRANSFER_DMA_MAP and URB_NO_SETUP_DMA_MAP to indicate which
@@ -54,29 +61,39 @@ and effects like cache-trashing can impose subtle penalties.
   The memory buffer returned is "dma-coherent"; sometimes you might need to
   The memory buffer returned is "dma-coherent"; sometimes you might need to
   force a consistent memory access ordering by using memory barriers.  It's
   force a consistent memory access ordering by using memory barriers.  It's
   not using a streaming DMA mapping, so it's good for small transfers on
   not using a streaming DMA mapping, so it's good for small transfers on
-  systems where the I/O would otherwise tie up an IOMMU mapping.  (See
+  systems where the I/O would otherwise thrash an IOMMU mapping.  (See
   Documentation/DMA-mapping.txt for definitions of "coherent" and "streaming"
   Documentation/DMA-mapping.txt for definitions of "coherent" and "streaming"
   DMA mappings.)
   DMA mappings.)
 
 
   Asking for 1/Nth of a page (as well as asking for N pages) is reasonably
   Asking for 1/Nth of a page (as well as asking for N pages) is reasonably
   space-efficient.
   space-efficient.
 
 
+  On most systems the memory returned will be uncached, because the
+  semantics of dma-coherent memory require either bypassing CPU caches
+  or using cache hardware with bus-snooping support.  While x86 hardware
+  has such bus-snooping, many other systems use software to flush cache
+  lines to prevent DMA conflicts.
+
 - Devices on some EHCI controllers could handle DMA to/from high memory.
 - Devices on some EHCI controllers could handle DMA to/from high memory.
-  Driver probe() routines can notice this using a generic DMA call, then
-  tell higher level code (network, scsi, etc) about it like this:
 
 
-	if (dma_supported (&intf->dev, 0xffffffffffffffffULL))
-		net->features |= NETIF_F_HIGHDMA;
+  Unfortunately, the current Linux DMA infrastructure doesn't have a sane
+  way to expose these capabilities ... and in any case, HIGHMEM is mostly a
+  design wart specific to x86_32.  So your best bet is to ensure you never
+  pass a highmem buffer into a USB driver.  That's easy; it's the default
+  behavior.  Just don't override it; e.g. with NETIF_F_HIGHDMA.
 
 
-  That can eliminate dma bounce buffering of requests that originate (or
-  terminate) in high memory, in cases where the buffers aren't allocated
-  with usb_buffer_alloc() but instead are dma-mapped.
+  This may force your callers to do some bounce buffering, copying from
+  high memory to "normal" DMA memory.  If you can come up with a good way
+  to fix this issue (for x86_32 machines with over 1 GByte of memory),
+  feel free to submit patches.
 
 
 
 
 WORKING WITH EXISTING BUFFERS
 WORKING WITH EXISTING BUFFERS
 
 
 Existing buffers aren't usable for DMA without first being mapped into the
 Existing buffers aren't usable for DMA without first being mapped into the
-DMA address space of the device.
+DMA address space of the device.  However, most buffers passed to your
+driver can safely be used with such DMA mapping.  (See the first section
+of DMA-mapping.txt, titled "What memory is DMA-able?")
 
 
 - When you're using scatterlists, you can map everything at once.  On some
 - When you're using scatterlists, you can map everything at once.  On some
   systems, this kicks in an IOMMU and turns the scatterlists into single
   systems, this kicks in an IOMMU and turns the scatterlists into single
@@ -114,3 +131,8 @@ DMA address space of the device.
   The calls manage urb->transfer_dma for you, and set URB_NO_TRANSFER_DMA_MAP
   The calls manage urb->transfer_dma for you, and set URB_NO_TRANSFER_DMA_MAP
   so that usbcore won't map or unmap the buffer.  The same goes for
   so that usbcore won't map or unmap the buffer.  The same goes for
   urb->setup_dma and URB_NO_SETUP_DMA_MAP for control requests.
   urb->setup_dma and URB_NO_SETUP_DMA_MAP for control requests.
+
+Note that several of those interfaces are currently commented out, since
+they don't have current users.  See the source code.  Other than the dmasync
+calls (where the underlying DMA primitives have changed), most of them can
+easily be commented back in if you want to use them.

+ 156 - 0
Documentation/usb/persist.txt

@@ -0,0 +1,156 @@
+		USB device persistence during system suspend
+
+		   Alan Stern <stern@rowland.harvard.edu>
+
+		 September 2, 2006 (Updated May 29, 2007)
+
+
+	What is the problem?
+
+According to the USB specification, when a USB bus is suspended the
+bus must continue to supply suspend current (around 1-5 mA).  This
+is so that devices can maintain their internal state and hubs can
+detect connect-change events (devices being plugged in or unplugged).
+The technical term is "power session".
+
+If a USB device's power session is interrupted then the system is
+required to behave as though the device has been unplugged.  It's a
+conservative approach; in the absence of suspend current the computer
+has no way to know what has actually happened.  Perhaps the same
+device is still attached or perhaps it was removed and a different
+device plugged into the port.  The system must assume the worst.
+
+By default, Linux behaves according to the spec.  If a USB host
+controller loses power during a system suspend, then when the system
+wakes up all the devices attached to that controller are treated as
+though they had disconnected.  This is always safe and it is the
+"officially correct" thing to do.
+
+For many sorts of devices this behavior doesn't matter in the least.
+If the kernel wants to believe that your USB keyboard was unplugged
+while the system was asleep and a new keyboard was plugged in when the
+system woke up, who cares?  It'll still work the same when you type on
+it.
+
+Unfortunately problems _can_ arise, particularly with mass-storage
+devices.  The effect is exactly the same as if the device really had
+been unplugged while the system was suspended.  If you had a mounted
+filesystem on the device, you're out of luck -- everything in that
+filesystem is now inaccessible.  This is especially annoying if your
+root filesystem was located on the device, since your system will
+instantly crash.
+
+Loss of power isn't the only mechanism to worry about.  Anything that
+interrupts a power session will have the same effect.  For example,
+even though suspend current may have been maintained while the system
+was asleep, on many systems during the initial stages of wakeup the
+firmware (i.e., the BIOS) resets the motherboard's USB host
+controllers.  Result: all the power sessions are destroyed and again
+it's as though you had unplugged all the USB devices.  Yes, it's
+entirely the BIOS's fault, but that doesn't do _you_ any good unless
+you can convince the BIOS supplier to fix the problem (lots of luck!).
+
+On many systems the USB host controllers will get reset after a
+suspend-to-RAM.  On almost all systems, no suspend current is
+available during hibernation (also known as swsusp or suspend-to-disk).
+You can check the kernel log after resuming to see if either of these
+has happened; look for lines saying "root hub lost power or was reset".
+
+In practice, people are forced to unmount any filesystems on a USB
+device before suspending.  If the root filesystem is on a USB device,
+the system can't be suspended at all.  (All right, it _can_ be
+suspended -- but it will crash as soon as it wakes up, which isn't
+much better.)
+
+
+	What is the solution?
+
+Setting CONFIG_USB_PERSIST will cause the kernel to work around these
+issues.  It enables a mode in which the core USB device data
+structures are allowed to persist across a power-session disruption.
+It works like this.  If the kernel sees that a USB host controller is
+not in the expected state during resume (i.e., if the controller was
+reset or otherwise had lost power) then it applies a persistence check
+to each of the USB devices below that controller for which the
+"persist" attribute is set.  It doesn't try to resume the device; that
+can't work once the power session is gone.  Instead it issues a USB
+port reset and then re-enumerates the device.  (This is exactly the
+same thing that happens whenever a USB device is reset.)  If the
+re-enumeration shows that the device now attached to that port has the
+same descriptors as before, including the Vendor and Product IDs, then
+the kernel continues to use the same device structure.  In effect, the
+kernel treats the device as though it had merely been reset instead of
+unplugged.
+
+If no device is now attached to the port, or if the descriptors are
+different from what the kernel remembers, then the treatment is what
+you would expect.  The kernel destroys the old device structure and
+behaves as though the old device had been unplugged and a new device
+plugged in, just as it would without the CONFIG_USB_PERSIST option.
+
+The end result is that the USB device remains available and usable.
+Filesystem mounts and memory mappings are unaffected, and the world is
+now a good and happy place.
+
+Note that even when CONFIG_USB_PERSIST is set, the "persist" feature
+will be applied only to those devices for which it is enabled.  You
+can enable the feature by doing (as root):
+
+	echo 1 >/sys/bus/usb/devices/.../power/persist
+
+where the "..." should be filled in the with the device's ID.  Disable
+the feature by writing 0 instead of 1.  For hubs the feature is
+automatically and permanently enabled, so you only have to worry about
+setting it for devices where it really matters.
+
+
+	Is this the best solution?
+
+Perhaps not.  Arguably, keeping track of mounted filesystems and
+memory mappings across device disconnects should be handled by a
+centralized Logical Volume Manager.  Such a solution would allow you
+to plug in a USB flash device, create a persistent volume associated
+with it, unplug the flash device, plug it back in later, and still
+have the same persistent volume associated with the device.  As such
+it would be more far-reaching than CONFIG_USB_PERSIST.
+
+On the other hand, writing a persistent volume manager would be a big
+job and using it would require significant input from the user.  This
+solution is much quicker and easier -- and it exists now, a giant
+point in its favor!
+
+Furthermore, the USB_PERSIST option applies to _all_ USB devices, not
+just mass-storage devices.  It might turn out to be equally useful for
+other device types, such as network interfaces.
+
+
+	WARNING: Using CONFIG_USB_PERSIST can be dangerous!!
+
+When recovering an interrupted power session the kernel does its best
+to make sure the USB device hasn't been changed; that is, the same
+device is still plugged into the port as before.  But the checks
+aren't guaranteed to be 100% accurate.
+
+If you replace one USB device with another of the same type (same
+manufacturer, same IDs, and so on) there's an excellent chance the
+kernel won't detect the change.  Serial numbers and other strings are
+not compared.  In many cases it wouldn't help if they were, because
+manufacturers frequently omit serial numbers entirely in their
+devices.
+
+Furthermore it's quite possible to leave a USB device exactly the same
+while changing its media.  If you replace the flash memory card in a
+USB card reader while the system is asleep, the kernel will have no
+way to know you did it.  The kernel will assume that nothing has
+happened and will continue to use the partition tables, inodes, and
+memory mappings for the old card.
+
+If the kernel gets fooled in this way, it's almost certain to cause
+data corruption and to crash your system.  You'll have no one to blame
+but yourself.
+
+YOU HAVE BEEN WARNED!  USE AT YOUR OWN RISK!
+
+That having been said, most of the time there shouldn't be any trouble
+at all.  The "persist" feature can be extremely useful.  Make the most
+of it.

+ 4 - 4
MAINTAINERS

@@ -3724,12 +3724,12 @@ L:	netdev@vger.kernel.org
 W:	http://pegasus2.sourceforge.net/
 W:	http://pegasus2.sourceforge.net/
 S:	Maintained
 S:	Maintained
 
 
-USB PRINTER DRIVER
-P:	Vojtech Pavlik
-M:	vojtech@suse.cz
+USB PRINTER DRIVER (usblp)
+P:	Pete Zaitcev
+M:	zaitcev@redhat.com
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-users@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
 L:	linux-usb-devel@lists.sourceforge.net
-S:	Maintained
+S:	Supported
 
 
 USB RTL8150 DRIVER
 USB RTL8150 DRIVER
 P:	Petko Manolov
 P:	Petko Manolov

+ 3 - 9
drivers/block/ub.c

@@ -1547,10 +1547,8 @@ static void ub_reset_enter(struct ub_dev *sc, int try)
 #endif
 #endif
 
 
 #if 0 /* We let them stop themselves. */
 #if 0 /* We let them stop themselves. */
-	struct list_head *p;
 	struct ub_lun *lun;
 	struct ub_lun *lun;
-	list_for_each(p, &sc->luns) {
-		lun = list_entry(p, struct ub_lun, link);
+	list_for_each_entry(lun, &sc->luns, link) {
 		blk_stop_queue(lun->disk->queue);
 		blk_stop_queue(lun->disk->queue);
 	}
 	}
 #endif
 #endif
@@ -1562,7 +1560,6 @@ static void ub_reset_task(struct work_struct *work)
 {
 {
 	struct ub_dev *sc = container_of(work, struct ub_dev, reset_work);
 	struct ub_dev *sc = container_of(work, struct ub_dev, reset_work);
 	unsigned long flags;
 	unsigned long flags;
-	struct list_head *p;
 	struct ub_lun *lun;
 	struct ub_lun *lun;
 	int lkr, rc;
 	int lkr, rc;
 
 
@@ -1608,8 +1605,7 @@ static void ub_reset_task(struct work_struct *work)
 	spin_lock_irqsave(sc->lock, flags);
 	spin_lock_irqsave(sc->lock, flags);
 	sc->reset = 0;
 	sc->reset = 0;
 	tasklet_schedule(&sc->tasklet);
 	tasklet_schedule(&sc->tasklet);
-	list_for_each(p, &sc->luns) {
-		lun = list_entry(p, struct ub_lun, link);
+	list_for_each_entry(lun, &sc->luns, link) {
 		blk_start_queue(lun->disk->queue);
 		blk_start_queue(lun->disk->queue);
 	}
 	}
 	wake_up(&sc->reset_wait);
 	wake_up(&sc->reset_wait);
@@ -2348,7 +2344,6 @@ err_alloc:
 static void ub_disconnect(struct usb_interface *intf)
 static void ub_disconnect(struct usb_interface *intf)
 {
 {
 	struct ub_dev *sc = usb_get_intfdata(intf);
 	struct ub_dev *sc = usb_get_intfdata(intf);
-	struct list_head *p;
 	struct ub_lun *lun;
 	struct ub_lun *lun;
 	unsigned long flags;
 	unsigned long flags;
 
 
@@ -2403,8 +2398,7 @@ static void ub_disconnect(struct usb_interface *intf)
 	/*
 	/*
 	 * Unregister the upper layer.
 	 * Unregister the upper layer.
 	 */
 	 */
-	list_for_each (p, &sc->luns) {
-		lun = list_entry(p, struct ub_lun, link);
+	list_for_each_entry(lun, &sc->luns, link) {
 		del_gendisk(lun->disk);
 		del_gendisk(lun->disk);
 		/*
 		/*
 		 * I wish I could do:
 		 * I wish I could do:

+ 6 - 3
drivers/hid/usbhid/hid-core.c

@@ -1009,20 +1009,22 @@ static int hid_resume(struct usb_interface *intf)
 }
 }
 
 
 /* Treat USB reset pretty much the same as suspend/resume */
 /* Treat USB reset pretty much the same as suspend/resume */
-static void hid_pre_reset(struct usb_interface *intf)
+static int hid_pre_reset(struct usb_interface *intf)
 {
 {
 	/* FIXME: What if the interface is already suspended? */
 	/* FIXME: What if the interface is already suspended? */
 	hid_suspend(intf, PMSG_ON);
 	hid_suspend(intf, PMSG_ON);
+	return 0;
 }
 }
 
 
-static void hid_post_reset(struct usb_interface *intf)
+/* Same routine used for post_reset and reset_resume */
+static int hid_post_reset(struct usb_interface *intf)
 {
 {
 	struct usb_device *dev = interface_to_usbdev (intf);
 	struct usb_device *dev = interface_to_usbdev (intf);
 
 
 	hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
 	hid_set_idle(dev, intf->cur_altsetting->desc.bInterfaceNumber, 0, 0);
 	/* FIXME: Any more reinitialization needed? */
 	/* FIXME: Any more reinitialization needed? */
 
 
-	hid_resume(intf);
+	return hid_resume(intf);
 }
 }
 
 
 static struct usb_device_id hid_usb_ids [] = {
 static struct usb_device_id hid_usb_ids [] = {
@@ -1039,6 +1041,7 @@ static struct usb_driver hid_driver = {
 	.disconnect =	hid_disconnect,
 	.disconnect =	hid_disconnect,
 	.suspend =	hid_suspend,
 	.suspend =	hid_suspend,
 	.resume =	hid_resume,
 	.resume =	hid_resume,
+	.reset_resume =	hid_post_reset,
 	.pre_reset =	hid_pre_reset,
 	.pre_reset =	hid_pre_reset,
 	.post_reset =	hid_post_reset,
 	.post_reset =	hid_post_reset,
 	.id_table =	hid_usb_ids,
 	.id_table =	hid_usb_ids,

+ 6 - 3
drivers/usb/Kconfig

@@ -2,9 +2,12 @@
 # USB device configuration
 # USB device configuration
 #
 #
 
 
-menu "USB support"
+menuconfig USB_SUPPORT
+	bool "USB support"
 	depends on HAS_IOMEM
 	depends on HAS_IOMEM
 
 
+if USB_SUPPORT
+
 # Host-side USB depends on having a host controller
 # Host-side USB depends on having a host controller
 # NOTE:  dummy_hcd is always an option, but it's ignored here ...
 # NOTE:  dummy_hcd is always an option, but it's ignored here ...
 # NOTE:  SL-811 option should be board-specific ...
 # NOTE:  SL-811 option should be board-specific ...
@@ -12,6 +15,7 @@ config USB_ARCH_HAS_HCD
 	boolean
 	boolean
 	default y if USB_ARCH_HAS_OHCI
 	default y if USB_ARCH_HAS_OHCI
 	default y if USB_ARCH_HAS_EHCI
 	default y if USB_ARCH_HAS_EHCI
+	default y if PCMCIA				# sl811_cs
 	default y if ARM				# SL-811
 	default y if ARM				# SL-811
 	default PCI
 	default PCI
 
 
@@ -130,5 +134,4 @@ source "drivers/usb/atm/Kconfig"
 
 
 source "drivers/usb/gadget/Kconfig"
 source "drivers/usb/gadget/Kconfig"
 
 
-endmenu
-
+endif # USB_SUPPORT

+ 1 - 1
drivers/usb/Makefile

@@ -15,7 +15,7 @@ obj-$(CONFIG_USB_OHCI_HCD)	+= host/
 obj-$(CONFIG_USB_UHCI_HCD)	+= host/
 obj-$(CONFIG_USB_UHCI_HCD)	+= host/
 obj-$(CONFIG_USB_SL811_HCD)	+= host/
 obj-$(CONFIG_USB_SL811_HCD)	+= host/
 obj-$(CONFIG_USB_U132_HCD)	+= host/
 obj-$(CONFIG_USB_U132_HCD)	+= host/
-obj-$(CONFIG_USB_OHCI_AT91)	+= host/
+obj-$(CONFIG_USB_R8A66597_HCD)	+= host/
 
 
 obj-$(CONFIG_USB_ACM)		+= class/
 obj-$(CONFIG_USB_ACM)		+= class/
 obj-$(CONFIG_USB_PRINTER)	+= class/
 obj-$(CONFIG_USB_PRINTER)	+= class/

+ 31 - 42
drivers/usb/atm/cxacru.c

@@ -171,7 +171,7 @@ struct cxacru_data {
 	struct delayed_work poll_work;
 	struct delayed_work poll_work;
 	u32 card_info[CXINF_MAX];
 	u32 card_info[CXINF_MAX];
 	struct mutex poll_state_serialize;
 	struct mutex poll_state_serialize;
-	int poll_state;
+	enum cxacru_poll_state poll_state;
 
 
 	/* contol handles */
 	/* contol handles */
 	struct mutex cm_serialize;
 	struct mutex cm_serialize;
@@ -226,58 +226,48 @@ static ssize_t cxacru_sysfs_showattr_s8(s8 value, char *buf)
 
 
 static ssize_t cxacru_sysfs_showattr_dB(s16 value, char *buf)
 static ssize_t cxacru_sysfs_showattr_dB(s16 value, char *buf)
 {
 {
-	if (unlikely(value < 0)) {
-		return snprintf(buf, PAGE_SIZE, "%d.%02u\n",
-						value / 100, -value % 100);
-	} else {
-		return snprintf(buf, PAGE_SIZE, "%d.%02u\n",
-						value / 100, value % 100);
-	}
+	return snprintf(buf, PAGE_SIZE, "%d.%02u\n",
+					value / 100, abs(value) % 100);
 }
 }
 
 
 static ssize_t cxacru_sysfs_showattr_bool(u32 value, char *buf)
 static ssize_t cxacru_sysfs_showattr_bool(u32 value, char *buf)
 {
 {
-	switch (value) {
-	case 0: return snprintf(buf, PAGE_SIZE, "no\n");
-	case 1: return snprintf(buf, PAGE_SIZE, "yes\n");
-	default: return 0;
-	}
+	static char *str[] = { "no", "yes" };
+	if (unlikely(value >= ARRAY_SIZE(str)))
+		return snprintf(buf, PAGE_SIZE, "%u\n", value);
+	return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
 }
 }
 
 
 static ssize_t cxacru_sysfs_showattr_LINK(u32 value, char *buf)
 static ssize_t cxacru_sysfs_showattr_LINK(u32 value, char *buf)
 {
 {
-	switch (value) {
-	case 1: return snprintf(buf, PAGE_SIZE, "not connected\n");
-	case 2: return snprintf(buf, PAGE_SIZE, "connected\n");
-	case 3: return snprintf(buf, PAGE_SIZE, "lost\n");
-	default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
-	}
+	static char *str[] = { NULL, "not connected", "connected", "lost" };
+	if (unlikely(value >= ARRAY_SIZE(str) || str[value] == NULL))
+		return snprintf(buf, PAGE_SIZE, "%u\n", value);
+	return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
 }
 }
 
 
 static ssize_t cxacru_sysfs_showattr_LINE(u32 value, char *buf)
 static ssize_t cxacru_sysfs_showattr_LINE(u32 value, char *buf)
 {
 {
-	switch (value) {
-	case 0: return snprintf(buf, PAGE_SIZE, "down\n");
-	case 1: return snprintf(buf, PAGE_SIZE, "attempting to activate\n");
-	case 2: return snprintf(buf, PAGE_SIZE, "training\n");
-	case 3: return snprintf(buf, PAGE_SIZE, "channel analysis\n");
-	case 4: return snprintf(buf, PAGE_SIZE, "exchange\n");
-	case 5: return snprintf(buf, PAGE_SIZE, "up\n");
-	case 6: return snprintf(buf, PAGE_SIZE, "waiting\n");
-	case 7: return snprintf(buf, PAGE_SIZE, "initialising\n");
-	default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
-	}
+	static char *str[] = { "down", "attempting to activate",
+		"training", "channel analysis", "exchange", "up",
+		"waiting", "initialising"
+	};
+	if (unlikely(value >= ARRAY_SIZE(str)))
+		return snprintf(buf, PAGE_SIZE, "%u\n", value);
+	return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
 }
 }
 
 
 static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf)
 static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf)
 {
 {
-	switch (value) {
-	case 0: return 0;
-	case 1: return snprintf(buf, PAGE_SIZE, "ANSI T1.413\n");
-	case 2: return snprintf(buf, PAGE_SIZE, "ITU-T G.992.1 (G.DMT)\n");
-	case 3: return snprintf(buf, PAGE_SIZE, "ITU-T G.992.2 (G.LITE)\n");
-	default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
-	}
+	static char *str[] = {
+			NULL,
+			"ANSI T1.413",
+			"ITU-T G.992.1 (G.DMT)",
+			"ITU-T G.992.2 (G.LITE)"
+	};
+	if (unlikely(value >= ARRAY_SIZE(str) || str[value] == NULL))
+		return snprintf(buf, PAGE_SIZE, "%u\n", value);
+	return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
 }
 }
 
 
 /*
 /*
@@ -308,11 +298,10 @@ static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev,
 	struct cxacru_data *instance = usbatm_instance->driver_data;
 	struct cxacru_data *instance = usbatm_instance->driver_data;
 	u32 value = instance->card_info[CXINF_LINE_STARTABLE];
 	u32 value = instance->card_info[CXINF_LINE_STARTABLE];
 
 
-	switch (value) {
-	case 0: return snprintf(buf, PAGE_SIZE, "running\n");
-	case 1: return snprintf(buf, PAGE_SIZE, "stopped\n");
-	default: return snprintf(buf, PAGE_SIZE, "unknown (%u)\n", value);
-	}
+	static char *str[] = { "running", "stopped" };
+	if (unlikely(value >= ARRAY_SIZE(str)))
+		return snprintf(buf, PAGE_SIZE, "%u\n", value);
+	return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
 }
 }
 
 
 static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
 static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,

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

@@ -1157,6 +1157,9 @@ static struct usb_device_id acm_ids[] = {
 	{ USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
 	{ USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
 	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
 	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
 	},
 	},
+	{ USB_DEVICE(0x0e8d, 0x0003), /* FIREFLY, MediaTek Inc; andrey.arapov@gmail.com */
+	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
+	},
 	{ USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
 	{ USB_DEVICE(0x0482, 0x0203), /* KYOCERA AH-K3001V */
 	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
 	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
 	},
 	},

+ 376 - 242
drivers/usb/class/usblp.c

@@ -1,5 +1,5 @@
 /*
 /*
- * usblp.c  Version 0.13
+ * usblp.c
  *
  *
  * Copyright (c) 1999 Michael Gee	<michael@linuxspecific.com>
  * Copyright (c) 1999 Michael Gee	<michael@linuxspecific.com>
  * Copyright (c) 1999 Pavel Machek	<pavel@suse.cz>
  * Copyright (c) 1999 Pavel Machek	<pavel@suse.cz>
@@ -61,11 +61,11 @@
 /*
 /*
  * Version Information
  * Version Information
  */
  */
-#define DRIVER_VERSION "v0.13"
 #define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal"
 #define DRIVER_AUTHOR "Michael Gee, Pavel Machek, Vojtech Pavlik, Randy Dunlap, Pete Zaitcev, David Paschal"
 #define DRIVER_DESC "USB Printer Device Class driver"
 #define DRIVER_DESC "USB Printer Device Class driver"
 
 
 #define USBLP_BUF_SIZE		8192
 #define USBLP_BUF_SIZE		8192
+#define USBLP_BUF_SIZE_IN	1024
 #define USBLP_DEVICE_ID_SIZE	1024
 #define USBLP_DEVICE_ID_SIZE	1024
 
 
 /* ioctls: */
 /* ioctls: */
@@ -127,14 +127,22 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
  */
  */
 #define STATUS_BUF_SIZE		8
 #define STATUS_BUF_SIZE		8
 
 
+/*
+ * Locks down the locking order:
+ * ->wmut locks wstatus.
+ * ->mut locks the whole usblp, except [rw]complete, and thus, by indirection,
+ * [rw]status. We only touch status when we know the side idle.
+ * ->lock locks what interrupt accesses.
+ */
 struct usblp {
 struct usblp {
 	struct usb_device 	*dev;			/* USB device */
 	struct usb_device 	*dev;			/* USB device */
-	struct mutex		mut;			/* locks this struct, especially "dev" */
-	char			*writebuf;		/* write transfer_buffer */
+	struct mutex		wmut;
+	struct mutex		mut;
+	spinlock_t		lock;		/* locks rcomplete, wcomplete */
 	char			*readbuf;		/* read transfer_buffer */
 	char			*readbuf;		/* read transfer_buffer */
 	char			*statusbuf;		/* status transfer_buffer */
 	char			*statusbuf;		/* status transfer_buffer */
-	struct urb		*readurb, *writeurb;	/* The urbs */
-	wait_queue_head_t	wait;			/* Zzzzz ... */
+	struct usb_anchor	urbs;
+	wait_queue_head_t	rwait, wwait;
 	int			readcount;		/* Counter for reads */
 	int			readcount;		/* Counter for reads */
 	int			ifnum;			/* Interface number */
 	int			ifnum;			/* Interface number */
 	struct usb_interface	*intf;			/* The interface */
 	struct usb_interface	*intf;			/* The interface */
@@ -147,8 +155,9 @@ struct usblp {
 	}			protocol[USBLP_MAX_PROTOCOLS];
 	}			protocol[USBLP_MAX_PROTOCOLS];
 	int			current_protocol;
 	int			current_protocol;
 	int			minor;			/* minor number of device */
 	int			minor;			/* minor number of device */
-	int			wcomplete;		/* writing is completed */
-	int			rcomplete;		/* reading is completed */
+	int			wcomplete, rcomplete;
+	int			wstatus;	/* bytes written or error */
+	int			rstatus;	/* bytes ready or error */
 	unsigned int		quirks;			/* quirks flags */
 	unsigned int		quirks;			/* quirks flags */
 	unsigned char		used;			/* True if open */
 	unsigned char		used;			/* True if open */
 	unsigned char		present;		/* True if not disconnected */
 	unsigned char		present;		/* True if not disconnected */
@@ -166,9 +175,6 @@ static void usblp_dump(struct usblp *usblp) {
 	dbg("dev=0x%p", usblp->dev);
 	dbg("dev=0x%p", usblp->dev);
 	dbg("present=%d", usblp->present);
 	dbg("present=%d", usblp->present);
 	dbg("readbuf=0x%p", usblp->readbuf);
 	dbg("readbuf=0x%p", usblp->readbuf);
-	dbg("writebuf=0x%p", usblp->writebuf);
-	dbg("readurb=0x%p", usblp->readurb);
-	dbg("writeurb=0x%p", usblp->writeurb);
 	dbg("readcount=%d", usblp->readcount);
 	dbg("readcount=%d", usblp->readcount);
 	dbg("ifnum=%d", usblp->ifnum);
 	dbg("ifnum=%d", usblp->ifnum);
     for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) {
     for (p = USBLP_FIRST_PROTOCOL; p <= USBLP_LAST_PROTOCOL; p++) {
@@ -178,8 +184,8 @@ static void usblp_dump(struct usblp *usblp) {
     }
     }
 	dbg("current_protocol=%d", usblp->current_protocol);
 	dbg("current_protocol=%d", usblp->current_protocol);
 	dbg("minor=%d", usblp->minor);
 	dbg("minor=%d", usblp->minor);
-	dbg("wcomplete=%d", usblp->wcomplete);
-	dbg("rcomplete=%d", usblp->rcomplete);
+	dbg("wstatus=%d", usblp->wstatus);
+	dbg("rstatus=%d", usblp->rstatus);
 	dbg("quirks=%d", usblp->quirks);
 	dbg("quirks=%d", usblp->quirks);
 	dbg("used=%d", usblp->used);
 	dbg("used=%d", usblp->used);
 	dbg("bidir=%d", usblp->bidir);
 	dbg("bidir=%d", usblp->bidir);
@@ -222,6 +228,11 @@ static const struct quirk_printer_struct quirk_printers[] = {
 	{ 0, 0 }
 	{ 0, 0 }
 };
 };
 
 
+static int usblp_wwait(struct usblp *usblp, int nonblock);
+static int usblp_wtest(struct usblp *usblp, int nonblock);
+static int usblp_rwait_and_lock(struct usblp *usblp, int nonblock);
+static int usblp_rtest(struct usblp *usblp, int nonblock);
+static int usblp_submit_read(struct usblp *usblp);
 static int usblp_select_alts(struct usblp *usblp);
 static int usblp_select_alts(struct usblp *usblp);
 static int usblp_set_protocol(struct usblp *usblp, int protocol);
 static int usblp_set_protocol(struct usblp *usblp, int protocol);
 static int usblp_cache_device_id_string(struct usblp *usblp);
 static int usblp_cache_device_id_string(struct usblp *usblp);
@@ -279,33 +290,47 @@ static void usblp_bulk_read(struct urb *urb)
 {
 {
 	struct usblp *usblp = urb->context;
 	struct usblp *usblp = urb->context;
 
 
-	if (unlikely(!usblp || !usblp->dev || !usblp->used))
-		return;
-
-	if (unlikely(!usblp->present))
-		goto unplug;
-	if (unlikely(urb->status))
-		warn("usblp%d: nonzero read/write bulk status received: %d",
-			usblp->minor, urb->status);
+	if (usblp->present && usblp->used) {
+		if (urb->status)
+			printk(KERN_WARNING "usblp%d: "
+			    "nonzero read bulk status received: %d\n",
+			    usblp->minor, urb->status);
+	}
+	spin_lock(&usblp->lock);
+	if (urb->status < 0)
+		usblp->rstatus = urb->status;
+	else
+		usblp->rstatus = urb->actual_length;
 	usblp->rcomplete = 1;
 	usblp->rcomplete = 1;
-unplug:
-	wake_up_interruptible(&usblp->wait);
+	wake_up(&usblp->rwait);
+	spin_unlock(&usblp->lock);
+
+	usb_free_urb(urb);
 }
 }
 
 
 static void usblp_bulk_write(struct urb *urb)
 static void usblp_bulk_write(struct urb *urb)
 {
 {
 	struct usblp *usblp = urb->context;
 	struct usblp *usblp = urb->context;
 
 
-	if (unlikely(!usblp || !usblp->dev || !usblp->used))
-		return;
-	if (unlikely(!usblp->present))
-		goto unplug;
-	if (unlikely(urb->status))
-		warn("usblp%d: nonzero read/write bulk status received: %d",
-			usblp->minor, urb->status);
+	if (usblp->present && usblp->used) {
+		if (urb->status)
+			printk(KERN_WARNING "usblp%d: "
+			    "nonzero write bulk status received: %d\n",
+			    usblp->minor, urb->status);
+	}
+	spin_lock(&usblp->lock);
+	if (urb->status < 0)
+		usblp->wstatus = urb->status;
+	else
+		usblp->wstatus = urb->actual_length;
 	usblp->wcomplete = 1;
 	usblp->wcomplete = 1;
-unplug:
-	wake_up_interruptible(&usblp->wait);
+	wake_up(&usblp->wwait);
+	spin_unlock(&usblp->lock);
+
+	/* XXX Use usb_setup_bulk_urb when available. Talk to Marcel. */
+	kfree(urb->transfer_buffer);
+	urb->transfer_buffer = NULL;	/* Not refcounted, so to be safe... */
+	usb_free_urb(urb);
 }
 }
 
 
 /*
 /*
@@ -322,7 +347,8 @@ static int usblp_check_status(struct usblp *usblp, int err)
 	error = usblp_read_status (usblp, usblp->statusbuf);
 	error = usblp_read_status (usblp, usblp->statusbuf);
 	if (error < 0) {
 	if (error < 0) {
 		if (printk_ratelimit())
 		if (printk_ratelimit())
-			err("usblp%d: error %d reading printer status",
+			printk(KERN_ERR
+				"usblp%d: error %d reading printer status\n",
 				usblp->minor, error);
 				usblp->minor, error);
 		return 0;
 		return 0;
 	}
 	}
@@ -336,8 +362,10 @@ static int usblp_check_status(struct usblp *usblp, int err)
 	if (~status & LP_PSELECD)
 	if (~status & LP_PSELECD)
 		newerr = 2;
 		newerr = 2;
 
 
-	if (newerr != err)
-		info("usblp%d: %s", usblp->minor, usblp_messages[newerr]);
+	if (newerr != err) {
+		printk(KERN_INFO "usblp%d: %s\n",
+		   usblp->minor, usblp_messages[newerr]);
+	}
 
 
 	return newerr;
 	return newerr;
 }
 }
@@ -345,12 +373,9 @@ static int usblp_check_status(struct usblp *usblp, int err)
 static int handle_bidir (struct usblp *usblp)
 static int handle_bidir (struct usblp *usblp)
 {
 {
 	if (usblp->bidir && usblp->used && !usblp->sleeping) {
 	if (usblp->bidir && usblp->used && !usblp->sleeping) {
-		usblp->readcount = 0;
-		usblp->readurb->dev = usblp->dev;
-		if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0)
+		if (usblp_submit_read(usblp) < 0)
 			return -EIO;
 			return -EIO;
 	}
 	}
-
 	return 0;
 	return 0;
 }
 }
 
 
@@ -403,11 +428,9 @@ static int usblp_open(struct inode *inode, struct file *file)
 	usblp->used = 1;
 	usblp->used = 1;
 	file->private_data = usblp;
 	file->private_data = usblp;
 
 
-	usblp->writeurb->transfer_buffer_length = 0;
 	usblp->wcomplete = 1; /* we begin writeable */
 	usblp->wcomplete = 1; /* we begin writeable */
+	usblp->wstatus = 0;
 	usblp->rcomplete = 0;
 	usblp->rcomplete = 0;
-	usblp->writeurb->status = 0;
-	usblp->readurb->status = 0;
 
 
 	if (handle_bidir(usblp) < 0) {
 	if (handle_bidir(usblp) < 0) {
 		usblp->used = 0;
 		usblp->used = 0;
@@ -421,20 +444,17 @@ out:
 
 
 static void usblp_cleanup (struct usblp *usblp)
 static void usblp_cleanup (struct usblp *usblp)
 {
 {
-	info("usblp%d: removed", usblp->minor);
+	printk(KERN_INFO "usblp%d: removed\n", usblp->minor);
 
 
+	kfree(usblp->readbuf);
 	kfree (usblp->device_id_string);
 	kfree (usblp->device_id_string);
 	kfree (usblp->statusbuf);
 	kfree (usblp->statusbuf);
-	usb_free_urb(usblp->writeurb);
-	usb_free_urb(usblp->readurb);
 	kfree (usblp);
 	kfree (usblp);
 }
 }
 
 
 static void usblp_unlink_urbs(struct usblp *usblp)
 static void usblp_unlink_urbs(struct usblp *usblp)
 {
 {
-	usb_kill_urb(usblp->writeurb);
-	if (usblp->bidir)
-		usb_kill_urb(usblp->readurb);
+	usb_kill_anchored_urbs(&usblp->urbs);
 }
 }
 
 
 static int usblp_release(struct inode *inode, struct file *file)
 static int usblp_release(struct inode *inode, struct file *file)
@@ -455,10 +475,18 @@ static int usblp_release(struct inode *inode, struct file *file)
 /* No kernel lock - fine */
 /* No kernel lock - fine */
 static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait)
 static unsigned int usblp_poll(struct file *file, struct poll_table_struct *wait)
 {
 {
+	int ret;
+	unsigned long flags;
+
 	struct usblp *usblp = file->private_data;
 	struct usblp *usblp = file->private_data;
-	poll_wait(file, &usblp->wait, wait);
- 	return ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN  | POLLRDNORM)
+	/* Should we check file->f_mode & FMODE_WRITE before poll_wait()? */
+	poll_wait(file, &usblp->rwait, wait);
+	poll_wait(file, &usblp->wwait, wait);
+	spin_lock_irqsave(&usblp->lock, flags);
+	ret = ((!usblp->bidir || !usblp->rcomplete) ? 0 : POLLIN  | POLLRDNORM)
  			       | (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM);
  			       | (!usblp->wcomplete ? 0 : POLLOUT | POLLWRNORM);
+	spin_unlock_irqrestore(&usblp->lock, flags);
+	return ret;
 }
 }
 
 
 static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
@@ -632,10 +660,11 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 		switch (cmd) {
 		switch (cmd) {
 
 
 			case LPGETSTATUS:
 			case LPGETSTATUS:
-				if (usblp_read_status(usblp, usblp->statusbuf)) {
+				if ((retval = usblp_read_status(usblp, usblp->statusbuf))) {
 					if (printk_ratelimit())
 					if (printk_ratelimit())
-						err("usblp%d: failed reading printer status",
-							usblp->minor);
+						printk(KERN_ERR "usblp%d:"
+						    "failed reading printer status (%d)\n",
+						    usblp->minor, retval);
 					retval = -EIO;
 					retval = -EIO;
 					goto done;
 					goto done;
 				}
 				}
@@ -656,168 +685,303 @@ done:
 static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 {
 {
 	struct usblp *usblp = file->private_data;
 	struct usblp *usblp = file->private_data;
-	int timeout, intr, rv, err = 0, transfer_length = 0;
-	size_t writecount = 0;
+	char *writebuf;
+	struct urb *writeurb;
+	int rv;
+	int transfer_length;
+	ssize_t writecount = 0;
+
+	if (mutex_lock_interruptible(&usblp->wmut)) {
+		rv = -EINTR;
+		goto raise_biglock;
+	}
+	if ((rv = usblp_wwait(usblp, !!(file->f_flags & O_NONBLOCK))) < 0)
+		goto raise_wait;
 
 
 	while (writecount < count) {
 	while (writecount < count) {
-		if (!usblp->wcomplete) {
-			barrier();
-			if (file->f_flags & O_NONBLOCK) {
-				writecount += transfer_length;
-				return writecount ? writecount : -EAGAIN;
-			}
-
-			timeout = USBLP_WRITE_TIMEOUT;
-
-			rv = wait_event_interruptible_timeout(usblp->wait, usblp->wcomplete || !usblp->present , timeout);
-			if (rv < 0)
-				return writecount ? writecount : -EINTR;
-		}
-		intr = mutex_lock_interruptible (&usblp->mut);
-		if (intr)
-			return writecount ? writecount : -EINTR;
-		if (!usblp->present) {
-			mutex_unlock (&usblp->mut);
-			return -ENODEV;
-		}
-
-		if (usblp->sleeping) {
-			mutex_unlock (&usblp->mut);
-			return writecount ? writecount : -ENODEV;
-		}
-
-		if (usblp->writeurb->status != 0) {
-			if (usblp->quirks & USBLP_QUIRK_BIDIR) {
-				if (!usblp->wcomplete)
-					err("usblp%d: error %d writing to printer",
-						usblp->minor, usblp->writeurb->status);
-				err = usblp->writeurb->status;
-			} else
-				err = usblp_check_status(usblp, err);
-			mutex_unlock (&usblp->mut);
-
-			/* if the fault was due to disconnect, let khubd's
-			 * call to usblp_disconnect() grab usblp->mut ...
-			 */
-			schedule ();
-			continue;
-		}
-
-		/* We must increment writecount here, and not at the
-		 * end of the loop. Otherwise, the final loop iteration may
-		 * be skipped, leading to incomplete printer output.
+		/*
+		 * Step 1: Submit next block.
 		 */
 		 */
-		writecount += transfer_length;
-		if (writecount == count) {
-			mutex_unlock(&usblp->mut);
-			break;
-		}
-
-		transfer_length=(count - writecount);
-		if (transfer_length > USBLP_BUF_SIZE)
+		if ((transfer_length = count - writecount) > USBLP_BUF_SIZE)
 			transfer_length = USBLP_BUF_SIZE;
 			transfer_length = USBLP_BUF_SIZE;
 
 
-		usblp->writeurb->transfer_buffer_length = transfer_length;
-
-		if (copy_from_user(usblp->writeurb->transfer_buffer, 
+		rv = -ENOMEM;
+		if ((writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL)) == NULL)
+			goto raise_buf;
+		if ((writeurb = usb_alloc_urb(0, GFP_KERNEL)) == NULL)
+			goto raise_urb;
+		usb_fill_bulk_urb(writeurb, usblp->dev,
+			usb_sndbulkpipe(usblp->dev,
+			  usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
+			writebuf, transfer_length, usblp_bulk_write, usblp);
+		usb_anchor_urb(writeurb, &usblp->urbs);
+
+		if (copy_from_user(writebuf,
 				   buffer + writecount, transfer_length)) {
 				   buffer + writecount, transfer_length)) {
-			mutex_unlock(&usblp->mut);
-			return writecount ? writecount : -EFAULT;
+			rv = -EFAULT;
+			goto raise_badaddr;
 		}
 		}
 
 
-		usblp->writeurb->dev = usblp->dev;
+		spin_lock_irq(&usblp->lock);
 		usblp->wcomplete = 0;
 		usblp->wcomplete = 0;
-		err = usb_submit_urb(usblp->writeurb, GFP_KERNEL);
-		if (err) {
+		spin_unlock_irq(&usblp->lock);
+		if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) {
+			usblp->wstatus = 0;
+			spin_lock_irq(&usblp->lock);
 			usblp->wcomplete = 1;
 			usblp->wcomplete = 1;
-			if (err != -ENOMEM)
-				count = -EIO;
-			else
-				count = writecount ? writecount : -ENOMEM;
-			mutex_unlock (&usblp->mut);
-			break;
+			wake_up(&usblp->wwait);
+			spin_unlock_irq(&usblp->lock);
+			if (rv != -ENOMEM)
+				rv = -EIO;
+			goto raise_submit;
+		}
+
+		/*
+		 * Step 2: Wait for transfer to end, collect results.
+		 */
+		rv = usblp_wwait(usblp, !!(file->f_flags&O_NONBLOCK));
+		if (rv < 0) {
+			/*
+			 * If interrupted, we simply leave the URB to dangle,
+			 * so the ->release will call usb_kill_urb().
+			 */
+			goto collect_error;
 		}
 		}
-		mutex_unlock (&usblp->mut);
+
+		if (usblp->wstatus < 0) {
+			usblp_check_status(usblp, 0);
+			rv = -EIO;
+			goto collect_error;
+		}
+		/*
+		 * This is critical: it must be our URB, not other writer's.
+		 * The wmut exists mainly to cover us here.
+		 */
+		writecount += usblp->wstatus;
 	}
 	}
 
 
-	return count;
+	mutex_unlock(&usblp->wmut);
+	return writecount;
+
+raise_submit:
+raise_badaddr:
+	usb_unanchor_urb(writeurb);
+	usb_free_urb(writeurb);
+raise_urb:
+	kfree(writebuf);
+raise_buf:
+raise_wait:
+collect_error:		/* Out of raise sequence */
+	mutex_unlock(&usblp->wmut);
+raise_biglock:
+	return writecount ? writecount : rv;
 }
 }
 
 
-static ssize_t usblp_read(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
+/*
+ * Notice that we fail to restart in a few cases: on EFAULT, on restart
+ * error, etc. This is the historical behaviour. In all such cases we return
+ * EIO, and applications loop in order to get the new read going.
+ */
+static ssize_t usblp_read(struct file *file, char __user *buffer, size_t len, loff_t *ppos)
 {
 {
 	struct usblp *usblp = file->private_data;
 	struct usblp *usblp = file->private_data;
-	int rv, intr;
+	ssize_t count;
+	ssize_t avail;
+	int rv;
 
 
 	if (!usblp->bidir)
 	if (!usblp->bidir)
 		return -EINVAL;
 		return -EINVAL;
 
 
-	intr = mutex_lock_interruptible (&usblp->mut);
-	if (intr)
-		return -EINTR;
-	if (!usblp->present) {
-		count = -ENODEV;
+	rv = usblp_rwait_and_lock(usblp, !!(file->f_flags & O_NONBLOCK));
+	if (rv < 0)
+		return rv;
+
+	if ((avail = usblp->rstatus) < 0) {
+		printk(KERN_ERR "usblp%d: error %d reading from printer\n",
+		    usblp->minor, (int)avail);
+		usblp_submit_read(usblp);
+		count = -EIO;
 		goto done;
 		goto done;
 	}
 	}
 
 
-	if (!usblp->rcomplete) {
-		barrier();
+	count = len < avail - usblp->readcount ? len : avail - usblp->readcount;
+	if (count != 0 &&
+	    copy_to_user(buffer, usblp->readbuf + usblp->readcount, count)) {
+		count = -EFAULT;
+		goto done;
+	}
 
 
-		if (file->f_flags & O_NONBLOCK) {
-			count = -EAGAIN;
-			goto done;
-		}
-		mutex_unlock(&usblp->mut);
-		rv = wait_event_interruptible(usblp->wait, usblp->rcomplete || !usblp->present);
-		mutex_lock(&usblp->mut);
-		if (rv < 0) {
-			count = -EINTR;
+	if ((usblp->readcount += count) == avail) {
+		if (usblp_submit_read(usblp) < 0) {
+			/* We don't want to leak USB return codes into errno. */
+			if (count == 0)
+				count = -EIO;
 			goto done;
 			goto done;
 		}
 		}
 	}
 	}
 
 
-	if (!usblp->present) {
-		count = -ENODEV;
-		goto done;
+done:
+	mutex_unlock (&usblp->mut);
+	return count;
+}
+
+/*
+ * Wait for the write path to come idle.
+ * This is called under the ->wmut, so the idle path stays idle.
+ *
+ * Our write path has a peculiar property: it does not buffer like a tty,
+ * but waits for the write to succeed. This allows our ->release to bug out
+ * without waiting for writes to drain. But it obviously does not work
+ * when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use
+ * select(2) or poll(2) to wait for the buffer to drain before closing.
+ * Alternatively, set blocking mode with fcntl and issue a zero-size write.
+ *
+ * Old v0.13 code had a non-functional timeout for wait_event(). Someone forgot
+ * to check the return code for timeout expiration, so it had no effect.
+ * Apparently, it was intended to check for error conditons, such as out
+ * of paper. It is going to return when we settle things with CUPS. XXX
+ */
+static int usblp_wwait(struct usblp *usblp, int nonblock)
+{
+	DECLARE_WAITQUEUE(waita, current);
+	int rc;
+
+	add_wait_queue(&usblp->wwait, &waita);
+	for (;;) {
+		if (mutex_lock_interruptible(&usblp->mut)) {
+			rc = -EINTR;
+			break;
+		}
+		set_current_state(TASK_INTERRUPTIBLE);
+		if ((rc = usblp_wtest(usblp, nonblock)) < 0) {
+			mutex_unlock(&usblp->mut);
+			break;
+		}
+		mutex_unlock(&usblp->mut);
+		if (rc == 0)
+			break;
+		schedule();
 	}
 	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&usblp->wwait, &waita);
+	return rc;
+}
 
 
-	if (usblp->sleeping) {
-		count = -ENODEV;
-		goto done;
+static int usblp_wtest(struct usblp *usblp, int nonblock)
+{
+	unsigned long flags;
+
+	if (!usblp->present)
+		return -ENODEV;
+	if (signal_pending(current))
+		return -EINTR;
+	spin_lock_irqsave(&usblp->lock, flags);
+	if (usblp->wcomplete) {
+		spin_unlock_irqrestore(&usblp->lock, flags);
+		return 0;
 	}
 	}
+	spin_unlock_irqrestore(&usblp->lock, flags);
+	if (usblp->sleeping)
+		return -ENODEV;
+	if (nonblock)
+		return -EAGAIN;
+	return 1;
+}
 
 
-	if (usblp->readurb->status) {
-		err("usblp%d: error %d reading from printer",
-			usblp->minor, usblp->readurb->status);
-		usblp->readurb->dev = usblp->dev;
- 		usblp->readcount = 0;
-		usblp->rcomplete = 0;
-		if (usb_submit_urb(usblp->readurb, GFP_KERNEL) < 0)
-			dbg("error submitting urb");
-		count = -EIO;
-		goto done;
+/*
+ * Wait for read bytes to become available. This probably should have been
+ * called usblp_r_lock_and_wait(), because we lock first. But it's a traditional
+ * name for functions which lock and return.
+ *
+ * We do not use wait_event_interruptible because it makes locking iffy.
+ */
+static int usblp_rwait_and_lock(struct usblp *usblp, int nonblock)
+{
+	DECLARE_WAITQUEUE(waita, current);
+	int rc;
+
+	add_wait_queue(&usblp->rwait, &waita);
+	for (;;) {
+		if (mutex_lock_interruptible(&usblp->mut)) {
+			rc = -EINTR;
+			break;
+		}
+		set_current_state(TASK_INTERRUPTIBLE);
+		if ((rc = usblp_rtest(usblp, nonblock)) < 0) {
+			mutex_unlock(&usblp->mut);
+			break;
+		}
+		if (rc == 0)	/* Keep it locked */
+			break;
+		mutex_unlock(&usblp->mut);
+		schedule();
 	}
 	}
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&usblp->rwait, &waita);
+	return rc;
+}
 
 
-	count = count < usblp->readurb->actual_length - usblp->readcount ?
-		count :	usblp->readurb->actual_length - usblp->readcount;
+static int usblp_rtest(struct usblp *usblp, int nonblock)
+{
+	unsigned long flags;
 
 
-	if (copy_to_user(buffer, usblp->readurb->transfer_buffer + usblp->readcount, count)) {
-		count = -EFAULT;
-		goto done;
+	if (!usblp->present)
+		return -ENODEV;
+	if (signal_pending(current))
+		return -EINTR;
+	spin_lock_irqsave(&usblp->lock, flags);
+	if (usblp->rcomplete) {
+		spin_unlock_irqrestore(&usblp->lock, flags);
+		return 0;
 	}
 	}
+	spin_unlock_irqrestore(&usblp->lock, flags);
+	if (usblp->sleeping)
+		return -ENODEV;
+	if (nonblock)
+		return -EAGAIN;
+	return 1;
+}
 
 
-	if ((usblp->readcount += count) == usblp->readurb->actual_length) {
-		usblp->readcount = 0;
-		usblp->readurb->dev = usblp->dev;
-		usblp->rcomplete = 0;
-		if (usb_submit_urb(usblp->readurb, GFP_KERNEL)) {
-			count = -EIO;
-			goto done;
-		}
+/*
+ * Please check ->bidir and other such things outside for now.
+ */
+static int usblp_submit_read(struct usblp *usblp)
+{
+	struct urb *urb;
+	unsigned long flags;
+	int rc;
+
+	rc = -ENOMEM;
+	if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL)
+		goto raise_urb;
+
+	usb_fill_bulk_urb(urb, usblp->dev,
+		usb_rcvbulkpipe(usblp->dev,
+		  usblp->protocol[usblp->current_protocol].epread->bEndpointAddress),
+		usblp->readbuf, USBLP_BUF_SIZE_IN,
+		usblp_bulk_read, usblp);
+	usb_anchor_urb(urb, &usblp->urbs);
+
+	spin_lock_irqsave(&usblp->lock, flags);
+	usblp->readcount = 0; /* XXX Why here? */
+	usblp->rcomplete = 0;
+	spin_unlock_irqrestore(&usblp->lock, flags);
+	if ((rc = usb_submit_urb(urb, GFP_KERNEL)) < 0) {
+		dbg("error submitting urb (%d)", rc);
+		spin_lock_irqsave(&usblp->lock, flags);
+		usblp->rstatus = rc;
+		usblp->rcomplete = 1;
+		spin_unlock_irqrestore(&usblp->lock, flags);
+		goto raise_submit;
 	}
 	}
 
 
-done:
-	mutex_unlock (&usblp->mut);
-	return count;
+	return 0;
+
+raise_submit:
+	usb_unanchor_urb(urb);
+	usb_free_urb(urb);
+raise_urb:
+	return rc;
 }
 }
 
 
 /*
 /*
@@ -891,55 +1055,41 @@ static int usblp_probe(struct usb_interface *intf,
 	/* Malloc and start initializing usblp structure so we can use it
 	/* Malloc and start initializing usblp structure so we can use it
 	 * directly. */
 	 * directly. */
 	if (!(usblp = kzalloc(sizeof(struct usblp), GFP_KERNEL))) {
 	if (!(usblp = kzalloc(sizeof(struct usblp), GFP_KERNEL))) {
-		err("out of memory for usblp");
+		retval = -ENOMEM;
 		goto abort;
 		goto abort;
 	}
 	}
 	usblp->dev = dev;
 	usblp->dev = dev;
+	mutex_init(&usblp->wmut);
 	mutex_init (&usblp->mut);
 	mutex_init (&usblp->mut);
-	init_waitqueue_head(&usblp->wait);
+	spin_lock_init(&usblp->lock);
+	init_waitqueue_head(&usblp->rwait);
+	init_waitqueue_head(&usblp->wwait);
+	init_usb_anchor(&usblp->urbs);
 	usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
 	usblp->ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
 	usblp->intf = intf;
 	usblp->intf = intf;
 
 
-	usblp->writeurb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!usblp->writeurb) {
-		err("out of memory");
-		goto abort;
-	}
-	usblp->readurb = usb_alloc_urb(0, GFP_KERNEL);
-	if (!usblp->readurb) {
-		err("out of memory");
-		goto abort;
-	}
-
 	/* Malloc device ID string buffer to the largest expected length,
 	/* Malloc device ID string buffer to the largest expected length,
 	 * since we can re-query it on an ioctl and a dynamic string
 	 * since we can re-query it on an ioctl and a dynamic string
 	 * could change in length. */
 	 * could change in length. */
 	if (!(usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL))) {
 	if (!(usblp->device_id_string = kmalloc(USBLP_DEVICE_ID_SIZE, GFP_KERNEL))) {
-		err("out of memory for device_id_string");
+		retval = -ENOMEM;
 		goto abort;
 		goto abort;
 	}
 	}
 
 
-	usblp->writebuf = usblp->readbuf = NULL;
-	usblp->writeurb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
-	usblp->readurb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
-	/* Malloc write & read buffers.  We somewhat wastefully
+	/*
+	 * Allocate read buffer. We somewhat wastefully
 	 * malloc both regardless of bidirectionality, because the
 	 * malloc both regardless of bidirectionality, because the
-	 * alternate setting can be changed later via an ioctl. */
-	if (!(usblp->writebuf = usb_buffer_alloc(dev, USBLP_BUF_SIZE,
-				GFP_KERNEL, &usblp->writeurb->transfer_dma))) {
-		err("out of memory for write buf");
-		goto abort;
-	}
-	if (!(usblp->readbuf = usb_buffer_alloc(dev, USBLP_BUF_SIZE,
-				GFP_KERNEL, &usblp->readurb->transfer_dma))) {
-		err("out of memory for read buf");
+	 * alternate setting can be changed later via an ioctl.
+	 */
+	if (!(usblp->readbuf = kmalloc(USBLP_BUF_SIZE_IN, GFP_KERNEL))) {
+		retval = -ENOMEM;
 		goto abort;
 		goto abort;
 	}
 	}
 
 
 	/* Allocate buffer for printer status */
 	/* Allocate buffer for printer status */
 	usblp->statusbuf = kmalloc(STATUS_BUF_SIZE, GFP_KERNEL);
 	usblp->statusbuf = kmalloc(STATUS_BUF_SIZE, GFP_KERNEL);
 	if (!usblp->statusbuf) {
 	if (!usblp->statusbuf) {
-		err("out of memory for statusbuf");
+		retval = -ENOMEM;
 		goto abort;
 		goto abort;
 	}
 	}
 
 
@@ -954,12 +1104,15 @@ static int usblp_probe(struct usb_interface *intf,
 		dbg("incompatible printer-class device 0x%4.4X/0x%4.4X",
 		dbg("incompatible printer-class device 0x%4.4X/0x%4.4X",
 			le16_to_cpu(dev->descriptor.idVendor),
 			le16_to_cpu(dev->descriptor.idVendor),
 			le16_to_cpu(dev->descriptor.idProduct));
 			le16_to_cpu(dev->descriptor.idProduct));
+		retval = -ENODEV;
 		goto abort;
 		goto abort;
 	}
 	}
 
 
 	/* Setup the selected alternate setting and endpoints. */
 	/* Setup the selected alternate setting and endpoints. */
-	if (usblp_set_protocol(usblp, protocol) < 0)
+	if (usblp_set_protocol(usblp, protocol) < 0) {
+		retval = -ENODEV;	/* ->probe isn't ->ioctl */
 		goto abort;
 		goto abort;
+	}
 
 
 	/* Retrieve and store the device ID string. */
 	/* Retrieve and store the device ID string. */
 	usblp_cache_device_id_string(usblp);
 	usblp_cache_device_id_string(usblp);
@@ -977,12 +1130,14 @@ static int usblp_probe(struct usb_interface *intf,
 
 
 	retval = usb_register_dev(intf, &usblp_class);
 	retval = usb_register_dev(intf, &usblp_class);
 	if (retval) {
 	if (retval) {
-		err("Not able to get a minor for this device.");
+		printk(KERN_ERR "usblp: Not able to get a minor"
+		    " (base %u, slice default): %d\n",
+		    USBLP_MINOR_BASE, retval);
 		goto abort_intfdata;
 		goto abort_intfdata;
 	}
 	}
 	usblp->minor = intf->minor;
 	usblp->minor = intf->minor;
-	info("usblp%d: USB %sdirectional printer dev %d "
-		"if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X",
+	printk(KERN_INFO "usblp%d: USB %sdirectional printer dev %d "
+		"if %d alt %d proto %d vid 0x%4.4X pid 0x%4.4X\n",
 		usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum,
 		usblp->minor, usblp->bidir ? "Bi" : "Uni", dev->devnum,
 		usblp->ifnum,
 		usblp->ifnum,
 		usblp->protocol[usblp->current_protocol].alt_setting,
 		usblp->protocol[usblp->current_protocol].alt_setting,
@@ -997,19 +1152,12 @@ abort_intfdata:
 	device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
 	device_remove_file(&intf->dev, &dev_attr_ieee1284_id);
 abort:
 abort:
 	if (usblp) {
 	if (usblp) {
-		if (usblp->writebuf)
-			usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
-				usblp->writebuf, usblp->writeurb->transfer_dma);
-		if (usblp->readbuf)
-			usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
-				usblp->readbuf, usblp->readurb->transfer_dma);
+		kfree(usblp->readbuf);
 		kfree(usblp->statusbuf);
 		kfree(usblp->statusbuf);
 		kfree(usblp->device_id_string);
 		kfree(usblp->device_id_string);
-		usb_free_urb(usblp->writeurb);
-		usb_free_urb(usblp->readurb);
 		kfree(usblp);
 		kfree(usblp);
 	}
 	}
-	return -EIO;
+	return retval;
 }
 }
 
 
 /*
 /*
@@ -1078,8 +1226,9 @@ static int usblp_select_alts(struct usblp *usblp)
 		if (ifd->desc.bInterfaceProtocol == 1) {
 		if (ifd->desc.bInterfaceProtocol == 1) {
 			epread = NULL;
 			epread = NULL;
 		} else if (usblp->quirks & USBLP_QUIRK_BIDIR) {
 		} else if (usblp->quirks & USBLP_QUIRK_BIDIR) {
-			info("Disabling reads from problem bidirectional "
-				"printer on usblp%d", usblp->minor);
+			printk(KERN_INFO "usblp%d: Disabling reads from "
+			    "problematic bidirectional printer\n",
+			    usblp->minor);
 			epread = NULL;
 			epread = NULL;
 		}
 		}
 
 
@@ -1119,25 +1268,12 @@ static int usblp_set_protocol(struct usblp *usblp, int protocol)
 		return -EINVAL;
 		return -EINVAL;
 	r = usb_set_interface(usblp->dev, usblp->ifnum, alts);
 	r = usb_set_interface(usblp->dev, usblp->ifnum, alts);
 	if (r < 0) {
 	if (r < 0) {
-		err("can't set desired altsetting %d on interface %d",
+		printk(KERN_ERR "usblp: can't set desired altsetting %d on interface %d\n",
 			alts, usblp->ifnum);
 			alts, usblp->ifnum);
 		return r;
 		return r;
 	}
 	}
 
 
-	usb_fill_bulk_urb(usblp->writeurb, usblp->dev,
-		usb_sndbulkpipe(usblp->dev,
-		  usblp->protocol[protocol].epwrite->bEndpointAddress),
-		usblp->writebuf, 0,
-		usblp_bulk_write, usblp);
-
 	usblp->bidir = (usblp->protocol[protocol].epread != NULL);
 	usblp->bidir = (usblp->protocol[protocol].epread != NULL);
-	if (usblp->bidir)
-		usb_fill_bulk_urb(usblp->readurb, usblp->dev,
-			usb_rcvbulkpipe(usblp->dev,
-			  usblp->protocol[protocol].epread->bEndpointAddress),
-			usblp->readbuf, USBLP_BUF_SIZE,
-			usblp_bulk_read, usblp);
-
 	usblp->current_protocol = protocol;
 	usblp->current_protocol = protocol;
 	dbg("usblp%d set protocol %d", usblp->minor, protocol);
 	dbg("usblp%d set protocol %d", usblp->minor, protocol);
 	return 0;
 	return 0;
@@ -1190,13 +1326,11 @@ static void usblp_disconnect(struct usb_interface *intf)
 	mutex_lock (&usblp_mutex);
 	mutex_lock (&usblp_mutex);
 	mutex_lock (&usblp->mut);
 	mutex_lock (&usblp->mut);
 	usblp->present = 0;
 	usblp->present = 0;
+	wake_up(&usblp->wwait);
+	wake_up(&usblp->rwait);
 	usb_set_intfdata (intf, NULL);
 	usb_set_intfdata (intf, NULL);
 
 
 	usblp_unlink_urbs(usblp);
 	usblp_unlink_urbs(usblp);
-	usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
-			usblp->writebuf, usblp->writeurb->transfer_dma);
-	usb_buffer_free (usblp->dev, USBLP_BUF_SIZE,
-			usblp->readbuf, usblp->readurb->transfer_dma);
 	mutex_unlock (&usblp->mut);
 	mutex_unlock (&usblp->mut);
 
 
 	if (!usblp->used)
 	if (!usblp->used)
@@ -1211,6 +1345,11 @@ static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
 	/* we take no more IO */
 	/* we take no more IO */
 	usblp->sleeping = 1;
 	usblp->sleeping = 1;
 	usblp_unlink_urbs(usblp);
 	usblp_unlink_urbs(usblp);
+#if 0 /* XXX Do we want this? What if someone is reading, should we fail? */
+	/* not strictly necessary, but just in case */
+	wake_up(&usblp->wwait);
+	wake_up(&usblp->rwait);
+#endif
 
 
 	return 0;
 	return 0;
 }
 }
@@ -1251,12 +1390,7 @@ static struct usb_driver usblp_driver = {
 
 
 static int __init usblp_init(void)
 static int __init usblp_init(void)
 {
 {
-	int retval;
-	retval = usb_register(&usblp_driver);
-	if (!retval)
-		info(DRIVER_VERSION ": " DRIVER_DESC);
-
-	return retval;
+	return usb_register(&usblp_driver);
 }
 }
 
 
 static void __exit usblp_exit(void)
 static void __exit usblp_exit(void)

+ 25 - 0
drivers/usb/core/Kconfig

@@ -86,6 +86,31 @@ config USB_SUSPEND
 
 
 	  If you are unsure about this, say N here.
 	  If you are unsure about this, say N here.
 
 
+config USB_PERSIST
+	bool "USB device persistence during system suspend (DANGEROUS)"
+	depends on USB && PM && EXPERIMENTAL
+	default n
+	help
+
+	  If you say Y here and enable the "power/persist" attribute
+	  for a USB device, the device's data structures will remain
+	  persistent across system suspend, even if the USB bus loses
+	  power.  (This includes hibernation, also known as swsusp or
+	  suspend-to-disk.)  The devices will reappear as if by magic
+	  when the system wakes up, with no need to unmount USB
+	  filesystems, rmmod host-controller drivers, or do anything
+	  else.
+
+	  	WARNING: This option can be dangerous!
+
+	  If a USB device is replaced by another of the same type while
+	  the system is asleep, there's a good chance the kernel won't
+	  detect the change.  Likewise if the media in a USB storage
+	  device is replaced.  When this happens it's almost certain to
+	  cause data corruption and maybe even crash your system.
+
+	  If you are unsure, say N here.
+
 config USB_OTG
 config USB_OTG
 	bool
 	bool
 	depends on USB && EXPERIMENTAL
 	depends on USB && EXPERIMENTAL

+ 39 - 3
drivers/usb/core/config.c

@@ -85,15 +85,21 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
 	memcpy(&endpoint->desc, d, n);
 	memcpy(&endpoint->desc, d, n);
 	INIT_LIST_HEAD(&endpoint->urb_list);
 	INIT_LIST_HEAD(&endpoint->urb_list);
 
 
-	/* If the bInterval value is outside the legal range,
-	 * set it to a default value: 32 ms */
+	/* Fix up bInterval values outside the legal range. Use 32 ms if no
+	 * proper value can be guessed. */
 	i = 0;		/* i = min, j = max, n = default */
 	i = 0;		/* i = min, j = max, n = default */
 	j = 255;
 	j = 255;
 	if (usb_endpoint_xfer_int(d)) {
 	if (usb_endpoint_xfer_int(d)) {
 		i = 1;
 		i = 1;
 		switch (to_usb_device(ddev)->speed) {
 		switch (to_usb_device(ddev)->speed) {
 		case USB_SPEED_HIGH:
 		case USB_SPEED_HIGH:
-			n = 9;		/* 32 ms = 2^(9-1) uframes */
+			/* Many device manufacturers are using full-speed
+			 * bInterval values in high-speed interrupt endpoint
+			 * descriptors. Try to fix those and fall back to a
+			 * 32 ms default value otherwise. */
+			n = fls(d->bInterval*8);
+			if (n == 0)
+				n = 9;	/* 32 ms = 2^(9-1) uframes */
 			j = 16;
 			j = 16;
 			break;
 			break;
 		default:		/* USB_SPEED_FULL or _LOW */
 		default:		/* USB_SPEED_FULL or _LOW */
@@ -124,6 +130,21 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
 		endpoint->desc.bInterval = n;
 		endpoint->desc.bInterval = n;
 	}
 	}
 
 
+	/* Some buggy low-speed devices have Bulk endpoints, which is
+	 * explicitly forbidden by the USB spec.  In an attempt to make
+	 * them usable, we will try treating them as Interrupt endpoints.
+	 */
+	if (to_usb_device(ddev)->speed == USB_SPEED_LOW &&
+			usb_endpoint_xfer_bulk(d)) {
+		dev_warn(ddev, "config %d interface %d altsetting %d "
+		    "endpoint 0x%X is Bulk; changing to Interrupt\n",
+		    cfgno, inum, asnum, d->bEndpointAddress);
+		endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT;
+		endpoint->desc.bInterval = 1;
+		if (le16_to_cpu(endpoint->desc.wMaxPacketSize) > 8)
+			endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
+	}
+
 	/* Skip over any Class Specific or Vendor Specific descriptors;
 	/* Skip over any Class Specific or Vendor Specific descriptors;
 	 * find the next endpoint or interface descriptor */
 	 * find the next endpoint or interface descriptor */
 	endpoint->extra = buffer;
 	endpoint->extra = buffer;
@@ -274,6 +295,7 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx,
 	struct usb_descriptor_header *header;
 	struct usb_descriptor_header *header;
 	int len, retval;
 	int len, retval;
 	u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES];
 	u8 inums[USB_MAXINTERFACES], nalts[USB_MAXINTERFACES];
+	unsigned iad_num = 0;
 
 
 	memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
 	memcpy(&config->desc, buffer, USB_DT_CONFIG_SIZE);
 	if (config->desc.bDescriptorType != USB_DT_CONFIG ||
 	if (config->desc.bDescriptorType != USB_DT_CONFIG ||
@@ -351,6 +373,20 @@ static int usb_parse_configuration(struct device *ddev, int cfgidx,
 				++n;
 				++n;
 			}
 			}
 
 
+		} else if (header->bDescriptorType ==
+				USB_DT_INTERFACE_ASSOCIATION) {
+			if (iad_num == USB_MAXIADS) {
+				dev_warn(ddev, "found more Interface "
+					       "Association Descriptors "
+					       "than allocated for in "
+					       "configuration %d\n", cfgno);
+			} else {
+				config->intf_assoc[iad_num] =
+					(struct usb_interface_assoc_descriptor
+					*)header;
+				iad_num++;
+			}
+
 		} else if (header->bDescriptorType == USB_DT_DEVICE ||
 		} else if (header->bDescriptorType == USB_DT_DEVICE ||
 			    header->bDescriptorType == USB_DT_CONFIG)
 			    header->bDescriptorType == USB_DT_CONFIG)
 			dev_warn(ddev, "config %d contains an unexpected "
 			dev_warn(ddev, "config %d contains an unexpected "

+ 26 - 0
drivers/usb/core/devices.c

@@ -102,6 +102,10 @@ static const char *format_config =
 /* C:  #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */
 /* C:  #Ifs=dd Cfg#=dd Atr=xx MPwr=dddmA */
   "C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
   "C:%c #Ifs=%2d Cfg#=%2d Atr=%02x MxPwr=%3dmA\n";
   
   
+static const char *format_iad =
+/* A:  FirstIf#=dd IfCount=dd Cls=xx(sssss) Sub=xx Prot=xx */
+  "A:  FirstIf#=%2d IfCount=%2d Cls=%02x(%-5s) Sub=%02x Prot=%02x\n";
+
 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:%c 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";
@@ -146,6 +150,7 @@ static const struct class_info clas_info[] =
 	{USB_CLASS_STILL_IMAGE,		"still"},
 	{USB_CLASS_STILL_IMAGE,		"still"},
 	{USB_CLASS_CSCID,		"scard"},
 	{USB_CLASS_CSCID,		"scard"},
 	{USB_CLASS_CONTENT_SEC,		"c-sec"},
 	{USB_CLASS_CONTENT_SEC,		"c-sec"},
+	{USB_CLASS_VIDEO,		"video"},
 	{-1,				"unk."}		/* leave as last */
 	{-1,				"unk."}		/* leave as last */
 };
 };
 
 
@@ -286,6 +291,21 @@ static char *usb_dump_interface(
 	return start;
 	return start;
 }
 }
 
 
+static char *usb_dump_iad_descriptor(char *start, char *end,
+	const struct usb_interface_assoc_descriptor *iad)
+{
+	if (start > end)
+		return start;
+	start += sprintf(start, format_iad,
+			 iad->bFirstInterface,
+			 iad->bInterfaceCount,
+			 iad->bFunctionClass,
+			 class_decode(iad->bFunctionClass),
+			 iad->bFunctionSubClass,
+			 iad->bFunctionProtocol);
+	return start;
+}
+
 /* TBD:
 /* TBD:
  * 0. TBDs
  * 0. TBDs
  * 1. marking active interface altsettings (code lists all, but should mark
  * 1. marking active interface altsettings (code lists all, but should mark
@@ -322,6 +342,12 @@ static char *usb_dump_config (
 	if (!config)		/* getting these some in 2.3.7; none in 2.3.6 */
 	if (!config)		/* getting these some in 2.3.7; none in 2.3.6 */
 		return start + sprintf(start, "(null Cfg. desc.)\n");
 		return start + sprintf(start, "(null Cfg. desc.)\n");
 	start = usb_dump_config_descriptor(start, end, &config->desc, active);
 	start = usb_dump_config_descriptor(start, end, &config->desc, active);
+	for (i = 0; i < USB_MAXIADS; i++) {
+		if (config->intf_assoc[i] == NULL)
+			break;
+		start = usb_dump_iad_descriptor(start, end,
+					config->intf_assoc[i]);
+	}
 	for (i = 0; i < config->desc.bNumInterfaces; i++) {
 	for (i = 0; i < config->desc.bNumInterfaces; i++) {
 		intfc = config->intf_cache[i];
 		intfc = config->intf_cache[i];
 		interface = config->interface[i];
 		interface = config->interface[i];

+ 105 - 57
drivers/usb/core/driver.c

@@ -24,10 +24,19 @@
 
 
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
+#include <linux/usb/quirks.h>
 #include <linux/workqueue.h>
 #include <linux/workqueue.h>
 #include "hcd.h"
 #include "hcd.h"
 #include "usb.h"
 #include "usb.h"
 
 
+#define VERBOSE_DEBUG	0
+
+#if VERBOSE_DEBUG
+#define dev_vdbg	dev_dbg
+#else
+#define dev_vdbg(dev, fmt, args...)	do { } while (0)
+#endif
+
 #ifdef CONFIG_HOTPLUG
 #ifdef CONFIG_HOTPLUG
 
 
 /*
 /*
@@ -802,18 +811,17 @@ static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
 			udev->state == USB_STATE_SUSPENDED)
 			udev->state == USB_STATE_SUSPENDED)
 		goto done;
 		goto done;
 
 
-	/* For devices that don't have a driver, we do a standard suspend. */
-	if (udev->dev.driver == NULL) {
+	/* For devices that don't have a driver, we do a generic suspend. */
+	if (udev->dev.driver)
+		udriver = to_usb_device_driver(udev->dev.driver);
+	else {
 		udev->do_remote_wakeup = 0;
 		udev->do_remote_wakeup = 0;
-		status = usb_port_suspend(udev);
-		goto done;
+		udriver = &usb_generic_driver;
 	}
 	}
-
-	udriver = to_usb_device_driver(udev->dev.driver);
 	status = udriver->suspend(udev, msg);
 	status = udriver->suspend(udev, msg);
 
 
-done:
-	// dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+ done:
+	dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
 	if (status == 0)
 	if (status == 0)
 		udev->dev.power.power_state.event = msg.event;
 		udev->dev.power.power_state.event = msg.event;
 	return status;
 	return status;
@@ -825,8 +833,9 @@ static int usb_resume_device(struct usb_device *udev)
 	struct usb_device_driver	*udriver;
 	struct usb_device_driver	*udriver;
 	int				status = 0;
 	int				status = 0;
 
 
-	if (udev->state == USB_STATE_NOTATTACHED ||
-			udev->state != USB_STATE_SUSPENDED)
+	if (udev->state == USB_STATE_NOTATTACHED)
+		goto done;
+	if (udev->state != USB_STATE_SUSPENDED && !udev->reset_resume)
 		goto done;
 		goto done;
 
 
 	/* Can't resume it if it doesn't have a driver. */
 	/* Can't resume it if it doesn't have a driver. */
@@ -835,11 +844,14 @@ static int usb_resume_device(struct usb_device *udev)
 		goto done;
 		goto done;
 	}
 	}
 
 
+	if (udev->quirks & USB_QUIRK_RESET_RESUME)
+		udev->reset_resume = 1;
+
 	udriver = to_usb_device_driver(udev->dev.driver);
 	udriver = to_usb_device_driver(udev->dev.driver);
 	status = udriver->resume(udev);
 	status = udriver->resume(udev);
 
 
-done:
-	// dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+ done:
+	dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
 	if (status == 0) {
 	if (status == 0) {
 		udev->autoresume_disabled = 0;
 		udev->autoresume_disabled = 0;
 		udev->dev.power.power_state.event = PM_EVENT_ON;
 		udev->dev.power.power_state.event = PM_EVENT_ON;
@@ -877,15 +889,13 @@ static int usb_suspend_interface(struct usb_interface *intf, pm_message_t msg)
 		mark_quiesced(intf);
 		mark_quiesced(intf);
 	}
 	}
 
 
-done:
-	// dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
-	if (status == 0)
-		intf->dev.power.power_state.event = msg.event;
+ done:
+	dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
 	return status;
 	return status;
 }
 }
 
 
 /* Caller has locked intf's usb_device's pm_mutex */
 /* Caller has locked intf's usb_device's pm_mutex */
-static int usb_resume_interface(struct usb_interface *intf)
+static int usb_resume_interface(struct usb_interface *intf, int reset_resume)
 {
 {
 	struct usb_driver	*driver;
 	struct usb_driver	*driver;
 	int			status = 0;
 	int			status = 0;
@@ -905,23 +915,37 @@ static int usb_resume_interface(struct usb_interface *intf)
 	}
 	}
 	driver = to_usb_driver(intf->dev.driver);
 	driver = to_usb_driver(intf->dev.driver);
 
 
-	if (driver->resume) {
-		status = driver->resume(intf);
-		if (status)
-			dev_err(&intf->dev, "%s error %d\n",
-					"resume", status);
-		else
-			mark_active(intf);
+	if (reset_resume) {
+		if (driver->reset_resume) {
+			status = driver->reset_resume(intf);
+			if (status)
+				dev_err(&intf->dev, "%s error %d\n",
+						"reset_resume", status);
+		} else {
+			// status = -EOPNOTSUPP;
+			dev_warn(&intf->dev, "no %s for driver %s?\n",
+					"reset_resume", driver->name);
+		}
 	} else {
 	} else {
-		dev_warn(&intf->dev, "no resume for driver %s?\n",
-				driver->name);
-		mark_active(intf);
+		if (driver->resume) {
+			status = driver->resume(intf);
+			if (status)
+				dev_err(&intf->dev, "%s error %d\n",
+						"resume", status);
+		} else {
+			// status = -EOPNOTSUPP;
+			dev_warn(&intf->dev, "no %s for driver %s?\n",
+					"resume", driver->name);
+		}
 	}
 	}
 
 
 done:
 done:
-	// dev_dbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
+	dev_vdbg(&intf->dev, "%s: status %d\n", __FUNCTION__, status);
 	if (status == 0)
 	if (status == 0)
-		intf->dev.power.power_state.event = PM_EVENT_ON;
+		mark_active(intf);
+
+	/* FIXME: Unbind the driver and reprobe if the resume failed
+	 * (not possible if auto_pm is set) */
 	return status;
 	return status;
 }
 }
 
 
@@ -958,6 +982,18 @@ static int autosuspend_check(struct usb_device *udev)
 						"for autosuspend\n");
 						"for autosuspend\n");
 				return -EOPNOTSUPP;
 				return -EOPNOTSUPP;
 			}
 			}
+
+			/* Don't allow autosuspend if the device will need
+			 * a reset-resume and any of its interface drivers
+			 * doesn't include support.
+			 */
+			if (udev->quirks & USB_QUIRK_RESET_RESUME) {
+				struct usb_driver *driver;
+
+				driver = to_usb_driver(intf->dev.driver);
+				if (!driver->reset_resume)
+					return -EOPNOTSUPP;
+			}
 		}
 		}
 	}
 	}
 
 
@@ -974,7 +1010,7 @@ static int autosuspend_check(struct usb_device *udev)
 			 * or for the past.
 			 * or for the past.
 			 */
 			 */
 			queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
 			queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
-					suspend_time - jiffies);
+				round_jiffies_relative(suspend_time - jiffies));
 			}
 			}
 		return -EAGAIN;
 		return -EAGAIN;
 	}
 	}
@@ -1054,14 +1090,21 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
 				break;
 				break;
 		}
 		}
 	}
 	}
-	if (status == 0)
+	if (status == 0) {
+
+		/* Non-root devices don't need to do anything for FREEZE
+		 * or PRETHAW. */
+		if (udev->parent && (msg.event == PM_EVENT_FREEZE ||
+				msg.event == PM_EVENT_PRETHAW))
+			goto done;
 		status = usb_suspend_device(udev, msg);
 		status = usb_suspend_device(udev, msg);
+	}
 
 
 	/* If the suspend failed, resume interfaces that did get suspended */
 	/* If the suspend failed, resume interfaces that did get suspended */
 	if (status != 0) {
 	if (status != 0) {
 		while (--i >= 0) {
 		while (--i >= 0) {
 			intf = udev->actconfig->interface[i];
 			intf = udev->actconfig->interface[i];
-			usb_resume_interface(intf);
+			usb_resume_interface(intf, 0);
 		}
 		}
 
 
 		/* Try another autosuspend when the interfaces aren't busy */
 		/* Try another autosuspend when the interfaces aren't busy */
@@ -1076,7 +1119,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
 	}
 	}
 
 
  done:
  done:
-	// dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+	dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
 	return status;
 	return status;
 }
 }
 
 
@@ -1131,7 +1174,8 @@ static int usb_resume_both(struct usb_device *udev)
 			status = usb_autoresume_device(parent);
 			status = usb_autoresume_device(parent);
 			if (status == 0) {
 			if (status == 0) {
 				status = usb_resume_device(udev);
 				status = usb_resume_device(udev);
-				if (status) {
+				if (status || udev->state ==
+						USB_STATE_NOTATTACHED) {
 					usb_autosuspend_device(parent);
 					usb_autosuspend_device(parent);
 
 
 					/* It's possible usb_resume_device()
 					/* It's possible usb_resume_device()
@@ -1152,28 +1196,25 @@ static int usb_resume_both(struct usb_device *udev)
 			/* We can't progagate beyond the USB subsystem,
 			/* We can't progagate beyond the USB subsystem,
 			 * so if a root hub's controller is suspended
 			 * so if a root hub's controller is suspended
 			 * then we're stuck. */
 			 * then we're stuck. */
-			if (udev->dev.parent->power.power_state.event !=
-					PM_EVENT_ON)
-				status = -EHOSTUNREACH;
-			else
-				status = usb_resume_device(udev);
+			status = usb_resume_device(udev);
  		}
  		}
 	} else {
 	} else {
 
 
-		/* Needed only for setting udev->dev.power.power_state.event
-		 * and for possible debugging message. */
+		/* Needed for setting udev->dev.power.power_state.event,
+		 * for possible debugging message, and for reset_resume. */
 		status = usb_resume_device(udev);
 		status = usb_resume_device(udev);
 	}
 	}
 
 
 	if (status == 0 && udev->actconfig) {
 	if (status == 0 && udev->actconfig) {
 		for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
 		for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
 			intf = udev->actconfig->interface[i];
 			intf = udev->actconfig->interface[i];
-			usb_resume_interface(intf);
+			usb_resume_interface(intf, udev->reset_resume);
 		}
 		}
 	}
 	}
 
 
  done:
  done:
-	// dev_dbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+	dev_vdbg(&udev->dev, "%s: status %d\n", __FUNCTION__, status);
+	udev->reset_resume = 0;
 	return status;
 	return status;
 }
 }
 
 
@@ -1240,8 +1281,8 @@ void usb_autosuspend_device(struct usb_device *udev)
 	int	status;
 	int	status;
 
 
 	status = usb_autopm_do_device(udev, -1);
 	status = usb_autopm_do_device(udev, -1);
-	// dev_dbg(&udev->dev, "%s: cnt %d\n",
-	//		__FUNCTION__, udev->pm_usage_cnt);
+	dev_vdbg(&udev->dev, "%s: cnt %d\n",
+			__FUNCTION__, udev->pm_usage_cnt);
 }
 }
 
 
 /**
 /**
@@ -1260,8 +1301,8 @@ void usb_autosuspend_device(struct usb_device *udev)
 void usb_try_autosuspend_device(struct usb_device *udev)
 void usb_try_autosuspend_device(struct usb_device *udev)
 {
 {
 	usb_autopm_do_device(udev, 0);
 	usb_autopm_do_device(udev, 0);
-	// dev_dbg(&udev->dev, "%s: cnt %d\n",
-	// 		__FUNCTION__, udev->pm_usage_cnt);
+	dev_vdbg(&udev->dev, "%s: cnt %d\n",
+			__FUNCTION__, udev->pm_usage_cnt);
 }
 }
 
 
 /**
 /**
@@ -1288,8 +1329,8 @@ int usb_autoresume_device(struct usb_device *udev)
 	int	status;
 	int	status;
 
 
 	status = usb_autopm_do_device(udev, 1);
 	status = usb_autopm_do_device(udev, 1);
-	// dev_dbg(&udev->dev, "%s: status %d cnt %d\n",
-	//		__FUNCTION__, status, udev->pm_usage_cnt);
+	dev_vdbg(&udev->dev, "%s: status %d cnt %d\n",
+			__FUNCTION__, status, udev->pm_usage_cnt);
 	return status;
 	return status;
 }
 }
 
 
@@ -1361,8 +1402,8 @@ void usb_autopm_put_interface(struct usb_interface *intf)
 	int	status;
 	int	status;
 
 
 	status = usb_autopm_do_interface(intf, -1);
 	status = usb_autopm_do_interface(intf, -1);
-	// dev_dbg(&intf->dev, "%s: status %d cnt %d\n",
-	//		__FUNCTION__, status, intf->pm_usage_cnt);
+	dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
+			__FUNCTION__, status, intf->pm_usage_cnt);
 }
 }
 EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
 EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
 
 
@@ -1405,8 +1446,8 @@ int usb_autopm_get_interface(struct usb_interface *intf)
 	int	status;
 	int	status;
 
 
 	status = usb_autopm_do_interface(intf, 1);
 	status = usb_autopm_do_interface(intf, 1);
-	// dev_dbg(&intf->dev, "%s: status %d cnt %d\n",
-	//		__FUNCTION__, status, intf->pm_usage_cnt);
+	dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
+			__FUNCTION__, status, intf->pm_usage_cnt);
 	return status;
 	return status;
 }
 }
 EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
 EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
@@ -1427,8 +1468,8 @@ int usb_autopm_set_interface(struct usb_interface *intf)
 	int	status;
 	int	status;
 
 
 	status = usb_autopm_do_interface(intf, 0);
 	status = usb_autopm_do_interface(intf, 0);
-	// dev_dbg(&intf->dev, "%s: status %d cnt %d\n",
-	//		__FUNCTION__, status, intf->pm_usage_cnt);
+	dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
+			__FUNCTION__, status, intf->pm_usage_cnt);
 	return status;
 	return status;
 }
 }
 EXPORT_SYMBOL_GPL(usb_autopm_set_interface);
 EXPORT_SYMBOL_GPL(usb_autopm_set_interface);
@@ -1508,8 +1549,15 @@ static int usb_resume(struct device *dev)
 	if (!is_usb_device(dev))	/* Ignore PM for interfaces */
 	if (!is_usb_device(dev))	/* Ignore PM for interfaces */
 		return 0;
 		return 0;
 	udev = to_usb_device(dev);
 	udev = to_usb_device(dev);
-	if (udev->autoresume_disabled)
-		return -EPERM;
+
+	/* If autoresume is disabled then we also want to prevent resume
+	 * during system wakeup.  However, a "persistent-device" reset-resume
+	 * after power loss counts as a wakeup event.  So allow a
+	 * reset-resume to occur if remote wakeup is enabled. */
+	if (udev->autoresume_disabled) {
+		if (!(udev->reset_resume && udev->do_remote_wakeup))
+			return -EPERM;
+	}
 	return usb_external_resume_device(udev);
 	return usb_external_resume_device(udev);
 }
 }
 
 

+ 13 - 16
drivers/usb/core/file.c

@@ -16,15 +16,15 @@
  */
  */
 
 
 #include <linux/module.h>
 #include <linux/module.h>
-#include <linux/spinlock.h>
 #include <linux/errno.h>
 #include <linux/errno.h>
+#include <linux/rwsem.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
 
 
 #include "usb.h"
 #include "usb.h"
 
 
 #define MAX_USB_MINORS	256
 #define MAX_USB_MINORS	256
 static const struct file_operations *usb_minors[MAX_USB_MINORS];
 static const struct file_operations *usb_minors[MAX_USB_MINORS];
-static DEFINE_SPINLOCK(minor_lock);
+static DECLARE_RWSEM(minor_rwsem);
 
 
 static int usb_open(struct inode * inode, struct file * file)
 static int usb_open(struct inode * inode, struct file * file)
 {
 {
@@ -33,14 +33,11 @@ static int usb_open(struct inode * inode, struct file * file)
 	int err = -ENODEV;
 	int err = -ENODEV;
 	const struct file_operations *old_fops, *new_fops = NULL;
 	const struct file_operations *old_fops, *new_fops = NULL;
 
 
-	spin_lock (&minor_lock);
+	down_read(&minor_rwsem);
 	c = usb_minors[minor];
 	c = usb_minors[minor];
 
 
-	if (!c || !(new_fops = fops_get(c))) {
-		spin_unlock(&minor_lock);
-		return err;
-	}
-	spin_unlock(&minor_lock);
+	if (!c || !(new_fops = fops_get(c)))
+		goto done;
 
 
 	old_fops = file->f_op;
 	old_fops = file->f_op;
 	file->f_op = new_fops;
 	file->f_op = new_fops;
@@ -52,6 +49,8 @@ static int usb_open(struct inode * inode, struct file * file)
 		file->f_op = fops_get(old_fops);
 		file->f_op = fops_get(old_fops);
 	}
 	}
 	fops_put(old_fops);
 	fops_put(old_fops);
+ done:
+	up_read(&minor_rwsem);
 	return err;
 	return err;
 }
 }
 
 
@@ -166,7 +165,7 @@ int usb_register_dev(struct usb_interface *intf,
 	if (class_driver->fops == NULL)
 	if (class_driver->fops == NULL)
 		goto exit;
 		goto exit;
 
 
-	spin_lock (&minor_lock);
+	down_write(&minor_rwsem);
 	for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
 	for (minor = minor_base; minor < MAX_USB_MINORS; ++minor) {
 		if (usb_minors[minor])
 		if (usb_minors[minor])
 			continue;
 			continue;
@@ -176,7 +175,7 @@ int usb_register_dev(struct usb_interface *intf,
 		retval = 0;
 		retval = 0;
 		break;
 		break;
 	}
 	}
-	spin_unlock (&minor_lock);
+	up_write(&minor_rwsem);
 
 
 	if (retval)
 	if (retval)
 		goto exit;
 		goto exit;
@@ -197,9 +196,9 @@ int usb_register_dev(struct usb_interface *intf,
 	intf->usb_dev = device_create(usb_class->class, &intf->dev,
 	intf->usb_dev = device_create(usb_class->class, &intf->dev,
 				      MKDEV(USB_MAJOR, minor), "%s", temp);
 				      MKDEV(USB_MAJOR, minor), "%s", temp);
 	if (IS_ERR(intf->usb_dev)) {
 	if (IS_ERR(intf->usb_dev)) {
-		spin_lock (&minor_lock);
+		down_write(&minor_rwsem);
 		usb_minors[intf->minor] = NULL;
 		usb_minors[intf->minor] = NULL;
-		spin_unlock (&minor_lock);
+		up_write(&minor_rwsem);
 		retval = PTR_ERR(intf->usb_dev);
 		retval = PTR_ERR(intf->usb_dev);
 	}
 	}
 exit:
 exit:
@@ -236,9 +235,9 @@ void usb_deregister_dev(struct usb_interface *intf,
 
 
 	dbg ("removing %d minor", intf->minor);
 	dbg ("removing %d minor", intf->minor);
 
 
-	spin_lock (&minor_lock);
+	down_write(&minor_rwsem);
 	usb_minors[intf->minor] = NULL;
 	usb_minors[intf->minor] = NULL;
-	spin_unlock (&minor_lock);
+	up_write(&minor_rwsem);
 
 
 	snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
 	snprintf(name, BUS_ID_SIZE, class_driver->name, intf->minor - minor_base);
 	device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
 	device_destroy(usb_class->class, MKDEV(USB_MAJOR, intf->minor));
@@ -247,5 +246,3 @@ void usb_deregister_dev(struct usb_interface *intf,
 	destroy_usb_class();
 	destroy_usb_class();
 }
 }
 EXPORT_SYMBOL(usb_deregister_dev);
 EXPORT_SYMBOL(usb_deregister_dev);
-
-

+ 24 - 5
drivers/usb/core/generic.c

@@ -19,6 +19,7 @@
 
 
 #include <linux/usb.h>
 #include <linux/usb.h>
 #include "usb.h"
 #include "usb.h"
+#include "hcd.h"
 
 
 static inline const char *plural(int n)
 static inline const char *plural(int n)
 {
 {
@@ -193,16 +194,34 @@ static void generic_disconnect(struct usb_device *udev)
 
 
 static int generic_suspend(struct usb_device *udev, pm_message_t msg)
 static int generic_suspend(struct usb_device *udev, pm_message_t msg)
 {
 {
-	/* USB devices enter SUSPEND state through their hubs, but can be
-	 * marked for FREEZE as soon as their children are already idled.
-	 * But those semantics are useless, so we equate the two (sigh).
+	int rc;
+
+	/* Normal USB devices suspend through their upstream port.
+	 * Root hubs don't have upstream ports to suspend,
+	 * so we have to shut down their downstream HC-to-USB
+	 * interfaces manually by doing a bus (or "global") suspend.
 	 */
 	 */
-	return usb_port_suspend(udev);
+	if (!udev->parent)
+		rc = hcd_bus_suspend(udev);
+	else
+		rc = usb_port_suspend(udev);
+	return rc;
 }
 }
 
 
 static int generic_resume(struct usb_device *udev)
 static int generic_resume(struct usb_device *udev)
 {
 {
-	return usb_port_resume(udev);
+	int rc;
+
+	/* Normal USB devices resume/reset through their upstream port.
+	 * Root hubs don't have upstream ports to resume or reset,
+	 * so we have to start up their downstream HC-to-USB
+	 * interfaces manually by doing a bus (or "global") resume.
+	 */
+	if (!udev->parent)
+		rc = hcd_bus_resume(udev);
+	else
+		rc = usb_port_resume(udev);
+	return rc;
 }
 }
 
 
 #endif	/* CONFIG_PM */
 #endif	/* CONFIG_PM */

+ 2 - 1
drivers/usb/core/hcd-pci.c

@@ -207,7 +207,8 @@ int usb_hcd_pci_suspend (struct pci_dev *dev, pm_message_t message)
 	 * We must ignore the FREEZE vs SUSPEND distinction here, because
 	 * We must ignore the FREEZE vs SUSPEND distinction here, because
 	 * otherwise the swsusp will save (and restore) garbage state.
 	 * otherwise the swsusp will save (and restore) garbage state.
 	 */
 	 */
-	if (hcd->self.root_hub->dev.power.power_state.event == PM_EVENT_ON)
+	if (!(hcd->state == HC_STATE_SUSPENDED ||
+			hcd->state == HC_STATE_HALT))
 		return -EBUSY;
 		return -EBUSY;
 
 
 	if (hcd->driver->suspend) {
 	if (hcd->driver->suspend) {

+ 65 - 61
drivers/usb/core/hcd.c

@@ -582,10 +582,12 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
 	}
 	}
 
 
 	/* The USB 2.0 spec says 256 ms.  This is close enough and won't
 	/* The USB 2.0 spec says 256 ms.  This is close enough and won't
-	 * exceed that limit if HZ is 100. */
+	 * exceed that limit if HZ is 100. The math is more clunky than
+	 * maybe expected, this is to make sure that all timers for USB devices
+	 * fire at the same time to give the CPU a break inbetween */
 	if (hcd->uses_new_polling ? hcd->poll_rh :
 	if (hcd->uses_new_polling ? hcd->poll_rh :
 			(length == 0 && hcd->status_urb != NULL))
 			(length == 0 && hcd->status_urb != NULL))
-		mod_timer (&hcd->rh_timer, jiffies + msecs_to_jiffies(250));
+		mod_timer (&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
 }
 }
 EXPORT_SYMBOL_GPL(usb_hcd_poll_rh_status);
 EXPORT_SYMBOL_GPL(usb_hcd_poll_rh_status);
 
 
@@ -614,8 +616,8 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)
 		urb->hcpriv = hcd;	/* indicate it's queued */
 		urb->hcpriv = hcd;	/* indicate it's queued */
 
 
 		if (!hcd->uses_new_polling)
 		if (!hcd->uses_new_polling)
-			mod_timer (&hcd->rh_timer, jiffies +
-					msecs_to_jiffies(250));
+			mod_timer (&hcd->rh_timer,
+				(jiffies/(HZ/4) + 1) * (HZ/4));
 
 
 		/* If a status change has already occurred, report it ASAP */
 		/* If a status change has already occurred, report it ASAP */
 		else if (hcd->poll_pending)
 		else if (hcd->poll_pending)
@@ -901,17 +903,32 @@ EXPORT_SYMBOL (usb_calc_bus_time);
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-static void urb_unlink (struct urb *urb)
+static void urb_unlink(struct usb_hcd *hcd, struct urb *urb)
 {
 {
 	unsigned long		flags;
 	unsigned long		flags;
+	int at_root_hub = (urb->dev == hcd->self.root_hub);
 
 
 	/* 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);
 	list_del_init (&urb->urb_list);
 	list_del_init (&urb->urb_list);
 	spin_unlock_irqrestore (&hcd_data_lock, flags);
 	spin_unlock_irqrestore (&hcd_data_lock, flags);
-}
 
 
+	if (hcd->self.uses_dma && !at_root_hub) {
+		if (usb_pipecontrol (urb->pipe)
+			&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
+			dma_unmap_single (hcd->self.controller, urb->setup_dma,
+					sizeof (struct usb_ctrlrequest),
+					DMA_TO_DEVICE);
+		if (urb->transfer_buffer_length != 0
+			&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
+			dma_unmap_single (hcd->self.controller,
+					urb->transfer_dma,
+					urb->transfer_buffer_length,
+					usb_pipein (urb->pipe)
+					    ? DMA_FROM_DEVICE
+					    : DMA_TO_DEVICE);
+	}
+}
 
 
 /* may be called in any context with a valid urb->dev usecount
 /* may be called in any context with a valid urb->dev usecount
  * caller surrenders "ownership" of urb
  * caller surrenders "ownership" of urb
@@ -948,19 +965,9 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
 	else switch (hcd->state) {
 	else switch (hcd->state) {
 	case HC_STATE_RUNNING:
 	case HC_STATE_RUNNING:
 	case HC_STATE_RESUMING:
 	case HC_STATE_RESUMING:
-doit:
 		list_add_tail (&urb->urb_list, &ep->urb_list);
 		list_add_tail (&urb->urb_list, &ep->urb_list);
 		status = 0;
 		status = 0;
 		break;
 		break;
-	case HC_STATE_SUSPENDED:
-		/* HC upstream links (register access, wakeup signaling) can work
-		 * even when the downstream links (and DMA etc) are quiesced; let
-		 * usbcore talk to the root hub.
-		 */
-		if (hcd->self.controller->power.power_state.event == PM_EVENT_ON
-				&& urb->dev->parent == NULL)
-			goto doit;
-		/* FALL THROUGH */
 	default:
 	default:
 		status = -ESHUTDOWN;
 		status = -ESHUTDOWN;
 		break;
 		break;
@@ -1014,7 +1021,7 @@ doit:
 	status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags);
 	status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags);
 done:
 done:
 	if (unlikely (status)) {
 	if (unlikely (status)) {
-		urb_unlink (urb);
+		urb_unlink(hcd, urb);
 		atomic_dec (&urb->use_count);
 		atomic_dec (&urb->use_count);
 		if (urb->reject)
 		if (urb->reject)
 			wake_up (&usb_kill_urb_queue);
 			wake_up (&usb_kill_urb_queue);
@@ -1255,42 +1262,59 @@ rescan:
 
 
 #ifdef	CONFIG_PM
 #ifdef	CONFIG_PM
 
 
-int hcd_bus_suspend (struct usb_bus *bus)
+int hcd_bus_suspend(struct usb_device *rhdev)
 {
 {
-	struct usb_hcd		*hcd;
-	int			status;
+	struct usb_hcd	*hcd = container_of(rhdev->bus, struct usb_hcd, self);
+	int		status;
+	int		old_state = hcd->state;
 
 
-	hcd = container_of (bus, struct usb_hcd, self);
-	if (!hcd->driver->bus_suspend)
-		return -ENOENT;
-	hcd->state = HC_STATE_QUIESCING;
-	status = hcd->driver->bus_suspend (hcd);
-	if (status == 0)
+	dev_dbg(&rhdev->dev, "bus %s%s\n",
+			rhdev->auto_pm ? "auto-" : "", "suspend");
+	if (!hcd->driver->bus_suspend) {
+		status = -ENOENT;
+	} else {
+		hcd->state = HC_STATE_QUIESCING;
+		status = hcd->driver->bus_suspend(hcd);
+	}
+	if (status == 0) {
+		usb_set_device_state(rhdev, USB_STATE_SUSPENDED);
 		hcd->state = HC_STATE_SUSPENDED;
 		hcd->state = HC_STATE_SUSPENDED;
-	else
-		dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n",
+	} else {
+		hcd->state = old_state;
+		dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
 				"suspend", status);
 				"suspend", status);
+	}
 	return status;
 	return status;
 }
 }
 
 
-int hcd_bus_resume (struct usb_bus *bus)
+int hcd_bus_resume(struct usb_device *rhdev)
 {
 {
-	struct usb_hcd		*hcd;
-	int			status;
+	struct usb_hcd	*hcd = container_of(rhdev->bus, struct usb_hcd, self);
+	int		status;
+	int		old_state = hcd->state;
 
 
-	hcd = container_of (bus, struct usb_hcd, self);
+	dev_dbg(&rhdev->dev, "usb %s%s\n",
+			rhdev->auto_pm ? "auto-" : "", "resume");
 	if (!hcd->driver->bus_resume)
 	if (!hcd->driver->bus_resume)
 		return -ENOENT;
 		return -ENOENT;
 	if (hcd->state == HC_STATE_RUNNING)
 	if (hcd->state == HC_STATE_RUNNING)
 		return 0;
 		return 0;
+
 	hcd->state = HC_STATE_RESUMING;
 	hcd->state = HC_STATE_RESUMING;
-	status = hcd->driver->bus_resume (hcd);
-	if (status == 0)
+	status = hcd->driver->bus_resume(hcd);
+	if (status == 0) {
+		/* TRSMRCY = 10 msec */
+		msleep(10);
+		usb_set_device_state(rhdev, rhdev->actconfig
+				? USB_STATE_CONFIGURED
+				: USB_STATE_ADDRESS);
 		hcd->state = HC_STATE_RUNNING;
 		hcd->state = HC_STATE_RUNNING;
-	else {
-		dev_dbg(&bus->root_hub->dev, "%s fail, err %d\n",
+	} else {
+		hcd->state = old_state;
+		dev_dbg(&rhdev->dev, "bus %s fail, err %d\n",
 				"resume", status);
 				"resume", status);
-		usb_hc_died(hcd);
+		if (status != -ESHUTDOWN)
+			usb_hc_died(hcd);
 	}
 	}
 	return status;
 	return status;
 }
 }
@@ -1384,30 +1408,10 @@ EXPORT_SYMBOL (usb_bus_start_enum);
  */
  */
 void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
 void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb)
 {
 {
-	int at_root_hub;
-
-	at_root_hub = (urb->dev == hcd->self.root_hub);
-	urb_unlink (urb);
-
-	/* lower level hcd code should use *_dma exclusively if the
-	 * host controller does DMA */
-	if (hcd->self.uses_dma && !at_root_hub) {
-		if (usb_pipecontrol (urb->pipe)
-			&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
-			dma_unmap_single (hcd->self.controller, urb->setup_dma,
-					sizeof (struct usb_ctrlrequest),
-					DMA_TO_DEVICE);
-		if (urb->transfer_buffer_length != 0
-			&& !(urb->transfer_flags & URB_NO_TRANSFER_DMA_MAP))
-			dma_unmap_single (hcd->self.controller, 
-					urb->transfer_dma,
-					urb->transfer_buffer_length,
-					usb_pipein (urb->pipe)
-					    ? DMA_FROM_DEVICE
-					    : DMA_TO_DEVICE);
-	}
-
+	urb_unlink(hcd, urb);
 	usbmon_urb_complete (&hcd->self, urb);
 	usbmon_urb_complete (&hcd->self, urb);
+	usb_unanchor_urb(urb);
+
 	/* pass ownership to the completion handler */
 	/* pass ownership to the completion handler */
 	urb->complete (urb);
 	urb->complete (urb);
 	atomic_dec (&urb->use_count);
 	atomic_dec (&urb->use_count);

+ 2 - 12
drivers/usb/core/hcd.h

@@ -364,23 +364,13 @@ extern int usb_find_interface_driver (struct usb_device *dev,
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
 extern void usb_hcd_resume_root_hub (struct usb_hcd *hcd);
 extern void usb_root_hub_lost_power (struct usb_device *rhdev);
 extern void usb_root_hub_lost_power (struct usb_device *rhdev);
-extern int hcd_bus_suspend (struct usb_bus *bus);
-extern int hcd_bus_resume (struct usb_bus *bus);
+extern int hcd_bus_suspend(struct usb_device *rhdev);
+extern int hcd_bus_resume(struct usb_device *rhdev);
 #else
 #else
 static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
 static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
 {
 {
 	return;
 	return;
 }
 }
-
-static inline int hcd_bus_suspend(struct usb_bus *bus)
-{
-	return 0;
-}
-
-static inline int hcd_bus_resume (struct usb_bus *bus)
-{
-	return 0;
-}
 #endif /* CONFIG_PM */
 #endif /* CONFIG_PM */
 
 
 /*
 /*

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 283 - 360
drivers/usb/core/hub.c


+ 34 - 4
drivers/usb/core/message.c

@@ -404,8 +404,6 @@ int usb_sg_init (
 
 
 		io->urbs [i]->complete = sg_complete;
 		io->urbs [i]->complete = sg_complete;
 		io->urbs [i]->context = io;
 		io->urbs [i]->context = io;
-		io->urbs [i]->status = -EINPROGRESS;
-		io->urbs [i]->actual_length = 0;
 
 
 		/*
 		/*
 		 * Some systems need to revert to PIO when DMA is temporarily
 		 * Some systems need to revert to PIO when DMA is temporarily
@@ -499,7 +497,8 @@ void usb_sg_wait (struct usb_sg_request *io)
 
 
 	/* queue the urbs.  */
 	/* queue the urbs.  */
 	spin_lock_irq (&io->lock);
 	spin_lock_irq (&io->lock);
-	for (i = 0; i < entries && !io->status; i++) {
+	i = 0;
+	while (i < entries && !io->status) {
 		int	retval;
 		int	retval;
 
 
 		io->urbs [i]->dev = io->dev;
 		io->urbs [i]->dev = io->dev;
@@ -516,7 +515,6 @@ void usb_sg_wait (struct usb_sg_request *io)
 		case -ENOMEM:
 		case -ENOMEM:
 			io->urbs[i]->dev = NULL;
 			io->urbs[i]->dev = NULL;
 			retval = 0;
 			retval = 0;
-			i--;
 			yield ();
 			yield ();
 			break;
 			break;
 
 
@@ -527,6 +525,7 @@ void usb_sg_wait (struct usb_sg_request *io)
 			 * URBs are queued at once; N milliseconds?
 			 * URBs are queued at once; N milliseconds?
 			 */
 			 */
 		case 0:
 		case 0:
+			++i;
 			cpu_relax ();
 			cpu_relax ();
 			break;
 			break;
 
 
@@ -1385,6 +1384,36 @@ struct device_type usb_if_device_type = {
 	.uevent =	usb_if_uevent,
 	.uevent =	usb_if_uevent,
 };
 };
 
 
+static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
+						       struct usb_host_config *config,
+						       u8 inum)
+{
+	struct usb_interface_assoc_descriptor *retval = NULL;
+	struct usb_interface_assoc_descriptor *intf_assoc;
+	int first_intf;
+	int last_intf;
+	int i;
+
+	for (i = 0; (i < USB_MAXIADS && config->intf_assoc[i]); i++) {
+		intf_assoc = config->intf_assoc[i];
+		if (intf_assoc->bInterfaceCount == 0)
+			continue;
+
+		first_intf = intf_assoc->bFirstInterface;
+		last_intf = first_intf + (intf_assoc->bInterfaceCount - 1);
+		if (inum >= first_intf && inum <= last_intf) {
+			if (!retval)
+				retval = intf_assoc;
+			else
+				dev_err(&dev->dev, "Interface #%d referenced"
+					" by multiple IADs\n", inum);
+		}
+	}
+
+	return retval;
+}
+
+
 /*
 /*
  * usb_set_configuration - Makes a particular device setting be current
  * usb_set_configuration - Makes a particular device setting be current
  * @dev: the device whose configuration is being updated
  * @dev: the device whose configuration is being updated
@@ -1531,6 +1560,7 @@ free_interfaces:
 		intfc = cp->intf_cache[i];
 		intfc = cp->intf_cache[i];
 		intf->altsetting = intfc->altsetting;
 		intf->altsetting = intfc->altsetting;
 		intf->num_altsetting = intfc->num_altsetting;
 		intf->num_altsetting = intfc->num_altsetting;
+		intf->intf_assoc = find_iad(dev, cp, i);
 		kref_get(&intfc->ref);
 		kref_get(&intfc->ref);
 
 
 		alt = usb_altnum_to_altsetting(intf, 0);
 		alt = usb_altnum_to_altsetting(intf, 0);

+ 18 - 0
drivers/usb/core/quirks.c

@@ -30,10 +30,28 @@
 static const struct usb_device_id usb_quirk_list[] = {
 static const struct usb_device_id usb_quirk_list[] = {
 	/* HP 5300/5370C scanner */
 	/* HP 5300/5370C scanner */
 	{ USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
 	{ USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
+	/* Benq S2W 3300U */
+	{ USB_DEVICE(0x04a5, 0x20b0), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+	/* Seiko Epson Corp. Perfection 1200 */
+	{ USB_DEVICE(0x04b8, 0x0104), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
 	/* Seiko Epson Corp - Perfection 1670 */
 	/* Seiko Epson Corp - Perfection 1670 */
 	{ USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
 	{ USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+	/* Samsung ML-2510 Series printer */
+	{ USB_DEVICE(0x04e8, 0x327e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
 	/* Elsa MicroLink 56k (V.250) */
 	/* Elsa MicroLink 56k (V.250) */
 	{ USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
 	{ USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+	/* Ultima Electronics Corp.*/
+	{ USB_DEVICE(0x05d8, 0x4005), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+	/* Umax [hex] Astra 3400U */
+	{ USB_DEVICE(0x1606, 0x0060), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+
+	/* Philips PSC805 audio device */
+	{ USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* RIM Blackberry */
+	{ USB_DEVICE(0x0fca, 0x0001), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+	{ USB_DEVICE(0x0fca, 0x0004), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
+	{ USB_DEVICE(0x0fca, 0x0006), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
 
 
 	{ }  /* terminating entry must be last */
 	{ }  /* terminating entry must be last */
 };
 };

+ 107 - 2
drivers/usb/core/sysfs.c

@@ -169,6 +169,73 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf)
 }
 }
 static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
 static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
 
 
+
+#if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND)
+static const char power_group[] = "power";
+#endif
+
+#ifdef	CONFIG_USB_PERSIST
+
+static ssize_t
+show_persist(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct usb_device *udev = to_usb_device(dev);
+
+	return sprintf(buf, "%d\n", udev->persist_enabled);
+}
+
+static ssize_t
+set_persist(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct usb_device *udev = to_usb_device(dev);
+	int value;
+
+	/* Hubs are always enabled for USB_PERSIST */
+	if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
+		return -EPERM;
+
+	if (sscanf(buf, "%d", &value) != 1)
+		return -EINVAL;
+	usb_pm_lock(udev);
+	udev->persist_enabled = !!value;
+	usb_pm_unlock(udev);
+	return count;
+}
+
+static DEVICE_ATTR(persist, S_IRUGO | S_IWUSR, show_persist, set_persist);
+
+static int add_persist_attributes(struct device *dev)
+{
+	int rc = 0;
+
+	if (is_usb_device(dev)) {
+		struct usb_device *udev = to_usb_device(dev);
+
+		/* Hubs are automatically enabled for USB_PERSIST */
+		if (udev->descriptor.bDeviceClass == USB_CLASS_HUB)
+			udev->persist_enabled = 1;
+		rc = sysfs_add_file_to_group(&dev->kobj,
+				&dev_attr_persist.attr,
+				power_group);
+	}
+	return rc;
+}
+
+static void remove_persist_attributes(struct device *dev)
+{
+	sysfs_remove_file_from_group(&dev->kobj,
+			&dev_attr_persist.attr,
+			power_group);
+}
+
+#else
+
+#define add_persist_attributes(dev)	0
+#define remove_persist_attributes(dev)	do {} while (0)
+
+#endif	/* CONFIG_USB_PERSIST */
+
 #ifdef	CONFIG_USB_SUSPEND
 #ifdef	CONFIG_USB_SUSPEND
 
 
 static ssize_t
 static ssize_t
@@ -276,8 +343,6 @@ set_level(struct device *dev, struct device_attribute *attr,
 
 
 static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level);
 static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level);
 
 
-static char power_group[] = "power";
-
 static int add_power_attributes(struct device *dev)
 static int add_power_attributes(struct device *dev)
 {
 {
 	int rc = 0;
 	int rc = 0;
@@ -311,6 +376,7 @@ static void remove_power_attributes(struct device *dev)
 
 
 #endif	/* CONFIG_USB_SUSPEND */
 #endif	/* CONFIG_USB_SUSPEND */
 
 
+
 /* 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								\
@@ -384,6 +450,10 @@ int usb_create_sysfs_dev_files(struct usb_device *udev)
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
 
 
+	retval = add_persist_attributes(dev);
+	if (retval)
+		goto error;
+
 	retval = add_power_attributes(dev);
 	retval = add_power_attributes(dev);
 	if (retval)
 	if (retval)
 		goto error;
 		goto error;
@@ -421,9 +491,29 @@ void usb_remove_sysfs_dev_files(struct usb_device *udev)
 	device_remove_file(dev, &dev_attr_product);
 	device_remove_file(dev, &dev_attr_product);
 	device_remove_file(dev, &dev_attr_serial);
 	device_remove_file(dev, &dev_attr_serial);
 	remove_power_attributes(dev);
 	remove_power_attributes(dev);
+	remove_persist_attributes(dev);
 	sysfs_remove_group(&dev->kobj, &dev_attr_grp);
 	sysfs_remove_group(&dev->kobj, &dev_attr_grp);
 }
 }
 
 
+/* Interface Accociation Descriptor fields */
+#define usb_intf_assoc_attr(field, format_string)			\
+static ssize_t								\
+show_iad_##field (struct device *dev, struct device_attribute *attr,	\
+		char *buf)						\
+{									\
+	struct usb_interface *intf = to_usb_interface (dev);		\
+									\
+	return sprintf (buf, format_string,				\
+			intf->intf_assoc->field); 		\
+}									\
+static DEVICE_ATTR(iad_##field, S_IRUGO, show_iad_##field, NULL);
+
+usb_intf_assoc_attr (bFirstInterface, "%02x\n")
+usb_intf_assoc_attr (bInterfaceCount, "%02d\n")
+usb_intf_assoc_attr (bFunctionClass, "%02x\n")
+usb_intf_assoc_attr (bFunctionSubClass, "%02x\n")
+usb_intf_assoc_attr (bFunctionProtocol, "%02x\n")
+
 /* Interface fields */
 /* Interface fields */
 #define usb_intf_attr(field, format_string)				\
 #define usb_intf_attr(field, format_string)				\
 static ssize_t								\
 static ssize_t								\
@@ -487,6 +577,18 @@ static ssize_t show_modalias(struct device *dev,
 }
 }
 static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
 static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
 
 
+static struct attribute *intf_assoc_attrs[] = {
+	&dev_attr_iad_bFirstInterface.attr,
+	&dev_attr_iad_bInterfaceCount.attr,
+	&dev_attr_iad_bFunctionClass.attr,
+	&dev_attr_iad_bFunctionSubClass.attr,
+	&dev_attr_iad_bFunctionProtocol.attr,
+	NULL,
+};
+static struct attribute_group intf_assoc_attr_grp = {
+	.attrs = intf_assoc_attrs,
+};
+
 static struct attribute *intf_attrs[] = {
 static struct attribute *intf_attrs[] = {
 	&dev_attr_bInterfaceNumber.attr,
 	&dev_attr_bInterfaceNumber.attr,
 	&dev_attr_bAlternateSetting.attr,
 	&dev_attr_bAlternateSetting.attr,
@@ -538,6 +640,8 @@ int usb_create_sysfs_intf_files(struct usb_interface *intf)
 		alt->string = usb_cache_string(udev, alt->desc.iInterface);
 		alt->string = usb_cache_string(udev, alt->desc.iInterface);
 	if (alt->string)
 	if (alt->string)
 		retval = device_create_file(dev, &dev_attr_interface);
 		retval = device_create_file(dev, &dev_attr_interface);
+	if (intf->intf_assoc)
+		retval = sysfs_create_group(&dev->kobj, &intf_assoc_attr_grp);
 	usb_create_intf_ep_files(intf, udev);
 	usb_create_intf_ep_files(intf, udev);
 	return 0;
 	return 0;
 }
 }
@@ -549,4 +653,5 @@ void usb_remove_sysfs_intf_files(struct usb_interface *intf)
 	usb_remove_intf_ep_files(intf);
 	usb_remove_intf_ep_files(intf);
 	device_remove_file(dev, &dev_attr_interface);
 	device_remove_file(dev, &dev_attr_interface);
 	sysfs_remove_group(&dev->kobj, &intf_attr_grp);
 	sysfs_remove_group(&dev->kobj, &intf_attr_grp);
+	sysfs_remove_group(&intf->dev.kobj, &intf_assoc_attr_grp);
 }
 }

+ 102 - 3
drivers/usb/core/urb.c

@@ -4,6 +4,7 @@
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
+#include <linux/wait.h>
 #include "hcd.h"
 #include "hcd.h"
 
 
 #define to_urb(d) container_of(d, struct urb, kref)
 #define to_urb(d) container_of(d, struct urb, kref)
@@ -11,6 +12,10 @@
 static void urb_destroy(struct kref *kref)
 static void urb_destroy(struct kref *kref)
 {
 {
 	struct urb *urb = to_urb(kref);
 	struct urb *urb = to_urb(kref);
+
+	if (urb->transfer_flags & URB_FREE_BUFFER)
+		kfree(urb->transfer_buffer);
+
 	kfree(urb);
 	kfree(urb);
 }
 }
 
 
@@ -34,6 +39,7 @@ void usb_init_urb(struct urb *urb)
 		memset(urb, 0, sizeof(*urb));
 		memset(urb, 0, sizeof(*urb));
 		kref_init(&urb->kref);
 		kref_init(&urb->kref);
 		spin_lock_init(&urb->lock);
 		spin_lock_init(&urb->lock);
+		INIT_LIST_HEAD(&urb->anchor_list);
 	}
 	}
 }
 }
 
 
@@ -100,8 +106,60 @@ struct urb * usb_get_urb(struct urb *urb)
 		kref_get(&urb->kref);
 		kref_get(&urb->kref);
 	return urb;
 	return urb;
 }
 }
-		
-		
+
+/**
+ * usb_anchor_urb - anchors an URB while it is processed
+ * @urb: pointer to the urb to anchor
+ * @anchor: pointer to the anchor
+ *
+ * This can be called to have access to URBs which are to be executed
+ * without bothering to track them
+ */
+void usb_anchor_urb(struct urb *urb, struct usb_anchor *anchor)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&anchor->lock, flags);
+	usb_get_urb(urb);
+	list_add_tail(&urb->anchor_list, &anchor->urb_list);
+	urb->anchor = anchor;
+	spin_unlock_irqrestore(&anchor->lock, flags);
+}
+EXPORT_SYMBOL_GPL(usb_anchor_urb);
+
+/**
+ * usb_unanchor_urb - unanchors an URB
+ * @urb: pointer to the urb to anchor
+ *
+ * Call this to stop the system keeping track of this URB
+ */
+void usb_unanchor_urb(struct urb *urb)
+{
+	unsigned long flags;
+	struct usb_anchor *anchor;
+
+	if (!urb)
+		return;
+
+	anchor = urb->anchor;
+	if (!anchor)
+		return;
+
+	spin_lock_irqsave(&anchor->lock, flags);
+	if (unlikely(anchor != urb->anchor)) {
+		/* we've lost the race to another thread */
+		spin_unlock_irqrestore(&anchor->lock, flags);
+		return;
+	}
+	urb->anchor = NULL;
+	list_del(&urb->anchor_list);
+	spin_unlock_irqrestore(&anchor->lock, flags);
+	usb_put_urb(urb);
+	if (list_empty(&anchor->urb_list))
+		wake_up(&anchor->wait);
+}
+EXPORT_SYMBOL_GPL(usb_unanchor_urb);
+
 /*-------------------------------------------------------------------*/
 /*-------------------------------------------------------------------*/
 
 
 /**
 /**
@@ -478,6 +536,48 @@ void usb_kill_urb(struct urb *urb)
 	spin_unlock_irq(&urb->lock);
 	spin_unlock_irq(&urb->lock);
 }
 }
 
 
+/**
+ * usb_kill_anchored_urbs - cancel transfer requests en masse
+ * @anchor: anchor the requests are bound to
+ *
+ * this allows all outstanding URBs to be killed starting
+ * from the back of the queue
+ */
+void usb_kill_anchored_urbs(struct usb_anchor *anchor)
+{
+	struct urb *victim;
+
+	spin_lock_irq(&anchor->lock);
+	while (!list_empty(&anchor->urb_list)) {
+		victim = list_entry(anchor->urb_list.prev, struct urb, anchor_list);
+		/* we must make sure the URB isn't freed before we kill it*/
+		usb_get_urb(victim);
+		spin_unlock_irq(&anchor->lock);
+		/* this will unanchor the URB */
+		usb_kill_urb(victim);
+		usb_put_urb(victim);
+		spin_lock_irq(&anchor->lock);
+	}
+	spin_unlock_irq(&anchor->lock);
+}
+EXPORT_SYMBOL_GPL(usb_kill_anchored_urbs);
+
+/**
+ * usb_wait_anchor_empty_timeout - wait for an anchor to be unused
+ * @anchor: the anchor you want to become unused
+ * @timeout: how long you are willing to wait in milliseconds
+ *
+ * Call this is you want to be sure all an anchor's
+ * URBs have finished
+ */
+int usb_wait_anchor_empty_timeout(struct usb_anchor *anchor,
+				  unsigned int timeout)
+{
+	return wait_event_timeout(anchor->wait, list_empty(&anchor->urb_list),
+				  msecs_to_jiffies(timeout));
+}
+EXPORT_SYMBOL_GPL(usb_wait_anchor_empty_timeout);
+
 EXPORT_SYMBOL(usb_init_urb);
 EXPORT_SYMBOL(usb_init_urb);
 EXPORT_SYMBOL(usb_alloc_urb);
 EXPORT_SYMBOL(usb_alloc_urb);
 EXPORT_SYMBOL(usb_free_urb);
 EXPORT_SYMBOL(usb_free_urb);
@@ -485,4 +585,3 @@ EXPORT_SYMBOL(usb_get_urb);
 EXPORT_SYMBOL(usb_submit_urb);
 EXPORT_SYMBOL(usb_submit_urb);
 EXPORT_SYMBOL(usb_unlink_urb);
 EXPORT_SYMBOL(usb_unlink_urb);
 EXPORT_SYMBOL(usb_kill_urb);
 EXPORT_SYMBOL(usb_kill_urb);
-

+ 7 - 5
drivers/usb/core/usb.c

@@ -253,6 +253,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
 	dev->dev.bus = &usb_bus_type;
 	dev->dev.bus = &usb_bus_type;
 	dev->dev.type = &usb_device_type;
 	dev->dev.type = &usb_device_type;
 	dev->dev.dma_mask = bus->controller->dma_mask;
 	dev->dev.dma_mask = bus->controller->dma_mask;
+	set_dev_node(&dev->dev, dev_to_node(bus->controller));
 	dev->state = USB_STATE_ATTACHED;
 	dev->state = USB_STATE_ATTACHED;
 
 
 	INIT_LIST_HEAD(&dev->ep0.urb_list);
 	INIT_LIST_HEAD(&dev->ep0.urb_list);
@@ -578,11 +579,12 @@ int __usb_get_extra_descriptor(char *buffer, unsigned size,
  * address (through the pointer provided).
  * address (through the pointer provided).
  *
  *
  * These buffers are used with URB_NO_xxx_DMA_MAP set in urb->transfer_flags
  * These buffers are used with URB_NO_xxx_DMA_MAP set in urb->transfer_flags
- * to avoid behaviors like using "DMA bounce buffers", or tying down I/O
- * mapping hardware for long idle periods.  The implementation varies between
+ * to avoid behaviors like using "DMA bounce buffers", or thrashing IOMMU
+ * hardware during URB completion/resubmit.  The implementation varies between
  * platforms, depending on details of how DMA will work to this device.
  * platforms, depending on details of how DMA will work to this device.
- * Using these buffers also helps prevent cacheline sharing problems on
- * architectures where CPU caches are not DMA-coherent.
+ * Using these buffers also eliminates cacheline sharing problems on
+ * architectures where CPU caches are not DMA-coherent.  On systems without
+ * bus-snooping caches, these buffers are uncached.
  *
  *
  * 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().
  */
  */
@@ -607,7 +609,7 @@ void *usb_buffer_alloc(
  *
  *
  * This reclaims an I/O buffer, letting it be reused.  The memory must have
  * This reclaims an I/O buffer, letting it be reused.  The memory must have
  * 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,

+ 12 - 2
drivers/usb/core/usb.h

@@ -52,8 +52,16 @@ static inline void usb_pm_unlock(struct usb_device *udev)
 
 
 #else
 #else
 
 
-#define usb_port_suspend(dev)		0
-#define usb_port_resume(dev)		0
+static inline int usb_port_suspend(struct usb_device *udev)
+{
+	return 0;
+}
+
+static inline int usb_port_resume(struct usb_device *udev)
+{
+	return 0;
+}
+
 static inline void usb_pm_lock(struct usb_device *udev) {}
 static inline void usb_pm_lock(struct usb_device *udev) {}
 static inline void usb_pm_unlock(struct usb_device *udev) {}
 static inline void usb_pm_unlock(struct usb_device *udev) {}
 
 
@@ -100,11 +108,13 @@ static inline int is_usb_device_driver(struct device_driver *drv)
 static inline void mark_active(struct usb_interface *f)
 static inline void mark_active(struct usb_interface *f)
 {
 {
 	f->is_active = 1;
 	f->is_active = 1;
+	f->dev.power.power_state.event = PM_EVENT_ON;
 }
 }
 
 
 static inline void mark_quiesced(struct usb_interface *f)
 static inline void mark_quiesced(struct usb_interface *f)
 {
 {
 	f->is_active = 0;
 	f->is_active = 0;
+	f->dev.power.power_state.event = PM_EVENT_SUSPEND;
 }
 }
 
 
 static inline int is_active(const struct usb_interface *f)
 static inline int is_active(const struct usb_interface *f)

+ 53 - 0
drivers/usb/gadget/Kconfig

@@ -42,6 +42,20 @@ config USB_GADGET
 	   For more information, see <http://www.linux-usb.org/gadget> and
 	   For more information, see <http://www.linux-usb.org/gadget> and
 	   the kernel DocBook documentation for this API.
 	   the kernel DocBook documentation for this API.
 
 
+config USB_GADGET_DEBUG
+	boolean "Debugging messages"
+	depends on USB_GADGET && DEBUG_KERNEL && EXPERIMENTAL
+	help
+	   Many controller and gadget drivers will print some debugging
+	   messages if you use this option to ask for those messages.
+
+	   Avoid enabling these messages, even if you're actively
+	   debugging such a driver.  Many drivers will emit so many
+	   messages that the driver timings are affected, which will
+	   either create new failure modes or remove the one you're
+	   trying to track down.  Never enable these messages for a
+	   production build.
+
 config USB_GADGET_DEBUG_FILES
 config USB_GADGET_DEBUG_FILES
 	boolean "Debugging information files"
 	boolean "Debugging information files"
 	depends on USB_GADGET && PROC_FS
 	depends on USB_GADGET && PROC_FS
@@ -208,6 +222,27 @@ config USB_OTG
 
 
 	   Select this only if your OMAP board has a Mini-AB connector.
 	   Select this only if your OMAP board has a Mini-AB connector.
 
 
+config USB_GADGET_S3C2410
+	boolean "S3C2410 USB Device Controller"
+	depends on ARCH_S3C2410
+	help
+	  Samsung's S3C2410 is an ARM-4 processor with an integrated
+	  full speed USB 1.1 device controller.  It has 4 configurable
+	  endpoints, as well as endpoint zero (for control transfers).
+
+	  This driver has been tested on the S3C2410, S3C2412, and
+	  S3C2440 processors.
+
+config USB_S3C2410
+	tristate
+	depends on USB_GADGET_S3C2410
+	default USB_GADGET
+	select USB_GADGET_SELECTED
+
+config USB_S3C2410_DEBUG
+	boolean "S3C2410 udc debug messages"
+	depends on USB_GADGET_S3C2410
+
 config USB_GADGET_AT91
 config USB_GADGET_AT91
 	boolean "AT91 USB Device Port"
 	boolean "AT91 USB Device Port"
 	depends on ARCH_AT91 && !ARCH_AT91SAM9RL
 	depends on ARCH_AT91 && !ARCH_AT91SAM9RL
@@ -226,6 +261,24 @@ config USB_AT91
 	depends on USB_GADGET_AT91
 	depends on USB_GADGET_AT91
 	default USB_GADGET
 	default USB_GADGET
 
 
+config USB_GADGET_M66592
+	boolean "M66592 driver"
+	select USB_GADGET_DUALSPEED
+	help
+	   M66592 is a USB 2.0 peripheral controller.
+
+	   It has seven configurable endpoints, and endpoint zero.
+
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "m66592_udc" and force all
+	   gadget drivers to also be dynamically linked.
+
+config USB_M66592
+	tristate
+	depends on USB_GADGET_M66592
+	default USB_GADGET
+	select USB_GADGET_SELECTED
+
 config USB_GADGET_DUMMY_HCD
 config USB_GADGET_DUMMY_HCD
 	boolean "Dummy HCD (DEVELOPMENT)"
 	boolean "Dummy HCD (DEVELOPMENT)"
 	depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL
 	depends on (USB=y || (USB=m && USB_GADGET=m)) && EXPERIMENTAL

+ 6 - 0
drivers/usb/gadget/Makefile

@@ -1,14 +1,20 @@
 #
 #
 # USB peripheral controller drivers
 # USB peripheral controller drivers
 #
 #
+ifeq ($(CONFIG_USB_GADGET_DEBUG),y)
+	EXTRA_CFLAGS		+= -DDEBUG
+endif
+
 obj-$(CONFIG_USB_DUMMY_HCD)	+= dummy_hcd.o
 obj-$(CONFIG_USB_DUMMY_HCD)	+= dummy_hcd.o
 obj-$(CONFIG_USB_NET2280)	+= net2280.o
 obj-$(CONFIG_USB_NET2280)	+= net2280.o
 obj-$(CONFIG_USB_PXA2XX)	+= pxa2xx_udc.o
 obj-$(CONFIG_USB_PXA2XX)	+= pxa2xx_udc.o
 obj-$(CONFIG_USB_GOKU)		+= goku_udc.o
 obj-$(CONFIG_USB_GOKU)		+= goku_udc.o
 obj-$(CONFIG_USB_OMAP)		+= omap_udc.o
 obj-$(CONFIG_USB_OMAP)		+= omap_udc.o
 obj-$(CONFIG_USB_LH7A40X)	+= lh7a40x_udc.o
 obj-$(CONFIG_USB_LH7A40X)	+= lh7a40x_udc.o
+obj-$(CONFIG_USB_S3C2410)	+= s3c2410_udc.o
 obj-$(CONFIG_USB_AT91)		+= at91_udc.o
 obj-$(CONFIG_USB_AT91)		+= at91_udc.o
 obj-$(CONFIG_USB_FSL_USB2)	+= fsl_usb2_udc.o
 obj-$(CONFIG_USB_FSL_USB2)	+= fsl_usb2_udc.o
+obj-$(CONFIG_USB_M66592)	+= m66592-udc.o
 
 
 #
 #
 # USB gadget drivers
 # USB gadget drivers

+ 0 - 21
drivers/usb/gadget/at91_udc.c

@@ -601,25 +601,6 @@ static void at91_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
 	kfree(req);
 	kfree(req);
 }
 }
 
 
-static void *at91_ep_alloc_buffer(
-	struct usb_ep *_ep,
-	unsigned bytes,
-	dma_addr_t *dma,
-	gfp_t gfp_flags)
-{
-	*dma = ~0;
-	return kmalloc(bytes, gfp_flags);
-}
-
-static void at91_ep_free_buffer(
-	struct usb_ep *ep,
-	void *buf,
-	dma_addr_t dma,
-	unsigned bytes)
-{
-	kfree(buf);
-}
-
 static int at91_ep_queue(struct usb_ep *_ep,
 static int at91_ep_queue(struct usb_ep *_ep,
 			struct usb_request *_req, gfp_t gfp_flags)
 			struct usb_request *_req, gfp_t gfp_flags)
 {
 {
@@ -788,8 +769,6 @@ static const struct usb_ep_ops at91_ep_ops = {
 	.disable	= at91_ep_disable,
 	.disable	= at91_ep_disable,
 	.alloc_request	= at91_ep_alloc_request,
 	.alloc_request	= at91_ep_alloc_request,
 	.free_request	= at91_ep_free_request,
 	.free_request	= at91_ep_free_request,
-	.alloc_buffer	= at91_ep_alloc_buffer,
-	.free_buffer	= at91_ep_free_buffer,
 	.queue		= at91_ep_queue,
 	.queue		= at91_ep_queue,
 	.dequeue	= at91_ep_dequeue,
 	.dequeue	= at91_ep_dequeue,
 	.set_halt	= at91_ep_set_halt,
 	.set_halt	= at91_ep_set_halt,

+ 1 - 38
drivers/usb/gadget/dummy_hcd.c

@@ -497,38 +497,6 @@ dummy_free_request (struct usb_ep *_ep, struct usb_request *_req)
 	kfree (req);
 	kfree (req);
 }
 }
 
 
-static void *
-dummy_alloc_buffer (
-	struct usb_ep *_ep,
-	unsigned bytes,
-	dma_addr_t *dma,
-	gfp_t mem_flags
-) {
-	char			*retval;
-	struct dummy_ep		*ep;
-	struct dummy		*dum;
-
-	ep = usb_ep_to_dummy_ep (_ep);
-	dum = ep_to_dummy (ep);
-
-	if (!dum->driver)
-		return NULL;
-	retval = kmalloc (bytes, mem_flags);
-	*dma = (dma_addr_t) retval;
-	return retval;
-}
-
-static void
-dummy_free_buffer (
-	struct usb_ep *_ep,
-	void *buf,
-	dma_addr_t dma,
-	unsigned bytes
-) {
-	if (bytes)
-		kfree (buf);
-}
-
 static void
 static void
 fifo_complete (struct usb_ep *ep, struct usb_request *req)
 fifo_complete (struct usb_ep *ep, struct usb_request *req)
 {
 {
@@ -659,10 +627,6 @@ static const struct usb_ep_ops dummy_ep_ops = {
 	.alloc_request	= dummy_alloc_request,
 	.alloc_request	= dummy_alloc_request,
 	.free_request	= dummy_free_request,
 	.free_request	= dummy_free_request,
 
 
-	.alloc_buffer	= dummy_alloc_buffer,
-	.free_buffer	= dummy_free_buffer,
-	/* map, unmap, ... eventually hook the "generic" dma calls */
-
 	.queue		= dummy_queue,
 	.queue		= dummy_queue,
 	.dequeue	= dummy_dequeue,
 	.dequeue	= dummy_dequeue,
 
 
@@ -1784,8 +1748,7 @@ static int dummy_bus_resume (struct usb_hcd *hcd)
 
 
 	spin_lock_irq (&dum->lock);
 	spin_lock_irq (&dum->lock);
 	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
 	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
-		dev_warn (&hcd->self.root_hub->dev, "HC isn't running!\n");
-		rc = -ENODEV;
+		rc = -ESHUTDOWN;
 	} else {
 	} else {
 		dum->rh_state = DUMMY_RH_RUNNING;
 		dum->rh_state = DUMMY_RH_RUNNING;
 		set_link_state (dum);
 		set_link_state (dum);

+ 6 - 2
drivers/usb/gadget/ether.c

@@ -277,7 +277,7 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 #define DEV_CONFIG_CDC
 #define DEV_CONFIG_CDC
 #endif
 #endif
 
 
-#ifdef CONFIG_USB_GADGET_HUSB2DEV
+#ifdef CONFIG_USB_GADGET_ATMEL_USBA
 #define DEV_CONFIG_CDC
 #define DEV_CONFIG_CDC
 #endif
 #endif
 
 
@@ -292,7 +292,7 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 #define	DEV_CONFIG_SUBSET
 #define	DEV_CONFIG_SUBSET
 #endif
 #endif
 
 
-#ifdef CONFIG_USB_GADGET_SH
+#ifdef CONFIG_USB_GADGET_SUPERH
 #define	DEV_CONFIG_SUBSET
 #define	DEV_CONFIG_SUBSET
 #endif
 #endif
 
 
@@ -301,6 +301,10 @@ MODULE_PARM_DESC(host_addr, "Host Ethernet Address");
 #define	DEV_CONFIG_SUBSET
 #define	DEV_CONFIG_SUBSET
 #endif
 #endif
 
 
+#ifdef CONFIG_USB_GADGET_M66592
+#define DEV_CONFIG_CDC
+#endif
+
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 

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

@@ -3733,19 +3733,12 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
 	}
 	}
 
 
 	/* Free the data buffers */
 	/* Free the data buffers */
-	for (i = 0; i < NUM_BUFFERS; ++i) {
-		struct fsg_buffhd	*bh = &fsg->buffhds[i];
-
-		if (bh->buf)
-			usb_ep_free_buffer(fsg->bulk_in, bh->buf, bh->dma,
-					mod_data.buflen);
-	}
+	for (i = 0; i < NUM_BUFFERS; ++i)
+		kfree(fsg->buffhds[i].buf);
 
 
 	/* Free the request and buffer for endpoint 0 */
 	/* Free the request and buffer for endpoint 0 */
 	if (req) {
 	if (req) {
-		if (req->buf)
-			usb_ep_free_buffer(fsg->ep0, req->buf,
-					req->dma, EP0_BUFSIZE);
+		kfree(req->buf);
 		usb_ep_free_request(fsg->ep0, req);
 		usb_ep_free_request(fsg->ep0, req);
 	}
 	}
 
 
@@ -3963,8 +3956,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
 #endif
 #endif
 
 
 	if (gadget->is_otg) {
 	if (gadget->is_otg) {
-		otg_desc.bmAttributes |= USB_OTG_HNP,
-		config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+		otg_desc.bmAttributes |= USB_OTG_HNP;
 	}
 	}
 
 
 	rc = -ENOMEM;
 	rc = -ENOMEM;
@@ -3973,8 +3965,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
 	fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);
 	fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL);
 	if (!req)
 	if (!req)
 		goto out;
 		goto out;
-	req->buf = usb_ep_alloc_buffer(fsg->ep0, EP0_BUFSIZE,
-			&req->dma, GFP_KERNEL);
+	req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL);
 	if (!req->buf)
 	if (!req->buf)
 		goto out;
 		goto out;
 	req->complete = ep0_complete;
 	req->complete = ep0_complete;
@@ -3986,8 +3977,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
 		/* Allocate for the bulk-in endpoint.  We assume that
 		/* Allocate for the bulk-in endpoint.  We assume that
 		 * the buffer will also work with the bulk-out (and
 		 * the buffer will also work with the bulk-out (and
 		 * interrupt-in) endpoint. */
 		 * interrupt-in) endpoint. */
-		bh->buf = usb_ep_alloc_buffer(fsg->bulk_in, mod_data.buflen,
-				&bh->dma, GFP_KERNEL);
+		bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL);
 		if (!bh->buf)
 		if (!bh->buf)
 			goto out;
 			goto out;
 		bh->next = bh + 1;
 		bh->next = bh + 1;

+ 36 - 63
drivers/usb/gadget/fsl_usb2_udc.c

@@ -228,7 +228,7 @@ static int dr_controller_setup(struct fsl_udc *udc)
 
 
 	/* Config PHY interface */
 	/* Config PHY interface */
 	portctrl = fsl_readl(&dr_regs->portsc1);
 	portctrl = fsl_readl(&dr_regs->portsc1);
-	portctrl &= ~(PORTSCX_PHY_TYPE_SEL & PORTSCX_PORT_WIDTH);
+	portctrl &= ~(PORTSCX_PHY_TYPE_SEL | PORTSCX_PORT_WIDTH);
 	switch (udc->phy_mode) {
 	switch (udc->phy_mode) {
 	case FSL_USB2_PHY_ULPI:
 	case FSL_USB2_PHY_ULPI:
 		portctrl |= PORTSCX_PTS_ULPI;
 		portctrl |= PORTSCX_PTS_ULPI;
@@ -601,39 +601,6 @@ static void fsl_free_request(struct usb_ep *_ep, struct usb_request *_req)
 		kfree(req);
 		kfree(req);
 }
 }
 
 
-/*------------------------------------------------------------------
- * Allocate an I/O buffer
-*---------------------------------------------------------------------*/
-static void *fsl_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
-		dma_addr_t *dma, gfp_t gfp_flags)
-{
-	struct fsl_ep *ep;
-
-	if (!_ep)
-		return NULL;
-
-	ep = container_of(_ep, struct fsl_ep, ep);
-
-	return dma_alloc_coherent(ep->udc->gadget.dev.parent,
-			bytes, dma, gfp_flags);
-}
-
-/*------------------------------------------------------------------
- * frees an i/o buffer
-*---------------------------------------------------------------------*/
-static void fsl_free_buffer(struct usb_ep *_ep, void *buf,
-		dma_addr_t dma, unsigned bytes)
-{
-	struct fsl_ep *ep;
-
-	if (!_ep)
-		return;
-
-	ep = container_of(_ep, struct fsl_ep, ep);
-
-	dma_free_coherent(ep->udc->gadget.dev.parent, bytes, buf, dma);
-}
-
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 static int fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
 static int fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
 {
 {
@@ -1047,9 +1014,6 @@ static struct usb_ep_ops fsl_ep_ops = {
 	.alloc_request = fsl_alloc_request,
 	.alloc_request = fsl_alloc_request,
 	.free_request = fsl_free_request,
 	.free_request = fsl_free_request,
 
 
-	.alloc_buffer = fsl_alloc_buffer,
-	.free_buffer = fsl_free_buffer,
-
 	.queue = fsl_ep_queue,
 	.queue = fsl_ep_queue,
 	.dequeue = fsl_ep_dequeue,
 	.dequeue = fsl_ep_dequeue,
 
 
@@ -2189,27 +2153,19 @@ static void fsl_udc_release(struct device *dev)
  * init resource for globle controller
  * init resource for globle controller
  * Return the udc handle on success or NULL on failure
  * Return the udc handle on success or NULL on failure
  ------------------------------------------------------------------*/
  ------------------------------------------------------------------*/
-static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev)
+static int __init struct_udc_setup(struct fsl_udc *udc,
+		struct platform_device *pdev)
 {
 {
-	struct fsl_udc *udc;
 	struct fsl_usb2_platform_data *pdata;
 	struct fsl_usb2_platform_data *pdata;
 	size_t size;
 	size_t size;
 
 
-	udc = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL);
-	if (udc == NULL) {
-		ERR("malloc udc failed\n");
-		return NULL;
-	}
-
 	pdata = pdev->dev.platform_data;
 	pdata = pdev->dev.platform_data;
 	udc->phy_mode = pdata->phy_mode;
 	udc->phy_mode = pdata->phy_mode;
-	/* max_ep_nr is bidirectional ep number, max_ep doubles the number */
-	udc->max_ep = pdata->max_ep_nr * 2;
 
 
 	udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL);
 	udc->eps = kzalloc(sizeof(struct fsl_ep) * udc->max_ep, GFP_KERNEL);
 	if (!udc->eps) {
 	if (!udc->eps) {
 		ERR("malloc fsl_ep failed\n");
 		ERR("malloc fsl_ep failed\n");
-		goto cleanup;
+		return -1;
 	}
 	}
 
 
 	/* initialized QHs, take care of alignment */
 	/* initialized QHs, take care of alignment */
@@ -2225,7 +2181,7 @@ static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev)
 	if (!udc->ep_qh) {
 	if (!udc->ep_qh) {
 		ERR("malloc QHs for udc failed\n");
 		ERR("malloc QHs for udc failed\n");
 		kfree(udc->eps);
 		kfree(udc->eps);
-		goto cleanup;
+		return -1;
 	}
 	}
 
 
 	udc->ep_qh_size = size;
 	udc->ep_qh_size = size;
@@ -2244,11 +2200,7 @@ static struct fsl_udc *__init struct_udc_setup(struct platform_device *pdev)
 	udc->remote_wakeup = 0;	/* default to 0 on reset */
 	udc->remote_wakeup = 0;	/* default to 0 on reset */
 	spin_lock_init(&udc->lock);
 	spin_lock_init(&udc->lock);
 
 
-	return udc;
-
-cleanup:
-	kfree(udc);
-	return NULL;
+	return 0;
 }
 }
 
 
 /*----------------------------------------------------------------
 /*----------------------------------------------------------------
@@ -2287,35 +2239,37 @@ static int __init struct_ep_setup(struct fsl_udc *udc, unsigned char index,
 }
 }
 
 
 /* Driver probe function
 /* Driver probe function
- * all intialize operations implemented here except enabling usb_intr reg
+ * all intialization operations implemented here except enabling usb_intr reg
+ * board setup should have been done in the platform code
  */
  */
 static int __init fsl_udc_probe(struct platform_device *pdev)
 static int __init fsl_udc_probe(struct platform_device *pdev)
 {
 {
 	struct resource *res;
 	struct resource *res;
 	int ret = -ENODEV;
 	int ret = -ENODEV;
 	unsigned int i;
 	unsigned int i;
+	u32 dccparams;
 
 
 	if (strcmp(pdev->name, driver_name)) {
 	if (strcmp(pdev->name, driver_name)) {
 		VDBG("Wrong device\n");
 		VDBG("Wrong device\n");
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
-	/* board setup should have been done in the platform code */
-
-	/* Initialize the udc structure including QH member and other member */
-	udc_controller = struct_udc_setup(pdev);
-	if (!udc_controller) {
-		VDBG("udc_controller is NULL \n");
+	udc_controller = kzalloc(sizeof(struct fsl_udc), GFP_KERNEL);
+	if (udc_controller == NULL) {
+		ERR("malloc udc failed\n");
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	if (!res)
+	if (!res) {
+		kfree(udc_controller);
 		return -ENXIO;
 		return -ENXIO;
+	}
 
 
 	if (!request_mem_region(res->start, res->end - res->start + 1,
 	if (!request_mem_region(res->start, res->end - res->start + 1,
 				driver_name)) {
 				driver_name)) {
 		ERR("request mem region for %s failed \n", pdev->name);
 		ERR("request mem region for %s failed \n", pdev->name);
+		kfree(udc_controller);
 		return -EBUSY;
 		return -EBUSY;
 	}
 	}
 
 
@@ -2328,13 +2282,24 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
 	usb_sys_regs = (struct usb_sys_interface *)
 	usb_sys_regs = (struct usb_sys_interface *)
 			((u32)dr_regs + USB_DR_SYS_OFFSET);
 			((u32)dr_regs + USB_DR_SYS_OFFSET);
 
 
+	/* Read Device Controller Capability Parameters register */
+	dccparams = fsl_readl(&dr_regs->dccparams);
+	if (!(dccparams & DCCPARAMS_DC)) {
+		ERR("This SOC doesn't support device role\n");
+		ret = -ENODEV;
+		goto err2;
+	}
+	/* Get max device endpoints */
+	/* DEN is bidirectional ep number, max_ep doubles the number */
+	udc_controller->max_ep = (dccparams & DCCPARAMS_DEN_MASK) * 2;
+
 	udc_controller->irq = platform_get_irq(pdev, 0);
 	udc_controller->irq = platform_get_irq(pdev, 0);
 	if (!udc_controller->irq) {
 	if (!udc_controller->irq) {
 		ret = -ENODEV;
 		ret = -ENODEV;
 		goto err2;
 		goto err2;
 	}
 	}
 
 
-	ret = request_irq(udc_controller->irq, fsl_udc_irq, SA_SHIRQ,
+	ret = request_irq(udc_controller->irq, fsl_udc_irq, IRQF_SHARED,
 			driver_name, udc_controller);
 			driver_name, udc_controller);
 	if (ret != 0) {
 	if (ret != 0) {
 		ERR("cannot request irq %d err %d \n",
 		ERR("cannot request irq %d err %d \n",
@@ -2342,6 +2307,13 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
 		goto err2;
 		goto err2;
 	}
 	}
 
 
+	/* Initialize the udc structure including QH member and other member */
+	if (struct_udc_setup(udc_controller, pdev)) {
+		ERR("Can't initialize udc data structure\n");
+		ret = -ENOMEM;
+		goto err3;
+	}
+
 	/* initialize usb hw reg except for regs for EP,
 	/* initialize usb hw reg except for regs for EP,
 	 * leave usbintr reg untouched */
 	 * leave usbintr reg untouched */
 	dr_controller_setup(udc_controller);
 	dr_controller_setup(udc_controller);
@@ -2403,6 +2375,7 @@ err2:
 	iounmap(dr_regs);
 	iounmap(dr_regs);
 err1:
 err1:
 	release_mem_region(res->start, res->end - res->start + 1);
 	release_mem_region(res->start, res->end - res->start + 1);
+	kfree(udc_controller);
 	return ret;
 	return ret;
 }
 }
 
 

+ 4 - 0
drivers/usb/gadget/fsl_usb2_udc.h

@@ -101,6 +101,10 @@ struct usb_sys_interface {
 #define WAIT_FOR_OUT_STATUS     3
 #define WAIT_FOR_OUT_STATUS     3
 #define DATA_STATE_RECV         4
 #define DATA_STATE_RECV         4
 
 
+/* Device Controller Capability Parameter register */
+#define DCCPARAMS_DC				0x00000080
+#define DCCPARAMS_DEN_MASK			0x0000001f
+
 /* Frame Index Register Bit Masks */
 /* Frame Index Register Bit Masks */
 #define	USB_FRINDEX_MASKS			0x3fff
 #define	USB_FRINDEX_MASKS			0x3fff
 /* USB CMD  Register Bit Masks */
 /* USB CMD  Register Bit Masks */

+ 23 - 4
drivers/usb/gadget/gadget_chips.h

@@ -8,6 +8,8 @@
  * (And avoiding all runtime comparisons in typical one-choice configs!)
  * (And avoiding all runtime comparisons in typical one-choice configs!)
  *
  *
  * NOTE:  some of these controller drivers may not be available yet.
  * NOTE:  some of these controller drivers may not be available yet.
+ * Some are available on 2.4 kernels; several are available, but not
+ * yet pushed in the 2.6 mainline tree.
  */
  */
 #ifdef CONFIG_USB_GADGET_NET2280
 #ifdef CONFIG_USB_GADGET_NET2280
 #define	gadget_is_net2280(g)	!strcmp("net2280", (g)->name)
 #define	gadget_is_net2280(g)	!strcmp("net2280", (g)->name)
@@ -33,12 +35,14 @@
 #define	gadget_is_goku(g)	0
 #define	gadget_is_goku(g)	0
 #endif
 #endif
 
 
+/* SH3 UDC -- not yet ported 2.4 --> 2.6 */
 #ifdef CONFIG_USB_GADGET_SUPERH
 #ifdef CONFIG_USB_GADGET_SUPERH
 #define	gadget_is_sh(g)		!strcmp("sh_udc", (g)->name)
 #define	gadget_is_sh(g)		!strcmp("sh_udc", (g)->name)
 #else
 #else
 #define	gadget_is_sh(g)		0
 #define	gadget_is_sh(g)		0
 #endif
 #endif
 
 
+/* not yet stable on 2.6 (would help "original Zaurus") */
 #ifdef CONFIG_USB_GADGET_SA1100
 #ifdef CONFIG_USB_GADGET_SA1100
 #define	gadget_is_sa1100(g)	!strcmp("sa1100_udc", (g)->name)
 #define	gadget_is_sa1100(g)	!strcmp("sa1100_udc", (g)->name)
 #else
 #else
@@ -51,6 +55,7 @@
 #define	gadget_is_lh7a40x(g)	0
 #define	gadget_is_lh7a40x(g)	0
 #endif
 #endif
 
 
+/* handhelds.org tree (?) */
 #ifdef CONFIG_USB_GADGET_MQ11XX
 #ifdef CONFIG_USB_GADGET_MQ11XX
 #define	gadget_is_mq11xx(g)	!strcmp("mq11xx_udc", (g)->name)
 #define	gadget_is_mq11xx(g)	!strcmp("mq11xx_udc", (g)->name)
 #else
 #else
@@ -63,22 +68,24 @@
 #define	gadget_is_omap(g)	0
 #define	gadget_is_omap(g)	0
 #endif
 #endif
 
 
+/* not yet ported 2.4 --> 2.6 */
 #ifdef CONFIG_USB_GADGET_N9604
 #ifdef CONFIG_USB_GADGET_N9604
 #define	gadget_is_n9604(g)	!strcmp("n9604_udc", (g)->name)
 #define	gadget_is_n9604(g)	!strcmp("n9604_udc", (g)->name)
 #else
 #else
 #define	gadget_is_n9604(g)	0
 #define	gadget_is_n9604(g)	0
 #endif
 #endif
 
 
+/* various unstable versions available */
 #ifdef CONFIG_USB_GADGET_PXA27X
 #ifdef CONFIG_USB_GADGET_PXA27X
 #define	gadget_is_pxa27x(g)	!strcmp("pxa27x_udc", (g)->name)
 #define	gadget_is_pxa27x(g)	!strcmp("pxa27x_udc", (g)->name)
 #else
 #else
 #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)
+#ifdef CONFIG_USB_GADGET_ATMEL_USBA
+#define gadget_is_atmel_usba(g)	!strcmp("atmel_usba_udc", (g)->name)
 #else
 #else
-#define gadget_is_husb2dev(g)	0
+#define gadget_is_atmel_usba(g)	0
 #endif
 #endif
 
 
 #ifdef CONFIG_USB_GADGET_S3C2410
 #ifdef CONFIG_USB_GADGET_S3C2410
@@ -93,6 +100,7 @@
 #define gadget_is_at91(g)	0
 #define gadget_is_at91(g)	0
 #endif
 #endif
 
 
+/* status unclear */
 #ifdef CONFIG_USB_GADGET_IMX
 #ifdef CONFIG_USB_GADGET_IMX
 #define gadget_is_imx(g)	!strcmp("imx_udc", (g)->name)
 #define gadget_is_imx(g)	!strcmp("imx_udc", (g)->name)
 #else
 #else
@@ -106,6 +114,7 @@
 #endif
 #endif
 
 
 /* Mentor high speed function controller */
 /* Mentor high speed function controller */
+/* from Montavista kernel (?) */
 #ifdef CONFIG_USB_GADGET_MUSBHSFC
 #ifdef CONFIG_USB_GADGET_MUSBHSFC
 #define gadget_is_musbhsfc(g)	!strcmp("musbhsfc_udc", (g)->name)
 #define gadget_is_musbhsfc(g)	!strcmp("musbhsfc_udc", (g)->name)
 #else
 #else
@@ -119,12 +128,20 @@
 #define gadget_is_musbhdrc(g)	0
 #define gadget_is_musbhdrc(g)	0
 #endif
 #endif
 
 
+/* from Montavista kernel (?) */
 #ifdef CONFIG_USB_GADGET_MPC8272
 #ifdef CONFIG_USB_GADGET_MPC8272
 #define gadget_is_mpc8272(g)	!strcmp("mpc8272_udc", (g)->name)
 #define gadget_is_mpc8272(g)	!strcmp("mpc8272_udc", (g)->name)
 #else
 #else
 #define gadget_is_mpc8272(g)	0
 #define gadget_is_mpc8272(g)	0
 #endif
 #endif
 
 
+#ifdef CONFIG_USB_GADGET_M66592
+#define	gadget_is_m66592(g)	!strcmp("m66592_udc", (g)->name)
+#else
+#define	gadget_is_m66592(g)	0
+#endif
+
+
 // CONFIG_USB_GADGET_SX2
 // CONFIG_USB_GADGET_SX2
 // CONFIG_USB_GADGET_AU1X00
 // CONFIG_USB_GADGET_AU1X00
 // ...
 // ...
@@ -181,9 +198,11 @@ 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))
+	else if (gadget_is_atmel_usba(gadget))
 		return 0x18;
 		return 0x18;
 	else if (gadget_is_fsl_usb2(gadget))
 	else if (gadget_is_fsl_usb2(gadget))
 		return 0x19;
 		return 0x19;
+	else if (gadget_is_m66592(gadget))
+		return 0x20;
 	return -ENOENT;
 	return -ENOENT;
 }
 }

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

@@ -1248,17 +1248,11 @@ autoconf_fail:
 	tasklet_init(&dev->tasklet, gmidi_in_tasklet, (unsigned long)dev);
 	tasklet_init(&dev->tasklet, gmidi_in_tasklet, (unsigned long)dev);
 
 
 	/* preallocate control response and buffer */
 	/* preallocate control response and buffer */
-	dev->req = usb_ep_alloc_request(gadget->ep0, GFP_KERNEL);
+	dev->req = alloc_ep_req(gadget->ep0, USB_BUFSIZ);
 	if (!dev->req) {
 	if (!dev->req) {
 		err = -ENOMEM;
 		err = -ENOMEM;
 		goto fail;
 		goto fail;
 	}
 	}
-	dev->req->buf = usb_ep_alloc_buffer(gadget->ep0, USB_BUFSIZ,
-				&dev->req->dma, GFP_KERNEL);
-	if (!dev->req->buf) {
-		err = -ENOMEM;
-		goto fail;
-	}
 
 
 	dev->req->complete = gmidi_setup_complete;
 	dev->req->complete = gmidi_setup_complete;
 
 

+ 17 - 67
drivers/usb/gadget/goku_udc.c

@@ -20,7 +20,6 @@
  *  - DMA works with ep1 (OUT transfers) and ep2 (IN transfers).
  *  - DMA works with ep1 (OUT transfers) and ep2 (IN transfers).
  */
  */
 
 
-#undef DEBUG
 // #define	VERBOSE		/* extra debug messages (success too) */
 // #define	VERBOSE		/* extra debug messages (success too) */
 // #define	USB_TRACE	/* packet-level success messages */
 // #define	USB_TRACE	/* packet-level success messages */
 
 
@@ -296,51 +295,6 @@ goku_free_request(struct usb_ep *_ep, struct usb_request *_req)
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-/* allocating buffers this way eliminates dma mapping overhead, which
- * on some platforms will mean eliminating a per-io buffer copy.  with
- * some kinds of system caches, further tweaks may still be needed.
- */
-static void *
-goku_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
-			dma_addr_t *dma, gfp_t gfp_flags)
-{
-	void		*retval;
-	struct goku_ep	*ep;
-
-	ep = container_of(_ep, struct goku_ep, ep);
-	if (!_ep)
-		return NULL;
-	*dma = DMA_ADDR_INVALID;
-
-	if (ep->dma) {
-		/* the main problem with this call is that it wastes memory
-		 * on typical 1/N page allocations: it allocates 1-N pages.
-		 */
-#warning Using dma_alloc_coherent even with buffers smaller than a page.
-		retval = dma_alloc_coherent(&ep->dev->pdev->dev,
-				bytes, dma, gfp_flags);
-	} else
-		retval = kmalloc(bytes, gfp_flags);
-	return retval;
-}
-
-static void
-goku_free_buffer(struct usb_ep *_ep, void *buf, dma_addr_t dma, unsigned bytes)
-{
-	/* free memory into the right allocator */
-	if (dma != DMA_ADDR_INVALID) {
-		struct goku_ep	*ep;
-
-		ep = container_of(_ep, struct goku_ep, ep);
-		if (!_ep)
-			return;
-		dma_free_coherent(&ep->dev->pdev->dev, bytes, buf, dma);
-	} else
-		kfree (buf);
-}
-
-/*-------------------------------------------------------------------------*/
-
 static void
 static void
 done(struct goku_ep *ep, struct goku_request *req, int status)
 done(struct goku_ep *ep, struct goku_request *req, int status)
 {
 {
@@ -485,7 +439,7 @@ top:
 			/* use ep1/ep2 double-buffering for OUT */
 			/* use ep1/ep2 double-buffering for OUT */
 			if (!(size & PACKET_ACTIVE))
 			if (!(size & PACKET_ACTIVE))
 				size = readl(&regs->EPxSizeLB[ep->num]);
 				size = readl(&regs->EPxSizeLB[ep->num]);
-			if (!(size & PACKET_ACTIVE)) 	// "can't happen"
+			if (!(size & PACKET_ACTIVE))	/* "can't happen" */
 				break;
 				break;
 			size &= DATASIZE;	/* EPxSizeH == 0 */
 			size &= DATASIZE;	/* EPxSizeH == 0 */
 
 
@@ -1026,9 +980,6 @@ static struct usb_ep_ops goku_ep_ops = {
 	.alloc_request	= goku_alloc_request,
 	.alloc_request	= goku_alloc_request,
 	.free_request	= goku_free_request,
 	.free_request	= goku_free_request,
 
 
-	.alloc_buffer	= goku_alloc_buffer,
-	.free_buffer	= goku_free_buffer,
-
 	.queue		= goku_queue,
 	.queue		= goku_queue,
 	.dequeue	= goku_dequeue,
 	.dequeue	= goku_dequeue,
 
 
@@ -1140,17 +1091,17 @@ udc_proc_read(char *buffer, char **start, off_t off, int count,
 		is_usb_connected
 		is_usb_connected
 			? ((tmp & PW_PULLUP) ? "full speed" : "powered")
 			? ((tmp & PW_PULLUP) ? "full speed" : "powered")
 			: "disconnected",
 			: "disconnected",
-		({char *tmp;
+		({char *state;
 		switch(dev->ep0state){
 		switch(dev->ep0state){
-		case EP0_DISCONNECT:	tmp = "ep0_disconnect"; break;
-		case EP0_IDLE:		tmp = "ep0_idle"; break;
-		case EP0_IN:		tmp = "ep0_in"; break;
-		case EP0_OUT:		tmp = "ep0_out"; break;
-		case EP0_STATUS:	tmp = "ep0_status"; break;
-		case EP0_STALL:		tmp = "ep0_stall"; break;
-		case EP0_SUSPEND:	tmp = "ep0_suspend"; break;
-		default:		tmp = "ep0_?"; break;
-		} tmp; })
+		case EP0_DISCONNECT:	state = "ep0_disconnect"; break;
+		case EP0_IDLE:		state = "ep0_idle"; break;
+		case EP0_IN:		state = "ep0_in"; break;
+		case EP0_OUT:		state = "ep0_out"; break;
+		case EP0_STATUS:	state = "ep0_status"; break;
+		case EP0_STALL:		state = "ep0_stall"; break;
+		case EP0_SUSPEND:	state = "ep0_suspend"; break;
+		default:		state = "ep0_?"; break;
+		} state; })
 		);
 		);
 	size -= t;
 	size -= t;
 	next += t;
 	next += t;
@@ -1195,7 +1146,6 @@ udc_proc_read(char *buffer, char **start, off_t off, int count,
 	for (i = 0; i < 4; i++) {
 	for (i = 0; i < 4; i++) {
 		struct goku_ep		*ep = &dev->ep [i];
 		struct goku_ep		*ep = &dev->ep [i];
 		struct goku_request	*req;
 		struct goku_request	*req;
-		int			t;
 
 
 		if (i && !ep->desc)
 		if (i && !ep->desc)
 			continue;
 			continue;
@@ -1283,7 +1233,7 @@ done:
 static void udc_reinit (struct goku_udc *dev)
 static void udc_reinit (struct goku_udc *dev)
 {
 {
 	static char *names [] = { "ep0", "ep1-bulk", "ep2-bulk", "ep3-bulk" };
 	static char *names [] = { "ep0", "ep1-bulk", "ep2-bulk", "ep3-bulk" };
-	
+
 	unsigned i;
 	unsigned i;
 
 
 	INIT_LIST_HEAD (&dev->gadget.ep_list);
 	INIT_LIST_HEAD (&dev->gadget.ep_list);
@@ -1896,9 +1846,9 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 
 
 	/* done */
 	/* done */
 	the_controller = dev;
 	the_controller = dev;
-	device_register(&dev->gadget.dev);
-
-	return 0;
+	retval = device_register(&dev->gadget.dev);
+	if (retval == 0)
+		return 0;
 
 
 done:
 done:
 	if (dev)
 	if (dev)
@@ -1910,8 +1860,8 @@ done:
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 static struct pci_device_id pci_ids [] = { {
 static struct pci_device_id pci_ids [] = { {
-	.class = 	((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
-	.class_mask = 	~0,
+	.class =	((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
+	.class_mask =	~0,
 	.vendor =	0x102f,		/* Toshiba */
 	.vendor =	0x102f,		/* Toshiba */
 	.device =	0x0107,		/* this UDC */
 	.device =	0x0107,		/* this UDC */
 	.subvendor =	PCI_ANY_ID,
 	.subvendor =	PCI_ANY_ID,

+ 6 - 4
drivers/usb/gadget/goku_udc.h

@@ -41,8 +41,10 @@ struct goku_udc_regs {
 #define INT_SYSERROR		0x40000
 #define INT_SYSERROR		0x40000
 #define INT_PWRDETECT		0x80000
 #define INT_PWRDETECT		0x80000
 
 
-#define	INT_DEVWIDE		(INT_PWRDETECT|INT_SYSERROR/*|INT_ERR*/|INT_USBRESET|INT_SUSPEND)
-#define	INT_EP0 		(INT_SETUP|INT_ENDPOINT0/*|INT_STATUS*/|INT_STATUSNAK)
+#define	INT_DEVWIDE \
+	(INT_PWRDETECT|INT_SYSERROR/*|INT_ERR*/|INT_USBRESET|INT_SUSPEND)
+#define	INT_EP0 \
+	(INT_SETUP|INT_ENDPOINT0/*|INT_STATUS*/|INT_STATUSNAK)
 
 
 	u32	dma_master;
 	u32	dma_master;
 #define MST_EOPB_DIS		0x0800
 #define MST_EOPB_DIS		0x0800
@@ -231,7 +233,7 @@ struct goku_request {
 enum ep0state {
 enum ep0state {
 	EP0_DISCONNECT,		/* no host */
 	EP0_DISCONNECT,		/* no host */
 	EP0_IDLE,		/* between STATUS ack and SETUP report */
 	EP0_IDLE,		/* between STATUS ack and SETUP report */
-	EP0_IN, EP0_OUT, 	/* data stage */
+	EP0_IN, EP0_OUT,	/* data stage */
 	EP0_STATUS,		/* status stage */
 	EP0_STATUS,		/* status stage */
 	EP0_STALL,		/* data or status stages */
 	EP0_STALL,		/* data or status stages */
 	EP0_SUSPEND,		/* usb suspend */
 	EP0_SUSPEND,		/* usb suspend */
@@ -242,7 +244,7 @@ struct goku_udc {
 	struct usb_gadget		gadget;
 	struct usb_gadget		gadget;
 	spinlock_t			lock;
 	spinlock_t			lock;
 	struct goku_ep			ep[4];
 	struct goku_ep			ep[4];
-	struct usb_gadget_driver 	*driver;
+	struct usb_gadget_driver	*driver;
 
 
 	enum ep0state			ep0state;
 	enum ep0state			ep0state;
 	unsigned			got_irq:1,
 	unsigned			got_irq:1,

+ 4 - 4
drivers/usb/gadget/inode.c

@@ -37,7 +37,7 @@
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/moduleparam.h>
 #include <linux/moduleparam.h>
 
 
-#include <linux/usb_gadgetfs.h>
+#include <linux/usb/gadgetfs.h>
 #include <linux/usb_gadget.h>
 #include <linux/usb_gadget.h>
 
 
 
 
@@ -923,7 +923,7 @@ static void clean_req (struct usb_ep *ep, struct usb_request *req)
 	struct dev_data		*dev = ep->driver_data;
 	struct dev_data		*dev = ep->driver_data;
 
 
 	if (req->buf != dev->rbuf) {
 	if (req->buf != dev->rbuf) {
-		usb_ep_free_buffer (ep, req->buf, req->dma, req->length);
+		kfree(req->buf);
 		req->buf = dev->rbuf;
 		req->buf = dev->rbuf;
 		req->dma = DMA_ADDR_INVALID;
 		req->dma = DMA_ADDR_INVALID;
 	}
 	}
@@ -963,7 +963,7 @@ static int setup_req (struct usb_ep *ep, struct usb_request *req, u16 len)
 		return -EBUSY;
 		return -EBUSY;
 	}
 	}
 	if (len > sizeof (dev->rbuf))
 	if (len > sizeof (dev->rbuf))
-		req->buf = usb_ep_alloc_buffer (ep, len, &req->dma, GFP_ATOMIC);
+		req->buf = kmalloc(len, GFP_ATOMIC);
 	if (req->buf == 0) {
 	if (req->buf == 0) {
 		req->buf = dev->rbuf;
 		req->buf = dev->rbuf;
 		return -ENOMEM;
 		return -ENOMEM;
@@ -1505,7 +1505,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 		}
 		}
 		break;
 		break;
 
 
-#ifndef	CONFIG_USB_GADGETFS_PXA2XX
+#ifndef	CONFIG_USB_GADGET_PXA2XX
 	/* PXA automagically handles this request too */
 	/* PXA automagically handles this request too */
 	case USB_REQ_GET_CONFIGURATION:
 	case USB_REQ_GET_CONFIGURATION:
 		if (ctrl->bRequestType != 0x80)
 		if (ctrl->bRequestType != 0x80)

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

@@ -75,10 +75,6 @@ static int lh7a40x_ep_enable(struct usb_ep *ep,
 static int lh7a40x_ep_disable(struct usb_ep *ep);
 static int lh7a40x_ep_disable(struct usb_ep *ep);
 static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, gfp_t);
 static struct usb_request *lh7a40x_alloc_request(struct usb_ep *ep, gfp_t);
 static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *);
 static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *);
-static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned, dma_addr_t *,
-				  gfp_t);
-static void lh7a40x_free_buffer(struct usb_ep *ep, void *, dma_addr_t,
-				unsigned);
 static int lh7a40x_queue(struct usb_ep *ep, struct usb_request *, gfp_t);
 static int lh7a40x_queue(struct usb_ep *ep, struct usb_request *, gfp_t);
 static int lh7a40x_dequeue(struct usb_ep *ep, struct usb_request *);
 static int lh7a40x_dequeue(struct usb_ep *ep, struct usb_request *);
 static int lh7a40x_set_halt(struct usb_ep *ep, int);
 static int lh7a40x_set_halt(struct usb_ep *ep, int);
@@ -104,9 +100,6 @@ static struct usb_ep_ops lh7a40x_ep_ops = {
 	.alloc_request = lh7a40x_alloc_request,
 	.alloc_request = lh7a40x_alloc_request,
 	.free_request = lh7a40x_free_request,
 	.free_request = lh7a40x_free_request,
 
 
-	.alloc_buffer = lh7a40x_alloc_buffer,
-	.free_buffer = lh7a40x_free_buffer,
-
 	.queue = lh7a40x_queue,
 	.queue = lh7a40x_queue,
 	.dequeue = lh7a40x_dequeue,
 	.dequeue = lh7a40x_dequeue,
 
 
@@ -1134,26 +1127,6 @@ static void lh7a40x_free_request(struct usb_ep *ep, struct usb_request *_req)
 	kfree(req);
 	kfree(req);
 }
 }
 
 
-static void *lh7a40x_alloc_buffer(struct usb_ep *ep, unsigned bytes,
-				  dma_addr_t * dma, gfp_t gfp_flags)
-{
-	char *retval;
-
-	DEBUG("%s (%p, %d, %d)\n", __FUNCTION__, ep, bytes, gfp_flags);
-
-	retval = kmalloc(bytes, gfp_flags & ~(__GFP_DMA | __GFP_HIGHMEM));
-	if (retval)
-		*dma = virt_to_bus(retval);
-	return retval;
-}
-
-static void lh7a40x_free_buffer(struct usb_ep *ep, void *buf, dma_addr_t dma,
-				unsigned bytes)
-{
-	DEBUG("%s, %p\n", __FUNCTION__, ep);
-	kfree(buf);
-}
-
 /** Queue one request
 /** Queue one request
  *  Kickstart transfer if needed
  *  Kickstart transfer if needed
  *  NOTE: Sets INDEX register
  *  NOTE: Sets INDEX register

+ 1653 - 0
drivers/usb/gadget/m66592-udc.c

@@ -0,0 +1,1653 @@
+/*
+ * M66592 UDC (USB gadget)
+ *
+ * Copyright (C) 2006-2007 Renesas Solutions Corp.
+ *
+ * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb_gadget.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "m66592-udc.h"
+
+MODULE_DESCRIPTION("M66592 USB gadget driiver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Yoshihiro Shimoda");
+
+#define DRIVER_VERSION	"29 May 2007"
+
+/* module parameters */
+static unsigned short clock = M66592_XTAL24;
+module_param(clock, ushort, 0644);
+MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0(default=16384)");
+static unsigned short vif = M66592_LDRV;
+module_param(vif, ushort, 0644);
+MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)");
+static unsigned short endian = 0;
+module_param(endian, ushort, 0644);
+MODULE_PARM_DESC(endian, "data endian: big=256, little=0(default=0)");
+static unsigned short irq_sense = M66592_INTL;
+module_param(irq_sense, ushort, 0644);
+MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=2, falling edge=0(default=2)");
+
+static const char udc_name[] = "m66592_udc";
+static const char *m66592_ep_name[] = {
+	"ep0", "ep1", "ep2", "ep3", "ep4", "ep5", "ep6", "ep7"
+};
+
+static void disable_controller(struct m66592 *m66592);
+static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req);
+static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req);
+static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req,
+			gfp_t gfp_flags);
+
+static void transfer_complete(struct m66592_ep *ep,
+			      struct m66592_request *req,
+			      int status);
+/*-------------------------------------------------------------------------*/
+static inline u16 get_usb_speed(struct m66592 *m66592)
+{
+	return (m66592_read(m66592, M66592_DVSTCTR) & M66592_RHST);
+}
+
+static void enable_pipe_irq(struct m66592 *m66592, u16 pipenum,
+			    unsigned long reg)
+{
+	u16 tmp;
+
+	tmp = m66592_read(m66592, M66592_INTENB0);
+	m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE,
+		    M66592_INTENB0);
+	m66592_bset(m66592, (1 << pipenum), reg);
+	m66592_write(m66592, tmp, M66592_INTENB0);
+}
+
+static void disable_pipe_irq(struct m66592 *m66592, u16 pipenum,
+			     unsigned long reg)
+{
+	u16 tmp;
+
+	tmp = m66592_read(m66592, M66592_INTENB0);
+	m66592_bclr(m66592, M66592_BEMPE | M66592_NRDYE | M66592_BRDYE,
+		    M66592_INTENB0);
+	m66592_bclr(m66592, (1 << pipenum), reg);
+	m66592_write(m66592, tmp, M66592_INTENB0);
+}
+
+static void m66592_usb_connect(struct m66592 *m66592)
+{
+	m66592_bset(m66592, M66592_CTRE, M66592_INTENB0);
+	m66592_bset(m66592, M66592_WDST | M66592_RDST | M66592_CMPL,
+		    M66592_INTENB0);
+	m66592_bset(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0);
+
+	m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG);
+}
+
+static void m66592_usb_disconnect(struct m66592 *m66592)
+{
+	m66592_bclr(m66592, M66592_CTRE, M66592_INTENB0);
+	m66592_bclr(m66592, M66592_WDST | M66592_RDST | M66592_CMPL,
+		    M66592_INTENB0);
+	m66592_bclr(m66592, M66592_BEMPE | M66592_BRDYE, M66592_INTENB0);
+	m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
+
+	m66592->gadget.speed = USB_SPEED_UNKNOWN;
+	spin_unlock(&m66592->lock);
+	m66592->driver->disconnect(&m66592->gadget);
+	spin_lock(&m66592->lock);
+
+	disable_controller(m66592);
+	INIT_LIST_HEAD(&m66592->ep[0].queue);
+}
+
+static inline u16 control_reg_get_pid(struct m66592 *m66592, u16 pipenum)
+{
+	u16 pid = 0;
+	unsigned long offset;
+
+	if (pipenum == 0)
+		pid = m66592_read(m66592, M66592_DCPCTR) & M66592_PID;
+	else if (pipenum < M66592_MAX_NUM_PIPE) {
+		offset = get_pipectr_addr(pipenum);
+		pid = m66592_read(m66592, offset) & M66592_PID;
+	} else
+		printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+
+	return pid;
+}
+
+static inline void control_reg_set_pid(struct m66592 *m66592, u16 pipenum,
+				       u16 pid)
+{
+	unsigned long offset;
+
+	if (pipenum == 0)
+		m66592_mdfy(m66592, pid, M66592_PID, M66592_DCPCTR);
+	else if (pipenum < M66592_MAX_NUM_PIPE) {
+		offset = get_pipectr_addr(pipenum);
+		m66592_mdfy(m66592, pid, M66592_PID, offset);
+	} else
+		printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+}
+
+static inline void pipe_start(struct m66592 *m66592, u16 pipenum)
+{
+	control_reg_set_pid(m66592, pipenum, M66592_PID_BUF);
+}
+
+static inline void pipe_stop(struct m66592 *m66592, u16 pipenum)
+{
+	control_reg_set_pid(m66592, pipenum, M66592_PID_NAK);
+}
+
+static inline void pipe_stall(struct m66592 *m66592, u16 pipenum)
+{
+	control_reg_set_pid(m66592, pipenum, M66592_PID_STALL);
+}
+
+static inline u16 control_reg_get(struct m66592 *m66592, u16 pipenum)
+{
+	u16 ret = 0;
+	unsigned long offset;
+
+	if (pipenum == 0)
+		ret = m66592_read(m66592, M66592_DCPCTR);
+	else if (pipenum < M66592_MAX_NUM_PIPE) {
+		offset = get_pipectr_addr(pipenum);
+		ret = m66592_read(m66592, offset);
+	} else
+		printk(KERN_ERR "unexpect pipe num (%d)\n", pipenum);
+
+	return ret;
+}
+
+static inline void control_reg_sqclr(struct m66592 *m66592, u16 pipenum)
+{
+	unsigned long offset;
+
+	pipe_stop(m66592, pipenum);
+
+	if (pipenum == 0)
+		m66592_bset(m66592, M66592_SQCLR, M66592_DCPCTR);
+	else if (pipenum < M66592_MAX_NUM_PIPE) {
+		offset = get_pipectr_addr(pipenum);
+		m66592_bset(m66592, M66592_SQCLR, offset);
+	} else
+		printk(KERN_ERR "unexpect pipe num(%d)\n", pipenum);
+}
+
+static inline int get_buffer_size(struct m66592 *m66592, u16 pipenum)
+{
+	u16 tmp;
+	int size;
+
+	if (pipenum == 0) {
+		tmp = m66592_read(m66592, M66592_DCPCFG);
+		if ((tmp & M66592_CNTMD) != 0)
+			size = 256;
+		else {
+			tmp = m66592_read(m66592, M66592_DCPMAXP);
+			size = tmp & M66592_MAXP;
+		}
+	} else {
+		m66592_write(m66592, pipenum, M66592_PIPESEL);
+		tmp = m66592_read(m66592, M66592_PIPECFG);
+		if ((tmp & M66592_CNTMD) != 0) {
+			tmp = m66592_read(m66592, M66592_PIPEBUF);
+			size = ((tmp >> 10) + 1) * 64;
+		} else {
+			tmp = m66592_read(m66592, M66592_PIPEMAXP);
+			size = tmp & M66592_MXPS;
+		}
+	}
+
+	return size;
+}
+
+static inline void pipe_change(struct m66592 *m66592, u16 pipenum)
+{
+	struct m66592_ep *ep = m66592->pipenum2ep[pipenum];
+
+	if (ep->use_dma)
+		return;
+
+	m66592_mdfy(m66592, pipenum, M66592_CURPIPE, ep->fifosel);
+
+	ndelay(450);
+
+	m66592_bset(m66592, M66592_MBW, ep->fifosel);
+}
+
+static int pipe_buffer_setting(struct m66592 *m66592,
+			       struct m66592_pipe_info *info)
+{
+	u16 bufnum = 0, buf_bsize = 0;
+	u16 pipecfg = 0;
+
+	if (info->pipe == 0)
+		return -EINVAL;
+
+	m66592_write(m66592, info->pipe, M66592_PIPESEL);
+
+	if (info->dir_in)
+		pipecfg |= M66592_DIR;
+	pipecfg |= info->type;
+	pipecfg |= info->epnum;
+	switch (info->type) {
+	case M66592_INT:
+		bufnum = 4 + (info->pipe - M66592_BASE_PIPENUM_INT);
+		buf_bsize = 0;
+		break;
+	case M66592_BULK:
+		bufnum = m66592->bi_bufnum +
+			 (info->pipe - M66592_BASE_PIPENUM_BULK) * 16;
+		m66592->bi_bufnum += 16;
+		buf_bsize = 7;
+		pipecfg |= M66592_DBLB;
+		if (!info->dir_in)
+			pipecfg |= M66592_SHTNAK;
+		break;
+	case M66592_ISO:
+		bufnum = m66592->bi_bufnum +
+			 (info->pipe - M66592_BASE_PIPENUM_ISOC) * 16;
+		m66592->bi_bufnum += 16;
+		buf_bsize = 7;
+		break;
+	}
+	if (m66592->bi_bufnum > M66592_MAX_BUFNUM) {
+		printk(KERN_ERR "m66592 pipe memory is insufficient(%d)\n",
+		       m66592->bi_bufnum);
+		return -ENOMEM;
+	}
+
+	m66592_write(m66592, pipecfg, M66592_PIPECFG);
+	m66592_write(m66592, (buf_bsize << 10) | (bufnum), M66592_PIPEBUF);
+	m66592_write(m66592, info->maxpacket, M66592_PIPEMAXP);
+	if (info->interval)
+		info->interval--;
+	m66592_write(m66592, info->interval, M66592_PIPEPERI);
+
+	return 0;
+}
+
+static void pipe_buffer_release(struct m66592 *m66592,
+				struct m66592_pipe_info *info)
+{
+	if (info->pipe == 0)
+		return;
+
+	switch (info->type) {
+	case M66592_BULK:
+		if (is_bulk_pipe(info->pipe))
+			m66592->bi_bufnum -= 16;
+		break;
+	case M66592_ISO:
+		if (is_isoc_pipe(info->pipe))
+			m66592->bi_bufnum -= 16;
+		break;
+	}
+
+	if (is_bulk_pipe(info->pipe)) {
+		m66592->bulk--;
+	} else if (is_interrupt_pipe(info->pipe))
+		m66592->interrupt--;
+	else if (is_isoc_pipe(info->pipe)) {
+		m66592->isochronous--;
+		if (info->type == M66592_BULK)
+			m66592->bulk--;
+	} else
+		printk(KERN_ERR "ep_release: unexpect pipenum (%d)\n",
+		       info->pipe);
+}
+
+static void pipe_initialize(struct m66592_ep *ep)
+{
+	struct m66592 *m66592 = ep->m66592;
+
+	m66592_mdfy(m66592, 0, M66592_CURPIPE, ep->fifosel);
+
+	m66592_write(m66592, M66592_ACLRM, ep->pipectr);
+	m66592_write(m66592, 0, ep->pipectr);
+	m66592_write(m66592, M66592_SQCLR, ep->pipectr);
+	if (ep->use_dma) {
+		m66592_mdfy(m66592, ep->pipenum, M66592_CURPIPE, ep->fifosel);
+
+		ndelay(450);
+
+		m66592_bset(m66592, M66592_MBW, ep->fifosel);
+	}
+}
+
+static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
+			      const struct usb_endpoint_descriptor *desc,
+			      u16 pipenum, int dma)
+{
+	if ((pipenum != 0) && dma) {
+		if (m66592->num_dma == 0) {
+			m66592->num_dma++;
+			ep->use_dma = 1;
+			ep->fifoaddr = M66592_D0FIFO;
+			ep->fifosel = M66592_D0FIFOSEL;
+			ep->fifoctr = M66592_D0FIFOCTR;
+			ep->fifotrn = M66592_D0FIFOTRN;
+		} else if (m66592->num_dma == 1) {
+			m66592->num_dma++;
+			ep->use_dma = 1;
+			ep->fifoaddr = M66592_D1FIFO;
+			ep->fifosel = M66592_D1FIFOSEL;
+			ep->fifoctr = M66592_D1FIFOCTR;
+			ep->fifotrn = M66592_D1FIFOTRN;
+		} else {
+			ep->use_dma = 0;
+			ep->fifoaddr = M66592_CFIFO;
+			ep->fifosel = M66592_CFIFOSEL;
+			ep->fifoctr = M66592_CFIFOCTR;
+			ep->fifotrn = 0;
+		}
+	} else {
+		ep->use_dma = 0;
+		ep->fifoaddr = M66592_CFIFO;
+		ep->fifosel = M66592_CFIFOSEL;
+		ep->fifoctr = M66592_CFIFOCTR;
+		ep->fifotrn = 0;
+	}
+
+	ep->pipectr = get_pipectr_addr(pipenum);
+	ep->pipenum = pipenum;
+	ep->ep.maxpacket = desc->wMaxPacketSize;
+	m66592->pipenum2ep[pipenum] = ep;
+	m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep;
+	INIT_LIST_HEAD(&ep->queue);
+}
+
+static void m66592_ep_release(struct m66592_ep *ep)
+{
+	struct m66592 *m66592 = ep->m66592;
+	u16 pipenum = ep->pipenum;
+
+	if (pipenum == 0)
+		return;
+
+	if (ep->use_dma)
+		m66592->num_dma--;
+	ep->pipenum = 0;
+	ep->busy = 0;
+	ep->use_dma = 0;
+}
+
+static int alloc_pipe_config(struct m66592_ep *ep,
+			     const struct usb_endpoint_descriptor *desc)
+{
+	struct m66592 *m66592 = ep->m66592;
+	struct m66592_pipe_info info;
+	int dma = 0;
+	int *counter;
+	int ret;
+
+	ep->desc = desc;
+
+	BUG_ON(ep->pipenum);
+
+	switch(desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_BULK:
+		if (m66592->bulk >= M66592_MAX_NUM_BULK) {
+			if (m66592->isochronous >= M66592_MAX_NUM_ISOC) {
+				printk(KERN_ERR "bulk pipe is insufficient\n");
+				return -ENODEV;
+			} else {
+				info.pipe = M66592_BASE_PIPENUM_ISOC +
+					    m66592->isochronous;
+				counter = &m66592->isochronous;
+			}
+		} else {
+			info.pipe = M66592_BASE_PIPENUM_BULK + m66592->bulk;
+			counter = &m66592->bulk;
+		}
+		info.type = M66592_BULK;
+		dma = 1;
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		if (m66592->interrupt >= M66592_MAX_NUM_INT) {
+			printk(KERN_ERR "interrupt pipe is insufficient\n");
+			return -ENODEV;
+		}
+		info.pipe = M66592_BASE_PIPENUM_INT + m66592->interrupt;
+		info.type = M66592_INT;
+		counter = &m66592->interrupt;
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		if (m66592->isochronous >= M66592_MAX_NUM_ISOC) {
+			printk(KERN_ERR "isochronous pipe is insufficient\n");
+			return -ENODEV;
+		}
+		info.pipe = M66592_BASE_PIPENUM_ISOC + m66592->isochronous;
+		info.type = M66592_ISO;
+		counter = &m66592->isochronous;
+		break;
+	default:
+		printk(KERN_ERR "unexpect xfer type\n");
+		return -EINVAL;
+	}
+	ep->type = info.type;
+
+	info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	info.maxpacket = desc->wMaxPacketSize;
+	info.interval = desc->bInterval;
+	if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+		info.dir_in = 1;
+	else
+		info.dir_in = 0;
+
+	ret = pipe_buffer_setting(m66592, &info);
+	if (ret < 0) {
+		printk(KERN_ERR "pipe_buffer_setting fail\n");
+		return ret;
+	}
+
+	(*counter)++;
+	if ((counter == &m66592->isochronous) && info.type == M66592_BULK)
+		m66592->bulk++;
+
+	m66592_ep_setting(m66592, ep, desc, info.pipe, dma);
+	pipe_initialize(ep);
+
+	return 0;
+}
+
+static int free_pipe_config(struct m66592_ep *ep)
+{
+	struct m66592 *m66592 = ep->m66592;
+	struct m66592_pipe_info info;
+
+	info.pipe = ep->pipenum;
+	info.type = ep->type;
+	pipe_buffer_release(m66592, &info);
+	m66592_ep_release(ep);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+static void pipe_irq_enable(struct m66592 *m66592, u16 pipenum)
+{
+	enable_irq_ready(m66592, pipenum);
+	enable_irq_nrdy(m66592, pipenum);
+}
+
+static void pipe_irq_disable(struct m66592 *m66592, u16 pipenum)
+{
+	disable_irq_ready(m66592, pipenum);
+	disable_irq_nrdy(m66592, pipenum);
+}
+
+/* if complete is true, gadget driver complete function is not call */
+static void control_end(struct m66592 *m66592, unsigned ccpl)
+{
+	m66592->ep[0].internal_ccpl = ccpl;
+	pipe_start(m66592, 0);
+	m66592_bset(m66592, M66592_CCPL, M66592_DCPCTR);
+}
+
+static void start_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
+{
+	struct m66592 *m66592 = ep->m66592;
+
+	pipe_change(m66592, ep->pipenum);
+	m66592_mdfy(m66592, M66592_ISEL | M66592_PIPE0,
+		    (M66592_ISEL | M66592_CURPIPE),
+		    M66592_CFIFOSEL);
+	m66592_write(m66592, M66592_BCLR, ep->fifoctr);
+	if (req->req.length == 0) {
+		m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
+		pipe_start(m66592, 0);
+		transfer_complete(ep, req, 0);
+	} else {
+		m66592_write(m66592, ~M66592_BEMP0, M66592_BEMPSTS);
+		irq_ep0_write(ep, req);
+	}
+}
+
+static void start_packet_write(struct m66592_ep *ep, struct m66592_request *req)
+{
+	struct m66592 *m66592 = ep->m66592;
+	u16 tmp;
+
+	pipe_change(m66592, ep->pipenum);
+	disable_irq_empty(m66592, ep->pipenum);
+	pipe_start(m66592, ep->pipenum);
+
+	tmp = m66592_read(m66592, ep->fifoctr);
+	if (unlikely((tmp & M66592_FRDY) == 0))
+		pipe_irq_enable(m66592, ep->pipenum);
+	else
+		irq_packet_write(ep, req);
+}
+
+static void start_packet_read(struct m66592_ep *ep, struct m66592_request *req)
+{
+	struct m66592 *m66592 = ep->m66592;
+	u16 pipenum = ep->pipenum;
+
+	if (ep->pipenum == 0) {
+		m66592_mdfy(m66592, M66592_PIPE0,
+			    (M66592_ISEL | M66592_CURPIPE),
+			    M66592_CFIFOSEL);
+		m66592_write(m66592, M66592_BCLR, ep->fifoctr);
+		pipe_start(m66592, pipenum);
+		pipe_irq_enable(m66592, pipenum);
+	} else {
+		if (ep->use_dma) {
+			m66592_bset(m66592, M66592_TRCLR, ep->fifosel);
+			pipe_change(m66592, pipenum);
+			m66592_bset(m66592, M66592_TRENB, ep->fifosel);
+			m66592_write(m66592,
+				     (req->req.length + ep->ep.maxpacket - 1) /
+				     ep->ep.maxpacket, ep->fifotrn);
+		}
+		pipe_start(m66592, pipenum);	/* trigger once */
+		pipe_irq_enable(m66592, pipenum);
+	}
+}
+
+static void start_packet(struct m66592_ep *ep, struct m66592_request *req)
+{
+	if (ep->desc->bEndpointAddress & USB_DIR_IN)
+		start_packet_write(ep, req);
+	else
+		start_packet_read(ep, req);
+}
+
+static void start_ep0(struct m66592_ep *ep, struct m66592_request *req)
+{
+	u16 ctsq;
+
+	ctsq = m66592_read(ep->m66592, M66592_INTSTS0) & M66592_CTSQ;
+
+	switch (ctsq) {
+	case M66592_CS_RDDS:
+		start_ep0_write(ep, req);
+		break;
+	case M66592_CS_WRDS:
+		start_packet_read(ep, req);
+		break;
+
+	case M66592_CS_WRND:
+		control_end(ep->m66592, 0);
+		break;
+	default:
+		printk(KERN_ERR "start_ep0: unexpect ctsq(%x)\n", ctsq);
+		break;
+	}
+}
+
+static void init_controller(struct m66592 *m66592)
+{
+	m66592_bset(m66592, (vif & M66592_LDRV) | (endian & M66592_BIGEND),
+		    M66592_PINCFG);
+	m66592_bset(m66592, M66592_HSE, M66592_SYSCFG);		/* High spd */
+	m66592_mdfy(m66592, clock & M66592_XTAL, M66592_XTAL, M66592_SYSCFG);
+
+	m66592_bclr(m66592, M66592_USBE, M66592_SYSCFG);
+	m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
+	m66592_bset(m66592, M66592_USBE, M66592_SYSCFG);
+
+	m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG);
+
+	msleep(3);
+
+	m66592_bset(m66592, M66592_RCKE | M66592_PLLC, M66592_SYSCFG);
+
+	msleep(1);
+
+	m66592_bset(m66592, M66592_SCKE, M66592_SYSCFG);
+
+	m66592_bset(m66592, irq_sense & M66592_INTL, M66592_INTENB1);
+	m66592_write(m66592, M66592_BURST | M66592_CPU_ADR_RD_WR,
+		     M66592_DMA0CFG);
+}
+
+static void disable_controller(struct m66592 *m66592)
+{
+	m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG);
+	udelay(1);
+	m66592_bclr(m66592, M66592_PLLC, M66592_SYSCFG);
+	udelay(1);
+	m66592_bclr(m66592, M66592_RCKE, M66592_SYSCFG);
+	udelay(1);
+	m66592_bclr(m66592, M66592_XCKE, M66592_SYSCFG);
+}
+
+static void m66592_start_xclock(struct m66592 *m66592)
+{
+	u16 tmp;
+
+	tmp = m66592_read(m66592, M66592_SYSCFG);
+	if (!(tmp & M66592_XCKE))
+		m66592_bset(m66592, M66592_XCKE, M66592_SYSCFG);
+}
+
+/*-------------------------------------------------------------------------*/
+static void transfer_complete(struct m66592_ep *ep,
+			      struct m66592_request *req,
+			      int status)
+{
+	int restart = 0;
+
+	if (unlikely(ep->pipenum == 0)) {
+		if (ep->internal_ccpl) {
+			ep->internal_ccpl = 0;
+			return;
+		}
+	}
+
+	list_del_init(&req->queue);
+	if (ep->m66592->gadget.speed == USB_SPEED_UNKNOWN)
+		req->req.status = -ESHUTDOWN;
+	else
+		req->req.status = status;
+
+	if (!list_empty(&ep->queue))
+		restart = 1;
+
+	if (likely(req->req.complete))
+		req->req.complete(&ep->ep, &req->req);
+
+	if (restart) {
+		req = list_entry(ep->queue.next, struct m66592_request, queue);
+		if (ep->desc)
+			start_packet(ep, req);
+	}
+}
+
+static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
+{
+	int i;
+	volatile u16 tmp;
+	unsigned bufsize;
+	size_t size;
+	void *buf;
+	u16 pipenum = ep->pipenum;
+	struct m66592 *m66592 = ep->m66592;
+
+	pipe_change(m66592, pipenum);
+	m66592_bset(m66592, M66592_ISEL, ep->fifosel);
+
+	i = 0;
+	do {
+		tmp = m66592_read(m66592, ep->fifoctr);
+		if (i++ > 100000) {
+			printk(KERN_ERR "pipe0 is busy. maybe cpu i/o bus"
+				"conflict. please power off this controller.");
+			return;
+		}
+		ndelay(1);
+	} while ((tmp & M66592_FRDY) == 0);
+
+	/* prepare parameters */
+	bufsize = get_buffer_size(m66592, pipenum);
+	buf = req->req.buf + req->req.actual;
+	size = min(bufsize, req->req.length - req->req.actual);
+
+	/* write fifo */
+	if (req->req.buf) {
+		if (size > 0)
+			m66592_write_fifo(m66592, ep->fifoaddr, buf, size);
+		if ((size == 0) || ((size % ep->ep.maxpacket) != 0))
+			m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
+	}
+
+	/* update parameters */
+	req->req.actual += size;
+
+	/* check transfer finish */
+	if ((!req->req.zero && (req->req.actual == req->req.length)) ||
+	    (size % ep->ep.maxpacket) || (size == 0)) {
+		disable_irq_ready(m66592, pipenum);
+		disable_irq_empty(m66592, pipenum);
+	} else {
+		disable_irq_ready(m66592, pipenum);
+		enable_irq_empty(m66592, pipenum);
+	}
+	pipe_start(m66592, pipenum);
+}
+
+static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req)
+{
+	u16 tmp;
+	unsigned bufsize;
+	size_t size;
+	void *buf;
+	u16 pipenum = ep->pipenum;
+	struct m66592 *m66592 = ep->m66592;
+
+	pipe_change(m66592, pipenum);
+	tmp = m66592_read(m66592, ep->fifoctr);
+	if (unlikely((tmp & M66592_FRDY) == 0)) {
+		pipe_stop(m66592, pipenum);
+		pipe_irq_disable(m66592, pipenum);
+		printk(KERN_ERR "write fifo not ready. pipnum=%d\n", pipenum);
+		return;
+	}
+
+	/* prepare parameters */
+	bufsize = get_buffer_size(m66592, pipenum);
+	buf = req->req.buf + req->req.actual;
+	size = min(bufsize, req->req.length - req->req.actual);
+
+	/* write fifo */
+	if (req->req.buf) {
+		m66592_write_fifo(m66592, ep->fifoaddr, buf, size);
+		if ((size == 0) || ((size % ep->ep.maxpacket) != 0) ||
+		    ((bufsize != ep->ep.maxpacket) && (bufsize > size)))
+			m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
+	}
+
+	/* update parameters */
+	req->req.actual += size;
+	/* check transfer finish */
+	if ((!req->req.zero && (req->req.actual == req->req.length)) ||
+	    (size % ep->ep.maxpacket) || (size == 0)) {
+		disable_irq_ready(m66592, pipenum);
+		enable_irq_empty(m66592, pipenum);
+	} else {
+		disable_irq_empty(m66592, pipenum);
+		pipe_irq_enable(m66592, pipenum);
+	}
+}
+
+static void irq_packet_read(struct m66592_ep *ep, struct m66592_request *req)
+{
+	u16 tmp;
+	int rcv_len, bufsize, req_len;
+	int size;
+	void *buf;
+	u16 pipenum = ep->pipenum;
+	struct m66592 *m66592 = ep->m66592;
+	int finish = 0;
+
+	pipe_change(m66592, pipenum);
+	tmp = m66592_read(m66592, ep->fifoctr);
+	if (unlikely((tmp & M66592_FRDY) == 0)) {
+		req->req.status = -EPIPE;
+		pipe_stop(m66592, pipenum);
+		pipe_irq_disable(m66592, pipenum);
+		printk(KERN_ERR "read fifo not ready");
+		return;
+	}
+
+	/* prepare parameters */
+	rcv_len = tmp & M66592_DTLN;
+	bufsize = get_buffer_size(m66592, pipenum);
+
+	buf = req->req.buf + req->req.actual;
+	req_len = req->req.length - req->req.actual;
+	if (rcv_len < bufsize)
+		size = min(rcv_len, req_len);
+	else
+		size = min(bufsize, req_len);
+
+	/* update parameters */
+	req->req.actual += size;
+
+	/* check transfer finish */
+	if ((!req->req.zero && (req->req.actual == req->req.length)) ||
+	    (size % ep->ep.maxpacket) || (size == 0)) {
+		pipe_stop(m66592, pipenum);
+		pipe_irq_disable(m66592, pipenum);
+		finish = 1;
+	}
+
+	/* read fifo */
+	if (req->req.buf) {
+		if (size == 0)
+			m66592_write(m66592, M66592_BCLR, ep->fifoctr);
+		else
+			m66592_read_fifo(m66592, ep->fifoaddr, buf, size);
+	}
+
+	if ((ep->pipenum != 0) && finish)
+		transfer_complete(ep, req, 0);
+}
+
+static void irq_pipe_ready(struct m66592 *m66592, u16 status, u16 enb)
+{
+	u16 check;
+	u16 pipenum;
+	struct m66592_ep *ep;
+	struct m66592_request *req;
+
+	if ((status & M66592_BRDY0) && (enb & M66592_BRDY0)) {
+		m66592_write(m66592, ~M66592_BRDY0, M66592_BRDYSTS);
+		m66592_mdfy(m66592, M66592_PIPE0, M66592_CURPIPE,
+			    M66592_CFIFOSEL);
+
+		ep = &m66592->ep[0];
+		req = list_entry(ep->queue.next, struct m66592_request, queue);
+		irq_packet_read(ep, req);
+	} else {
+		for (pipenum = 1; pipenum < M66592_MAX_NUM_PIPE; pipenum++) {
+			check = 1 << pipenum;
+			if ((status & check) && (enb & check)) {
+				m66592_write(m66592, ~check, M66592_BRDYSTS);
+				ep = m66592->pipenum2ep[pipenum];
+				req = list_entry(ep->queue.next,
+						 struct m66592_request, queue);
+				if (ep->desc->bEndpointAddress & USB_DIR_IN)
+					irq_packet_write(ep, req);
+				else
+					irq_packet_read(ep, req);
+			}
+		}
+	}
+}
+
+static void irq_pipe_empty(struct m66592 *m66592, u16 status, u16 enb)
+{
+	u16 tmp;
+	u16 check;
+	u16 pipenum;
+	struct m66592_ep *ep;
+	struct m66592_request *req;
+
+	if ((status & M66592_BEMP0) && (enb & M66592_BEMP0)) {
+		m66592_write(m66592, ~M66592_BEMP0, M66592_BEMPSTS);
+
+		ep = &m66592->ep[0];
+		req = list_entry(ep->queue.next, struct m66592_request, queue);
+		irq_ep0_write(ep, req);
+	} else {
+		for (pipenum = 1; pipenum < M66592_MAX_NUM_PIPE; pipenum++) {
+			check = 1 << pipenum;
+			if ((status & check) && (enb & check)) {
+				m66592_write(m66592, ~check, M66592_BEMPSTS);
+				tmp = control_reg_get(m66592, pipenum);
+				if ((tmp & M66592_INBUFM) == 0) {
+					disable_irq_empty(m66592, pipenum);
+					pipe_irq_disable(m66592, pipenum);
+					pipe_stop(m66592, pipenum);
+					ep = m66592->pipenum2ep[pipenum];
+					req = list_entry(ep->queue.next,
+							 struct m66592_request,
+							 queue);
+					if (!list_empty(&ep->queue))
+						transfer_complete(ep, req, 0);
+				}
+			}
+		}
+	}
+}
+
+static void get_status(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
+{
+	struct m66592_ep *ep;
+	u16 pid;
+	u16 status = 0;
+
+	switch (ctrl->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_DEVICE:
+		status = 1;	/* selfpower */
+		break;
+	case USB_RECIP_INTERFACE:
+		status = 0;
+		break;
+	case USB_RECIP_ENDPOINT:
+		ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+		pid = control_reg_get_pid(m66592, ep->pipenum);
+		if (pid == M66592_PID_STALL)
+			status = 1;
+		else
+			status = 0;
+		break;
+	default:
+		pipe_stall(m66592, 0);
+		return;		/* exit */
+	}
+
+	*m66592->ep0_buf = status;
+	m66592->ep0_req->buf = m66592->ep0_buf;
+	m66592->ep0_req->length = 2;
+	m66592_queue(m66592->gadget.ep0, m66592->ep0_req, GFP_KERNEL);
+}
+
+static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
+{
+	switch (ctrl->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_DEVICE:
+		control_end(m66592, 1);
+		break;
+	case USB_RECIP_INTERFACE:
+		control_end(m66592, 1);
+		break;
+	case USB_RECIP_ENDPOINT: {
+		struct m66592_ep *ep;
+		struct m66592_request *req;
+
+		ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+		pipe_stop(m66592, ep->pipenum);
+		control_reg_sqclr(m66592, ep->pipenum);
+
+		control_end(m66592, 1);
+
+		req = list_entry(ep->queue.next,
+		struct m66592_request, queue);
+		if (ep->busy) {
+			ep->busy = 0;
+			if (list_empty(&ep->queue))
+				break;
+			start_packet(ep, req);
+		} else if (!list_empty(&ep->queue))
+			pipe_start(m66592, ep->pipenum);
+		}
+		break;
+	default:
+		pipe_stall(m66592, 0);
+		break;
+	}
+}
+
+static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
+{
+
+	switch (ctrl->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_DEVICE:
+		control_end(m66592, 1);
+		break;
+	case USB_RECIP_INTERFACE:
+		control_end(m66592, 1);
+		break;
+	case USB_RECIP_ENDPOINT: {
+		struct m66592_ep *ep;
+
+		ep = m66592->epaddr2ep[ctrl->wIndex&USB_ENDPOINT_NUMBER_MASK];
+		pipe_stall(m66592, ep->pipenum);
+
+		control_end(m66592, 1);
+		}
+		break;
+	default:
+		pipe_stall(m66592, 0);
+		break;
+	}
+}
+
+/* if return value is true, call class driver's setup() */
+static int setup_packet(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
+{
+	u16 *p = (u16 *)ctrl;
+	unsigned long offset = M66592_USBREQ;
+	int i, ret = 0;
+
+	/* read fifo */
+	m66592_write(m66592, ~M66592_VALID, M66592_INTSTS0);
+
+	for (i = 0; i < 4; i++)
+		p[i] = m66592_read(m66592, offset + i*2);
+
+	/* check request */
+	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
+		switch (ctrl->bRequest) {
+		case USB_REQ_GET_STATUS:
+			get_status(m66592, ctrl);
+			break;
+		case USB_REQ_CLEAR_FEATURE:
+			clear_feature(m66592, ctrl);
+			break;
+		case USB_REQ_SET_FEATURE:
+			set_feature(m66592, ctrl);
+			break;
+		default:
+			ret = 1;
+			break;
+		}
+	} else
+		ret = 1;
+	return ret;
+}
+
+static void m66592_update_usb_speed(struct m66592 *m66592)
+{
+	u16 speed = get_usb_speed(m66592);
+
+	switch (speed) {
+	case M66592_HSMODE:
+		m66592->gadget.speed = USB_SPEED_HIGH;
+		break;
+	case M66592_FSMODE:
+		m66592->gadget.speed = USB_SPEED_FULL;
+		break;
+	default:
+		m66592->gadget.speed = USB_SPEED_UNKNOWN;
+		printk(KERN_ERR "USB speed unknown\n");
+	}
+}
+
+static void irq_device_state(struct m66592 *m66592)
+{
+	u16 dvsq;
+
+	dvsq = m66592_read(m66592, M66592_INTSTS0) & M66592_DVSQ;
+	m66592_write(m66592, ~M66592_DVST, M66592_INTSTS0);
+
+	if (dvsq == M66592_DS_DFLT) {	/* bus reset */
+		m66592->driver->disconnect(&m66592->gadget);
+		m66592_update_usb_speed(m66592);
+	}
+	if (m66592->old_dvsq == M66592_DS_CNFG && dvsq != M66592_DS_CNFG)
+		m66592_update_usb_speed(m66592);
+	if ((dvsq == M66592_DS_CNFG || dvsq == M66592_DS_ADDS) &&
+	    m66592->gadget.speed == USB_SPEED_UNKNOWN)
+		m66592_update_usb_speed(m66592);
+
+	m66592->old_dvsq = dvsq;
+}
+
+static void irq_control_stage(struct m66592 *m66592)
+{
+	struct usb_ctrlrequest ctrl;
+	u16 ctsq;
+
+	ctsq = m66592_read(m66592, M66592_INTSTS0) & M66592_CTSQ;
+	m66592_write(m66592, ~M66592_CTRT, M66592_INTSTS0);
+
+	switch (ctsq) {
+	case M66592_CS_IDST: {
+		struct m66592_ep *ep;
+		struct m66592_request *req;
+		ep = &m66592->ep[0];
+		req = list_entry(ep->queue.next, struct m66592_request, queue);
+		transfer_complete(ep, req, 0);
+		}
+		break;
+
+	case M66592_CS_RDDS:
+	case M66592_CS_WRDS:
+	case M66592_CS_WRND:
+		if (setup_packet(m66592, &ctrl)) {
+			if (m66592->driver->setup(&m66592->gadget, &ctrl) < 0)
+				pipe_stall(m66592, 0);
+		}
+		break;
+	case M66592_CS_RDSS:
+	case M66592_CS_WRSS:
+		control_end(m66592, 0);
+		break;
+	default:
+		printk(KERN_ERR "ctrl_stage: unexpect ctsq(%x)\n", ctsq);
+		break;
+	}
+}
+
+static irqreturn_t m66592_irq(int irq, void *_m66592)
+{
+	struct m66592 *m66592 = _m66592;
+	u16 intsts0;
+	u16 intenb0;
+	u16 brdysts, nrdysts, bempsts;
+	u16 brdyenb, nrdyenb, bempenb;
+	u16 savepipe;
+	u16 mask0;
+
+	intsts0 = m66592_read(m66592, M66592_INTSTS0);
+	intenb0 = m66592_read(m66592, M66592_INTENB0);
+
+	savepipe = m66592_read(m66592, M66592_CFIFOSEL);
+
+	mask0 = intsts0 & intenb0;
+	if (mask0) {
+		brdysts = m66592_read(m66592, M66592_BRDYSTS);
+		nrdysts = m66592_read(m66592, M66592_NRDYSTS);
+		bempsts = m66592_read(m66592, M66592_BEMPSTS);
+		brdyenb = m66592_read(m66592, M66592_BRDYENB);
+		nrdyenb = m66592_read(m66592, M66592_NRDYENB);
+		bempenb = m66592_read(m66592, M66592_BEMPENB);
+
+		if (mask0 & M66592_VBINT) {
+			m66592_write(m66592, (u16)~M66592_VBINT,
+				     M66592_INTSTS0);
+			m66592_start_xclock(m66592);
+
+			/* start vbus sampling */
+			m66592->old_vbus = m66592_read(m66592, M66592_INTSTS0)
+					   & M66592_VBSTS;
+			m66592->scount = M66592_MAX_SAMPLING;
+
+			mod_timer(&m66592->timer,
+				  jiffies + msecs_to_jiffies(50));
+		}
+		if (intsts0 & M66592_DVSQ)
+			irq_device_state(m66592);
+
+		if ((intsts0 & M66592_BRDY) && (intenb0 & M66592_BRDYE) &&
+		    (brdysts & brdyenb)) {
+			irq_pipe_ready(m66592, brdysts, brdyenb);
+		}
+		if ((intsts0 & M66592_BEMP) && (intenb0 & M66592_BEMPE) &&
+		    (bempsts & bempenb)) {
+			irq_pipe_empty(m66592, bempsts, bempenb);
+		}
+
+		if (intsts0 & M66592_CTRT)
+			irq_control_stage(m66592);
+	}
+
+	m66592_write(m66592, savepipe, M66592_CFIFOSEL);
+
+	return IRQ_HANDLED;
+}
+
+static void m66592_timer(unsigned long _m66592)
+{
+	struct m66592 *m66592 = (struct m66592 *)_m66592;
+	unsigned long flags;
+	u16 tmp;
+
+	spin_lock_irqsave(&m66592->lock, flags);
+	tmp = m66592_read(m66592, M66592_SYSCFG);
+	if (!(tmp & M66592_RCKE)) {
+		m66592_bset(m66592, M66592_RCKE | M66592_PLLC, M66592_SYSCFG);
+		udelay(10);
+		m66592_bset(m66592, M66592_SCKE, M66592_SYSCFG);
+	}
+	if (m66592->scount > 0) {
+		tmp = m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS;
+		if (tmp == m66592->old_vbus) {
+			m66592->scount--;
+			if (m66592->scount == 0) {
+				if (tmp == M66592_VBSTS)
+					m66592_usb_connect(m66592);
+				else
+					m66592_usb_disconnect(m66592);
+			} else {
+				mod_timer(&m66592->timer,
+					  jiffies + msecs_to_jiffies(50));
+			}
+		} else {
+			m66592->scount = M66592_MAX_SAMPLING;
+			m66592->old_vbus = tmp;
+			mod_timer(&m66592->timer,
+				  jiffies + msecs_to_jiffies(50));
+		}
+	}
+	spin_unlock_irqrestore(&m66592->lock, flags);
+}
+
+/*-------------------------------------------------------------------------*/
+static int m66592_enable(struct usb_ep *_ep,
+			 const struct usb_endpoint_descriptor *desc)
+{
+	struct m66592_ep *ep;
+
+	ep = container_of(_ep, struct m66592_ep, ep);
+	return alloc_pipe_config(ep, desc);
+}
+
+static int m66592_disable(struct usb_ep *_ep)
+{
+	struct m66592_ep *ep;
+	struct m66592_request *req;
+	unsigned long flags;
+
+	ep = container_of(_ep, struct m66592_ep, ep);
+	BUG_ON(!ep);
+
+	while (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next, struct m66592_request, queue);
+		spin_lock_irqsave(&ep->m66592->lock, flags);
+		transfer_complete(ep, req, -ECONNRESET);
+		spin_unlock_irqrestore(&ep->m66592->lock, flags);
+	}
+
+	pipe_irq_disable(ep->m66592, ep->pipenum);
+	return free_pipe_config(ep);
+}
+
+static struct usb_request *m66592_alloc_request(struct usb_ep *_ep,
+						gfp_t gfp_flags)
+{
+	struct m66592_request *req;
+
+	req = kzalloc(sizeof(struct m66592_request), gfp_flags);
+	if (!req)
+		return NULL;
+
+	INIT_LIST_HEAD(&req->queue);
+
+	return &req->req;
+}
+
+static void m66592_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct m66592_request *req;
+
+	req = container_of(_req, struct m66592_request, req);
+	kfree(req);
+}
+
+static void *m66592_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
+				 dma_addr_t *dma, gfp_t gfp_flags)
+{
+	void *buf;
+
+	buf = kzalloc(bytes, gfp_flags);
+	if (dma)
+		*dma = virt_to_bus(buf);
+
+	return buf;
+}
+
+static void m66592_free_buffer(struct usb_ep *_ep, void *buf,
+			       dma_addr_t dma, unsigned bytes)
+{
+	kfree(buf);
+}
+
+static int m66592_queue(struct usb_ep *_ep, struct usb_request *_req,
+			gfp_t gfp_flags)
+{
+	struct m66592_ep *ep;
+	struct m66592_request *req;
+	unsigned long flags;
+	int request = 0;
+
+	ep = container_of(_ep, struct m66592_ep, ep);
+	req = container_of(_req, struct m66592_request, req);
+
+	if (ep->m66592->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	spin_lock_irqsave(&ep->m66592->lock, flags);
+
+	if (list_empty(&ep->queue))
+		request = 1;
+
+	list_add_tail(&req->queue, &ep->queue);
+	req->req.actual = 0;
+	req->req.status = -EINPROGRESS;
+
+	if (ep->desc == 0)	/* control */
+		start_ep0(ep, req);
+	else {
+		if (request && !ep->busy)
+			start_packet(ep, req);
+	}
+
+	spin_unlock_irqrestore(&ep->m66592->lock, flags);
+
+	return 0;
+}
+
+static int m66592_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct m66592_ep *ep;
+	struct m66592_request *req;
+	unsigned long flags;
+
+	ep = container_of(_ep, struct m66592_ep, ep);
+	req = container_of(_req, struct m66592_request, req);
+
+	spin_lock_irqsave(&ep->m66592->lock, flags);
+	if (!list_empty(&ep->queue))
+		transfer_complete(ep, req, -ECONNRESET);
+	spin_unlock_irqrestore(&ep->m66592->lock, flags);
+
+	return 0;
+}
+
+static int m66592_set_halt(struct usb_ep *_ep, int value)
+{
+	struct m66592_ep *ep;
+	struct m66592_request *req;
+	unsigned long flags;
+	int ret = 0;
+
+	ep = container_of(_ep, struct m66592_ep, ep);
+	req = list_entry(ep->queue.next, struct m66592_request, queue);
+
+	spin_lock_irqsave(&ep->m66592->lock, flags);
+	if (!list_empty(&ep->queue)) {
+		ret = -EAGAIN;
+		goto out;
+	}
+	if (value) {
+		ep->busy = 1;
+		pipe_stall(ep->m66592, ep->pipenum);
+	} else {
+		ep->busy = 0;
+		pipe_stop(ep->m66592, ep->pipenum);
+	}
+
+out:
+	spin_unlock_irqrestore(&ep->m66592->lock, flags);
+	return ret;
+}
+
+static int m66592_fifo_status(struct usb_ep *_ep)
+{
+	return -EOPNOTSUPP;
+}
+
+static void m66592_fifo_flush(struct usb_ep *_ep)
+{
+	struct m66592_ep *ep;
+	unsigned long flags;
+
+	ep = container_of(_ep, struct m66592_ep, ep);
+	spin_lock_irqsave(&ep->m66592->lock, flags);
+	if (list_empty(&ep->queue) && !ep->busy) {
+		pipe_stop(ep->m66592, ep->pipenum);
+		m66592_bclr(ep->m66592, M66592_BCLR, ep->fifoctr);
+	}
+	spin_unlock_irqrestore(&ep->m66592->lock, flags);
+}
+
+static struct usb_ep_ops m66592_ep_ops = {
+	.enable		= m66592_enable,
+	.disable	= m66592_disable,
+
+	.alloc_request	= m66592_alloc_request,
+	.free_request	= m66592_free_request,
+
+	.alloc_buffer	= m66592_alloc_buffer,
+	.free_buffer	= m66592_free_buffer,
+
+	.queue		= m66592_queue,
+	.dequeue	= m66592_dequeue,
+
+	.set_halt	= m66592_set_halt,
+	.fifo_status	= m66592_fifo_status,
+	.fifo_flush	= m66592_fifo_flush,
+};
+
+/*-------------------------------------------------------------------------*/
+static struct m66592 *the_controller;
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct m66592 *m66592 = the_controller;
+	int retval;
+
+	if (!driver ||
+	    driver->speed != USB_SPEED_HIGH ||
+	    !driver->bind ||
+	    !driver->unbind ||
+	    !driver->setup)
+		return -EINVAL;
+	if (!m66592)
+		return -ENODEV;
+	if (m66592->driver)
+		return -EBUSY;
+
+	/* hook up the driver */
+	driver->driver.bus = NULL;
+	m66592->driver = driver;
+	m66592->gadget.dev.driver = &driver->driver;
+
+	retval = device_add(&m66592->gadget.dev);
+	if (retval) {
+		printk(KERN_ERR "device_add error (%d)\n", retval);
+		goto error;
+	}
+
+	retval = driver->bind (&m66592->gadget);
+	if (retval) {
+		printk(KERN_ERR "bind to driver error (%d)\n", retval);
+		device_del(&m66592->gadget.dev);
+		goto error;
+	}
+
+	m66592_bset(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
+	if (m66592_read(m66592, M66592_INTSTS0) & M66592_VBSTS) {
+		m66592_start_xclock(m66592);
+		/* start vbus sampling */
+		m66592->old_vbus = m66592_read(m66592,
+					 M66592_INTSTS0) & M66592_VBSTS;
+		m66592->scount = M66592_MAX_SAMPLING;
+		mod_timer(&m66592->timer,
+			  jiffies + msecs_to_jiffies(50));
+	}
+
+	return 0;
+
+error:
+	m66592->driver = NULL;
+	m66592->gadget.dev.driver = NULL;
+
+	return retval;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct m66592 *m66592 = the_controller;
+	unsigned long flags;
+
+	spin_lock_irqsave(&m66592->lock, flags);
+	if (m66592->gadget.speed != USB_SPEED_UNKNOWN)
+		m66592_usb_disconnect(m66592);
+	spin_unlock_irqrestore(&m66592->lock, flags);
+
+	m66592_bclr(m66592, M66592_VBSE | M66592_URST, M66592_INTENB0);
+
+	driver->unbind(&m66592->gadget);
+
+	init_controller(m66592);
+	disable_controller(m66592);
+
+	device_del(&m66592->gadget.dev);
+	m66592->driver = NULL;
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+/*-------------------------------------------------------------------------*/
+static int m66592_get_frame(struct usb_gadget *_gadget)
+{
+	struct m66592 *m66592 = gadget_to_m66592(_gadget);
+	return m66592_read(m66592, M66592_FRMNUM) & 0x03FF;
+}
+
+static struct usb_gadget_ops m66592_gadget_ops = {
+	.get_frame		= m66592_get_frame,
+};
+
+#if defined(CONFIG_PM)
+static int m66592_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	pdev->dev.power.power_state = state;
+	return 0;
+}
+
+static int m66592_resume(struct platform_device *pdev)
+{
+	pdev->dev.power.power_state = PMSG_ON;
+	return 0;
+}
+#else	/* if defined(CONFIG_PM) */
+#define m66592_suspend		NULL
+#define m66592_resume		NULL
+#endif
+
+static int __init_or_module m66592_remove(struct platform_device *pdev)
+{
+	struct m66592		*m66592 = dev_get_drvdata(&pdev->dev);
+
+	del_timer_sync(&m66592->timer);
+	iounmap(m66592->reg);
+	free_irq(platform_get_irq(pdev, 0), m66592);
+	kfree(m66592);
+	return 0;
+}
+
+#define resource_len(r) (((r)->end - (r)->start) + 1)
+static int __init m66592_probe(struct platform_device *pdev)
+{
+	struct resource *res = NULL;
+	int irq = -1;
+	void __iomem *reg = NULL;
+	struct m66592 *m66592 = NULL;
+	int ret = 0;
+	int i;
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+					   (char *)udc_name);
+	if (!res) {
+		ret = -ENODEV;
+		printk(KERN_ERR "platform_get_resource_byname error.\n");
+		goto clean_up;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		ret = -ENODEV;
+		printk(KERN_ERR "platform_get_irq error.\n");
+		goto clean_up;
+	}
+
+	reg = ioremap(res->start, resource_len(res));
+	if (reg == NULL) {
+		ret = -ENOMEM;
+		printk(KERN_ERR "ioremap error.\n");
+		goto clean_up;
+	}
+
+	/* initialize ucd */
+	m66592 = kzalloc(sizeof(struct m66592), GFP_KERNEL);
+	if (m66592 == NULL) {
+		printk(KERN_ERR "kzalloc error\n");
+		goto clean_up;
+	}
+
+	spin_lock_init(&m66592->lock);
+	dev_set_drvdata(&pdev->dev, m66592);
+
+	m66592->gadget.ops = &m66592_gadget_ops;
+	device_initialize(&m66592->gadget.dev);
+	strcpy(m66592->gadget.dev.bus_id, "gadget");
+	m66592->gadget.is_dualspeed = 1;
+	m66592->gadget.dev.parent = &pdev->dev;
+	m66592->gadget.dev.dma_mask = pdev->dev.dma_mask;
+	m66592->gadget.dev.release = pdev->dev.release;
+	m66592->gadget.name = udc_name;
+
+	init_timer(&m66592->timer);
+	m66592->timer.function = m66592_timer;
+	m66592->timer.data = (unsigned long)m66592;
+	m66592->reg = reg;
+
+	m66592->bi_bufnum = M66592_BASE_BUFNUM;
+
+	ret = request_irq(irq, m66592_irq, IRQF_DISABLED | IRQF_SHARED,
+			  udc_name, m66592);
+	if (ret < 0) {
+		printk(KERN_ERR "request_irq error (%d)\n", ret);
+		goto clean_up;
+	}
+
+	INIT_LIST_HEAD(&m66592->gadget.ep_list);
+	m66592->gadget.ep0 = &m66592->ep[0].ep;
+	INIT_LIST_HEAD(&m66592->gadget.ep0->ep_list);
+	for (i = 0; i < M66592_MAX_NUM_PIPE; i++) {
+		struct m66592_ep *ep = &m66592->ep[i];
+
+		if (i != 0) {
+			INIT_LIST_HEAD(&m66592->ep[i].ep.ep_list);
+			list_add_tail(&m66592->ep[i].ep.ep_list,
+				      &m66592->gadget.ep_list);
+		}
+		ep->m66592 = m66592;
+		INIT_LIST_HEAD(&ep->queue);
+		ep->ep.name = m66592_ep_name[i];
+		ep->ep.ops = &m66592_ep_ops;
+		ep->ep.maxpacket = 512;
+	}
+	m66592->ep[0].ep.maxpacket = 64;
+	m66592->ep[0].pipenum = 0;
+	m66592->ep[0].fifoaddr = M66592_CFIFO;
+	m66592->ep[0].fifosel = M66592_CFIFOSEL;
+	m66592->ep[0].fifoctr = M66592_CFIFOCTR;
+	m66592->ep[0].fifotrn = 0;
+	m66592->ep[0].pipectr = get_pipectr_addr(0);
+	m66592->pipenum2ep[0] = &m66592->ep[0];
+	m66592->epaddr2ep[0] = &m66592->ep[0];
+
+	the_controller = m66592;
+
+	m66592->ep0_req = m66592_alloc_request(&m66592->ep[0].ep, GFP_KERNEL);
+	if (m66592->ep0_req == NULL)
+		goto clean_up;
+	m66592->ep0_buf = m66592_alloc_buffer(&m66592->ep[0].ep, 2, NULL,
+					      GFP_KERNEL);
+	if (m66592->ep0_buf == NULL)
+		goto clean_up;
+
+	init_controller(m66592);
+
+	printk("driver %s, %s\n", udc_name, DRIVER_VERSION);
+	return 0;
+
+clean_up:
+	if (m66592) {
+		if (m66592->ep0_req)
+			m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
+		kfree(m66592);
+	}
+	if (reg)
+		iounmap(reg);
+
+	return ret;
+}
+
+/*-------------------------------------------------------------------------*/
+static struct platform_driver m66592_driver = {
+	.probe =	m66592_probe,
+	.remove =	m66592_remove,
+	.suspend =	m66592_suspend,
+	.resume =	m66592_resume,
+	.driver		= {
+		.name =	(char *) udc_name,
+	},
+};
+
+static int __init m66592_udc_init(void)
+{
+	return platform_driver_register(&m66592_driver);
+}
+module_init(m66592_udc_init);
+
+static void __exit m66592_udc_cleanup(void)
+{
+	platform_driver_unregister(&m66592_driver);
+}
+module_exit(m66592_udc_cleanup);
+

+ 577 - 0
drivers/usb/gadget/m66592-udc.h

@@ -0,0 +1,577 @@
+/*
+ * M66592 UDC (USB gadget)
+ *
+ * Copyright (C) 2006-2007 Renesas Solutions Corp.
+ *
+ * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __M66592_UDC_H__
+#define __M66592_UDC_H__
+
+#define M66592_SYSCFG		0x00
+#define	M66592_XTAL		0xC000	/* b15-14: Crystal selection */
+#define	  M66592_XTAL48		 0x8000		  /* 48MHz */
+#define   M66592_XTAL24		 0x4000		  /* 24MHz */
+#define	  M66592_XTAL12		 0x0000		  /* 12MHz */
+#define	M66592_XCKE		0x2000	/* b13: External clock enable */
+#define	M66592_RCKE		0x1000	/* b12: Register clock enable */
+#define	M66592_PLLC		0x0800	/* b11: PLL control */
+#define	M66592_SCKE		0x0400	/* b10: USB clock enable */
+#define	M66592_ATCKM		0x0100	/* b8: Automatic supply functional enable */
+#define	M66592_HSE		0x0080	/* b7: Hi-speed enable */
+#define	M66592_DCFM		0x0040	/* b6: Controller function select  */
+#define	M66592_DMRPD		0x0020	/* b5: D- pull down control */
+#define	M66592_DPRPU		0x0010	/* b4: D+ pull up control */
+#define	M66592_FSRPC		0x0004	/* b2: Full-speed receiver enable */
+#define	M66592_PCUT		0x0002	/* b1: Low power sleep enable */
+#define	M66592_USBE		0x0001	/* b0: USB module operation enable */
+
+#define M66592_SYSSTS		0x02
+#define	M66592_LNST		0x0003	/* b1-0: D+, D- line status */
+#define	  M66592_SE1		 0x0003		  /* SE1 */
+#define	  M66592_KSTS		 0x0002		  /* K State */
+#define	  M66592_JSTS		 0x0001		  /* J State */
+#define	  M66592_SE0		 0x0000		  /* SE0 */
+
+#define M66592_DVSTCTR		0x04
+#define	M66592_WKUP		0x0100	/* b8: Remote wakeup */
+#define	M66592_RWUPE		0x0080	/* b7: Remote wakeup sense */
+#define	M66592_USBRST		0x0040	/* b6: USB reset enable */
+#define	M66592_RESUME		0x0020	/* b5: Resume enable */
+#define	M66592_UACT		0x0010	/* b4: USB bus enable */
+#define	M66592_RHST		0x0003	/* b1-0: Reset handshake status */
+#define	  M66592_HSMODE		 0x0003		  /* Hi-Speed mode */
+#define	  M66592_FSMODE		 0x0002		  /* Full-Speed mode */
+#define	  M66592_HSPROC		 0x0001		  /* HS handshake is processing */
+
+#define M66592_TESTMODE		0x06
+#define	M66592_UTST		0x000F	/* b4-0: Test select */
+#define	  M66592_H_TST_PACKET	 0x000C		  /* HOST TEST Packet */
+#define	  M66592_H_TST_SE0_NAK	 0x000B		  /* HOST TEST SE0 NAK */
+#define	  M66592_H_TST_K	 0x000A		  /* HOST TEST K */
+#define	  M66592_H_TST_J	 0x0009		  /* HOST TEST J */
+#define	  M66592_H_TST_NORMAL	 0x0000		  /* HOST Normal Mode */
+#define	  M66592_P_TST_PACKET	 0x0004		  /* PERI TEST Packet */
+#define	  M66592_P_TST_SE0_NAK	 0x0003		  /* PERI TEST SE0 NAK */
+#define	  M66592_P_TST_K	 0x0002		  /* PERI TEST K */
+#define	  M66592_P_TST_J	 0x0001		  /* PERI TEST J */
+#define	  M66592_P_TST_NORMAL	 0x0000		  /* PERI Normal Mode */
+
+#define M66592_PINCFG		0x0A
+#define	M66592_LDRV		0x8000	/* b15: Drive Current Adjust */
+#define	M66592_BIGEND		0x0100	/* b8: Big endian mode */
+
+#define M66592_DMA0CFG		0x0C
+#define M66592_DMA1CFG		0x0E
+#define	M66592_DREQA		0x4000	/* b14: Dreq active select */
+#define	M66592_BURST		0x2000	/* b13: Burst mode */
+#define	M66592_DACKA		0x0400	/* b10: Dack active select */
+#define	M66592_DFORM		0x0380	/* b9-7: DMA mode select */
+#define	  M66592_CPU_ADR_RD_WR	 0x0000		  /* Address + RD/WR mode (CPU bus) */
+#define	  M66592_CPU_DACK_RD_WR	 0x0100		  /* DACK + RD/WR mode (CPU bus) */
+#define	  M66592_CPU_DACK_ONLY	 0x0180		  /* DACK only mode (CPU bus) */
+#define	  M66592_SPLIT_DACK_ONLY	 0x0200		  /* DACK only mode (SPLIT bus) */
+#define	  M66592_SPLIT_DACK_DSTB	 0x0300		  /* DACK + DSTB0 mode (SPLIT bus) */
+#define	M66592_DENDA		0x0040	/* b6: Dend active select */
+#define	M66592_PKTM		0x0020	/* b5: Packet mode */
+#define	M66592_DENDE		0x0010	/* b4: Dend enable */
+#define	M66592_OBUS		0x0004	/* b2: OUTbus mode */
+
+#define M66592_CFIFO		0x10
+#define M66592_D0FIFO		0x14
+#define M66592_D1FIFO		0x18
+
+#define M66592_CFIFOSEL		0x1E
+#define M66592_D0FIFOSEL	0x24
+#define M66592_D1FIFOSEL	0x2A
+#define	M66592_RCNT		0x8000	/* b15: Read count mode */
+#define	M66592_REW		0x4000	/* b14: Buffer rewind */
+#define	M66592_DCLRM		0x2000	/* b13: DMA buffer clear mode */
+#define	M66592_DREQE		0x1000	/* b12: DREQ output enable */
+#define	M66592_MBW		0x0400	/* b10: Maximum bit width for FIFO access */
+#define	  M66592_MBW_8		 0x0000	  /*  8bit */
+#define	  M66592_MBW_16		 0x0400		  /* 16bit */
+#define	M66592_TRENB		0x0200	/* b9: Transaction counter enable */
+#define	M66592_TRCLR		0x0100	/* b8: Transaction counter clear */
+#define	M66592_DEZPM		0x0080	/* b7: Zero-length packet additional mode */
+#define	M66592_ISEL		0x0020	/* b5: DCP FIFO port direction select */
+#define	M66592_CURPIPE		0x0007	/* b2-0: PIPE select */
+
+#define M66592_CFIFOCTR		0x20
+#define M66592_D0FIFOCTR	0x26
+#define M66592_D1FIFOCTR	0x2c
+#define	M66592_BVAL		0x8000	/* b15: Buffer valid flag */
+#define	M66592_BCLR		0x4000	/* b14: Buffer clear */
+#define	M66592_FRDY		0x2000	/* b13: FIFO ready */
+#define	M66592_DTLN		0x0FFF	/* b11-0: FIFO received data length */
+
+#define M66592_CFIFOSIE		0x22
+#define	M66592_TGL		0x8000	/* b15: Buffer toggle */
+#define	M66592_SCLR		0x4000	/* b14: Buffer clear */
+#define	M66592_SBUSY		0x2000	/* b13: SIE_FIFO busy */
+
+#define M66592_D0FIFOTRN	0x28
+#define M66592_D1FIFOTRN	0x2E
+#define	M66592_TRNCNT		0xFFFF	/* b15-0: Transaction counter */
+
+#define M66592_INTENB0	0x30
+#define	M66592_VBSE	0x8000	/* b15: VBUS interrupt */
+#define	M66592_RSME	0x4000	/* b14: Resume interrupt */
+#define	M66592_SOFE	0x2000	/* b13: Frame update interrupt */
+#define	M66592_DVSE	0x1000	/* b12: Device state transition interrupt */
+#define	M66592_CTRE	0x0800	/* b11: Control transfer stage transition interrupt */
+#define	M66592_BEMPE	0x0400	/* b10: Buffer empty interrupt */
+#define	M66592_NRDYE	0x0200	/* b9: Buffer not ready interrupt */
+#define	M66592_BRDYE	0x0100	/* b8: Buffer ready interrupt */
+#define	M66592_URST	0x0080	/* b7: USB reset detected interrupt */
+#define	M66592_SADR	0x0040	/* b6: Set address executed interrupt */
+#define	M66592_SCFG	0x0020	/* b5: Set configuration executed interrupt */
+#define	M66592_SUSP	0x0010	/* b4: Suspend detected interrupt */
+#define	M66592_WDST	0x0008	/* b3: Control write data stage completed interrupt */
+#define	M66592_RDST	0x0004	/* b2: Control read data stage completed interrupt */
+#define	M66592_CMPL	0x0002	/* b1: Control transfer complete interrupt */
+#define	M66592_SERR	0x0001	/* b0: Sequence error interrupt */
+
+#define M66592_INTENB1	0x32
+#define	M66592_BCHGE	0x4000	/* b14: USB us chenge interrupt */
+#define	M66592_DTCHE	0x1000	/* b12: Detach sense interrupt */
+#define	M66592_SIGNE	0x0020	/* b5: SETUP IGNORE interrupt */
+#define	M66592_SACKE	0x0010	/* b4: SETUP ACK interrupt */
+#define	M66592_BRDYM	0x0004	/* b2: BRDY clear timing */
+#define	M66592_INTL	0x0002	/* b1: Interrupt sense select */
+#define	M66592_PCSE	0x0001	/* b0: PCUT enable by CS assert */
+
+#define M66592_BRDYENB		0x36
+#define M66592_BRDYSTS		0x46
+#define	M66592_BRDY7		0x0080	/* b7: PIPE7 */
+#define	M66592_BRDY6		0x0040	/* b6: PIPE6 */
+#define	M66592_BRDY5		0x0020	/* b5: PIPE5 */
+#define	M66592_BRDY4		0x0010	/* b4: PIPE4 */
+#define	M66592_BRDY3		0x0008	/* b3: PIPE3 */
+#define	M66592_BRDY2		0x0004	/* b2: PIPE2 */
+#define	M66592_BRDY1		0x0002	/* b1: PIPE1 */
+#define	M66592_BRDY0		0x0001	/* b1: PIPE0 */
+
+#define M66592_NRDYENB		0x38
+#define M66592_NRDYSTS		0x48
+#define	M66592_NRDY7		0x0080	/* b7: PIPE7 */
+#define	M66592_NRDY6		0x0040	/* b6: PIPE6 */
+#define	M66592_NRDY5		0x0020	/* b5: PIPE5 */
+#define	M66592_NRDY4		0x0010	/* b4: PIPE4 */
+#define	M66592_NRDY3		0x0008	/* b3: PIPE3 */
+#define	M66592_NRDY2		0x0004	/* b2: PIPE2 */
+#define	M66592_NRDY1		0x0002	/* b1: PIPE1 */
+#define	M66592_NRDY0		0x0001	/* b1: PIPE0 */
+
+#define M66592_BEMPENB		0x3A
+#define M66592_BEMPSTS		0x4A
+#define	M66592_BEMP7		0x0080	/* b7: PIPE7 */
+#define	M66592_BEMP6		0x0040	/* b6: PIPE6 */
+#define	M66592_BEMP5		0x0020	/* b5: PIPE5 */
+#define	M66592_BEMP4		0x0010	/* b4: PIPE4 */
+#define	M66592_BEMP3		0x0008	/* b3: PIPE3 */
+#define	M66592_BEMP2		0x0004	/* b2: PIPE2 */
+#define	M66592_BEMP1		0x0002	/* b1: PIPE1 */
+#define	M66592_BEMP0		0x0001	/* b0: PIPE0 */
+
+#define M66592_SOFCFG		0x3C
+#define	M66592_SOFM		0x000C	/* b3-2: SOF palse mode */
+#define	  M66592_SOF_125US	 0x0008		  /* SOF OUT 125us uFrame Signal */
+#define	  M66592_SOF_1MS	 0x0004		  /* SOF OUT 1ms Frame Signal */
+#define	  M66592_SOF_DISABLE	 0x0000		  /* SOF OUT Disable */
+
+#define M66592_INTSTS0		0x40
+#define	M66592_VBINT		0x8000	/* b15: VBUS interrupt */
+#define	M66592_RESM		0x4000	/* b14: Resume interrupt */
+#define	M66592_SOFR		0x2000	/* b13: SOF frame update interrupt */
+#define	M66592_DVST		0x1000	/* b12: Device state transition interrupt */
+#define	M66592_CTRT		0x0800	/* b11: Control transfer stage transition interrupt */
+#define	M66592_BEMP		0x0400	/* b10: Buffer empty interrupt */
+#define	M66592_NRDY		0x0200	/* b9: Buffer not ready interrupt */
+#define	M66592_BRDY		0x0100	/* b8: Buffer ready interrupt */
+#define	M66592_VBSTS		0x0080	/* b7: VBUS input port */
+#define	M66592_DVSQ		0x0070	/* b6-4: Device state */
+#define	  M66592_DS_SPD_CNFG	 0x0070		  /* Suspend Configured */
+#define	  M66592_DS_SPD_ADDR	 0x0060		  /* Suspend Address */
+#define	  M66592_DS_SPD_DFLT	 0x0050		  /* Suspend Default */
+#define	  M66592_DS_SPD_POWR	 0x0040		  /* Suspend Powered */
+#define	  M66592_DS_SUSP	 0x0040		  /* Suspend */
+#define	  M66592_DS_CNFG	 0x0030		  /* Configured */
+#define	  M66592_DS_ADDS	 0x0020		  /* Address */
+#define	  M66592_DS_DFLT	 0x0010		  /* Default */
+#define	  M66592_DS_POWR	 0x0000		  /* Powered */
+#define	M66592_DVSQS		0x0030	/* b5-4: Device state */
+#define	M66592_VALID		0x0008	/* b3: Setup packet detected flag */
+#define	M66592_CTSQ		0x0007	/* b2-0: Control transfer stage */
+#define	  M66592_CS_SQER	 0x0006		  /* Sequence error */
+#define	  M66592_CS_WRND	 0x0005		  /* Control write nodata status stage */
+#define	  M66592_CS_WRSS	 0x0004		  /* Control write status stage */
+#define	  M66592_CS_WRDS	 0x0003		  /* Control write data stage */
+#define	  M66592_CS_RDSS	 0x0002		  /* Control read status stage */
+#define	  M66592_CS_RDDS	 0x0001		  /* Control read data stage */
+#define	  M66592_CS_IDST	 0x0000		  /* Idle or setup stage */
+
+#define M66592_INTSTS1		0x42
+#define	M66592_BCHG		0x4000	/* b14: USB bus chenge interrupt */
+#define	M66592_DTCH		0x1000	/* b12: Detach sense interrupt */
+#define	M66592_SIGN		0x0020	/* b5: SETUP IGNORE interrupt */
+#define	M66592_SACK		0x0010	/* b4: SETUP ACK interrupt */
+
+#define M66592_FRMNUM		0x4C
+#define	M66592_OVRN		0x8000	/* b15: Overrun error */
+#define	M66592_CRCE		0x4000	/* b14: Received data error */
+#define	M66592_SOFRM		0x0800	/* b11: SOF output mode */
+#define	M66592_FRNM		0x07FF	/* b10-0: Frame number */
+
+#define M66592_UFRMNUM		0x4E
+#define	M66592_UFRNM		0x0007	/* b2-0: Micro frame number */
+
+#define M66592_RECOVER		0x50
+#define	M66592_STSRECOV		0x0700	/* Status recovery */
+#define	  M66592_STSR_HI	 0x0400		  /* FULL(0) or HI(1) Speed */
+#define	  M66592_STSR_DEFAULT	 0x0100		  /* Default state */
+#define	  M66592_STSR_ADDRESS	 0x0200		  /* Address state */
+#define	  M66592_STSR_CONFIG	 0x0300		  /* Configured state */
+#define	M66592_USBADDR		0x007F	/* b6-0: USB address */
+
+#define M66592_USBREQ			0x54
+#define	M66592_bRequest			0xFF00	/* b15-8: bRequest */
+#define	  M66592_GET_STATUS		 0x0000
+#define	  M66592_CLEAR_FEATURE		 0x0100
+#define	  M66592_ReqRESERVED		 0x0200
+#define	  M66592_SET_FEATURE		 0x0300
+#define	  M66592_ReqRESERVED1		 0x0400
+#define	  M66592_SET_ADDRESS		 0x0500
+#define	  M66592_GET_DESCRIPTOR		 0x0600
+#define	  M66592_SET_DESCRIPTOR		 0x0700
+#define	  M66592_GET_CONFIGURATION	 0x0800
+#define	  M66592_SET_CONFIGURATION	 0x0900
+#define	  M66592_GET_INTERFACE		 0x0A00
+#define	  M66592_SET_INTERFACE		 0x0B00
+#define	  M66592_SYNCH_FRAME		 0x0C00
+#define	M66592_bmRequestType		0x00FF	/* b7-0: bmRequestType */
+#define	M66592_bmRequestTypeDir		0x0080	/* b7  : Data transfer direction */
+#define	  M66592_HOST_TO_DEVICE		 0x0000
+#define	  M66592_DEVICE_TO_HOST		 0x0080
+#define	M66592_bmRequestTypeType	0x0060	/* b6-5: Type */
+#define	  M66592_STANDARD		 0x0000
+#define	  M66592_CLASS			 0x0020
+#define	  M66592_VENDOR			 0x0040
+#define	M66592_bmRequestTypeRecip	0x001F	/* b4-0: Recipient */
+#define	  M66592_DEVICE			 0x0000
+#define	  M66592_INTERFACE		 0x0001
+#define	  M66592_ENDPOINT		 0x0002
+
+#define M66592_USBVAL				0x56
+#define	M66592_wValue				0xFFFF	/* b15-0: wValue */
+/* Standard Feature Selector */
+#define	  M66592_ENDPOINT_HALT			0x0000
+#define	  M66592_DEVICE_REMOTE_WAKEUP		0x0001
+#define	  M66592_TEST_MODE			0x0002
+/* Descriptor Types */
+#define	M66592_DT_TYPE				0xFF00
+#define	M66592_GET_DT_TYPE(v)			(((v) & DT_TYPE) >> 8)
+#define	  M66592_DT_DEVICE			0x01
+#define	  M66592_DT_CONFIGURATION		0x02
+#define	  M66592_DT_STRING			0x03
+#define	  M66592_DT_INTERFACE			0x04
+#define	  M66592_DT_ENDPOINT			0x05
+#define	  M66592_DT_DEVICE_QUALIFIER		0x06
+#define	  M66592_DT_OTHER_SPEED_CONFIGURATION	0x07
+#define	  M66592_DT_INTERFACE_POWER		0x08
+#define	M66592_DT_INDEX				0x00FF
+#define	M66592_CONF_NUM				0x00FF
+#define	M66592_ALT_SET				0x00FF
+
+#define M66592_USBINDEX			0x58
+#define	M66592_wIndex			0xFFFF	/* b15-0: wIndex */
+#define	M66592_TEST_SELECT		0xFF00	/* b15-b8: Test Mode Selectors */
+#define	  M66592_TEST_J			 0x0100		  /* Test_J */
+#define	  M66592_TEST_K			 0x0200		  /* Test_K */
+#define	  M66592_TEST_SE0_NAK		 0x0300		  /* Test_SE0_NAK */
+#define	  M66592_TEST_PACKET		 0x0400		  /* Test_Packet */
+#define	  M66592_TEST_FORCE_ENABLE	 0x0500		  /* Test_Force_Enable */
+#define	  M66592_TEST_STSelectors	 0x0600		  /* Standard test selectors */
+#define	  M66592_TEST_Reserved		 0x4000		  /* Reserved */
+#define	  M66592_TEST_VSTModes		 0xC000		  /* Vendor-specific test modes */
+#define	M66592_EP_DIR			0x0080	/* b7: Endpoint Direction */
+#define	  M66592_EP_DIR_IN		 0x0080
+#define	  M66592_EP_DIR_OUT		 0x0000
+
+#define M66592_USBLENG		0x5A
+#define	M66592_wLength		0xFFFF	/* b15-0: wLength */
+
+#define M66592_DCPCFG		0x5C
+#define	M66592_CNTMD		0x0100	/* b8: Continuous transfer mode select */
+#define	M66592_DIR		0x0010	/* b4: Control transfer DIR select */
+
+#define M66592_DCPMAXP		0x5E
+#define	M66592_DEVSEL		0xC000	/* b15-14: Device address select */
+#define	  M66592_DEVICE_0	 0x0000		  /* Device address 0 */
+#define	  M66592_DEVICE_1	 0x4000		  /* Device address 1 */
+#define	  M66592_DEVICE_2	 0x8000		  /* Device address 2 */
+#define	  M66592_DEVICE_3	 0xC000		  /* Device address 3 */
+#define	M66592_MAXP		0x007F	/* b6-0: Maxpacket size of default control pipe */
+
+#define M66592_DCPCTR		0x60
+#define	M66592_BSTS		0x8000	/* b15: Buffer status */
+#define	M66592_SUREQ		0x4000	/* b14: Send USB request  */
+#define	M66592_SQCLR		0x0100	/* b8: Sequence toggle bit clear */
+#define	M66592_SQSET		0x0080	/* b7: Sequence toggle bit set */
+#define	M66592_SQMON		0x0040	/* b6: Sequence toggle bit monitor */
+#define	M66592_CCPL		0x0004	/* b2: Enable control transfer complete */
+#define	M66592_PID		0x0003	/* b1-0: Response PID */
+#define	  M66592_PID_STALL	 0x0002		  /* STALL */
+#define	  M66592_PID_BUF	 0x0001		  /* BUF */
+#define	  M66592_PID_NAK	 0x0000		  /* NAK */
+
+#define M66592_PIPESEL		0x64
+#define	M66592_PIPENM		0x0007	/* b2-0: Pipe select */
+#define	  M66592_PIPE0		 0x0000		  /* PIPE 0 */
+#define	  M66592_PIPE1		 0x0001		  /* PIPE 1 */
+#define	  M66592_PIPE2		 0x0002		  /* PIPE 2 */
+#define	  M66592_PIPE3		 0x0003		  /* PIPE 3 */
+#define	  M66592_PIPE4		 0x0004		  /* PIPE 4 */
+#define	  M66592_PIPE5		 0x0005		  /* PIPE 5 */
+#define	  M66592_PIPE6		 0x0006		  /* PIPE 6 */
+#define	  M66592_PIPE7		 0x0007		  /* PIPE 7 */
+
+#define M66592_PIPECFG		0x66
+#define	M66592_TYP		0xC000	/* b15-14: Transfer type */
+#define	  M66592_ISO		 0xC000		  /* Isochronous */
+#define	  M66592_INT		 0x8000		  /* Interrupt */
+#define	  M66592_BULK		 0x4000		  /* Bulk */
+#define	M66592_BFRE		0x0400	/* b10: Buffer ready interrupt mode select */
+#define	M66592_DBLB		0x0200	/* b9: Double buffer mode select */
+#define	M66592_CNTMD		0x0100	/* b8: Continuous transfer mode select */
+#define	M66592_SHTNAK		0x0080	/* b7: Transfer end NAK */
+#define	M66592_DIR		0x0010	/* b4: Transfer direction select */
+#define	  M66592_DIR_H_OUT	 0x0010		  /* HOST OUT */
+#define	  M66592_DIR_P_IN	 0x0010		  /* PERI IN */
+#define	  M66592_DIR_H_IN	 0x0000		  /* HOST IN */
+#define	  M66592_DIR_P_OUT	 0x0000		  /* PERI OUT */
+#define	M66592_EPNUM		0x000F	/* b3-0: Eendpoint number select */
+#define	  M66592_EP1		 0x0001
+#define	  M66592_EP2		 0x0002
+#define	  M66592_EP3		 0x0003
+#define	  M66592_EP4		 0x0004
+#define	  M66592_EP5		 0x0005
+#define	  M66592_EP6		 0x0006
+#define	  M66592_EP7		 0x0007
+#define	  M66592_EP8		 0x0008
+#define	  M66592_EP9		 0x0009
+#define	  M66592_EP10		 0x000A
+#define	  M66592_EP11		 0x000B
+#define	  M66592_EP12		 0x000C
+#define	  M66592_EP13		 0x000D
+#define	  M66592_EP14		 0x000E
+#define	  M66592_EP15		 0x000F
+
+#define M66592_PIPEBUF		0x68
+#define	M66592_BUFSIZE		0x7C00	/* b14-10: Pipe buffer size */
+#define	M66592_BUF_SIZE(x)	((((x) / 64) - 1) << 10)
+#define	M66592_BUFNMB		0x00FF	/* b7-0: Pipe buffer number */
+
+#define M66592_PIPEMAXP		0x6A
+#define	M66592_MXPS		0x07FF	/* b10-0: Maxpacket size */
+
+#define M66592_PIPEPERI		0x6C
+#define	M66592_IFIS		0x1000	/* b12: Isochronous in-buffer flush mode select */
+#define	M66592_IITV		0x0007	/* b2-0: Isochronous interval */
+
+#define M66592_PIPE1CTR		0x70
+#define M66592_PIPE2CTR		0x72
+#define M66592_PIPE3CTR		0x74
+#define M66592_PIPE4CTR		0x76
+#define M66592_PIPE5CTR		0x78
+#define M66592_PIPE6CTR		0x7A
+#define M66592_PIPE7CTR		0x7C
+#define	M66592_BSTS		0x8000	/* b15: Buffer status */
+#define	M66592_INBUFM		0x4000	/* b14: IN buffer monitor (Only for PIPE1 to 5) */
+#define	M66592_ACLRM		0x0200	/* b9: Out buffer auto clear mode */
+#define	M66592_SQCLR		0x0100	/* b8: Sequence toggle bit clear */
+#define	M66592_SQSET		0x0080	/* b7: Sequence toggle bit set */
+#define	M66592_SQMON		0x0040	/* b6: Sequence toggle bit monitor */
+#define	M66592_PID		0x0003	/* b1-0: Response PID */
+
+#define M66592_INVALID_REG	0x7E
+
+
+#define __iomem
+
+#define get_pipectr_addr(pipenum)	(M66592_PIPE1CTR + (pipenum - 1) * 2)
+
+#define M66592_MAX_SAMPLING	10
+
+#define M66592_MAX_NUM_PIPE	8
+#define M66592_MAX_NUM_BULK	3
+#define M66592_MAX_NUM_ISOC	2
+#define M66592_MAX_NUM_INT	2
+
+#define M66592_BASE_PIPENUM_BULK	3
+#define M66592_BASE_PIPENUM_ISOC	1
+#define M66592_BASE_PIPENUM_INT		6
+
+#define M66592_BASE_BUFNUM	6
+#define M66592_MAX_BUFNUM	0x4F
+
+struct m66592_pipe_info {
+	u16	pipe;
+	u16	epnum;
+	u16	maxpacket;
+	u16	type;
+	u16	interval;
+	u16	dir_in;
+};
+
+struct m66592_request {
+	struct usb_request	req;
+	struct list_head	queue;
+};
+
+struct m66592_ep {
+	struct usb_ep		ep;
+	struct m66592		*m66592;
+
+	struct list_head	queue;
+	unsigned 		busy:1;
+	unsigned		internal_ccpl:1;	/* use only control */
+
+	/* this member can able to after m66592_enable */
+	unsigned		use_dma:1;
+	u16			pipenum;
+	u16			type;
+	const struct usb_endpoint_descriptor	*desc;
+	/* register address */
+	unsigned long		fifoaddr;
+	unsigned long		fifosel;
+	unsigned long		fifoctr;
+	unsigned long		fifotrn;
+	unsigned long		pipectr;
+};
+
+struct m66592 {
+	spinlock_t		lock;
+	void __iomem		*reg;
+
+	struct usb_gadget		gadget;
+	struct usb_gadget_driver	*driver;
+
+	struct m66592_ep	ep[M66592_MAX_NUM_PIPE];
+	struct m66592_ep	*pipenum2ep[M66592_MAX_NUM_PIPE];
+	struct m66592_ep	*epaddr2ep[16];
+
+	struct usb_request	*ep0_req;	/* for internal request */
+	u16			*ep0_buf;	/* for internal request */
+
+	struct timer_list	timer;
+
+	u16			old_vbus;
+	int			scount;
+
+	int			old_dvsq;
+
+	/* pipe config */
+	int bulk;
+	int interrupt;
+	int isochronous;
+	int num_dma;
+	int bi_bufnum;	/* bulk and isochronous's bufnum */
+};
+
+#define gadget_to_m66592(_gadget) container_of(_gadget, struct m66592, gadget)
+#define m66592_to_gadget(m66592) (&m66592->gadget)
+
+#define is_bulk_pipe(pipenum)	\
+	((pipenum >= M66592_BASE_PIPENUM_BULK) && \
+	 (pipenum < (M66592_BASE_PIPENUM_BULK + M66592_MAX_NUM_BULK)))
+#define is_interrupt_pipe(pipenum)	\
+	((pipenum >= M66592_BASE_PIPENUM_INT) && \
+	 (pipenum < (M66592_BASE_PIPENUM_INT + M66592_MAX_NUM_INT)))
+#define is_isoc_pipe(pipenum)	\
+	((pipenum >= M66592_BASE_PIPENUM_ISOC) && \
+	 (pipenum < (M66592_BASE_PIPENUM_ISOC + M66592_MAX_NUM_ISOC)))
+
+#define enable_irq_ready(m66592, pipenum)	\
+	enable_pipe_irq(m66592, pipenum, M66592_BRDYENB)
+#define disable_irq_ready(m66592, pipenum)	\
+	disable_pipe_irq(m66592, pipenum, M66592_BRDYENB)
+#define enable_irq_empty(m66592, pipenum)	\
+	enable_pipe_irq(m66592, pipenum, M66592_BEMPENB)
+#define disable_irq_empty(m66592, pipenum)	\
+	disable_pipe_irq(m66592, pipenum, M66592_BEMPENB)
+#define enable_irq_nrdy(m66592, pipenum)	\
+	enable_pipe_irq(m66592, pipenum, M66592_NRDYENB)
+#define disable_irq_nrdy(m66592, pipenum)	\
+	disable_pipe_irq(m66592, pipenum, M66592_NRDYENB)
+
+/*-------------------------------------------------------------------------*/
+static inline u16 m66592_read(struct m66592 *m66592, unsigned long offset)
+{
+	return inw((unsigned long)m66592->reg + offset);
+}
+
+static inline void m66592_read_fifo(struct m66592 *m66592,
+				    unsigned long offset,
+				    void *buf, unsigned long len)
+{
+	unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
+
+	len = (len + 1) / 2;
+	insw(fifoaddr, buf, len);
+}
+
+static inline void m66592_write(struct m66592 *m66592, u16 val,
+				unsigned long offset)
+{
+	outw(val, (unsigned long)m66592->reg + offset);
+}
+
+static inline void m66592_write_fifo(struct m66592 *m66592,
+				     unsigned long offset,
+				     void *buf, unsigned long len)
+{
+	unsigned long fifoaddr = (unsigned long)m66592->reg + offset;
+	unsigned long odd = len & 0x0001;
+
+	len = len / 2;
+	outsw(fifoaddr, buf, len);
+	if (odd) {
+		unsigned char *p = buf + len*2;
+		outb(*p, fifoaddr);
+	}
+}
+
+static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
+			       unsigned long offset)
+{
+	u16 tmp;
+	tmp = m66592_read(m66592, offset);
+	tmp = tmp & (~pat);
+	tmp = tmp | val;
+	m66592_write(m66592, tmp, offset);
+}
+
+#define m66592_bclr(m66592, val, offset)	\
+			m66592_mdfy(m66592, 0, val, offset)
+#define m66592_bset(m66592, val, offset)	\
+			m66592_mdfy(m66592, val, 0, offset)
+
+#endif	/* ifndef __M66592_UDC_H__ */
+
+

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

@@ -450,100 +450,6 @@ net2280_free_request (struct usb_ep *_ep, struct usb_request *_req)
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-/*
- * dma-coherent memory allocation (for dma-capable endpoints)
- *
- * NOTE: the dma_*_coherent() API calls suck.  Most implementations are
- * (a) page-oriented, so small buffers lose big; and (b) asymmetric with
- * respect to calls with irqs disabled:  alloc is safe, free is not.
- * We currently work around (b), but not (a).
- */
-
-static void *
-net2280_alloc_buffer (
-	struct usb_ep		*_ep,
-	unsigned		bytes,
-	dma_addr_t		*dma,
-	gfp_t			gfp_flags
-)
-{
-	void			*retval;
-	struct net2280_ep	*ep;
-
-	ep = container_of (_ep, struct net2280_ep, ep);
-	if (!_ep)
-		return NULL;
-	*dma = DMA_ADDR_INVALID;
-
-	if (ep->dma)
-		retval = dma_alloc_coherent(&ep->dev->pdev->dev,
-				bytes, dma, gfp_flags);
-	else
-		retval = kmalloc(bytes, gfp_flags);
-	return retval;
-}
-
-static DEFINE_SPINLOCK(buflock);
-static LIST_HEAD(buffers);
-
-struct free_record {
-	struct list_head	list;
-	struct device		*dev;
-	unsigned		bytes;
-	dma_addr_t		dma;
-};
-
-static void do_free(unsigned long ignored)
-{
-	spin_lock_irq(&buflock);
-	while (!list_empty(&buffers)) {
-		struct free_record	*buf;
-
-		buf = list_entry(buffers.next, struct free_record, list);
-		list_del(&buf->list);
-		spin_unlock_irq(&buflock);
-
-		dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma);
-
-		spin_lock_irq(&buflock);
-	}
-	spin_unlock_irq(&buflock);
-}
-
-static DECLARE_TASKLET(deferred_free, do_free, 0);
-
-static void
-net2280_free_buffer (
-	struct usb_ep *_ep,
-	void *address,
-	dma_addr_t dma,
-	unsigned bytes
-) {
-	/* free memory into the right allocator */
-	if (dma != DMA_ADDR_INVALID) {
-		struct net2280_ep	*ep;
-		struct free_record	*buf = address;
-		unsigned long		flags;
-
-		ep = container_of(_ep, struct net2280_ep, ep);
-		if (!_ep)
-			return;
-
-		ep = container_of (_ep, struct net2280_ep, ep);
-		buf->dev = &ep->dev->pdev->dev;
-		buf->bytes = bytes;
-		buf->dma = dma;
-
-		spin_lock_irqsave(&buflock, flags);
-		list_add_tail(&buf->list, &buffers);
-		tasklet_schedule(&deferred_free);
-		spin_unlock_irqrestore(&buflock, flags);
-	} else
-		kfree (address);
-}
-
-/*-------------------------------------------------------------------------*/
-
 /* load a packet into the fifo we use for usb IN transfers.
 /* load a packet into the fifo we use for usb IN transfers.
  * works for all endpoints.
  * works for all endpoints.
  *
  *
@@ -1392,9 +1298,6 @@ static const struct usb_ep_ops net2280_ep_ops = {
 	.alloc_request	= net2280_alloc_request,
 	.alloc_request	= net2280_alloc_request,
 	.free_request	= net2280_free_request,
 	.free_request	= net2280_free_request,
 
 
-	.alloc_buffer	= net2280_alloc_buffer,
-	.free_buffer	= net2280_free_buffer,
-
 	.queue		= net2280_queue,
 	.queue		= net2280_queue,
 	.dequeue	= net2280_dequeue,
 	.dequeue	= net2280_dequeue,
 
 

+ 0 - 108
drivers/usb/gadget/omap_udc.c

@@ -296,111 +296,6 @@ omap_free_request(struct usb_ep *ep, struct usb_request *_req)
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-/*
- * dma-coherent memory allocation (for dma-capable endpoints)
- *
- * NOTE: the dma_*_coherent() API calls suck.  Most implementations are
- * (a) page-oriented, so small buffers lose big; and (b) asymmetric with
- * respect to calls with irqs disabled:  alloc is safe, free is not.
- * We currently work around (b), but not (a).
- */
-
-static void *
-omap_alloc_buffer(
-	struct usb_ep	*_ep,
-	unsigned	bytes,
-	dma_addr_t	*dma,
-	gfp_t		gfp_flags
-)
-{
-	void		*retval;
-	struct omap_ep	*ep;
-
-	if (!_ep)
-		return NULL;
-
-	ep = container_of(_ep, struct omap_ep, ep);
-	if (use_dma && ep->has_dma) {
-		static int	warned;
-		if (!warned && bytes < PAGE_SIZE) {
-			dev_warn(ep->udc->gadget.dev.parent,
-				"using dma_alloc_coherent for "
-				"small allocations wastes memory\n");
-			warned++;
-		}
-		return dma_alloc_coherent(ep->udc->gadget.dev.parent,
-				bytes, dma, gfp_flags);
-	}
-
-	retval = kmalloc(bytes, gfp_flags);
-	if (retval)
-		*dma = virt_to_phys(retval);
-	return retval;
-}
-
-static DEFINE_SPINLOCK(buflock);
-static LIST_HEAD(buffers);
-
-struct free_record {
-	struct list_head	list;
-	struct device		*dev;
-	unsigned		bytes;
-	dma_addr_t		dma;
-};
-
-static void do_free(unsigned long ignored)
-{
-	spin_lock_irq(&buflock);
-	while (!list_empty(&buffers)) {
-		struct free_record	*buf;
-
-		buf = list_entry(buffers.next, struct free_record, list);
-		list_del(&buf->list);
-		spin_unlock_irq(&buflock);
-
-		dma_free_coherent(buf->dev, buf->bytes, buf, buf->dma);
-
-		spin_lock_irq(&buflock);
-	}
-	spin_unlock_irq(&buflock);
-}
-
-static DECLARE_TASKLET(deferred_free, do_free, 0);
-
-static void omap_free_buffer(
-	struct usb_ep	*_ep,
-	void		*buf,
-	dma_addr_t	dma,
-	unsigned	bytes
-)
-{
-	if (!_ep) {
-		WARN_ON(1);
-		return;
-	}
-
-	/* free memory into the right allocator */
-	if (dma != DMA_ADDR_INVALID) {
-		struct omap_ep		*ep;
-		struct free_record	*rec = buf;
-		unsigned long		flags;
-
-		ep = container_of(_ep, struct omap_ep, ep);
-
-		rec->dev = ep->udc->gadget.dev.parent;
-		rec->bytes = bytes;
-		rec->dma = dma;
-
-		spin_lock_irqsave(&buflock, flags);
-		list_add_tail(&rec->list, &buffers);
-		tasklet_schedule(&deferred_free);
-		spin_unlock_irqrestore(&buflock, flags);
-	} else
-		kfree(buf);
-}
-
-/*-------------------------------------------------------------------------*/
-
 static void
 static void
 done(struct omap_ep *ep, struct omap_req *req, int status)
 done(struct omap_ep *ep, struct omap_req *req, int status)
 {
 {
@@ -1271,9 +1166,6 @@ static struct usb_ep_ops omap_ep_ops = {
 	.alloc_request	= omap_alloc_request,
 	.alloc_request	= omap_alloc_request,
 	.free_request	= omap_free_request,
 	.free_request	= omap_free_request,
 
 
-	.alloc_buffer	= omap_alloc_buffer,
-	.free_buffer	= omap_free_buffer,
-
 	.queue		= omap_ep_queue,
 	.queue		= omap_ep_queue,
 	.dequeue	= omap_ep_dequeue,
 	.dequeue	= omap_ep_dequeue,
 
 

+ 72 - 401
drivers/usb/gadget/pxa2xx_udc.c

@@ -24,9 +24,9 @@
  *
  *
  */
  */
 
 
-#undef	DEBUG
 // #define	VERBOSE	DBG_VERBOSE
 // #define	VERBOSE	DBG_VERBOSE
 
 
+#include <linux/device.h>
 #include <linux/module.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/ioport.h>
 #include <linux/ioport.h>
@@ -46,19 +46,17 @@
 
 
 #include <asm/byteorder.h>
 #include <asm/byteorder.h>
 #include <asm/dma.h>
 #include <asm/dma.h>
+#include <asm/gpio.h>
 #include <asm/io.h>
 #include <asm/io.h>
 #include <asm/system.h>
 #include <asm/system.h>
 #include <asm/mach-types.h>
 #include <asm/mach-types.h>
 #include <asm/unaligned.h>
 #include <asm/unaligned.h>
 #include <asm/hardware.h>
 #include <asm/hardware.h>
-#ifdef CONFIG_ARCH_PXA
-#include <asm/arch/pxa-regs.h>
-#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/mach/udc_pxa2xx.h>
 
 
 
 
 /*
 /*
@@ -76,9 +74,17 @@
  * it constrains the sorts of USB configuration change events that work.
  * it constrains the sorts of USB configuration change events that work.
  * The errata for these chips are misleading; some "fixed" bugs from
  * The errata for these chips are misleading; some "fixed" bugs from
  * pxa250 a0/a1 b0/b1/b2 sure act like they're still there.
  * pxa250 a0/a1 b0/b1/b2 sure act like they're still there.
+ *
+ * Note that the UDC hardware supports DMA (except on IXP) but that's
+ * not used here.  IN-DMA (to host) is simple enough, when the data is
+ * suitably aligned (16 bytes) ... the network stack doesn't do that,
+ * other software can.  OUT-DMA is buggy in most chip versions, as well
+ * as poorly designed (data toggle not automatic).  So this driver won't
+ * bother using DMA.  (Mostly-working IN-DMA support was available in
+ * kernels before 2.6.23, but was never enabled or well tested.)
  */
  */
 
 
-#define	DRIVER_VERSION	"4-May-2005"
+#define	DRIVER_VERSION	"30-June-2007"
 #define	DRIVER_DESC	"PXA 25x USB Device Controller driver"
 #define	DRIVER_DESC	"PXA 25x USB Device Controller driver"
 
 
 
 
@@ -87,12 +93,9 @@ static const char driver_name [] = "pxa2xx_udc";
 static const char ep0name [] = "ep0";
 static const char ep0name [] = "ep0";
 
 
 
 
-// #define	USE_DMA
-// #define	USE_OUT_DMA
 // #define	DISABLE_TEST_MODE
 // #define	DISABLE_TEST_MODE
 
 
 #ifdef CONFIG_ARCH_IXP4XX
 #ifdef CONFIG_ARCH_IXP4XX
-#undef USE_DMA
 
 
 /* cpu-specific register addresses are compiled in to this code */
 /* cpu-specific register addresses are compiled in to this code */
 #ifdef CONFIG_ARCH_PXA
 #ifdef CONFIG_ARCH_PXA
@@ -104,25 +107,6 @@ static const char ep0name [] = "ep0";
 #include "pxa2xx_udc.h"
 #include "pxa2xx_udc.h"
 
 
 
 
-#ifdef	USE_DMA
-static int use_dma = 1;
-module_param(use_dma, bool, 0);
-MODULE_PARM_DESC (use_dma, "true to use dma");
-
-static void dma_nodesc_handler (int dmach, void *_ep);
-static void kick_dma(struct pxa2xx_ep *ep, struct pxa2xx_request *req);
-
-#ifdef USE_OUT_DMA
-#define	DMASTR " (dma support)"
-#else
-#define	DMASTR " (dma in)"
-#endif
-
-#else	/* !USE_DMA */
-#define	DMASTR " (pio only)"
-#undef	USE_OUT_DMA
-#endif
-
 #ifdef	CONFIG_USB_PXA2XX_SMALL
 #ifdef	CONFIG_USB_PXA2XX_SMALL
 #define SIZE_STR	" (small)"
 #define SIZE_STR	" (small)"
 #else
 #else
@@ -155,7 +139,7 @@ static int is_vbus_present(void)
 	struct pxa2xx_udc_mach_info		*mach = the_controller->mach;
 	struct pxa2xx_udc_mach_info		*mach = the_controller->mach;
 
 
 	if (mach->gpio_vbus)
 	if (mach->gpio_vbus)
-		return udc_gpio_get(mach->gpio_vbus);
+		return gpio_get_value(mach->gpio_vbus);
 	if (mach->udc_is_connected)
 	if (mach->udc_is_connected)
 		return mach->udc_is_connected();
 		return mach->udc_is_connected();
 	return 1;
 	return 1;
@@ -167,7 +151,7 @@ static void pullup_off(void)
 	struct pxa2xx_udc_mach_info		*mach = the_controller->mach;
 	struct pxa2xx_udc_mach_info		*mach = the_controller->mach;
 
 
 	if (mach->gpio_pullup)
 	if (mach->gpio_pullup)
-		udc_gpio_set(mach->gpio_pullup, 0);
+		gpio_set_value(mach->gpio_pullup, 0);
 	else if (mach->udc_command)
 	else if (mach->udc_command)
 		mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
 		mach->udc_command(PXA2XX_UDC_CMD_DISCONNECT);
 }
 }
@@ -177,7 +161,7 @@ static void pullup_on(void)
 	struct pxa2xx_udc_mach_info		*mach = the_controller->mach;
 	struct pxa2xx_udc_mach_info		*mach = the_controller->mach;
 
 
 	if (mach->gpio_pullup)
 	if (mach->gpio_pullup)
-		udc_gpio_set(mach->gpio_pullup, 1);
+		gpio_set_value(mach->gpio_pullup, 1);
 	else if (mach->udc_command)
 	else if (mach->udc_command)
 		mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
 		mach->udc_command(PXA2XX_UDC_CMD_CONNECT);
 }
 }
@@ -281,9 +265,8 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
 	}
 	}
 
 
 	ep->desc = desc;
 	ep->desc = desc;
-	ep->dma = -1;
 	ep->stopped = 0;
 	ep->stopped = 0;
-	ep->pio_irqs = ep->dma_irqs = 0;
+	ep->pio_irqs = 0;
 	ep->ep.maxpacket = le16_to_cpu (desc->wMaxPacketSize);
 	ep->ep.maxpacket = le16_to_cpu (desc->wMaxPacketSize);
 
 
 	/* flush fifo (mostly for OUT buffers) */
 	/* flush fifo (mostly for OUT buffers) */
@@ -291,30 +274,6 @@ static int pxa2xx_ep_enable (struct usb_ep *_ep,
 
 
 	/* ... reset halt state too, if we could ... */
 	/* ... reset halt state too, if we could ... */
 
 
-#ifdef	USE_DMA
-	/* for (some) bulk and ISO endpoints, try to get a DMA channel and
-	 * bind it to the endpoint.  otherwise use PIO.
-	 */
-	switch (ep->bmAttributes) {
-	case USB_ENDPOINT_XFER_ISOC:
-		if (le16_to_cpu(desc->wMaxPacketSize) % 32)
-			break;
-		// fall through
-	case USB_ENDPOINT_XFER_BULK:
-		if (!use_dma || !ep->reg_drcmr)
-			break;
-		ep->dma = pxa_request_dma ((char *)_ep->name,
-				(le16_to_cpu (desc->wMaxPacketSize) > 64)
-					? DMA_PRIO_MEDIUM /* some iso */
-					: DMA_PRIO_LOW,
-				dma_nodesc_handler, ep);
-		if (ep->dma >= 0) {
-			*ep->reg_drcmr = DRCMR_MAPVLD | ep->dma;
-			DMSG("%s using dma%d\n", _ep->name, ep->dma);
-		}
-	}
-#endif
-
 	DBG(DBG_VERBOSE, "enabled %s\n", _ep->name);
 	DBG(DBG_VERBOSE, "enabled %s\n", _ep->name);
 	return 0;
 	return 0;
 }
 }
@@ -334,14 +293,6 @@ static int pxa2xx_ep_disable (struct usb_ep *_ep)
 
 
 	nuke (ep, -ESHUTDOWN);
 	nuke (ep, -ESHUTDOWN);
 
 
-#ifdef	USE_DMA
-	if (ep->dma >= 0) {
-		*ep->reg_drcmr = 0;
-		pxa_free_dma (ep->dma);
-		ep->dma = -1;
-	}
-#endif
-
 	/* flush fifo (mostly for IN buffers) */
 	/* flush fifo (mostly for IN buffers) */
 	pxa2xx_ep_fifo_flush (_ep);
 	pxa2xx_ep_fifo_flush (_ep);
 
 
@@ -390,35 +341,6 @@ pxa2xx_ep_free_request (struct usb_ep *_ep, struct usb_request *_req)
 	kfree(req);
 	kfree(req);
 }
 }
 
 
-
-/* PXA cache needs flushing with DMA I/O (it's dma-incoherent), but there's
- * no device-affinity and the heap works perfectly well for i/o buffers.
- * It wastes much less memory than dma_alloc_coherent() would, and even
- * prevents cacheline (32 bytes wide) sharing problems.
- */
-static void *
-pxa2xx_ep_alloc_buffer(struct usb_ep *_ep, unsigned bytes,
-	dma_addr_t *dma, gfp_t gfp_flags)
-{
-	char			*retval;
-
-	retval = kmalloc (bytes, gfp_flags & ~(__GFP_DMA|__GFP_HIGHMEM));
-	if (retval)
-#ifdef	USE_DMA
-		*dma = virt_to_bus (retval);
-#else
-		*dma = (dma_addr_t)~0;
-#endif
-	return retval;
-}
-
-static void
-pxa2xx_ep_free_buffer(struct usb_ep *_ep, void *buf, dma_addr_t dma,
-		unsigned bytes)
-{
-	kfree (buf);
-}
-
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 /*
 /*
@@ -518,18 +440,8 @@ write_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req)
 		/* requests complete when all IN data is in the FIFO */
 		/* requests complete when all IN data is in the FIFO */
 		if (is_last) {
 		if (is_last) {
 			done (ep, req, 0);
 			done (ep, req, 0);
-			if (list_empty(&ep->queue) || unlikely(ep->dma >= 0)) {
+			if (list_empty(&ep->queue))
 				pio_irq_disable (ep->bEndpointAddress);
 				pio_irq_disable (ep->bEndpointAddress);
-#ifdef USE_DMA
-				/* unaligned data and zlps couldn't use dma */
-				if (unlikely(!list_empty(&ep->queue))) {
-					req = list_entry(ep->queue.next,
-						struct pxa2xx_request, queue);
-					kick_dma(ep,req);
-					return 0;
-				}
-#endif
-			}
 			return 1;
 			return 1;
 		}
 		}
 
 
@@ -728,182 +640,6 @@ read_ep0_fifo (struct pxa2xx_ep *ep, struct pxa2xx_request *req)
 	return 0;
 	return 0;
 }
 }
 
 
-#ifdef	USE_DMA
-
-#define	MAX_IN_DMA	((DCMD_LENGTH + 1) - BULK_FIFO_SIZE)
-
-static void
-start_dma_nodesc(struct pxa2xx_ep *ep, struct pxa2xx_request *req, int is_in)
-{
-	u32	dcmd = req->req.length;
-	u32	buf = req->req.dma;
-	u32	fifo = io_v2p ((u32)ep->reg_uddr);
-
-	/* caller guarantees there's a packet or more remaining
-	 *  - IN may end with a short packet (TSP set separately),
-	 *  - OUT is always full length
-	 */
-	buf += req->req.actual;
-	dcmd -= req->req.actual;
-	ep->dma_fixup = 0;
-
-	/* no-descriptor mode can be simple for bulk-in, iso-in, iso-out */
-	DCSR(ep->dma) = DCSR_NODESC;
-	if (is_in) {
-		DSADR(ep->dma) = buf;
-		DTADR(ep->dma) = fifo;
-		if (dcmd > MAX_IN_DMA)
-			dcmd = MAX_IN_DMA;
-		else
-			ep->dma_fixup = (dcmd % ep->ep.maxpacket) != 0;
-		dcmd |= DCMD_BURST32 | DCMD_WIDTH1
-			| DCMD_FLOWTRG | DCMD_INCSRCADDR;
-	} else {
-#ifdef USE_OUT_DMA
-		DSADR(ep->dma) = fifo;
-		DTADR(ep->dma) = buf;
-		if (ep->bmAttributes != USB_ENDPOINT_XFER_ISOC)
-			dcmd = ep->ep.maxpacket;
-		dcmd |= DCMD_BURST32 | DCMD_WIDTH1
-			| DCMD_FLOWSRC | DCMD_INCTRGADDR;
-#endif
-	}
-	DCMD(ep->dma) = dcmd;
-	DCSR(ep->dma) = DCSR_RUN | DCSR_NODESC
-		| (unlikely(is_in)
-			? DCSR_STOPIRQEN	/* use dma_nodesc_handler() */
-			: 0);			/* use handle_ep() */
-}
-
-static void kick_dma(struct pxa2xx_ep *ep, struct pxa2xx_request *req)
-{
-	int	is_in = ep->bEndpointAddress & USB_DIR_IN;
-
-	if (is_in) {
-		/* unaligned tx buffers and zlps only work with PIO */
-		if ((req->req.dma & 0x0f) != 0
-				|| unlikely((req->req.length - req->req.actual)
-						== 0)) {
-			pio_irq_enable(ep->bEndpointAddress);
-			if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0)
-				(void) write_fifo(ep, req);
-		} else {
-			start_dma_nodesc(ep, req, USB_DIR_IN);
-		}
-	} else {
-		if ((req->req.length - req->req.actual) < ep->ep.maxpacket) {
-			DMSG("%s short dma read...\n", ep->ep.name);
-			/* we're always set up for pio out */
-			read_fifo (ep, req);
-		} else {
-			*ep->reg_udccs = UDCCS_BO_DME
-				| (*ep->reg_udccs & UDCCS_BO_FST);
-			start_dma_nodesc(ep, req, USB_DIR_OUT);
-		}
-	}
-}
-
-static void cancel_dma(struct pxa2xx_ep *ep)
-{
-	struct pxa2xx_request	*req;
-	u32			tmp;
-
-	if (DCSR(ep->dma) == 0 || list_empty(&ep->queue))
-		return;
-
-	DCSR(ep->dma) = 0;
-	while ((DCSR(ep->dma) & DCSR_STOPSTATE) == 0)
-		cpu_relax();
-
-	req = list_entry(ep->queue.next, struct pxa2xx_request, queue);
-	tmp = DCMD(ep->dma) & DCMD_LENGTH;
-	req->req.actual = req->req.length - (tmp & DCMD_LENGTH);
-
-	/* the last tx packet may be incomplete, so flush the fifo.
-	 * FIXME correct req.actual if we can
-	 */
-	if (ep->bEndpointAddress & USB_DIR_IN)
-		*ep->reg_udccs = UDCCS_BI_FTF;
-}
-
-/* dma channel stopped ... normal tx end (IN), or on error (IN/OUT) */
-static void dma_nodesc_handler(int dmach, void *_ep)
-{
-	struct pxa2xx_ep	*ep = _ep;
-	struct pxa2xx_request	*req;
-	u32			tmp, completed;
-
-	local_irq_disable();
-
-	req = list_entry(ep->queue.next, struct pxa2xx_request, queue);
-
-	ep->dma_irqs++;
-	ep->dev->stats.irqs++;
-	HEX_DISPLAY(ep->dev->stats.irqs);
-
-	/* ack/clear */
-	tmp = DCSR(ep->dma);
-	DCSR(ep->dma) = tmp;
-	if ((tmp & DCSR_STOPSTATE) == 0
-			|| (DDADR(ep->dma) & DDADR_STOP) != 0) {
-		DBG(DBG_VERBOSE, "%s, dcsr %08x ddadr %08x\n",
-			ep->ep.name, DCSR(ep->dma), DDADR(ep->dma));
-		goto done;
-	}
-	DCSR(ep->dma) = 0;	/* clear DCSR_STOPSTATE */
-
-	/* update transfer status */
-	completed = tmp & DCSR_BUSERR;
-	if (ep->bEndpointAddress & USB_DIR_IN)
-		tmp = DSADR(ep->dma);
-	else
-		tmp = DTADR(ep->dma);
-	req->req.actual = tmp - req->req.dma;
-
-	/* FIXME seems we sometimes see partial transfers... */
-
-	if (unlikely(completed != 0))
-		req->req.status = -EIO;
-	else if (req->req.actual) {
-		/* these registers have zeroes in low bits; they miscount
-		 * some (end-of-transfer) short packets:  tx 14 as tx 12
-		 */
-		if (ep->dma_fixup)
-			req->req.actual = min(req->req.actual + 3,
-						req->req.length);
-
-		tmp = (req->req.length - req->req.actual);
-		completed = (tmp == 0);
-		if (completed && (ep->bEndpointAddress & USB_DIR_IN)) {
-
-			/* maybe validate final short packet ... */
-			if ((req->req.actual % ep->ep.maxpacket) != 0)
-				*ep->reg_udccs = UDCCS_BI_TSP/*|UDCCS_BI_TPC*/;
-
-			/* ... or zlp, using pio fallback */
-			else if (ep->bmAttributes == USB_ENDPOINT_XFER_BULK
-					&& req->req.zero) {
-				DMSG("%s zlp terminate ...\n", ep->ep.name);
-				completed = 0;
-			}
-		}
-	}
-
-	if (likely(completed)) {
-		done(ep, req, 0);
-
-		/* maybe re-activate after completion */
-		if (ep->stopped || list_empty(&ep->queue))
-			goto done;
-		req = list_entry(ep->queue.next, struct pxa2xx_request, queue);
-	}
-	kick_dma(ep, req);
-done:
-	local_irq_enable();
-}
-
-#endif
-
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 static int
 static int
@@ -942,19 +678,8 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 						(ep->desc->wMaxPacketSize)))
 						(ep->desc->wMaxPacketSize)))
 		return -EMSGSIZE;
 		return -EMSGSIZE;
 
 
-#ifdef	USE_DMA
-	// FIXME caller may already have done the dma mapping
-	if (ep->dma >= 0) {
-		_req->dma = dma_map_single(dev->dev,
-			_req->buf, _req->length,
-			((ep->bEndpointAddress & USB_DIR_IN) != 0)
-				? DMA_TO_DEVICE
-				: DMA_FROM_DEVICE);
-	}
-#endif
-
 	DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n",
 	DBG(DBG_NOISY, "%s queue req %p, len %d buf %p\n",
-	     _ep->name, _req, _req->length, _req->buf);
+		_ep->name, _req, _req->length, _req->buf);
 
 
 	local_irq_save(flags);
 	local_irq_save(flags);
 
 
@@ -1002,11 +727,6 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 				local_irq_restore (flags);
 				local_irq_restore (flags);
 				return -EL2HLT;
 				return -EL2HLT;
 			}
 			}
-#ifdef	USE_DMA
-		/* either start dma or prime pio pump */
-		} else if (ep->dma >= 0) {
-			kick_dma(ep, req);
-#endif
 		/* can the FIFO can satisfy the request immediately? */
 		/* can the FIFO can satisfy the request immediately? */
 		} else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) {
 		} else if ((ep->bEndpointAddress & USB_DIR_IN) != 0) {
 			if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0
 			if ((*ep->reg_udccs & UDCCS_BI_TFS) != 0
@@ -1017,7 +737,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
 			req = NULL;
 			req = NULL;
 		}
 		}
 
 
-		if (likely (req && ep->desc) && ep->dma < 0)
+		if (likely (req && ep->desc))
 			pio_irq_enable(ep->bEndpointAddress);
 			pio_irq_enable(ep->bEndpointAddress);
 	}
 	}
 
 
@@ -1038,10 +758,6 @@ static void nuke(struct pxa2xx_ep *ep, int status)
 	struct pxa2xx_request *req;
 	struct pxa2xx_request *req;
 
 
 	/* called with irqs blocked */
 	/* called with irqs blocked */
-#ifdef	USE_DMA
-	if (ep->dma >= 0 && !ep->stopped)
-		cancel_dma(ep);
-#endif
 	while (!list_empty(&ep->queue)) {
 	while (!list_empty(&ep->queue)) {
 		req = list_entry(ep->queue.next,
 		req = list_entry(ep->queue.next,
 				struct pxa2xx_request,
 				struct pxa2xx_request,
@@ -1076,19 +792,7 @@ static int pxa2xx_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 
 
-#ifdef	USE_DMA
-	if (ep->dma >= 0 && ep->queue.next == &req->queue && !ep->stopped) {
-		cancel_dma(ep);
-		done(ep, req, -ECONNRESET);
-		/* restart i/o */
-		if (!list_empty(&ep->queue)) {
-			req = list_entry(ep->queue.next,
-					struct pxa2xx_request, queue);
-			kick_dma(ep, req);
-		}
-	} else
-#endif
-		done(ep, req, -ECONNRESET);
+	done(ep, req, -ECONNRESET);
 
 
 	local_irq_restore(flags);
 	local_irq_restore(flags);
 	return 0;
 	return 0;
@@ -1203,9 +907,6 @@ static struct usb_ep_ops pxa2xx_ep_ops = {
 	.alloc_request	= pxa2xx_ep_alloc_request,
 	.alloc_request	= pxa2xx_ep_alloc_request,
 	.free_request	= pxa2xx_ep_free_request,
 	.free_request	= pxa2xx_ep_free_request,
 
 
-	.alloc_buffer	= pxa2xx_ep_alloc_buffer,
-	.free_buffer	= pxa2xx_ep_free_buffer,
-
 	.queue		= pxa2xx_ep_queue,
 	.queue		= pxa2xx_ep_queue,
 	.dequeue	= pxa2xx_ep_dequeue,
 	.dequeue	= pxa2xx_ep_dequeue,
 
 
@@ -1325,7 +1026,7 @@ udc_proc_read(char *page, char **start, off_t off, int count,
 	/* basic device status */
 	/* basic device status */
 	t = scnprintf(next, size, DRIVER_DESC "\n"
 	t = scnprintf(next, size, DRIVER_DESC "\n"
 		"%s version: %s\nGadget driver: %s\nHost %s\n\n",
 		"%s version: %s\nGadget driver: %s\nHost %s\n\n",
-		driver_name, DRIVER_VERSION SIZE_STR DMASTR,
+		driver_name, DRIVER_VERSION SIZE_STR "(pio)",
 		dev->driver ? dev->driver->driver.name : "(none)",
 		dev->driver ? dev->driver->driver.name : "(none)",
 		is_vbus_present() ? "full speed" : "disconnected");
 		is_vbus_present() ? "full speed" : "disconnected");
 	size -= t;
 	size -= t;
@@ -1390,7 +1091,6 @@ udc_proc_read(char *page, char **start, off_t off, int count,
 	for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {
 	for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {
 		struct pxa2xx_ep	*ep = &dev->ep [i];
 		struct pxa2xx_ep	*ep = &dev->ep [i];
 		struct pxa2xx_request	*req;
 		struct pxa2xx_request	*req;
-		int			t;
 
 
 		if (i != 0) {
 		if (i != 0) {
 			const struct usb_endpoint_descriptor	*d;
 			const struct usb_endpoint_descriptor	*d;
@@ -1400,10 +1100,9 @@ udc_proc_read(char *page, char **start, off_t off, int count,
 				continue;
 				continue;
 			tmp = *dev->ep [i].reg_udccs;
 			tmp = *dev->ep [i].reg_udccs;
 			t = scnprintf(next, size,
 			t = scnprintf(next, size,
-				"%s max %d %s udccs %02x irqs %lu/%lu\n",
+				"%s max %d %s udccs %02x irqs %lu\n",
 				ep->ep.name, le16_to_cpu (d->wMaxPacketSize),
 				ep->ep.name, le16_to_cpu (d->wMaxPacketSize),
-				(ep->dma >= 0) ? "dma" : "pio", tmp,
-				ep->pio_irqs, ep->dma_irqs);
+				"pio", tmp, ep->pio_irqs);
 			/* TODO translate all five groups of udccs bits! */
 			/* TODO translate all five groups of udccs bits! */
 
 
 		} else /* ep0 should only have one transfer queued */
 		} else /* ep0 should only have one transfer queued */
@@ -1423,19 +1122,7 @@ udc_proc_read(char *page, char **start, off_t off, int count,
 			continue;
 			continue;
 		}
 		}
 		list_for_each_entry(req, &ep->queue, queue) {
 		list_for_each_entry(req, &ep->queue, queue) {
-#ifdef	USE_DMA
-			if (ep->dma >= 0 && req->queue.prev == &ep->queue)
-				t = scnprintf(next, size,
-					"\treq %p len %d/%d "
-					"buf %p (dma%d dcmd %08x)\n",
-					&req->req, req->req.actual,
-					req->req.length, req->req.buf,
-					ep->dma, DCMD(ep->dma)
-					// low 13 bits == bytes-to-go
-					);
-			else
-#endif
-				t = scnprintf(next, size,
+			t = scnprintf(next, size,
 					"\treq %p len %d/%d buf %p\n",
 					"\treq %p len %d/%d buf %p\n",
 					&req->req, req->req.actual,
 					&req->req, req->req.actual,
 					req->req.length, req->req.buf);
 					req->req.length, req->req.buf);
@@ -1488,7 +1175,6 @@ static void udc_disable(struct pxa2xx_udc *dev)
 
 
 	ep0_idle (dev);
 	ep0_idle (dev);
 	dev->gadget.speed = USB_SPEED_UNKNOWN;
 	dev->gadget.speed = USB_SPEED_UNKNOWN;
-	LED_CONNECTED_OFF;
 }
 }
 
 
 
 
@@ -1514,7 +1200,7 @@ static void udc_reinit(struct pxa2xx_udc *dev)
 		ep->desc = NULL;
 		ep->desc = NULL;
 		ep->stopped = 0;
 		ep->stopped = 0;
 		INIT_LIST_HEAD (&ep->queue);
 		INIT_LIST_HEAD (&ep->queue);
-		ep->pio_irqs = ep->dma_irqs = 0;
+		ep->pio_irqs = 0;
 	}
 	}
 
 
 	/* the rest was statically initialized, and is read-only */
 	/* the rest was statically initialized, and is read-only */
@@ -1666,7 +1352,6 @@ stop_activity(struct pxa2xx_udc *dev, struct usb_gadget_driver *driver)
 	del_timer_sync(&dev->timer);
 	del_timer_sync(&dev->timer);
 
 
 	/* report disconnect; the driver is already quiesced */
 	/* report disconnect; the driver is already quiesced */
-	LED_CONNECTED_OFF;
 	if (driver)
 	if (driver)
 		driver->disconnect(&dev->gadget);
 		driver->disconnect(&dev->gadget);
 
 
@@ -1715,16 +1400,13 @@ lubbock_vbus_irq(int irq, void *_dev)
 	int			vbus;
 	int			vbus;
 
 
 	dev->stats.irqs++;
 	dev->stats.irqs++;
-	HEX_DISPLAY(dev->stats.irqs);
 	switch (irq) {
 	switch (irq) {
 	case LUBBOCK_USB_IRQ:
 	case LUBBOCK_USB_IRQ:
-		LED_CONNECTED_ON;
 		vbus = 1;
 		vbus = 1;
 		disable_irq(LUBBOCK_USB_IRQ);
 		disable_irq(LUBBOCK_USB_IRQ);
 		enable_irq(LUBBOCK_USB_DISC_IRQ);
 		enable_irq(LUBBOCK_USB_DISC_IRQ);
 		break;
 		break;
 	case LUBBOCK_USB_DISC_IRQ:
 	case LUBBOCK_USB_DISC_IRQ:
-		LED_CONNECTED_OFF;
 		vbus = 0;
 		vbus = 0;
 		disable_irq(LUBBOCK_USB_DISC_IRQ);
 		disable_irq(LUBBOCK_USB_DISC_IRQ);
 		enable_irq(LUBBOCK_USB_IRQ);
 		enable_irq(LUBBOCK_USB_IRQ);
@@ -1742,7 +1424,7 @@ lubbock_vbus_irq(int irq, void *_dev)
 static irqreturn_t udc_vbus_irq(int irq, void *_dev)
 static irqreturn_t udc_vbus_irq(int irq, void *_dev)
 {
 {
 	struct pxa2xx_udc	*dev = _dev;
 	struct pxa2xx_udc	*dev = _dev;
-	int			vbus = udc_gpio_get(dev->mach->gpio_vbus);
+	int			vbus = gpio_get_value(dev->mach->gpio_vbus);
 
 
 	pxa2xx_udc_vbus_session(&dev->gadget, vbus);
 	pxa2xx_udc_vbus_session(&dev->gadget, vbus);
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
@@ -2040,18 +1722,6 @@ static void handle_ep(struct pxa2xx_ep *ep)
 
 
 			/* fifos can hold packets, ready for reading... */
 			/* fifos can hold packets, ready for reading... */
 			if (likely(req)) {
 			if (likely(req)) {
-#ifdef USE_OUT_DMA
-// TODO didn't yet debug out-dma.  this approach assumes
-// the worst about short packets and RPC; it might be better.
-
-				if (likely(ep->dma >= 0)) {
-					if (!(udccs & UDCCS_BO_RSP)) {
-						*ep->reg_udccs = UDCCS_BO_RPC;
-						ep->dma_irqs++;
-						return;
-					}
-				}
-#endif
 				completed = read_fifo(ep, req);
 				completed = read_fifo(ep, req);
 			} else
 			} else
 				pio_irq_disable (ep->bEndpointAddress);
 				pio_irq_disable (ep->bEndpointAddress);
@@ -2074,7 +1744,6 @@ pxa2xx_udc_irq(int irq, void *_dev)
 	int			handled;
 	int			handled;
 
 
 	dev->stats.irqs++;
 	dev->stats.irqs++;
-	HEX_DISPLAY(dev->stats.irqs);
 	do {
 	do {
 		u32		udccr = UDCCR;
 		u32		udccr = UDCCR;
 
 
@@ -2125,7 +1794,6 @@ pxa2xx_udc_irq(int irq, void *_dev)
 			} else {
 			} else {
 				DBG(DBG_VERBOSE, "USB reset end\n");
 				DBG(DBG_VERBOSE, "USB reset end\n");
 				dev->gadget.speed = USB_SPEED_FULL;
 				dev->gadget.speed = USB_SPEED_FULL;
-				LED_CONNECTED_ON;
 				memset(&dev->stats, 0, sizeof dev->stats);
 				memset(&dev->stats, 0, sizeof dev->stats);
 				/* driver and endpoints are still reset */
 				/* driver and endpoints are still reset */
 			}
 			}
@@ -2217,7 +1885,6 @@ static struct pxa2xx_udc memory = {
 		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
 		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
 		.reg_udccs	= &UDCCS1,
 		.reg_udccs	= &UDCCS1,
 		.reg_uddr	= &UDDR1,
 		.reg_uddr	= &UDDR1,
-		drcmr (25)
 	},
 	},
 	.ep[2] = {
 	.ep[2] = {
 		.ep = {
 		.ep = {
@@ -2232,7 +1899,6 @@ static struct pxa2xx_udc memory = {
 		.reg_udccs	= &UDCCS2,
 		.reg_udccs	= &UDCCS2,
 		.reg_ubcr	= &UBCR2,
 		.reg_ubcr	= &UBCR2,
 		.reg_uddr	= &UDDR2,
 		.reg_uddr	= &UDDR2,
-		drcmr (26)
 	},
 	},
 #ifndef CONFIG_USB_PXA2XX_SMALL
 #ifndef CONFIG_USB_PXA2XX_SMALL
 	.ep[3] = {
 	.ep[3] = {
@@ -2247,7 +1913,6 @@ static struct pxa2xx_udc memory = {
 		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,
 		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,
 		.reg_udccs	= &UDCCS3,
 		.reg_udccs	= &UDCCS3,
 		.reg_uddr	= &UDDR3,
 		.reg_uddr	= &UDDR3,
-		drcmr (27)
 	},
 	},
 	.ep[4] = {
 	.ep[4] = {
 		.ep = {
 		.ep = {
@@ -2262,7 +1927,6 @@ static struct pxa2xx_udc memory = {
 		.reg_udccs	= &UDCCS4,
 		.reg_udccs	= &UDCCS4,
 		.reg_ubcr	= &UBCR4,
 		.reg_ubcr	= &UBCR4,
 		.reg_uddr	= &UDDR4,
 		.reg_uddr	= &UDDR4,
-		drcmr (28)
 	},
 	},
 	.ep[5] = {
 	.ep[5] = {
 		.ep = {
 		.ep = {
@@ -2291,7 +1955,6 @@ static struct pxa2xx_udc memory = {
 		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
 		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
 		.reg_udccs	= &UDCCS6,
 		.reg_udccs	= &UDCCS6,
 		.reg_uddr	= &UDDR6,
 		.reg_uddr	= &UDDR6,
-		drcmr (30)
 	},
 	},
 	.ep[7] = {
 	.ep[7] = {
 		.ep = {
 		.ep = {
@@ -2306,7 +1969,6 @@ static struct pxa2xx_udc memory = {
 		.reg_udccs	= &UDCCS7,
 		.reg_udccs	= &UDCCS7,
 		.reg_ubcr	= &UBCR7,
 		.reg_ubcr	= &UBCR7,
 		.reg_uddr	= &UDDR7,
 		.reg_uddr	= &UDDR7,
-		drcmr (31)
 	},
 	},
 	.ep[8] = {
 	.ep[8] = {
 		.ep = {
 		.ep = {
@@ -2320,7 +1982,6 @@ static struct pxa2xx_udc memory = {
 		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,
 		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,
 		.reg_udccs	= &UDCCS8,
 		.reg_udccs	= &UDCCS8,
 		.reg_uddr	= &UDDR8,
 		.reg_uddr	= &UDDR8,
-		drcmr (32)
 	},
 	},
 	.ep[9] = {
 	.ep[9] = {
 		.ep = {
 		.ep = {
@@ -2335,7 +1996,6 @@ static struct pxa2xx_udc memory = {
 		.reg_udccs	= &UDCCS9,
 		.reg_udccs	= &UDCCS9,
 		.reg_ubcr	= &UBCR9,
 		.reg_ubcr	= &UBCR9,
 		.reg_uddr	= &UDDR9,
 		.reg_uddr	= &UDDR9,
-		drcmr (33)
 	},
 	},
 	.ep[10] = {
 	.ep[10] = {
 		.ep = {
 		.ep = {
@@ -2364,7 +2024,6 @@ static struct pxa2xx_udc memory = {
 		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
 		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
 		.reg_udccs	= &UDCCS11,
 		.reg_udccs	= &UDCCS11,
 		.reg_uddr	= &UDDR11,
 		.reg_uddr	= &UDDR11,
-		drcmr (35)
 	},
 	},
 	.ep[12] = {
 	.ep[12] = {
 		.ep = {
 		.ep = {
@@ -2379,7 +2038,6 @@ static struct pxa2xx_udc memory = {
 		.reg_udccs	= &UDCCS12,
 		.reg_udccs	= &UDCCS12,
 		.reg_ubcr	= &UBCR12,
 		.reg_ubcr	= &UBCR12,
 		.reg_uddr	= &UDDR12,
 		.reg_uddr	= &UDDR12,
-		drcmr (36)
 	},
 	},
 	.ep[13] = {
 	.ep[13] = {
 		.ep = {
 		.ep = {
@@ -2393,7 +2051,6 @@ static struct pxa2xx_udc memory = {
 		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,
 		.bmAttributes	= USB_ENDPOINT_XFER_ISOC,
 		.reg_udccs	= &UDCCS13,
 		.reg_udccs	= &UDCCS13,
 		.reg_uddr	= &UDDR13,
 		.reg_uddr	= &UDDR13,
-		drcmr (37)
 	},
 	},
 	.ep[14] = {
 	.ep[14] = {
 		.ep = {
 		.ep = {
@@ -2408,7 +2065,6 @@ static struct pxa2xx_udc memory = {
 		.reg_udccs	= &UDCCS14,
 		.reg_udccs	= &UDCCS14,
 		.reg_ubcr	= &UBCR14,
 		.reg_ubcr	= &UBCR14,
 		.reg_uddr	= &UDDR14,
 		.reg_uddr	= &UDDR14,
-		drcmr (38)
 	},
 	},
 	.ep[15] = {
 	.ep[15] = {
 		.ep = {
 		.ep = {
@@ -2466,7 +2122,7 @@ static struct pxa2xx_udc memory = {
 static int __init pxa2xx_udc_probe(struct platform_device *pdev)
 static int __init pxa2xx_udc_probe(struct platform_device *pdev)
 {
 {
 	struct pxa2xx_udc *dev = &memory;
 	struct pxa2xx_udc *dev = &memory;
-	int retval, out_dma = 1, vbus_irq, irq;
+	int retval, vbus_irq, irq;
 	u32 chiprev;
 	u32 chiprev;
 
 
 	/* insist on Intel/ARM/XScale */
 	/* insist on Intel/ARM/XScale */
@@ -2489,7 +2145,7 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
 	case PXA250_B2: case PXA210_B2:
 	case PXA250_B2: case PXA210_B2:
 	case PXA250_B1: case PXA210_B1:
 	case PXA250_B1: case PXA210_B1:
 	case PXA250_B0: case PXA210_B0:
 	case PXA250_B0: case PXA210_B0:
-		out_dma = 0;
+		/* OUT-DMA is broken ... */
 		/* fall through */
 		/* fall through */
 	case PXA250_C0: case PXA210_C0:
 	case PXA250_C0: case PXA210_C0:
 		break;
 		break;
@@ -2498,11 +2154,9 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
 	case IXP425_B0:
 	case IXP425_B0:
 	case IXP465_AD:
 	case IXP465_AD:
 		dev->has_cfr = 1;
 		dev->has_cfr = 1;
-		out_dma = 0;
 		break;
 		break;
 #endif
 #endif
 	default:
 	default:
-		out_dma = 0;
 		printk(KERN_ERR "%s: unrecognized processor: %08x\n",
 		printk(KERN_ERR "%s: unrecognized processor: %08x\n",
 			driver_name, chiprev);
 			driver_name, chiprev);
 		/* iop3xx, ixp4xx, ... */
 		/* iop3xx, ixp4xx, ... */
@@ -2513,36 +2167,41 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
 	if (irq < 0)
 	if (irq < 0)
 		return -ENODEV;
 		return -ENODEV;
 
 
-	pr_debug("%s: IRQ %d%s%s%s\n", driver_name, irq,
+	pr_debug("%s: IRQ %d%s%s\n", driver_name, irq,
 		dev->has_cfr ? "" : " (!cfr)",
 		dev->has_cfr ? "" : " (!cfr)",
-		out_dma ? "" : " (broken dma-out)",
-		SIZE_STR DMASTR
+		SIZE_STR "(pio)"
 		);
 		);
 
 
-#ifdef	USE_DMA
-#ifndef	USE_OUT_DMA
-	out_dma = 0;
-#endif
-	/* pxa 250 erratum 130 prevents using OUT dma (fixed C0) */
-	if (!out_dma) {
-		DMSG("disabled OUT dma\n");
-		dev->ep[ 2].reg_drcmr = dev->ep[ 4].reg_drcmr = 0;
-		dev->ep[ 7].reg_drcmr = dev->ep[ 9].reg_drcmr = 0;
-		dev->ep[12].reg_drcmr = dev->ep[14].reg_drcmr = 0;
-	}
-#endif
-
 	/* other non-static parts of init */
 	/* other non-static parts of init */
 	dev->dev = &pdev->dev;
 	dev->dev = &pdev->dev;
 	dev->mach = pdev->dev.platform_data;
 	dev->mach = pdev->dev.platform_data;
+
 	if (dev->mach->gpio_vbus) {
 	if (dev->mach->gpio_vbus) {
-		udc_gpio_init_vbus(dev->mach->gpio_vbus);
-		vbus_irq = udc_gpio_to_irq(dev->mach->gpio_vbus);
+		if ((retval = gpio_request(dev->mach->gpio_vbus,
+				"pxa2xx_udc GPIO VBUS"))) {
+			dev_dbg(&pdev->dev,
+				"can't get vbus gpio %d, err: %d\n",
+				dev->mach->gpio_vbus, retval);
+			return -EBUSY;
+		}
+		gpio_direction_input(dev->mach->gpio_vbus);
+		vbus_irq = gpio_to_irq(dev->mach->gpio_vbus);
 		set_irq_type(vbus_irq, IRQT_BOTHEDGE);
 		set_irq_type(vbus_irq, IRQT_BOTHEDGE);
 	} else
 	} else
 		vbus_irq = 0;
 		vbus_irq = 0;
-	if (dev->mach->gpio_pullup)
-		udc_gpio_init_pullup(dev->mach->gpio_pullup);
+
+	if (dev->mach->gpio_pullup) {
+		if ((retval = gpio_request(dev->mach->gpio_pullup,
+				"pca2xx_udc GPIO PULLUP"))) {
+			dev_dbg(&pdev->dev,
+				"can't get pullup gpio %d, err: %d\n",
+				dev->mach->gpio_pullup, retval);
+			if (dev->mach->gpio_vbus)
+				gpio_free(dev->mach->gpio_vbus);
+			return -EBUSY;
+		}
+		gpio_direction_output(dev->mach->gpio_pullup, 0);
+	}
 
 
 	init_timer(&dev->timer);
 	init_timer(&dev->timer);
 	dev->timer.function = udc_watchdog;
 	dev->timer.function = udc_watchdog;
@@ -2566,6 +2225,10 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
 	if (retval != 0) {
 	if (retval != 0) {
 		printk(KERN_ERR "%s: can't get irq %d, err %d\n",
 		printk(KERN_ERR "%s: can't get irq %d, err %d\n",
 			driver_name, irq, retval);
 			driver_name, irq, retval);
+		if (dev->mach->gpio_pullup)
+			gpio_free(dev->mach->gpio_pullup);
+		if (dev->mach->gpio_vbus)
+			gpio_free(dev->mach->gpio_vbus);
 		return -EBUSY;
 		return -EBUSY;
 	}
 	}
 	dev->got_irq = 1;
 	dev->got_irq = 1;
@@ -2581,6 +2244,10 @@ static int __init pxa2xx_udc_probe(struct platform_device *pdev)
 				driver_name, LUBBOCK_USB_DISC_IRQ, retval);
 				driver_name, LUBBOCK_USB_DISC_IRQ, retval);
 lubbock_fail0:
 lubbock_fail0:
 			free_irq(irq, dev);
 			free_irq(irq, dev);
+			if (dev->mach->gpio_pullup)
+				gpio_free(dev->mach->gpio_pullup);
+			if (dev->mach->gpio_vbus)
+				gpio_free(dev->mach->gpio_vbus);
 			return -EBUSY;
 			return -EBUSY;
 		}
 		}
 		retval = request_irq(LUBBOCK_USB_IRQ,
 		retval = request_irq(LUBBOCK_USB_IRQ,
@@ -2593,11 +2260,6 @@ lubbock_fail0:
 			free_irq(LUBBOCK_USB_DISC_IRQ, dev);
 			free_irq(LUBBOCK_USB_DISC_IRQ, dev);
 			goto lubbock_fail0;
 			goto lubbock_fail0;
 		}
 		}
-#ifdef DEBUG
-		/* with U-Boot (but not BLOB), hex is off by default */
-		HEX_DISPLAY(dev->stats.irqs);
-		LUB_DISC_BLNK_LED &= 0xff;
-#endif
 	} else
 	} else
 #endif
 #endif
 	if (vbus_irq) {
 	if (vbus_irq) {
@@ -2608,6 +2270,10 @@ lubbock_fail0:
 			printk(KERN_ERR "%s: can't get irq %i, err %d\n",
 			printk(KERN_ERR "%s: can't get irq %i, err %d\n",
 				driver_name, vbus_irq, retval);
 				driver_name, vbus_irq, retval);
 			free_irq(irq, dev);
 			free_irq(irq, dev);
+			if (dev->mach->gpio_pullup)
+				gpio_free(dev->mach->gpio_pullup);
+			if (dev->mach->gpio_vbus)
+				gpio_free(dev->mach->gpio_vbus);
 			return -EBUSY;
 			return -EBUSY;
 		}
 		}
 	}
 	}
@@ -2641,8 +2307,13 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
 		free_irq(LUBBOCK_USB_IRQ, dev);
 		free_irq(LUBBOCK_USB_IRQ, dev);
 	}
 	}
 #endif
 #endif
-	if (dev->mach->gpio_vbus)
-		free_irq(IRQ_GPIO(dev->mach->gpio_vbus), dev);
+	if (dev->mach->gpio_vbus) {
+		free_irq(gpio_to_irq(dev->mach->gpio_vbus), dev);
+		gpio_free(dev->mach->gpio_vbus);
+	}
+	if (dev->mach->gpio_pullup)
+		gpio_free(dev->mach->gpio_pullup);
+
 	platform_set_drvdata(pdev, NULL);
 	platform_set_drvdata(pdev, NULL);
 	the_controller = NULL;
 	the_controller = NULL;
 	return 0;
 	return 0;

+ 5 - 43
drivers/usb/gadget/pxa2xx_udc.h

@@ -54,8 +54,6 @@ struct pxa2xx_ep {
 	const struct usb_endpoint_descriptor	*desc;
 	const struct usb_endpoint_descriptor	*desc;
 	struct list_head			queue;
 	struct list_head			queue;
 	unsigned long				pio_irqs;
 	unsigned long				pio_irqs;
-	unsigned long				dma_irqs;
-	short					dma; 
 
 
 	unsigned short				fifo_size;
 	unsigned short				fifo_size;
 	u8					bEndpointAddress;
 	u8					bEndpointAddress;
@@ -63,7 +61,7 @@ struct pxa2xx_ep {
 
 
 	unsigned				stopped : 1;
 	unsigned				stopped : 1;
 	unsigned				dma_fixup : 1;
 	unsigned				dma_fixup : 1;
-							 
+
 	/* UDCCS = UDC Control/Status for this EP
 	/* UDCCS = UDC Control/Status for this EP
 	 * UBCR = UDC Byte Count Remaining (contents of OUT fifo)
 	 * UBCR = UDC Byte Count Remaining (contents of OUT fifo)
 	 * UDDR = UDC Endpoint Data Register (the fifo)
 	 * UDDR = UDC Endpoint Data Register (the fifo)
@@ -72,12 +70,6 @@ struct pxa2xx_ep {
 	volatile u32				*reg_udccs;
 	volatile u32				*reg_udccs;
 	volatile u32				*reg_ubcr;
 	volatile u32				*reg_ubcr;
 	volatile u32				*reg_uddr;
 	volatile u32				*reg_uddr;
-#ifdef USE_DMA
-	volatile u32			*reg_drcmr;
-#define	drcmr(n)  .reg_drcmr = & DRCMR ## n ,
-#else
-#define	drcmr(n)  
-#endif
 };
 };
 
 
 struct pxa2xx_request {
 struct pxa2xx_request {
@@ -85,7 +77,7 @@ struct pxa2xx_request {
 	struct list_head			queue;
 	struct list_head			queue;
 };
 };
 
 
-enum ep0_state { 
+enum ep0_state {
 	EP0_IDLE,
 	EP0_IDLE,
 	EP0_IN_DATA_PHASE,
 	EP0_IN_DATA_PHASE,
 	EP0_OUT_DATA_PHASE,
 	EP0_OUT_DATA_PHASE,
@@ -108,7 +100,6 @@ struct udc_stats {
 
 
 #ifdef CONFIG_USB_PXA2XX_SMALL
 #ifdef CONFIG_USB_PXA2XX_SMALL
 /* when memory's tight, SMALL config saves code+data.  */
 /* when memory's tight, SMALL config saves code+data.  */
-#undef	USE_DMA
 #define	PXA_UDC_NUM_ENDPOINTS	3
 #define	PXA_UDC_NUM_ENDPOINTS	3
 #endif
 #endif
 
 
@@ -144,37 +135,8 @@ struct pxa2xx_udc {
 #ifdef CONFIG_ARCH_LUBBOCK
 #ifdef CONFIG_ARCH_LUBBOCK
 #include <asm/arch/lubbock.h>
 #include <asm/arch/lubbock.h>
 /* lubbock can also report usb connect/disconnect irqs */
 /* lubbock can also report usb connect/disconnect irqs */
-
-#ifdef DEBUG
-#define HEX_DISPLAY(n)	if (machine_is_lubbock()) { LUB_HEXLED = (n); }
 #endif
 #endif
 
 
-#endif
-
-/*-------------------------------------------------------------------------*/
-
-/* LEDs are only for debug */
-#ifndef HEX_DISPLAY
-#define HEX_DISPLAY(n)		do {} while(0)
-#endif
-
-#ifdef DEBUG
-#include <asm/leds.h>
-
-#define LED_CONNECTED_ON	leds_event(led_green_on)
-#define LED_CONNECTED_OFF	do { \
-					leds_event(led_green_off); \
-					HEX_DISPLAY(0); \
-				} while(0)
-#endif
-
-#ifndef LED_CONNECTED_ON
-#define LED_CONNECTED_ON	do {} while(0)
-#define LED_CONNECTED_OFF	do {} while(0)
-#endif
-
-/*-------------------------------------------------------------------------*/
-
 static struct pxa2xx_udc *the_controller;
 static struct pxa2xx_udc *the_controller;
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -204,7 +166,7 @@ static const char *state_name[] = {
 #    define UDC_DEBUG DBG_NORMAL
 #    define UDC_DEBUG DBG_NORMAL
 #endif
 #endif
 
 
-static void __attribute__ ((__unused__))
+static void __maybe_unused
 dump_udccr(const char *label)
 dump_udccr(const char *label)
 {
 {
 	u32	udccr = UDCCR;
 	u32	udccr = UDCCR;
@@ -220,7 +182,7 @@ dump_udccr(const char *label)
 		(udccr & UDCCR_UDE) ? " ude" : "");
 		(udccr & UDCCR_UDE) ? " ude" : "");
 }
 }
 
 
-static void __attribute__ ((__unused__))
+static void __maybe_unused
 dump_udccs0(const char *label)
 dump_udccs0(const char *label)
 {
 {
 	u32		udccs0 = UDCCS0;
 	u32		udccs0 = UDCCS0;
@@ -237,7 +199,7 @@ dump_udccs0(const char *label)
 		(udccs0 & UDCCS0_OPR) ? " opr" : "");
 		(udccs0 & UDCCS0_OPR) ? " opr" : "");
 }
 }
 
 
-static void __attribute__ ((__unused__))
+static void __maybe_unused
 dump_state(struct pxa2xx_udc *dev)
 dump_state(struct pxa2xx_udc *dev)
 {
 {
 	u32		tmp;
 	u32		tmp;

+ 82 - 82
drivers/usb/gadget/rndis.c

@@ -53,7 +53,7 @@
  */
  */
 
 
 #if 0
 #if 0
-#define DEBUG(str,args...) do { \
+#define DBG(str,args...) do { \
 	if (rndis_debug) \
 	if (rndis_debug) \
 		printk(KERN_DEBUG str , ## args ); \
 		printk(KERN_DEBUG str , ## args ); \
 	} while (0)
 	} while (0)
@@ -65,7 +65,7 @@ MODULE_PARM_DESC (rndis_debug, "enable debugging");
 #else
 #else
 
 
 #define rndis_debug		0
 #define rndis_debug		0
-#define DEBUG(str,args...)	do{}while(0)
+#define DBG(str,args...)	do{}while(0)
 #endif
 #endif
 
 
 #define RNDIS_MAX_CONFIGS	1
 #define RNDIS_MAX_CONFIGS	1
@@ -183,9 +183,9 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 	if (!resp) return -ENOMEM;
 	if (!resp) return -ENOMEM;
 
 
 	if (buf_len && rndis_debug > 1) {
 	if (buf_len && rndis_debug > 1) {
-		DEBUG("query OID %08x value, len %d:\n", OID, buf_len);
+		DBG("query OID %08x value, len %d:\n", OID, buf_len);
 		for (i = 0; i < buf_len; i += 16) {
 		for (i = 0; i < buf_len; i += 16) {
-			DEBUG ("%03d: %08x %08x %08x %08x\n", i,
+			DBG("%03d: %08x %08x %08x %08x\n", i,
 				le32_to_cpu(get_unaligned((__le32 *)
 				le32_to_cpu(get_unaligned((__le32 *)
 					&buf[i])),
 					&buf[i])),
 				le32_to_cpu(get_unaligned((__le32 *)
 				le32_to_cpu(get_unaligned((__le32 *)
@@ -207,7 +207,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 
 
 	/* mandatory */
 	/* mandatory */
 	case OID_GEN_SUPPORTED_LIST:
 	case OID_GEN_SUPPORTED_LIST:
-		DEBUG ("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__);
+		DBG("%s: OID_GEN_SUPPORTED_LIST\n", __FUNCTION__);
 		length = sizeof (oid_supported_list);
 		length = sizeof (oid_supported_list);
 		count  = length / sizeof (u32);
 		count  = length / sizeof (u32);
 		for (i = 0; i < count; i++)
 		for (i = 0; i < count; i++)
@@ -217,7 +217,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 
 
 	/* mandatory */
 	/* mandatory */
 	case OID_GEN_HARDWARE_STATUS:
 	case OID_GEN_HARDWARE_STATUS:
-		DEBUG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__);
+		DBG("%s: OID_GEN_HARDWARE_STATUS\n", __FUNCTION__);
 		/* Bogus question!
 		/* Bogus question!
 		 * Hardware must be ready to receive high level protocols.
 		 * Hardware must be ready to receive high level protocols.
 		 * BTW:
 		 * BTW:
@@ -230,14 +230,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 
 
 	/* mandatory */
 	/* mandatory */
 	case OID_GEN_MEDIA_SUPPORTED:
 	case OID_GEN_MEDIA_SUPPORTED:
-		DEBUG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__);
+		DBG("%s: OID_GEN_MEDIA_SUPPORTED\n", __FUNCTION__);
 		*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
 		*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
 		retval = 0;
 		retval = 0;
 		break;
 		break;
 
 
 	/* mandatory */
 	/* mandatory */
 	case OID_GEN_MEDIA_IN_USE:
 	case OID_GEN_MEDIA_IN_USE:
-		DEBUG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__);
+		DBG("%s: OID_GEN_MEDIA_IN_USE\n", __FUNCTION__);
 		/* one medium, one transport... (maybe you do it better) */
 		/* one medium, one transport... (maybe you do it better) */
 		*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
 		*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr].medium);
 		retval = 0;
 		retval = 0;
@@ -245,7 +245,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 
 
 	/* mandatory */
 	/* mandatory */
 	case OID_GEN_MAXIMUM_FRAME_SIZE:
 	case OID_GEN_MAXIMUM_FRAME_SIZE:
-		DEBUG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__);
+		DBG("%s: OID_GEN_MAXIMUM_FRAME_SIZE\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
 		if (rndis_per_dev_params [configNr].dev) {
 			*outbuf = cpu_to_le32 (
 			*outbuf = cpu_to_le32 (
 				rndis_per_dev_params [configNr].dev->mtu);
 				rndis_per_dev_params [configNr].dev->mtu);
@@ -256,7 +256,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 	/* mandatory */
 	/* mandatory */
 	case OID_GEN_LINK_SPEED:
 	case OID_GEN_LINK_SPEED:
 		if (rndis_debug > 1)
 		if (rndis_debug > 1)
-			DEBUG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
+			DBG("%s: OID_GEN_LINK_SPEED\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].media_state
 		if (rndis_per_dev_params [configNr].media_state
 				== NDIS_MEDIA_STATE_DISCONNECTED)
 				== NDIS_MEDIA_STATE_DISCONNECTED)
 			*outbuf = __constant_cpu_to_le32 (0);
 			*outbuf = __constant_cpu_to_le32 (0);
@@ -268,7 +268,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 
 
 	/* mandatory */
 	/* mandatory */
 	case OID_GEN_TRANSMIT_BLOCK_SIZE:
 	case OID_GEN_TRANSMIT_BLOCK_SIZE:
-		DEBUG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__);
+		DBG("%s: OID_GEN_TRANSMIT_BLOCK_SIZE\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
 		if (rndis_per_dev_params [configNr].dev) {
 			*outbuf = cpu_to_le32 (
 			*outbuf = cpu_to_le32 (
 				rndis_per_dev_params [configNr].dev->mtu);
 				rndis_per_dev_params [configNr].dev->mtu);
@@ -278,7 +278,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 
 
 	/* mandatory */
 	/* mandatory */
 	case OID_GEN_RECEIVE_BLOCK_SIZE:
 	case OID_GEN_RECEIVE_BLOCK_SIZE:
-		DEBUG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__);
+		DBG("%s: OID_GEN_RECEIVE_BLOCK_SIZE\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
 		if (rndis_per_dev_params [configNr].dev) {
 			*outbuf = cpu_to_le32 (
 			*outbuf = cpu_to_le32 (
 				rndis_per_dev_params [configNr].dev->mtu);
 				rndis_per_dev_params [configNr].dev->mtu);
@@ -288,7 +288,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 
 
 	/* mandatory */
 	/* mandatory */
 	case OID_GEN_VENDOR_ID:
 	case OID_GEN_VENDOR_ID:
-		DEBUG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__);
+		DBG("%s: OID_GEN_VENDOR_ID\n", __FUNCTION__);
 		*outbuf = cpu_to_le32 (
 		*outbuf = cpu_to_le32 (
 			rndis_per_dev_params [configNr].vendorID);
 			rndis_per_dev_params [configNr].vendorID);
 		retval = 0;
 		retval = 0;
@@ -296,7 +296,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 
 
 	/* mandatory */
 	/* mandatory */
 	case OID_GEN_VENDOR_DESCRIPTION:
 	case OID_GEN_VENDOR_DESCRIPTION:
-		DEBUG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__);
+		DBG("%s: OID_GEN_VENDOR_DESCRIPTION\n", __FUNCTION__);
 		length = strlen (rndis_per_dev_params [configNr].vendorDescr);
 		length = strlen (rndis_per_dev_params [configNr].vendorDescr);
 		memcpy (outbuf,
 		memcpy (outbuf,
 			rndis_per_dev_params [configNr].vendorDescr, length);
 			rndis_per_dev_params [configNr].vendorDescr, length);
@@ -304,7 +304,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 		break;
 		break;
 
 
 	case OID_GEN_VENDOR_DRIVER_VERSION:
 	case OID_GEN_VENDOR_DRIVER_VERSION:
-		DEBUG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__);
+		DBG("%s: OID_GEN_VENDOR_DRIVER_VERSION\n", __FUNCTION__);
 		/* Created as LE */
 		/* Created as LE */
 		*outbuf = rndis_driver_version;
 		*outbuf = rndis_driver_version;
 		retval = 0;
 		retval = 0;
@@ -312,14 +312,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 
 
 	/* mandatory */
 	/* mandatory */
 	case OID_GEN_CURRENT_PACKET_FILTER:
 	case OID_GEN_CURRENT_PACKET_FILTER:
-		DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__);
+		DBG("%s: OID_GEN_CURRENT_PACKET_FILTER\n", __FUNCTION__);
 		*outbuf = cpu_to_le32 (*rndis_per_dev_params[configNr].filter);
 		*outbuf = cpu_to_le32 (*rndis_per_dev_params[configNr].filter);
 		retval = 0;
 		retval = 0;
 		break;
 		break;
 
 
 	/* mandatory */
 	/* mandatory */
 	case OID_GEN_MAXIMUM_TOTAL_SIZE:
 	case OID_GEN_MAXIMUM_TOTAL_SIZE:
-		DEBUG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__);
+		DBG("%s: OID_GEN_MAXIMUM_TOTAL_SIZE\n", __FUNCTION__);
 		*outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
 		*outbuf = __constant_cpu_to_le32(RNDIS_MAX_TOTAL_SIZE);
 		retval = 0;
 		retval = 0;
 		break;
 		break;
@@ -327,14 +327,14 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 	/* mandatory */
 	/* mandatory */
 	case OID_GEN_MEDIA_CONNECT_STATUS:
 	case OID_GEN_MEDIA_CONNECT_STATUS:
 		if (rndis_debug > 1)
 		if (rndis_debug > 1)
-			DEBUG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
+			DBG("%s: OID_GEN_MEDIA_CONNECT_STATUS\n", __FUNCTION__);
 		*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 		*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 						.media_state);
 						.media_state);
 		retval = 0;
 		retval = 0;
 		break;
 		break;
 
 
 	case OID_GEN_PHYSICAL_MEDIUM:
 	case OID_GEN_PHYSICAL_MEDIUM:
-		DEBUG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__);
+		DBG("%s: OID_GEN_PHYSICAL_MEDIUM\n", __FUNCTION__);
 		*outbuf = __constant_cpu_to_le32 (0);
 		*outbuf = __constant_cpu_to_le32 (0);
 		retval = 0;
 		retval = 0;
 		break;
 		break;
@@ -344,7 +344,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 	 * versions emit undefined RNDIS messages. DOCUMENT ALL THESE!
 	 * versions emit undefined RNDIS messages. DOCUMENT ALL THESE!
 	 */
 	 */
 	case OID_GEN_MAC_OPTIONS:		/* from WinME */
 	case OID_GEN_MAC_OPTIONS:		/* from WinME */
-		DEBUG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__);
+		DBG("%s: OID_GEN_MAC_OPTIONS\n", __FUNCTION__);
 		*outbuf = __constant_cpu_to_le32(
 		*outbuf = __constant_cpu_to_le32(
 			  NDIS_MAC_OPTION_RECEIVE_SERIALIZED
 			  NDIS_MAC_OPTION_RECEIVE_SERIALIZED
 			| NDIS_MAC_OPTION_FULL_DUPLEX);
 			| NDIS_MAC_OPTION_FULL_DUPLEX);
@@ -356,7 +356,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 	/* mandatory */
 	/* mandatory */
 	case OID_GEN_XMIT_OK:
 	case OID_GEN_XMIT_OK:
 		if (rndis_debug > 1)
 		if (rndis_debug > 1)
-			DEBUG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
+			DBG("%s: OID_GEN_XMIT_OK\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 		if (rndis_per_dev_params [configNr].stats) {
 			*outbuf = cpu_to_le32 (
 			*outbuf = cpu_to_le32 (
 			    rndis_per_dev_params [configNr].stats->tx_packets -
 			    rndis_per_dev_params [configNr].stats->tx_packets -
@@ -369,7 +369,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 	/* mandatory */
 	/* mandatory */
 	case OID_GEN_RCV_OK:
 	case OID_GEN_RCV_OK:
 		if (rndis_debug > 1)
 		if (rndis_debug > 1)
-			DEBUG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
+			DBG("%s: OID_GEN_RCV_OK\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 		if (rndis_per_dev_params [configNr].stats) {
 			*outbuf = cpu_to_le32 (
 			*outbuf = cpu_to_le32 (
 			    rndis_per_dev_params [configNr].stats->rx_packets -
 			    rndis_per_dev_params [configNr].stats->rx_packets -
@@ -382,7 +382,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 	/* mandatory */
 	/* mandatory */
 	case OID_GEN_XMIT_ERROR:
 	case OID_GEN_XMIT_ERROR:
 		if (rndis_debug > 1)
 		if (rndis_debug > 1)
-			DEBUG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
+			DBG("%s: OID_GEN_XMIT_ERROR\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 		if (rndis_per_dev_params [configNr].stats) {
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->tx_errors);
 					.stats->tx_errors);
@@ -393,7 +393,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 	/* mandatory */
 	/* mandatory */
 	case OID_GEN_RCV_ERROR:
 	case OID_GEN_RCV_ERROR:
 		if (rndis_debug > 1)
 		if (rndis_debug > 1)
-			DEBUG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
+			DBG("%s: OID_GEN_RCV_ERROR\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 		if (rndis_per_dev_params [configNr].stats) {
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->rx_errors);
 					.stats->rx_errors);
@@ -403,7 +403,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 
 
 	/* mandatory */
 	/* mandatory */
 	case OID_GEN_RCV_NO_BUFFER:
 	case OID_GEN_RCV_NO_BUFFER:
-		DEBUG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__);
+		DBG("%s: OID_GEN_RCV_NO_BUFFER\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 		if (rndis_per_dev_params [configNr].stats) {
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->rx_dropped);
 					.stats->rx_dropped);
@@ -413,7 +413,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 
 
 #ifdef	RNDIS_OPTIONAL_STATS
 #ifdef	RNDIS_OPTIONAL_STATS
 	case OID_GEN_DIRECTED_BYTES_XMIT:
 	case OID_GEN_DIRECTED_BYTES_XMIT:
-		DEBUG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __FUNCTION__);
+		DBG("%s: OID_GEN_DIRECTED_BYTES_XMIT\n", __FUNCTION__);
 		/*
 		/*
 		 * Aunt Tilly's size of shoes
 		 * Aunt Tilly's size of shoes
 		 * minus antarctica count of penguins
 		 * minus antarctica count of penguins
@@ -433,7 +433,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 		break;
 		break;
 
 
 	case OID_GEN_DIRECTED_FRAMES_XMIT:
 	case OID_GEN_DIRECTED_FRAMES_XMIT:
-		DEBUG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__);
+		DBG("%s: OID_GEN_DIRECTED_FRAMES_XMIT\n", __FUNCTION__);
 		/* dito */
 		/* dito */
 		if (rndis_per_dev_params [configNr].stats) {
 		if (rndis_per_dev_params [configNr].stats) {
 			*outbuf = cpu_to_le32 (
 			*outbuf = cpu_to_le32 (
@@ -449,7 +449,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 		break;
 		break;
 
 
 	case OID_GEN_MULTICAST_BYTES_XMIT:
 	case OID_GEN_MULTICAST_BYTES_XMIT:
-		DEBUG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__);
+		DBG("%s: OID_GEN_MULTICAST_BYTES_XMIT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 		if (rndis_per_dev_params [configNr].stats) {
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->multicast*1234);
 					.stats->multicast*1234);
@@ -458,7 +458,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 		break;
 		break;
 
 
 	case OID_GEN_MULTICAST_FRAMES_XMIT:
 	case OID_GEN_MULTICAST_FRAMES_XMIT:
-		DEBUG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__);
+		DBG("%s: OID_GEN_MULTICAST_FRAMES_XMIT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 		if (rndis_per_dev_params [configNr].stats) {
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->multicast);
 					.stats->multicast);
@@ -467,7 +467,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 		break;
 		break;
 
 
 	case OID_GEN_BROADCAST_BYTES_XMIT:
 	case OID_GEN_BROADCAST_BYTES_XMIT:
-		DEBUG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__);
+		DBG("%s: OID_GEN_BROADCAST_BYTES_XMIT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 		if (rndis_per_dev_params [configNr].stats) {
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->tx_packets/42*255);
 					.stats->tx_packets/42*255);
@@ -476,7 +476,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 		break;
 		break;
 
 
 	case OID_GEN_BROADCAST_FRAMES_XMIT:
 	case OID_GEN_BROADCAST_FRAMES_XMIT:
-		DEBUG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__);
+		DBG("%s: OID_GEN_BROADCAST_FRAMES_XMIT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 		if (rndis_per_dev_params [configNr].stats) {
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->tx_packets/42);
 					.stats->tx_packets/42);
@@ -485,19 +485,19 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 		break;
 		break;
 
 
 	case OID_GEN_DIRECTED_BYTES_RCV:
 	case OID_GEN_DIRECTED_BYTES_RCV:
-		DEBUG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__);
+		DBG("%s: OID_GEN_DIRECTED_BYTES_RCV\n", __FUNCTION__);
 		*outbuf = __constant_cpu_to_le32 (0);
 		*outbuf = __constant_cpu_to_le32 (0);
 		retval = 0;
 		retval = 0;
 		break;
 		break;
 
 
 	case OID_GEN_DIRECTED_FRAMES_RCV:
 	case OID_GEN_DIRECTED_FRAMES_RCV:
-		DEBUG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__);
+		DBG("%s: OID_GEN_DIRECTED_FRAMES_RCV\n", __FUNCTION__);
 		*outbuf = __constant_cpu_to_le32 (0);
 		*outbuf = __constant_cpu_to_le32 (0);
 		retval = 0;
 		retval = 0;
 		break;
 		break;
 
 
 	case OID_GEN_MULTICAST_BYTES_RCV:
 	case OID_GEN_MULTICAST_BYTES_RCV:
-		DEBUG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__);
+		DBG("%s: OID_GEN_MULTICAST_BYTES_RCV\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 		if (rndis_per_dev_params [configNr].stats) {
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->multicast * 1111);
 					.stats->multicast * 1111);
@@ -506,7 +506,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 		break;
 		break;
 
 
 	case OID_GEN_MULTICAST_FRAMES_RCV:
 	case OID_GEN_MULTICAST_FRAMES_RCV:
-		DEBUG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__);
+		DBG("%s: OID_GEN_MULTICAST_FRAMES_RCV\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 		if (rndis_per_dev_params [configNr].stats) {
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->multicast);
 					.stats->multicast);
@@ -515,7 +515,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 		break;
 		break;
 
 
 	case OID_GEN_BROADCAST_BYTES_RCV:
 	case OID_GEN_BROADCAST_BYTES_RCV:
-		DEBUG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__);
+		DBG("%s: OID_GEN_BROADCAST_BYTES_RCV\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 		if (rndis_per_dev_params [configNr].stats) {
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->rx_packets/42*255);
 					.stats->rx_packets/42*255);
@@ -524,7 +524,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 		break;
 		break;
 
 
 	case OID_GEN_BROADCAST_FRAMES_RCV:
 	case OID_GEN_BROADCAST_FRAMES_RCV:
-		DEBUG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__);
+		DBG("%s: OID_GEN_BROADCAST_FRAMES_RCV\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 		if (rndis_per_dev_params [configNr].stats) {
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->rx_packets/42);
 					.stats->rx_packets/42);
@@ -533,7 +533,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 		break;
 		break;
 
 
 	case OID_GEN_RCV_CRC_ERROR:
 	case OID_GEN_RCV_CRC_ERROR:
-		DEBUG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__);
+		DBG("%s: OID_GEN_RCV_CRC_ERROR\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 		if (rndis_per_dev_params [configNr].stats) {
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->rx_crc_errors);
 					.stats->rx_crc_errors);
@@ -542,7 +542,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 		break;
 		break;
 
 
 	case OID_GEN_TRANSMIT_QUEUE_LENGTH:
 	case OID_GEN_TRANSMIT_QUEUE_LENGTH:
-		DEBUG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__);
+		DBG("%s: OID_GEN_TRANSMIT_QUEUE_LENGTH\n", __FUNCTION__);
 		*outbuf = __constant_cpu_to_le32 (0);
 		*outbuf = __constant_cpu_to_le32 (0);
 		retval = 0;
 		retval = 0;
 		break;
 		break;
@@ -552,7 +552,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 
 
 	/* mandatory */
 	/* mandatory */
 	case OID_802_3_PERMANENT_ADDRESS:
 	case OID_802_3_PERMANENT_ADDRESS:
-		DEBUG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__);
+		DBG("%s: OID_802_3_PERMANENT_ADDRESS\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
 		if (rndis_per_dev_params [configNr].dev) {
 			length = ETH_ALEN;
 			length = ETH_ALEN;
 			memcpy (outbuf,
 			memcpy (outbuf,
@@ -564,7 +564,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 
 
 	/* mandatory */
 	/* mandatory */
 	case OID_802_3_CURRENT_ADDRESS:
 	case OID_802_3_CURRENT_ADDRESS:
-		DEBUG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__);
+		DBG("%s: OID_802_3_CURRENT_ADDRESS\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].dev) {
 		if (rndis_per_dev_params [configNr].dev) {
 			length = ETH_ALEN;
 			length = ETH_ALEN;
 			memcpy (outbuf,
 			memcpy (outbuf,
@@ -576,7 +576,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 
 
 	/* mandatory */
 	/* mandatory */
 	case OID_802_3_MULTICAST_LIST:
 	case OID_802_3_MULTICAST_LIST:
-		DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
+		DBG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
 		/* Multicast base address only */
 		/* Multicast base address only */
 		*outbuf = __constant_cpu_to_le32 (0xE0000000);
 		*outbuf = __constant_cpu_to_le32 (0xE0000000);
 		retval = 0;
 		retval = 0;
@@ -584,21 +584,21 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 
 
 	/* mandatory */
 	/* mandatory */
 	case OID_802_3_MAXIMUM_LIST_SIZE:
 	case OID_802_3_MAXIMUM_LIST_SIZE:
-		DEBUG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__);
+		DBG("%s: OID_802_3_MAXIMUM_LIST_SIZE\n", __FUNCTION__);
 		/* Multicast base address only */
 		/* Multicast base address only */
 		*outbuf = __constant_cpu_to_le32 (1);
 		*outbuf = __constant_cpu_to_le32 (1);
 		retval = 0;
 		retval = 0;
 		break;
 		break;
 
 
 	case OID_802_3_MAC_OPTIONS:
 	case OID_802_3_MAC_OPTIONS:
-		DEBUG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__);
+		DBG("%s: OID_802_3_MAC_OPTIONS\n", __FUNCTION__);
 		break;
 		break;
 
 
 	/* ieee802.3 statistics OIDs (table 4-4) */
 	/* ieee802.3 statistics OIDs (table 4-4) */
 
 
 	/* mandatory */
 	/* mandatory */
 	case OID_802_3_RCV_ERROR_ALIGNMENT:
 	case OID_802_3_RCV_ERROR_ALIGNMENT:
-		DEBUG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__);
+		DBG("%s: OID_802_3_RCV_ERROR_ALIGNMENT\n", __FUNCTION__);
 		if (rndis_per_dev_params [configNr].stats) {
 		if (rndis_per_dev_params [configNr].stats) {
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 			*outbuf = cpu_to_le32 (rndis_per_dev_params [configNr]
 					.stats->rx_frame_errors);
 					.stats->rx_frame_errors);
@@ -608,51 +608,51 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 
 
 	/* mandatory */
 	/* mandatory */
 	case OID_802_3_XMIT_ONE_COLLISION:
 	case OID_802_3_XMIT_ONE_COLLISION:
-		DEBUG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__);
+		DBG("%s: OID_802_3_XMIT_ONE_COLLISION\n", __FUNCTION__);
 		*outbuf = __constant_cpu_to_le32 (0);
 		*outbuf = __constant_cpu_to_le32 (0);
 		retval = 0;
 		retval = 0;
 		break;
 		break;
 
 
 	/* mandatory */
 	/* mandatory */
 	case OID_802_3_XMIT_MORE_COLLISIONS:
 	case OID_802_3_XMIT_MORE_COLLISIONS:
-		DEBUG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__);
+		DBG("%s: OID_802_3_XMIT_MORE_COLLISIONS\n", __FUNCTION__);
 		*outbuf = __constant_cpu_to_le32 (0);
 		*outbuf = __constant_cpu_to_le32 (0);
 		retval = 0;
 		retval = 0;
 		break;
 		break;
 
 
 #ifdef	RNDIS_OPTIONAL_STATS
 #ifdef	RNDIS_OPTIONAL_STATS
 	case OID_802_3_XMIT_DEFERRED:
 	case OID_802_3_XMIT_DEFERRED:
-		DEBUG("%s: OID_802_3_XMIT_DEFERRED\n", __FUNCTION__);
+		DBG("%s: OID_802_3_XMIT_DEFERRED\n", __FUNCTION__);
 		/* TODO */
 		/* TODO */
 		break;
 		break;
 
 
 	case OID_802_3_XMIT_MAX_COLLISIONS:
 	case OID_802_3_XMIT_MAX_COLLISIONS:
-		DEBUG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __FUNCTION__);
+		DBG("%s: OID_802_3_XMIT_MAX_COLLISIONS\n", __FUNCTION__);
 		/* TODO */
 		/* TODO */
 		break;
 		break;
 
 
 	case OID_802_3_RCV_OVERRUN:
 	case OID_802_3_RCV_OVERRUN:
-		DEBUG("%s: OID_802_3_RCV_OVERRUN\n", __FUNCTION__);
+		DBG("%s: OID_802_3_RCV_OVERRUN\n", __FUNCTION__);
 		/* TODO */
 		/* TODO */
 		break;
 		break;
 
 
 	case OID_802_3_XMIT_UNDERRUN:
 	case OID_802_3_XMIT_UNDERRUN:
-		DEBUG("%s: OID_802_3_XMIT_UNDERRUN\n", __FUNCTION__);
+		DBG("%s: OID_802_3_XMIT_UNDERRUN\n", __FUNCTION__);
 		/* TODO */
 		/* TODO */
 		break;
 		break;
 
 
 	case OID_802_3_XMIT_HEARTBEAT_FAILURE:
 	case OID_802_3_XMIT_HEARTBEAT_FAILURE:
-		DEBUG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __FUNCTION__);
+		DBG("%s: OID_802_3_XMIT_HEARTBEAT_FAILURE\n", __FUNCTION__);
 		/* TODO */
 		/* TODO */
 		break;
 		break;
 
 
 	case OID_802_3_XMIT_TIMES_CRS_LOST:
 	case OID_802_3_XMIT_TIMES_CRS_LOST:
-		DEBUG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __FUNCTION__);
+		DBG("%s: OID_802_3_XMIT_TIMES_CRS_LOST\n", __FUNCTION__);
 		/* TODO */
 		/* TODO */
 		break;
 		break;
 
 
 	case OID_802_3_XMIT_LATE_COLLISIONS:
 	case OID_802_3_XMIT_LATE_COLLISIONS:
-		DEBUG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __FUNCTION__);
+		DBG("%s: OID_802_3_XMIT_LATE_COLLISIONS\n", __FUNCTION__);
 		/* TODO */
 		/* TODO */
 		break;
 		break;
 #endif	/* RNDIS_OPTIONAL_STATS */
 #endif	/* RNDIS_OPTIONAL_STATS */
@@ -660,7 +660,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 #ifdef	RNDIS_PM
 #ifdef	RNDIS_PM
 	/* power management OIDs (table 4-5) */
 	/* power management OIDs (table 4-5) */
 	case OID_PNP_CAPABILITIES:
 	case OID_PNP_CAPABILITIES:
-		DEBUG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__);
+		DBG("%s: OID_PNP_CAPABILITIES\n", __FUNCTION__);
 
 
 		/* for now, no wakeup capabilities */
 		/* for now, no wakeup capabilities */
 		length = sizeof (struct NDIS_PNP_CAPABILITIES);
 		length = sizeof (struct NDIS_PNP_CAPABILITIES);
@@ -668,7 +668,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
 		retval = 0;
 		retval = 0;
 		break;
 		break;
 	case OID_PNP_QUERY_POWER:
 	case OID_PNP_QUERY_POWER:
-		DEBUG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__,
+		DBG("%s: OID_PNP_QUERY_POWER D%d\n", __FUNCTION__,
 				le32_to_cpu(get_unaligned((__le32 *)buf)) - 1);
 				le32_to_cpu(get_unaligned((__le32 *)buf)) - 1);
 		/* only suspend is a real power state, and
 		/* only suspend is a real power state, and
 		 * it can't be entered by OID_PNP_SET_POWER...
 		 * it can't be entered by OID_PNP_SET_POWER...
@@ -705,9 +705,9 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	if (buf_len && rndis_debug > 1) {
 	if (buf_len && rndis_debug > 1) {
-		DEBUG("set OID %08x value, len %d:\n", OID, buf_len);
+		DBG("set OID %08x value, len %d:\n", OID, buf_len);
 		for (i = 0; i < buf_len; i += 16) {
 		for (i = 0; i < buf_len; i += 16) {
-			DEBUG ("%03d: %08x %08x %08x %08x\n", i,
+			DBG("%03d: %08x %08x %08x %08x\n", i,
 				le32_to_cpu(get_unaligned((__le32 *)
 				le32_to_cpu(get_unaligned((__le32 *)
 					&buf[i])),
 					&buf[i])),
 				le32_to_cpu(get_unaligned((__le32 *)
 				le32_to_cpu(get_unaligned((__le32 *)
@@ -731,7 +731,7 @@ static int gen_ndis_set_resp (u8 configNr, u32 OID, u8 *buf, u32 buf_len,
 		 */
 		 */
 		*params->filter = (u16) le32_to_cpu(get_unaligned(
 		*params->filter = (u16) le32_to_cpu(get_unaligned(
 				(__le32 *)buf));
 				(__le32 *)buf));
-		DEBUG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
+		DBG("%s: OID_GEN_CURRENT_PACKET_FILTER %08x\n",
 			__FUNCTION__, *params->filter);
 			__FUNCTION__, *params->filter);
 
 
 		/* this call has a significant side effect:  it's
 		/* this call has a significant side effect:  it's
@@ -756,7 +756,7 @@ update_linkstate:
 
 
 	case OID_802_3_MULTICAST_LIST:
 	case OID_802_3_MULTICAST_LIST:
 		/* I think we can ignore this */
 		/* I think we can ignore this */
-		DEBUG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
+		DBG("%s: OID_802_3_MULTICAST_LIST\n", __FUNCTION__);
 		retval = 0;
 		retval = 0;
 		break;
 		break;
 #if 0
 #if 0
@@ -764,7 +764,7 @@ update_linkstate:
 		{
 		{
 		struct rndis_config_parameter	*param;
 		struct rndis_config_parameter	*param;
 		param = (struct rndis_config_parameter *) buf;
 		param = (struct rndis_config_parameter *) buf;
-		DEBUG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n",
+		DBG("%s: OID_GEN_RNDIS_CONFIG_PARAMETER '%*s'\n",
 			__FUNCTION__,
 			__FUNCTION__,
 			min(cpu_to_le32(param->ParameterNameLength),80),
 			min(cpu_to_le32(param->ParameterNameLength),80),
 			buf + param->ParameterNameOffset);
 			buf + param->ParameterNameOffset);
@@ -781,7 +781,7 @@ update_linkstate:
 		 * FIXME ... then things go batty; Windows wedges itself.
 		 * FIXME ... then things go batty; Windows wedges itself.
 		 */
 		 */
 		i = le32_to_cpu(get_unaligned((__le32 *)buf));
 		i = le32_to_cpu(get_unaligned((__le32 *)buf));
-		DEBUG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1);
+		DBG("%s: OID_PNP_SET_POWER D%d\n", __FUNCTION__, i - 1);
 		switch (i) {
 		switch (i) {
 		case NdisDeviceStateD0:
 		case NdisDeviceStateD0:
 			*params->filter = params->saved_filter;
 			*params->filter = params->saved_filter;
@@ -858,7 +858,7 @@ static int rndis_query_response (int configNr, rndis_query_msg_type *buf)
 	rndis_query_cmplt_type *resp;
 	rndis_query_cmplt_type *resp;
 	rndis_resp_t            *r;
 	rndis_resp_t            *r;
 
 
-	// DEBUG("%s: OID = %08X\n", __FUNCTION__, cpu_to_le32(buf->OID));
+	// DBG("%s: OID = %08X\n", __FUNCTION__, cpu_to_le32(buf->OID));
 	if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP;
 	if (!rndis_per_dev_params [configNr].dev) return -ENOTSUPP;
 
 
 	/*
 	/*
@@ -911,15 +911,15 @@ static int rndis_set_response (int configNr, rndis_set_msg_type *buf)
 	BufOffset = le32_to_cpu (buf->InformationBufferOffset);
 	BufOffset = le32_to_cpu (buf->InformationBufferOffset);
 
 
 #ifdef	VERBOSE
 #ifdef	VERBOSE
-	DEBUG("%s: Length: %d\n", __FUNCTION__, BufLength);
-	DEBUG("%s: Offset: %d\n", __FUNCTION__, BufOffset);
-	DEBUG("%s: InfoBuffer: ", __FUNCTION__);
+	DBG("%s: Length: %d\n", __FUNCTION__, BufLength);
+	DBG("%s: Offset: %d\n", __FUNCTION__, BufOffset);
+	DBG("%s: InfoBuffer: ", __FUNCTION__);
 
 
 	for (i = 0; i < BufLength; i++) {
 	for (i = 0; i < BufLength; i++) {
-		DEBUG ("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
+		DBG("%02x ", *(((u8 *) buf) + i + 8 + BufOffset));
 	}
 	}
 
 
-	DEBUG ("\n");
+	DBG("\n");
 #endif
 #endif
 
 
 	resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_SET_CMPLT);
 	resp->MessageType = __constant_cpu_to_le32 (REMOTE_NDIS_SET_CMPLT);
@@ -1082,14 +1082,14 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
 	/* For USB: responses may take up to 10 seconds */
 	/* For USB: responses may take up to 10 seconds */
 	switch (MsgType) {
 	switch (MsgType) {
 	case REMOTE_NDIS_INITIALIZE_MSG:
 	case REMOTE_NDIS_INITIALIZE_MSG:
-		DEBUG("%s: REMOTE_NDIS_INITIALIZE_MSG\n",
+		DBG("%s: REMOTE_NDIS_INITIALIZE_MSG\n",
 			__FUNCTION__ );
 			__FUNCTION__ );
 		params->state = RNDIS_INITIALIZED;
 		params->state = RNDIS_INITIALIZED;
 		return  rndis_init_response (configNr,
 		return  rndis_init_response (configNr,
 					(rndis_init_msg_type *) buf);
 					(rndis_init_msg_type *) buf);
 
 
 	case REMOTE_NDIS_HALT_MSG:
 	case REMOTE_NDIS_HALT_MSG:
-		DEBUG("%s: REMOTE_NDIS_HALT_MSG\n",
+		DBG("%s: REMOTE_NDIS_HALT_MSG\n",
 			__FUNCTION__ );
 			__FUNCTION__ );
 		params->state = RNDIS_UNINITIALIZED;
 		params->state = RNDIS_UNINITIALIZED;
 		if (params->dev) {
 		if (params->dev) {
@@ -1107,7 +1107,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
 					(rndis_set_msg_type *) buf);
 					(rndis_set_msg_type *) buf);
 
 
 	case REMOTE_NDIS_RESET_MSG:
 	case REMOTE_NDIS_RESET_MSG:
-		DEBUG("%s: REMOTE_NDIS_RESET_MSG\n",
+		DBG("%s: REMOTE_NDIS_RESET_MSG\n",
 			__FUNCTION__ );
 			__FUNCTION__ );
 		return rndis_reset_response (configNr,
 		return rndis_reset_response (configNr,
 					(rndis_reset_msg_type *) buf);
 					(rndis_reset_msg_type *) buf);
@@ -1115,7 +1115,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
 	case REMOTE_NDIS_KEEPALIVE_MSG:
 	case REMOTE_NDIS_KEEPALIVE_MSG:
 		/* For USB: host does this every 5 seconds */
 		/* For USB: host does this every 5 seconds */
 		if (rndis_debug > 1)
 		if (rndis_debug > 1)
-			DEBUG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n",
+			DBG("%s: REMOTE_NDIS_KEEPALIVE_MSG\n",
 				__FUNCTION__ );
 				__FUNCTION__ );
 		return rndis_keepalive_response (configNr,
 		return rndis_keepalive_response (configNr,
 						 (rndis_keepalive_msg_type *)
 						 (rndis_keepalive_msg_type *)
@@ -1132,7 +1132,7 @@ int rndis_msg_parser (u8 configNr, u8 *buf)
 		{
 		{
 			unsigned i;
 			unsigned i;
 			for (i = 0; i < MsgLength; i += 16) {
 			for (i = 0; i < MsgLength; i += 16) {
-				DEBUG ("%03d: "
+				DBG("%03d: "
 					" %02x %02x %02x %02x"
 					" %02x %02x %02x %02x"
 					" %02x %02x %02x %02x"
 					" %02x %02x %02x %02x"
 					" %02x %02x %02x %02x"
 					" %02x %02x %02x %02x"
@@ -1163,18 +1163,18 @@ int rndis_register (int (* rndis_control_ack) (struct net_device *))
 		if (!rndis_per_dev_params [i].used) {
 		if (!rndis_per_dev_params [i].used) {
 			rndis_per_dev_params [i].used = 1;
 			rndis_per_dev_params [i].used = 1;
 			rndis_per_dev_params [i].ack = rndis_control_ack;
 			rndis_per_dev_params [i].ack = rndis_control_ack;
-			DEBUG("%s: configNr = %d\n", __FUNCTION__, i);
+			DBG("%s: configNr = %d\n", __FUNCTION__, i);
 			return i;
 			return i;
 		}
 		}
 	}
 	}
-	DEBUG("failed\n");
+	DBG("failed\n");
 
 
 	return -1;
 	return -1;
 }
 }
 
 
 void rndis_deregister (int configNr)
 void rndis_deregister (int configNr)
 {
 {
-	DEBUG("%s: \n", __FUNCTION__ );
+	DBG("%s: \n", __FUNCTION__ );
 
 
 	if (configNr >= RNDIS_MAX_CONFIGS) return;
 	if (configNr >= RNDIS_MAX_CONFIGS) return;
 	rndis_per_dev_params [configNr].used = 0;
 	rndis_per_dev_params [configNr].used = 0;
@@ -1186,7 +1186,7 @@ int rndis_set_param_dev (u8 configNr, struct net_device *dev,
 			 struct net_device_stats *stats,
 			 struct net_device_stats *stats,
 			 u16 *cdc_filter)
 			 u16 *cdc_filter)
 {
 {
-	DEBUG("%s:\n", __FUNCTION__ );
+	DBG("%s:\n", __FUNCTION__ );
 	if (!dev || !stats) return -1;
 	if (!dev || !stats) return -1;
 	if (configNr >= RNDIS_MAX_CONFIGS) return -1;
 	if (configNr >= RNDIS_MAX_CONFIGS) return -1;
 
 
@@ -1199,7 +1199,7 @@ int rndis_set_param_dev (u8 configNr, struct net_device *dev,
 
 
 int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr)
 int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr)
 {
 {
-	DEBUG("%s:\n", __FUNCTION__ );
+	DBG("%s:\n", __FUNCTION__ );
 	if (!vendorDescr) return -1;
 	if (!vendorDescr) return -1;
 	if (configNr >= RNDIS_MAX_CONFIGS) return -1;
 	if (configNr >= RNDIS_MAX_CONFIGS) return -1;
 
 
@@ -1211,7 +1211,7 @@ int rndis_set_param_vendor (u8 configNr, u32 vendorID, const char *vendorDescr)
 
 
 int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed)
 int rndis_set_param_medium (u8 configNr, u32 medium, u32 speed)
 {
 {
-	DEBUG("%s: %u %u\n", __FUNCTION__, medium, speed);
+	DBG("%s: %u %u\n", __FUNCTION__, medium, speed);
 	if (configNr >= RNDIS_MAX_CONFIGS) return -1;
 	if (configNr >= RNDIS_MAX_CONFIGS) return -1;
 
 
 	rndis_per_dev_params [configNr].medium = medium;
 	rndis_per_dev_params [configNr].medium = medium;
@@ -1390,7 +1390,7 @@ static int rndis_proc_write (struct file *file, const char __user *buffer,
 			break;
 			break;
 		default:
 		default:
 			if (fl_speed) p->speed = speed;
 			if (fl_speed) p->speed = speed;
-			else DEBUG ("%c is not valid\n", c);
+			else DBG("%c is not valid\n", c);
 			break;
 			break;
 		}
 		}
 
 
@@ -1419,12 +1419,12 @@ int __devinit rndis_init (void)
 		if (!(rndis_connect_state [i]
 		if (!(rndis_connect_state [i]
 				= create_proc_entry (name, 0660, NULL)))
 				= create_proc_entry (name, 0660, NULL)))
 		{
 		{
-			DEBUG ("%s :remove entries", __FUNCTION__);
+			DBG("%s :remove entries", __FUNCTION__);
 			while (i) {
 			while (i) {
 				sprintf (name, NAME_TEMPLATE, --i);
 				sprintf (name, NAME_TEMPLATE, --i);
 				remove_proc_entry (name, NULL);
 				remove_proc_entry (name, NULL);
 			}
 			}
-			DEBUG ("\n");
+			DBG("\n");
 			return -EIO;
 			return -EIO;
 		}
 		}
 
 

+ 2045 - 0
drivers/usb/gadget/s3c2410_udc.c

@@ -0,0 +1,2045 @@
+/*
+ * linux/drivers/usb/gadget/s3c2410_udc.c
+ *
+ * Samsung S3C24xx series on-chip full speed USB device controllers
+ *
+ * Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard
+ *	Additional cleanups by Ben Dooks <ben-linux@fluff.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/version.h>
+#include <linux/clk.h>
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+#include <linux/usb.h>
+#include <linux/usb_gadget.h>
+
+#include <asm/byteorder.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+#include <asm/arch/irqs.h>
+
+#include <asm/arch/hardware.h>
+#include <asm/arch/regs-clock.h>
+#include <asm/arch/regs-gpio.h>
+#include <asm/arch/regs-udc.h>
+#include <asm/arch/udc.h>
+
+#include <asm/mach-types.h>
+
+#include "s3c2410_udc.h"
+
+#define DRIVER_DESC	"S3C2410 USB Device Controller Gadget"
+#define DRIVER_VERSION	"29 Apr 2007"
+#define DRIVER_AUTHOR	"Herbert Pötzl <herbert@13thfloor.at>, " \
+			"Arnaud Patard <arnaud.patard@rtp-net.org>"
+
+static const char		gadget_name[] = "s3c2410_udc";
+static const char		driver_desc[] = DRIVER_DESC;
+
+static struct s3c2410_udc	*the_controller;
+static struct clk		*udc_clock;
+static struct clk		*usb_bus_clock;
+static void __iomem		*base_addr;
+static u64			rsrc_start;
+static u64			rsrc_len;
+static struct dentry		*s3c2410_udc_debugfs_root;
+
+static inline u32 udc_read(u32 reg)
+{
+	return readb(base_addr + reg);
+}
+
+static inline void udc_write(u32 value, u32 reg)
+{
+	writeb(value, base_addr + reg);
+}
+
+static inline void udc_writeb(void __iomem *base, u32 value, u32 reg)
+{
+	writeb(value, base + reg);
+}
+
+static struct s3c2410_udc_mach_info *udc_info;
+
+/*************************** DEBUG FUNCTION ***************************/
+#define DEBUG_NORMAL	1
+#define DEBUG_VERBOSE	2
+
+#ifdef CONFIG_USB_S3C2410_DEBUG
+#define USB_S3C2410_DEBUG_LEVEL 0
+
+static uint32_t s3c2410_ticks = 0;
+
+static int dprintk(int level, const char *fmt, ...)
+{
+	static char printk_buf[1024];
+	static long prevticks;
+	static int invocation;
+	va_list args;
+	int len;
+
+	if (level > USB_S3C2410_DEBUG_LEVEL)
+		return 0;
+
+	if (s3c2410_ticks != prevticks) {
+		prevticks = s3c2410_ticks;
+		invocation = 0;
+	}
+
+	len = scnprintf(printk_buf,
+			sizeof(printk_buf), "%1lu.%02d USB: ",
+			prevticks, invocation++);
+
+	va_start(args, fmt);
+	len = vscnprintf(printk_buf+len,
+			sizeof(printk_buf)-len, fmt, args);
+	va_end(args);
+
+	return printk(KERN_DEBUG "%s", printk_buf);
+}
+#else
+static int dprintk(int level, const char *fmt, ...)
+{
+	return 0;
+}
+#endif
+static int s3c2410_udc_debugfs_seq_show(struct seq_file *m, void *p)
+{
+	u32 addr_reg,pwr_reg,ep_int_reg,usb_int_reg;
+	u32 ep_int_en_reg, usb_int_en_reg, ep0_csr;
+	u32 ep1_i_csr1,ep1_i_csr2,ep1_o_csr1,ep1_o_csr2;
+	u32 ep2_i_csr1,ep2_i_csr2,ep2_o_csr1,ep2_o_csr2;
+
+	addr_reg       = udc_read(S3C2410_UDC_FUNC_ADDR_REG);
+	pwr_reg        = udc_read(S3C2410_UDC_PWR_REG);
+	ep_int_reg     = udc_read(S3C2410_UDC_EP_INT_REG);
+	usb_int_reg    = udc_read(S3C2410_UDC_USB_INT_REG);
+	ep_int_en_reg  = udc_read(S3C2410_UDC_EP_INT_EN_REG);
+	usb_int_en_reg = udc_read(S3C2410_UDC_USB_INT_EN_REG);
+	udc_write(0, S3C2410_UDC_INDEX_REG);
+	ep0_csr        = udc_read(S3C2410_UDC_IN_CSR1_REG);
+	udc_write(1, S3C2410_UDC_INDEX_REG);
+	ep1_i_csr1     = udc_read(S3C2410_UDC_IN_CSR1_REG);
+	ep1_i_csr2     = udc_read(S3C2410_UDC_IN_CSR2_REG);
+	ep1_o_csr1     = udc_read(S3C2410_UDC_IN_CSR1_REG);
+	ep1_o_csr2     = udc_read(S3C2410_UDC_IN_CSR2_REG);
+	udc_write(2, S3C2410_UDC_INDEX_REG);
+	ep2_i_csr1     = udc_read(S3C2410_UDC_IN_CSR1_REG);
+	ep2_i_csr2     = udc_read(S3C2410_UDC_IN_CSR2_REG);
+	ep2_o_csr1     = udc_read(S3C2410_UDC_IN_CSR1_REG);
+	ep2_o_csr2     = udc_read(S3C2410_UDC_IN_CSR2_REG);
+
+	seq_printf(m, "FUNC_ADDR_REG  : 0x%04X\n"
+		 "PWR_REG        : 0x%04X\n"
+		 "EP_INT_REG     : 0x%04X\n"
+		 "USB_INT_REG    : 0x%04X\n"
+		 "EP_INT_EN_REG  : 0x%04X\n"
+		 "USB_INT_EN_REG : 0x%04X\n"
+		 "EP0_CSR        : 0x%04X\n"
+		 "EP1_I_CSR1     : 0x%04X\n"
+		 "EP1_I_CSR2     : 0x%04X\n"
+		 "EP1_O_CSR1     : 0x%04X\n"
+		 "EP1_O_CSR2     : 0x%04X\n"
+		 "EP2_I_CSR1     : 0x%04X\n"
+		 "EP2_I_CSR2     : 0x%04X\n"
+		 "EP2_O_CSR1     : 0x%04X\n"
+		 "EP2_O_CSR2     : 0x%04X\n",
+			addr_reg,pwr_reg,ep_int_reg,usb_int_reg,
+			ep_int_en_reg, usb_int_en_reg, ep0_csr,
+			ep1_i_csr1,ep1_i_csr2,ep1_o_csr1,ep1_o_csr2,
+			ep2_i_csr1,ep2_i_csr2,ep2_o_csr1,ep2_o_csr2
+		);
+
+	return 0;
+}
+
+static int s3c2410_udc_debugfs_fops_open(struct inode *inode,
+					 struct file *file)
+{
+	return single_open(file, s3c2410_udc_debugfs_seq_show, NULL);
+}
+
+static const struct file_operations s3c2410_udc_debugfs_fops = {
+	.open		= s3c2410_udc_debugfs_fops_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= single_release,
+	.owner		= THIS_MODULE,
+};
+
+/* io macros */
+
+static inline void s3c2410_udc_clear_ep0_opr(void __iomem *base)
+{
+	udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+	udc_writeb(base, S3C2410_UDC_EP0_CSR_SOPKTRDY,
+			S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_clear_ep0_sst(void __iomem *base)
+{
+	udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+	writeb(0x00, base + S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_clear_ep0_se(void __iomem *base)
+{
+	udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+	udc_writeb(base, S3C2410_UDC_EP0_CSR_SSE, S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_set_ep0_ipr(void __iomem *base)
+{
+	udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+	udc_writeb(base, S3C2410_UDC_EP0_CSR_IPKRDY, S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_set_ep0_de(void __iomem *base)
+{
+	udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+	udc_writeb(base, S3C2410_UDC_EP0_CSR_DE, S3C2410_UDC_EP0_CSR_REG);
+}
+
+inline void s3c2410_udc_set_ep0_ss(void __iomem *b)
+{
+	udc_writeb(b, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+	udc_writeb(b, S3C2410_UDC_EP0_CSR_SENDSTL, S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_set_ep0_de_out(void __iomem *base)
+{
+	udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+
+	udc_writeb(base,(S3C2410_UDC_EP0_CSR_SOPKTRDY
+				| S3C2410_UDC_EP0_CSR_DE),
+			S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_set_ep0_sse_out(void __iomem *base)
+{
+	udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+	udc_writeb(base, (S3C2410_UDC_EP0_CSR_SOPKTRDY
+				| S3C2410_UDC_EP0_CSR_SSE),
+			S3C2410_UDC_EP0_CSR_REG);
+}
+
+static inline void s3c2410_udc_set_ep0_de_in(void __iomem *base)
+{
+	udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+	udc_writeb(base, (S3C2410_UDC_EP0_CSR_IPKRDY
+			| S3C2410_UDC_EP0_CSR_DE),
+		S3C2410_UDC_EP0_CSR_REG);
+}
+
+/*------------------------- I/O ----------------------------------*/
+
+/*
+ *	s3c2410_udc_done
+ */
+static void s3c2410_udc_done(struct s3c2410_ep *ep,
+		struct s3c2410_request *req, int status)
+{
+	unsigned halted = ep->halted;
+
+	list_del_init(&req->queue);
+
+	if (likely (req->req.status == -EINPROGRESS))
+		req->req.status = status;
+	else
+		status = req->req.status;
+
+	ep->halted = 1;
+	req->req.complete(&ep->ep, &req->req);
+	ep->halted = halted;
+}
+
+static void s3c2410_udc_nuke(struct s3c2410_udc *udc,
+		struct s3c2410_ep *ep, int status)
+{
+	/* Sanity check */
+	if (&ep->queue == NULL)
+		return;
+
+	while (!list_empty (&ep->queue)) {
+		struct s3c2410_request *req;
+		req = list_entry (ep->queue.next, struct s3c2410_request,
+				queue);
+		s3c2410_udc_done(ep, req, status);
+	}
+}
+
+static inline void s3c2410_udc_clear_ep_state(struct s3c2410_udc *dev)
+{
+	unsigned i;
+
+	/* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint
+	 * fifos, and pending transactions mustn't be continued in any case.
+	 */
+
+	for (i = 1; i < S3C2410_ENDPOINTS; i++)
+		s3c2410_udc_nuke(dev, &dev->ep[i], -ECONNABORTED);
+}
+
+static inline int s3c2410_udc_fifo_count_out(void)
+{
+	int tmp;
+
+	tmp = udc_read(S3C2410_UDC_OUT_FIFO_CNT2_REG) << 8;
+	tmp |= udc_read(S3C2410_UDC_OUT_FIFO_CNT1_REG);
+	return tmp;
+}
+
+/*
+ *	s3c2410_udc_write_packet
+ */
+static inline int s3c2410_udc_write_packet(int fifo,
+		struct s3c2410_request *req,
+		unsigned max)
+{
+	unsigned len = min(req->req.length - req->req.actual, max);
+	u8 *buf = req->req.buf + req->req.actual;
+
+	prefetch(buf);
+
+	dprintk(DEBUG_VERBOSE, "%s %d %d %d %d\n", __func__,
+		req->req.actual, req->req.length, len, req->req.actual + len);
+
+	req->req.actual += len;
+
+	udelay(5);
+	writesb(base_addr + fifo, buf, len);
+	return len;
+}
+
+/*
+ *	s3c2410_udc_write_fifo
+ *
+ * return:  0 = still running, 1 = completed, negative = errno
+ */
+static int s3c2410_udc_write_fifo(struct s3c2410_ep *ep,
+		struct s3c2410_request *req)
+{
+	unsigned	count;
+	int		is_last;
+	u32		idx;
+	int		fifo_reg;
+	u32		ep_csr;
+
+	idx = ep->bEndpointAddress & 0x7F;
+	switch (idx) {
+	default:
+		idx = 0;
+	case 0:
+		fifo_reg = S3C2410_UDC_EP0_FIFO_REG;
+		break;
+	case 1:
+		fifo_reg = S3C2410_UDC_EP1_FIFO_REG;
+		break;
+	case 2:
+		fifo_reg = S3C2410_UDC_EP2_FIFO_REG;
+		break;
+	case 3:
+		fifo_reg = S3C2410_UDC_EP3_FIFO_REG;
+		break;
+	case 4:
+		fifo_reg = S3C2410_UDC_EP4_FIFO_REG;
+		break;
+	}
+
+	count = s3c2410_udc_write_packet(fifo_reg, req, ep->ep.maxpacket);
+
+	/* last packet is often short (sometimes a zlp) */
+	if (count != ep->ep.maxpacket)
+		is_last = 1;
+	else if (req->req.length != req->req.actual || req->req.zero)
+		is_last = 0;
+	else
+		is_last = 2;
+
+	/* Only ep0 debug messages are interesting */
+	if (idx == 0)
+		dprintk(DEBUG_NORMAL,
+			"Written ep%d %d.%d of %d b [last %d,z %d]\n",
+			idx, count, req->req.actual, req->req.length,
+			is_last, req->req.zero);
+
+	if (is_last) {
+		/* The order is important. It prevents sending 2 packets
+		 * at the same time */
+
+		if (idx == 0) {
+			/* Reset signal => no need to say 'data sent' */
+			if (! (udc_read(S3C2410_UDC_USB_INT_REG)
+					& S3C2410_UDC_USBINT_RESET))
+				s3c2410_udc_set_ep0_de_in(base_addr);
+			ep->dev->ep0state=EP0_IDLE;
+		} else {
+			udc_write(idx, S3C2410_UDC_INDEX_REG);
+			ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
+			udc_write(idx, S3C2410_UDC_INDEX_REG);
+			udc_write(ep_csr | S3C2410_UDC_ICSR1_PKTRDY,
+					S3C2410_UDC_IN_CSR1_REG);
+		}
+
+		s3c2410_udc_done(ep, req, 0);
+		is_last = 1;
+	} else {
+		if (idx == 0) {
+			/* Reset signal => no need to say 'data sent' */
+			if (! (udc_read(S3C2410_UDC_USB_INT_REG)
+					& S3C2410_UDC_USBINT_RESET))
+				s3c2410_udc_set_ep0_ipr(base_addr);
+		} else {
+			udc_write(idx, S3C2410_UDC_INDEX_REG);
+			ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
+			udc_write(idx, S3C2410_UDC_INDEX_REG);
+			udc_write(ep_csr | S3C2410_UDC_ICSR1_PKTRDY,
+					S3C2410_UDC_IN_CSR1_REG);
+		}
+	}
+
+	return is_last;
+}
+
+static inline int s3c2410_udc_read_packet(int fifo, u8 *buf,
+		struct s3c2410_request *req, unsigned avail)
+{
+	unsigned len;
+
+	len = min(req->req.length - req->req.actual, avail);
+	req->req.actual += len;
+
+	readsb(fifo + base_addr, buf, len);
+	return len;
+}
+
+/*
+ * return:  0 = still running, 1 = queue empty, negative = errno
+ */
+static int s3c2410_udc_read_fifo(struct s3c2410_ep *ep,
+				 struct s3c2410_request *req)
+{
+	u8		*buf;
+	u32		ep_csr;
+	unsigned	bufferspace;
+	int		is_last=1;
+	unsigned	avail;
+	int		fifo_count = 0;
+	u32		idx;
+	int		fifo_reg;
+
+	idx = ep->bEndpointAddress & 0x7F;
+
+	switch (idx) {
+	default:
+		idx = 0;
+	case 0:
+		fifo_reg = S3C2410_UDC_EP0_FIFO_REG;
+		break;
+	case 1:
+		fifo_reg = S3C2410_UDC_EP1_FIFO_REG;
+		break;
+	case 2:
+		fifo_reg = S3C2410_UDC_EP2_FIFO_REG;
+		break;
+	case 3:
+		fifo_reg = S3C2410_UDC_EP3_FIFO_REG;
+		break;
+	case 4:
+		fifo_reg = S3C2410_UDC_EP4_FIFO_REG;
+		break;
+	}
+
+	if (!req->req.length)
+		return 1;
+
+	buf = req->req.buf + req->req.actual;
+	bufferspace = req->req.length - req->req.actual;
+	if (!bufferspace) {
+		dprintk(DEBUG_NORMAL, "%s: buffer full!\n", __func__);
+		return -1;
+	}
+
+	udc_write(idx, S3C2410_UDC_INDEX_REG);
+
+	fifo_count = s3c2410_udc_fifo_count_out();
+	dprintk(DEBUG_NORMAL, "%s fifo count : %d\n", __func__, fifo_count);
+
+	if (fifo_count > ep->ep.maxpacket)
+		avail = ep->ep.maxpacket;
+	else
+		avail = fifo_count;
+
+	fifo_count = s3c2410_udc_read_packet(fifo_reg, buf, req, avail);
+
+	/* checking this with ep0 is not accurate as we already
+	 * read a control request
+	 **/
+	if (idx != 0 && fifo_count < ep->ep.maxpacket) {
+		is_last = 1;
+		/* overflowed this request?  flush extra data */
+		if (fifo_count != avail)
+			req->req.status = -EOVERFLOW;
+	} else {
+		is_last = (req->req.length <= req->req.actual) ? 1 : 0;
+	}
+
+	udc_write(idx, S3C2410_UDC_INDEX_REG);
+	fifo_count = s3c2410_udc_fifo_count_out();
+
+	/* Only ep0 debug messages are interesting */
+	if (idx == 0)
+		dprintk(DEBUG_VERBOSE, "%s fifo count : %d [last %d]\n",
+			__func__, fifo_count,is_last);
+
+	if (is_last) {
+		if (idx == 0) {
+			s3c2410_udc_set_ep0_de_out(base_addr);
+			ep->dev->ep0state = EP0_IDLE;
+		} else {
+			udc_write(idx, S3C2410_UDC_INDEX_REG);
+			ep_csr = udc_read(S3C2410_UDC_OUT_CSR1_REG);
+			udc_write(idx, S3C2410_UDC_INDEX_REG);
+			udc_write(ep_csr & ~S3C2410_UDC_OCSR1_PKTRDY,
+					S3C2410_UDC_OUT_CSR1_REG);
+		}
+
+		s3c2410_udc_done(ep, req, 0);
+	} else {
+		if (idx == 0) {
+			s3c2410_udc_clear_ep0_opr(base_addr);
+		} else {
+			udc_write(idx, S3C2410_UDC_INDEX_REG);
+			ep_csr = udc_read(S3C2410_UDC_OUT_CSR1_REG);
+			udc_write(idx, S3C2410_UDC_INDEX_REG);
+			udc_write(ep_csr & ~S3C2410_UDC_OCSR1_PKTRDY,
+					S3C2410_UDC_OUT_CSR1_REG);
+		}
+	}
+
+	return is_last;
+}
+
+static int s3c2410_udc_read_fifo_crq(struct usb_ctrlrequest *crq)
+{
+	unsigned char *outbuf = (unsigned char*)crq;
+	int bytes_read = 0;
+
+	udc_write(0, S3C2410_UDC_INDEX_REG);
+
+	bytes_read = s3c2410_udc_fifo_count_out();
+
+	dprintk(DEBUG_NORMAL, "%s: fifo_count=%d\n", __func__, bytes_read);
+
+	if (bytes_read > sizeof(struct usb_ctrlrequest))
+		bytes_read = sizeof(struct usb_ctrlrequest);
+
+	readsb(S3C2410_UDC_EP0_FIFO_REG + base_addr, outbuf, bytes_read);
+
+	dprintk(DEBUG_VERBOSE, "%s: len=%d %02x:%02x {%x,%x,%x}\n", __func__,
+		bytes_read, crq->bRequest, crq->bRequestType,
+		crq->wValue, crq->wIndex, crq->wLength);
+
+	return bytes_read;
+}
+
+static int s3c2410_udc_get_status(struct s3c2410_udc *dev,
+		struct usb_ctrlrequest *crq)
+{
+	u16 status = 0;
+	u8 ep_num = crq->wIndex & 0x7F;
+	u8 is_in = crq->wIndex & USB_DIR_IN;
+
+	switch (crq->bRequestType & USB_RECIP_MASK) {
+	case USB_RECIP_INTERFACE:
+		break;
+
+	case USB_RECIP_DEVICE:
+		status = dev->devstatus;
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		if (ep_num > 4 || crq->wLength > 2)
+			return 1;
+
+		if (ep_num == 0) {
+			udc_write(0, S3C2410_UDC_INDEX_REG);
+			status = udc_read(S3C2410_UDC_IN_CSR1_REG);
+			status = status & S3C2410_UDC_EP0_CSR_SENDSTL;
+		} else {
+			udc_write(ep_num, S3C2410_UDC_INDEX_REG);
+			if (is_in) {
+				status = udc_read(S3C2410_UDC_IN_CSR1_REG);
+				status = status & S3C2410_UDC_ICSR1_SENDSTL;
+			} else {
+				status = udc_read(S3C2410_UDC_OUT_CSR1_REG);
+				status = status & S3C2410_UDC_OCSR1_SENDSTL;
+			}
+		}
+
+		status = status ? 1 : 0;
+		break;
+
+	default:
+		return 1;
+	}
+
+	/* Seems to be needed to get it working. ouch :( */
+	udelay(5);
+	udc_write(status & 0xFF, S3C2410_UDC_EP0_FIFO_REG);
+	udc_write(status >> 8, S3C2410_UDC_EP0_FIFO_REG);
+	s3c2410_udc_set_ep0_de_in(base_addr);
+
+	return 0;
+}
+/*------------------------- usb state machine -------------------------------*/
+static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value);
+
+static void s3c2410_udc_handle_ep0_idle(struct s3c2410_udc *dev,
+					struct s3c2410_ep *ep,
+					struct usb_ctrlrequest *crq,
+					u32 ep0csr)
+{
+	int len, ret, tmp;
+
+	/* start control request? */
+	if (!(ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY))
+		return;
+
+	s3c2410_udc_nuke(dev, ep, -EPROTO);
+
+	len = s3c2410_udc_read_fifo_crq(crq);
+	if (len != sizeof(*crq)) {
+		dprintk(DEBUG_NORMAL, "setup begin: fifo READ ERROR"
+			" wanted %d bytes got %d. Stalling out...\n",
+			sizeof(*crq), len);
+		s3c2410_udc_set_ep0_ss(base_addr);
+		return;
+	}
+
+	dprintk(DEBUG_NORMAL, "bRequest = %d bRequestType %d wLength = %d\n",
+		crq->bRequest, crq->bRequestType, crq->wLength);
+
+	/* cope with automagic for some standard requests. */
+	dev->req_std = (crq->bRequestType & USB_TYPE_MASK)
+		== USB_TYPE_STANDARD;
+	dev->req_config = 0;
+	dev->req_pending = 1;
+
+	switch (crq->bRequest) {
+	case USB_REQ_SET_CONFIGURATION:
+		dprintk(DEBUG_NORMAL, "USB_REQ_SET_CONFIGURATION ... \n");
+
+		if (crq->bRequestType == USB_RECIP_DEVICE) {
+			dev->req_config = 1;
+			s3c2410_udc_set_ep0_de_out(base_addr);
+		}
+		break;
+
+	case USB_REQ_SET_INTERFACE:
+		dprintk(DEBUG_NORMAL, "USB_REQ_SET_INTERFACE ... \n");
+
+		if (crq->bRequestType == USB_RECIP_INTERFACE) {
+			dev->req_config = 1;
+			s3c2410_udc_set_ep0_de_out(base_addr);
+		}
+		break;
+
+	case USB_REQ_SET_ADDRESS:
+		dprintk(DEBUG_NORMAL, "USB_REQ_SET_ADDRESS ... \n");
+
+		if (crq->bRequestType == USB_RECIP_DEVICE) {
+			tmp = crq->wValue & 0x7F;
+			dev->address = tmp;
+			udc_write((tmp | S3C2410_UDC_FUNCADDR_UPDATE),
+					S3C2410_UDC_FUNC_ADDR_REG);
+			s3c2410_udc_set_ep0_de_out(base_addr);
+			return;
+		}
+		break;
+
+	case USB_REQ_GET_STATUS:
+		dprintk(DEBUG_NORMAL, "USB_REQ_GET_STATUS ... \n");
+		s3c2410_udc_clear_ep0_opr(base_addr);
+
+		if (dev->req_std) {
+			if (!s3c2410_udc_get_status(dev, crq)) {
+				return;
+			}
+		}
+		break;
+
+	case USB_REQ_CLEAR_FEATURE:
+		s3c2410_udc_clear_ep0_opr(base_addr);
+
+		if (crq->bRequestType != USB_RECIP_ENDPOINT)
+			break;
+
+		if (crq->wValue != USB_ENDPOINT_HALT || crq->wLength != 0)
+			break;
+
+		s3c2410_udc_set_halt(&dev->ep[crq->wIndex & 0x7f].ep, 0);
+		s3c2410_udc_set_ep0_de_out(base_addr);
+		return;
+
+	case USB_REQ_SET_FEATURE:
+		s3c2410_udc_clear_ep0_opr(base_addr);
+
+		if (crq->bRequestType != USB_RECIP_ENDPOINT)
+			break;
+
+		if (crq->wValue != USB_ENDPOINT_HALT || crq->wLength != 0)
+			break;
+
+		s3c2410_udc_set_halt(&dev->ep[crq->wIndex & 0x7f].ep, 1);
+		s3c2410_udc_set_ep0_de_out(base_addr);
+		return;
+
+	default:
+		s3c2410_udc_clear_ep0_opr(base_addr);
+		break;
+	}
+
+	if (crq->bRequestType & USB_DIR_IN)
+		dev->ep0state = EP0_IN_DATA_PHASE;
+	else
+		dev->ep0state = EP0_OUT_DATA_PHASE;
+
+	ret = dev->driver->setup(&dev->gadget, crq);
+	if (ret < 0) {
+		if (dev->req_config) {
+			dprintk(DEBUG_NORMAL, "config change %02x fail %d?\n",
+				crq->bRequest, ret);
+			return;
+		}
+
+		if (ret == -EOPNOTSUPP)
+			dprintk(DEBUG_NORMAL, "Operation not supported\n");
+		else
+			dprintk(DEBUG_NORMAL,
+				"dev->driver->setup failed. (%d)\n", ret);
+
+		udelay(5);
+		s3c2410_udc_set_ep0_ss(base_addr);
+		s3c2410_udc_set_ep0_de_out(base_addr);
+		dev->ep0state = EP0_IDLE;
+		/* deferred i/o == no response yet */
+	} else if (dev->req_pending) {
+		dprintk(DEBUG_VERBOSE, "dev->req_pending... what now?\n");
+		dev->req_pending=0;
+	}
+
+	dprintk(DEBUG_VERBOSE, "ep0state %s\n", ep0states[dev->ep0state]);
+}
+
+static void s3c2410_udc_handle_ep0(struct s3c2410_udc *dev)
+{
+	u32			ep0csr;
+	struct s3c2410_ep	*ep = &dev->ep[0];
+	struct s3c2410_request	*req;
+	struct usb_ctrlrequest	crq;
+
+	if (list_empty(&ep->queue))
+		req = NULL;
+	else
+		req = list_entry(ep->queue.next, struct s3c2410_request, queue);
+
+	/* We make the assumption that S3C2410_UDC_IN_CSR1_REG equal to
+	 * S3C2410_UDC_EP0_CSR_REG when index is zero */
+
+	udc_write(0, S3C2410_UDC_INDEX_REG);
+	ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
+
+	dprintk(DEBUG_NORMAL, "ep0csr %x ep0state %s\n",
+		ep0csr, ep0states[dev->ep0state]);
+
+	/* clear stall status */
+	if (ep0csr & S3C2410_UDC_EP0_CSR_SENTSTL) {
+		s3c2410_udc_nuke(dev, ep, -EPIPE);
+		dprintk(DEBUG_NORMAL, "... clear SENT_STALL ...\n");
+		s3c2410_udc_clear_ep0_sst(base_addr);
+		dev->ep0state = EP0_IDLE;
+		return;
+	}
+
+	/* clear setup end */
+	if (ep0csr & S3C2410_UDC_EP0_CSR_SE) {
+		dprintk(DEBUG_NORMAL, "... serviced SETUP_END ...\n");
+		s3c2410_udc_nuke(dev, ep, 0);
+		s3c2410_udc_clear_ep0_se(base_addr);
+		dev->ep0state = EP0_IDLE;
+	}
+
+	switch (dev->ep0state) {
+	case EP0_IDLE:
+		s3c2410_udc_handle_ep0_idle(dev, ep, &crq, ep0csr);
+		break;
+
+	case EP0_IN_DATA_PHASE:			/* GET_DESCRIPTOR etc */
+		dprintk(DEBUG_NORMAL, "EP0_IN_DATA_PHASE ... what now?\n");
+		if (!(ep0csr & S3C2410_UDC_EP0_CSR_IPKRDY) && req) {
+			s3c2410_udc_write_fifo(ep, req);
+		}
+		break;
+
+	case EP0_OUT_DATA_PHASE:		/* SET_DESCRIPTOR etc */
+		dprintk(DEBUG_NORMAL, "EP0_OUT_DATA_PHASE ... what now?\n");
+		if ((ep0csr & S3C2410_UDC_EP0_CSR_OPKRDY) && req ) {
+			s3c2410_udc_read_fifo(ep,req);
+		}
+		break;
+
+	case EP0_END_XFER:
+		dprintk(DEBUG_NORMAL, "EP0_END_XFER ... what now?\n");
+		dev->ep0state = EP0_IDLE;
+		break;
+
+	case EP0_STALL:
+		dprintk(DEBUG_NORMAL, "EP0_STALL ... what now?\n");
+		dev->ep0state = EP0_IDLE;
+		break;
+	}
+}
+
+/*
+ *	handle_ep - Manage I/O endpoints
+ */
+
+static void s3c2410_udc_handle_ep(struct s3c2410_ep *ep)
+{
+	struct s3c2410_request	*req;
+	int			is_in = ep->bEndpointAddress & USB_DIR_IN;
+	u32			ep_csr1;
+	u32			idx;
+
+	if (likely (!list_empty(&ep->queue)))
+		req = list_entry(ep->queue.next,
+				struct s3c2410_request, queue);
+	else
+		req = NULL;
+
+	idx = ep->bEndpointAddress & 0x7F;
+
+	if (is_in) {
+		udc_write(idx, S3C2410_UDC_INDEX_REG);
+		ep_csr1 = udc_read(S3C2410_UDC_IN_CSR1_REG);
+		dprintk(DEBUG_VERBOSE, "ep%01d write csr:%02x %d\n",
+			idx, ep_csr1, req ? 1 : 0);
+
+		if (ep_csr1 & S3C2410_UDC_ICSR1_SENTSTL) {
+			dprintk(DEBUG_VERBOSE, "st\n");
+			udc_write(idx, S3C2410_UDC_INDEX_REG);
+			udc_write(ep_csr1 & ~S3C2410_UDC_ICSR1_SENTSTL,
+					S3C2410_UDC_IN_CSR1_REG);
+			return;
+		}
+
+		if (!(ep_csr1 & S3C2410_UDC_ICSR1_PKTRDY) && req) {
+			s3c2410_udc_write_fifo(ep,req);
+		}
+	} else {
+		udc_write(idx, S3C2410_UDC_INDEX_REG);
+		ep_csr1 = udc_read(S3C2410_UDC_OUT_CSR1_REG);
+		dprintk(DEBUG_VERBOSE, "ep%01d rd csr:%02x\n", idx, ep_csr1);
+
+		if (ep_csr1 & S3C2410_UDC_OCSR1_SENTSTL) {
+			udc_write(idx, S3C2410_UDC_INDEX_REG);
+			udc_write(ep_csr1 & ~S3C2410_UDC_OCSR1_SENTSTL,
+					S3C2410_UDC_OUT_CSR1_REG);
+			return;
+		}
+
+		if ((ep_csr1 & S3C2410_UDC_OCSR1_PKTRDY) && req) {
+			s3c2410_udc_read_fifo(ep,req);
+		}
+	}
+}
+
+#include <asm/arch/regs-irq.h>
+
+/*
+ *	s3c2410_udc_irq - interrupt handler
+ */
+static irqreturn_t s3c2410_udc_irq(int irq, void *_dev)
+{
+	struct s3c2410_udc *dev = _dev;
+	int usb_status;
+	int usbd_status;
+	int pwr_reg;
+	int ep0csr;
+	int i;
+	u32 idx;
+	unsigned long flags;
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	/* Driver connected ? */
+	if (!dev->driver) {
+		/* Clear interrupts */
+		udc_write(udc_read(S3C2410_UDC_USB_INT_REG),
+				S3C2410_UDC_USB_INT_REG);
+		udc_write(udc_read(S3C2410_UDC_EP_INT_REG),
+				S3C2410_UDC_EP_INT_REG);
+	}
+
+	/* Save index */
+	idx = udc_read(S3C2410_UDC_INDEX_REG);
+
+	/* Read status registers */
+	usb_status = udc_read(S3C2410_UDC_USB_INT_REG);
+	usbd_status = udc_read(S3C2410_UDC_EP_INT_REG);
+	pwr_reg = udc_read(S3C2410_UDC_PWR_REG);
+
+	udc_writeb(base_addr, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
+	ep0csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
+
+	dprintk(DEBUG_NORMAL, "usbs=%02x, usbds=%02x, pwr=%02x ep0csr=%02x\n",
+		usb_status, usbd_status, pwr_reg, ep0csr);
+
+	/*
+	 * Now, handle interrupts. There's two types :
+	 * - Reset, Resume, Suspend coming -> usb_int_reg
+	 * - EP -> ep_int_reg
+	 */
+
+	/* RESET */
+	if (usb_status & S3C2410_UDC_USBINT_RESET) {
+		/* two kind of reset :
+		 * - reset start -> pwr reg = 8
+		 * - reset end   -> pwr reg = 0
+		 **/
+		dprintk(DEBUG_NORMAL, "USB reset csr %x pwr %x\n",
+			ep0csr, pwr_reg);
+
+		dev->gadget.speed = USB_SPEED_UNKNOWN;
+		udc_write(0x00, S3C2410_UDC_INDEX_REG);
+		udc_write((dev->ep[0].ep.maxpacket & 0x7ff) >> 3,
+				S3C2410_UDC_MAXP_REG);
+		dev->address = 0;
+
+		dev->ep0state = EP0_IDLE;
+		dev->gadget.speed = USB_SPEED_FULL;
+
+		/* clear interrupt */
+		udc_write(S3C2410_UDC_USBINT_RESET,
+				S3C2410_UDC_USB_INT_REG);
+
+		udc_write(idx, S3C2410_UDC_INDEX_REG);
+		spin_unlock_irqrestore(&dev->lock, flags);
+		return IRQ_HANDLED;
+	}
+
+	/* RESUME */
+	if (usb_status & S3C2410_UDC_USBINT_RESUME) {
+		dprintk(DEBUG_NORMAL, "USB resume\n");
+
+		/* clear interrupt */
+		udc_write(S3C2410_UDC_USBINT_RESUME,
+				S3C2410_UDC_USB_INT_REG);
+
+		if (dev->gadget.speed != USB_SPEED_UNKNOWN
+				&& dev->driver
+				&& dev->driver->resume)
+			dev->driver->resume(&dev->gadget);
+	}
+
+	/* SUSPEND */
+	if (usb_status & S3C2410_UDC_USBINT_SUSPEND) {
+		dprintk(DEBUG_NORMAL, "USB suspend\n");
+
+		/* clear interrupt */
+		udc_write(S3C2410_UDC_USBINT_SUSPEND,
+				S3C2410_UDC_USB_INT_REG);
+
+		if (dev->gadget.speed != USB_SPEED_UNKNOWN
+				&& dev->driver
+				&& dev->driver->suspend)
+			dev->driver->suspend(&dev->gadget);
+
+		dev->ep0state = EP0_IDLE;
+	}
+
+	/* EP */
+	/* control traffic */
+	/* check on ep0csr != 0 is not a good idea as clearing in_pkt_ready
+	 * generate an interrupt
+	 */
+	if (usbd_status & S3C2410_UDC_INT_EP0) {
+		dprintk(DEBUG_VERBOSE, "USB ep0 irq\n");
+		/* Clear the interrupt bit by setting it to 1 */
+		udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_REG);
+		s3c2410_udc_handle_ep0(dev);
+	}
+
+	/* endpoint data transfers */
+	for (i = 1; i < S3C2410_ENDPOINTS; i++) {
+		u32 tmp = 1 << i;
+		if (usbd_status & tmp) {
+			dprintk(DEBUG_VERBOSE, "USB ep%d irq\n", i);
+
+			/* Clear the interrupt bit by setting it to 1 */
+			udc_write(tmp, S3C2410_UDC_EP_INT_REG);
+			s3c2410_udc_handle_ep(&dev->ep[i]);
+		}
+	}
+
+	dprintk(DEBUG_VERBOSE, "irq: %d s3c2410_udc_done.\n", irq);
+
+	/* Restore old index */
+	udc_write(idx, S3C2410_UDC_INDEX_REG);
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return IRQ_HANDLED;
+}
+/*------------------------- s3c2410_ep_ops ----------------------------------*/
+
+static inline struct s3c2410_ep *to_s3c2410_ep(struct usb_ep *ep)
+{
+	return container_of(ep, struct s3c2410_ep, ep);
+}
+
+static inline struct s3c2410_udc *to_s3c2410_udc(struct usb_gadget *gadget)
+{
+	return container_of(gadget, struct s3c2410_udc, gadget);
+}
+
+static inline struct s3c2410_request *to_s3c2410_req(struct usb_request *req)
+{
+	return container_of(req, struct s3c2410_request, req);
+}
+
+/*
+ *	s3c2410_udc_ep_enable
+ */
+static int s3c2410_udc_ep_enable(struct usb_ep *_ep,
+				 const struct usb_endpoint_descriptor *desc)
+{
+	struct s3c2410_udc	*dev;
+	struct s3c2410_ep	*ep;
+	u32			max, tmp;
+	unsigned long		flags;
+	u32			csr1,csr2;
+	u32			int_en_reg;
+
+	ep = to_s3c2410_ep(_ep);
+
+	if (!_ep || !desc || ep->desc
+			|| _ep->name == ep0name
+			|| desc->bDescriptorType != USB_DT_ENDPOINT)
+		return -EINVAL;
+
+	dev = ep->dev;
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	max = le16_to_cpu(desc->wMaxPacketSize) & 0x1fff;
+
+	local_irq_save (flags);
+	_ep->maxpacket = max & 0x7ff;
+	ep->desc = desc;
+	ep->halted = 0;
+	ep->bEndpointAddress = desc->bEndpointAddress;
+
+	/* set max packet */
+	udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+	udc_write(max >> 3, S3C2410_UDC_MAXP_REG);
+
+	/* set type, direction, address; reset fifo counters */
+	if (desc->bEndpointAddress & USB_DIR_IN) {
+		csr1 = S3C2410_UDC_ICSR1_FFLUSH|S3C2410_UDC_ICSR1_CLRDT;
+		csr2 = S3C2410_UDC_ICSR2_MODEIN|S3C2410_UDC_ICSR2_DMAIEN;
+
+		udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+		udc_write(csr1, S3C2410_UDC_IN_CSR1_REG);
+		udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+		udc_write(csr2, S3C2410_UDC_IN_CSR2_REG);
+	} else {
+		/* don't flush in fifo or it will cause endpoint interrupt */
+		csr1 = S3C2410_UDC_ICSR1_CLRDT;
+		csr2 = S3C2410_UDC_ICSR2_DMAIEN;
+
+		udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+		udc_write(csr1, S3C2410_UDC_IN_CSR1_REG);
+		udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+		udc_write(csr2, S3C2410_UDC_IN_CSR2_REG);
+
+		csr1 = S3C2410_UDC_OCSR1_FFLUSH | S3C2410_UDC_OCSR1_CLRDT;
+		csr2 = S3C2410_UDC_OCSR2_DMAIEN;
+
+		udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+		udc_write(csr1, S3C2410_UDC_OUT_CSR1_REG);
+		udc_write(ep->num, S3C2410_UDC_INDEX_REG);
+		udc_write(csr2, S3C2410_UDC_OUT_CSR2_REG);
+	}
+
+	/* enable irqs */
+	int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG);
+	udc_write(int_en_reg | (1 << ep->num), S3C2410_UDC_EP_INT_EN_REG);
+
+	/* print some debug message */
+	tmp = desc->bEndpointAddress;
+	dprintk (DEBUG_NORMAL, "enable %s(%d) ep%x%s-blk max %02x\n",
+		 _ep->name,ep->num, tmp,
+		 desc->bEndpointAddress & USB_DIR_IN ? "in" : "out", max);
+
+	local_irq_restore (flags);
+	s3c2410_udc_set_halt(_ep, 0);
+
+	return 0;
+}
+
+/*
+ * s3c2410_udc_ep_disable
+ */
+static int s3c2410_udc_ep_disable(struct usb_ep *_ep)
+{
+	struct s3c2410_ep *ep = to_s3c2410_ep(_ep);
+	unsigned long flags;
+	u32 int_en_reg;
+
+	if (!_ep || !ep->desc) {
+		dprintk(DEBUG_NORMAL, "%s not enabled\n",
+			_ep ? ep->ep.name : NULL);
+		return -EINVAL;
+	}
+
+	local_irq_save(flags);
+
+	dprintk(DEBUG_NORMAL, "ep_disable: %s\n", _ep->name);
+
+	ep->desc = NULL;
+	ep->halted = 1;
+
+	s3c2410_udc_nuke (ep->dev, ep, -ESHUTDOWN);
+
+	/* disable irqs */
+	int_en_reg = udc_read(S3C2410_UDC_EP_INT_EN_REG);
+	udc_write(int_en_reg & ~(1<<ep->num), S3C2410_UDC_EP_INT_EN_REG);
+
+	local_irq_restore(flags);
+
+	dprintk(DEBUG_NORMAL, "%s disabled\n", _ep->name);
+
+	return 0;
+}
+
+/*
+ * s3c2410_udc_alloc_request
+ */
+static struct usb_request *
+s3c2410_udc_alloc_request(struct usb_ep *_ep, gfp_t mem_flags)
+{
+	struct s3c2410_request *req;
+
+	dprintk(DEBUG_VERBOSE,"%s(%p,%d)\n", __func__, _ep, mem_flags);
+
+	if (!_ep)
+		return NULL;
+
+	req = kzalloc (sizeof(struct s3c2410_request), mem_flags);
+	if (!req)
+		return NULL;
+
+	INIT_LIST_HEAD (&req->queue);
+	return &req->req;
+}
+
+/*
+ * s3c2410_udc_free_request
+ */
+static void
+s3c2410_udc_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct s3c2410_ep	*ep = to_s3c2410_ep(_ep);
+	struct s3c2410_request	*req = to_s3c2410_req(_req);
+
+	dprintk(DEBUG_VERBOSE, "%s(%p,%p)\n", __func__, _ep, _req);
+
+	if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
+		return;
+
+	WARN_ON (!list_empty (&req->queue));
+	kfree(req);
+}
+
+/*
+ *	s3c2410_udc_queue
+ */
+static int s3c2410_udc_queue(struct usb_ep *_ep, struct usb_request *_req,
+		gfp_t gfp_flags)
+{
+	struct s3c2410_request	*req = to_s3c2410_req(_req);
+	struct s3c2410_ep	*ep = to_s3c2410_ep(_ep);
+	struct s3c2410_udc	*dev;
+	u32			ep_csr = 0;
+	int			fifo_count = 0;
+	unsigned long		flags;
+
+	if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+		dprintk(DEBUG_NORMAL, "%s: invalid args\n", __func__);
+		return -EINVAL;
+	}
+
+	dev = ep->dev;
+	if (unlikely (!dev->driver
+			|| dev->gadget.speed == USB_SPEED_UNKNOWN)) {
+		return -ESHUTDOWN;
+	}
+
+	local_irq_save (flags);
+
+	if (unlikely(!_req || !_req->complete
+			|| !_req->buf || !list_empty(&req->queue))) {
+		if (!_req)
+			dprintk(DEBUG_NORMAL, "%s: 1 X X X\n", __func__);
+		else {
+			dprintk(DEBUG_NORMAL, "%s: 0 %01d %01d %01d\n",
+				__func__, !_req->complete,!_req->buf,
+				!list_empty(&req->queue));
+		}
+
+		local_irq_restore(flags);
+		return -EINVAL;
+	}
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	dprintk(DEBUG_VERBOSE, "%s: ep%x len %d\n",
+		 __func__, ep->bEndpointAddress, _req->length);
+
+	if (ep->bEndpointAddress) {
+		udc_write(ep->bEndpointAddress & 0x7F, S3C2410_UDC_INDEX_REG);
+
+		ep_csr = udc_read((ep->bEndpointAddress & USB_DIR_IN)
+				? S3C2410_UDC_IN_CSR1_REG
+				: S3C2410_UDC_OUT_CSR1_REG);
+		fifo_count = s3c2410_udc_fifo_count_out();
+	} else {
+		udc_write(0, S3C2410_UDC_INDEX_REG);
+		ep_csr = udc_read(S3C2410_UDC_IN_CSR1_REG);
+		fifo_count = s3c2410_udc_fifo_count_out();
+	}
+
+	/* kickstart this i/o queue? */
+	if (list_empty(&ep->queue) && !ep->halted) {
+		if (ep->bEndpointAddress == 0 /* ep0 */) {
+			switch (dev->ep0state) {
+			case EP0_IN_DATA_PHASE:
+				if (!(ep_csr&S3C2410_UDC_EP0_CSR_IPKRDY)
+						&& s3c2410_udc_write_fifo(ep,
+							req)) {
+					dev->ep0state = EP0_IDLE;
+					req = NULL;
+				}
+				break;
+
+			case EP0_OUT_DATA_PHASE:
+				if ((!_req->length)
+					|| ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY)
+						&& s3c2410_udc_read_fifo(ep,
+							req))) {
+					dev->ep0state = EP0_IDLE;
+					req = NULL;
+				}
+				break;
+
+			default:
+				local_irq_restore(flags);
+				return -EL2HLT;
+			}
+		} else if ((ep->bEndpointAddress & USB_DIR_IN) != 0
+				&& (!(ep_csr&S3C2410_UDC_OCSR1_PKTRDY))
+				&& s3c2410_udc_write_fifo(ep, req)) {
+			req = NULL;
+		} else if ((ep_csr & S3C2410_UDC_OCSR1_PKTRDY)
+				&& fifo_count
+				&& s3c2410_udc_read_fifo(ep, req)) {
+			req = NULL;
+		}
+	}
+
+	/* pio or dma irq handler advances the queue. */
+	if (likely (req != 0))
+		list_add_tail(&req->queue, &ep->queue);
+
+	local_irq_restore(flags);
+
+	dprintk(DEBUG_VERBOSE, "%s ok\n", __func__);
+	return 0;
+}
+
+/*
+ *	s3c2410_udc_dequeue
+ */
+static int s3c2410_udc_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct s3c2410_ep	*ep = to_s3c2410_ep(_ep);
+	struct s3c2410_udc	*udc;
+	int			retval = -EINVAL;
+	unsigned long		flags;
+	struct s3c2410_request	*req = NULL;
+
+	dprintk(DEBUG_VERBOSE, "%s(%p,%p)\n", __func__, _ep, _req);
+
+	if (!the_controller->driver)
+		return -ESHUTDOWN;
+
+	if (!_ep || !_req)
+		return retval;
+
+	udc = to_s3c2410_udc(ep->gadget);
+
+	local_irq_save (flags);
+
+	list_for_each_entry (req, &ep->queue, queue) {
+		if (&req->req == _req) {
+			list_del_init (&req->queue);
+			_req->status = -ECONNRESET;
+			retval = 0;
+			break;
+		}
+	}
+
+	if (retval == 0) {
+		dprintk(DEBUG_VERBOSE,
+			"dequeued req %p from %s, len %d buf %p\n",
+			req, _ep->name, _req->length, _req->buf);
+
+		s3c2410_udc_done(ep, req, -ECONNRESET);
+	}
+
+	local_irq_restore (flags);
+	return retval;
+}
+
+/*
+ * s3c2410_udc_set_halt
+ */
+static int s3c2410_udc_set_halt(struct usb_ep *_ep, int value)
+{
+	struct s3c2410_ep	*ep = to_s3c2410_ep(_ep);
+	u32			ep_csr = 0;
+	unsigned long		flags;
+	u32			idx;
+
+	if (unlikely (!_ep || (!ep->desc && ep->ep.name != ep0name))) {
+		dprintk(DEBUG_NORMAL, "%s: inval 2\n", __func__);
+		return -EINVAL;
+	}
+
+	local_irq_save (flags);
+
+	idx = ep->bEndpointAddress & 0x7F;
+
+	if (idx == 0) {
+		s3c2410_udc_set_ep0_ss(base_addr);
+		s3c2410_udc_set_ep0_de_out(base_addr);
+	} else {
+		udc_write(idx, S3C2410_UDC_INDEX_REG);
+		ep_csr = udc_read((ep->bEndpointAddress &USB_DIR_IN)
+				? S3C2410_UDC_IN_CSR1_REG
+				: S3C2410_UDC_OUT_CSR1_REG);
+
+		if ((ep->bEndpointAddress & USB_DIR_IN) != 0) {
+			if (value)
+				udc_write(ep_csr | S3C2410_UDC_ICSR1_SENDSTL,
+					S3C2410_UDC_IN_CSR1_REG);
+			else {
+				ep_csr &= ~S3C2410_UDC_ICSR1_SENDSTL;
+				udc_write(ep_csr, S3C2410_UDC_IN_CSR1_REG);
+				ep_csr |= S3C2410_UDC_ICSR1_CLRDT;
+				udc_write(ep_csr, S3C2410_UDC_IN_CSR1_REG);
+			}
+		} else {
+			if (value)
+				udc_write(ep_csr | S3C2410_UDC_OCSR1_SENDSTL,
+					S3C2410_UDC_OUT_CSR1_REG);
+			else {
+				ep_csr &= ~S3C2410_UDC_OCSR1_SENDSTL;
+				udc_write(ep_csr, S3C2410_UDC_OUT_CSR1_REG);
+				ep_csr |= S3C2410_UDC_OCSR1_CLRDT;
+				udc_write(ep_csr, S3C2410_UDC_OUT_CSR1_REG);
+			}
+		}
+	}
+
+	ep->halted = value ? 1 : 0;
+	local_irq_restore (flags);
+
+	return 0;
+}
+
+static const struct usb_ep_ops s3c2410_ep_ops = {
+	.enable		= s3c2410_udc_ep_enable,
+	.disable	= s3c2410_udc_ep_disable,
+
+	.alloc_request	= s3c2410_udc_alloc_request,
+	.free_request	= s3c2410_udc_free_request,
+
+	.queue		= s3c2410_udc_queue,
+	.dequeue	= s3c2410_udc_dequeue,
+
+	.set_halt	= s3c2410_udc_set_halt,
+};
+
+/*------------------------- usb_gadget_ops ----------------------------------*/
+
+/*
+ *	s3c2410_udc_get_frame
+ */
+static int s3c2410_udc_get_frame(struct usb_gadget *_gadget)
+{
+	int tmp;
+
+	dprintk(DEBUG_VERBOSE, "%s()\n", __func__);
+
+	tmp = udc_read(S3C2410_UDC_FRAME_NUM2_REG) << 8;
+	tmp |= udc_read(S3C2410_UDC_FRAME_NUM1_REG);
+	return tmp;
+}
+
+/*
+ *	s3c2410_udc_wakeup
+ */
+static int s3c2410_udc_wakeup(struct usb_gadget *_gadget)
+{
+	dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+	return 0;
+}
+
+/*
+ *	s3c2410_udc_set_selfpowered
+ */
+static int s3c2410_udc_set_selfpowered(struct usb_gadget *gadget, int value)
+{
+	struct s3c2410_udc *udc = to_s3c2410_udc(gadget);
+
+	dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+
+	if (value)
+		udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
+	else
+		udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
+
+	return 0;
+}
+
+static void s3c2410_udc_disable(struct s3c2410_udc *dev);
+static void s3c2410_udc_enable(struct s3c2410_udc *dev);
+
+static int s3c2410_udc_set_pullup(struct s3c2410_udc *udc, int is_on)
+{
+	dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+
+	if (udc_info && udc_info->udc_command) {
+		if (is_on)
+			s3c2410_udc_enable(udc);
+		else {
+			if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
+				if (udc->driver && udc->driver->disconnect)
+					udc->driver->disconnect(&udc->gadget);
+
+			}
+			s3c2410_udc_disable(udc);
+		}
+	}
+	else
+		return -EOPNOTSUPP;
+
+	return 0;
+}
+
+static int s3c2410_udc_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+	struct s3c2410_udc *udc = to_s3c2410_udc(gadget);
+
+	dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+
+	udc->vbus = (is_active != 0);
+	s3c2410_udc_set_pullup(udc, is_active);
+	return 0;
+}
+
+static int s3c2410_udc_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct s3c2410_udc *udc = to_s3c2410_udc(gadget);
+
+	dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+
+	s3c2410_udc_set_pullup(udc, is_on ? 0 : 1);
+	return 0;
+}
+
+static irqreturn_t s3c2410_udc_vbus_irq(int irq, void *_dev)
+{
+	struct s3c2410_udc	*dev = _dev;
+	unsigned int		value;
+
+	dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+	value = s3c2410_gpio_getpin(udc_info->vbus_pin);
+
+	if (udc_info->vbus_pin_inverted)
+		value = !value;
+
+	if (value != dev->vbus)
+		s3c2410_udc_vbus_session(&dev->gadget, value);
+
+	return IRQ_HANDLED;
+}
+
+static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
+{
+	dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+
+	if (udc_info && udc_info->vbus_draw) {
+		udc_info->vbus_draw(ma);
+		return 0;
+	}
+
+	return -ENOTSUPP;
+}
+
+static const struct usb_gadget_ops s3c2410_ops = {
+	.get_frame		= s3c2410_udc_get_frame,
+	.wakeup			= s3c2410_udc_wakeup,
+	.set_selfpowered	= s3c2410_udc_set_selfpowered,
+	.pullup			= s3c2410_udc_pullup,
+	.vbus_session		= s3c2410_udc_vbus_session,
+	.vbus_draw		= s3c2410_vbus_draw,
+};
+
+/*------------------------- gadget driver handling---------------------------*/
+/*
+ * s3c2410_udc_disable
+ */
+static void s3c2410_udc_disable(struct s3c2410_udc *dev)
+{
+	dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+
+	/* Disable all interrupts */
+	udc_write(0x00, S3C2410_UDC_USB_INT_EN_REG);
+	udc_write(0x00, S3C2410_UDC_EP_INT_EN_REG);
+
+	/* Clear the interrupt registers */
+	udc_write(S3C2410_UDC_USBINT_RESET
+				| S3C2410_UDC_USBINT_RESUME
+				| S3C2410_UDC_USBINT_SUSPEND,
+			S3C2410_UDC_USB_INT_REG);
+
+	udc_write(0x1F, S3C2410_UDC_EP_INT_REG);
+
+	/* Good bye, cruel world */
+	if (udc_info && udc_info->udc_command)
+		udc_info->udc_command(S3C2410_UDC_P_DISABLE);
+
+	/* Set speed to unknown */
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+}
+
+/*
+ * s3c2410_udc_reinit
+ */
+static void s3c2410_udc_reinit(struct s3c2410_udc *dev)
+{
+	u32 i;
+
+	/* device/ep0 records init */
+	INIT_LIST_HEAD (&dev->gadget.ep_list);
+	INIT_LIST_HEAD (&dev->gadget.ep0->ep_list);
+	dev->ep0state = EP0_IDLE;
+
+	for (i = 0; i < S3C2410_ENDPOINTS; i++) {
+		struct s3c2410_ep *ep = &dev->ep[i];
+
+		if (i != 0)
+			list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
+
+		ep->dev = dev;
+		ep->desc = NULL;
+		ep->halted = 0;
+		INIT_LIST_HEAD (&ep->queue);
+	}
+}
+
+/*
+ * s3c2410_udc_enable
+ */
+static void s3c2410_udc_enable(struct s3c2410_udc *dev)
+{
+	int i;
+
+	dprintk(DEBUG_NORMAL, "s3c2410_udc_enable called\n");
+
+	/* dev->gadget.speed = USB_SPEED_UNKNOWN; */
+	dev->gadget.speed = USB_SPEED_FULL;
+
+	/* Set MAXP for all endpoints */
+	for (i = 0; i < S3C2410_ENDPOINTS; i++) {
+		udc_write(i, S3C2410_UDC_INDEX_REG);
+		udc_write((dev->ep[i].ep.maxpacket & 0x7ff) >> 3,
+				S3C2410_UDC_MAXP_REG);
+	}
+
+	/* Set default power state */
+	udc_write(DEFAULT_POWER_STATE, S3C2410_UDC_PWR_REG);
+
+	/* Enable reset and suspend interrupt interrupts */
+	udc_write(S3C2410_UDC_USBINT_RESET | S3C2410_UDC_USBINT_SUSPEND,
+			S3C2410_UDC_USB_INT_EN_REG);
+
+	/* Enable ep0 interrupt */
+	udc_write(S3C2410_UDC_INT_EP0, S3C2410_UDC_EP_INT_EN_REG);
+
+	/* time to say "hello, world" */
+	if (udc_info && udc_info->udc_command)
+		udc_info->udc_command(S3C2410_UDC_P_ENABLE);
+}
+
+/*
+ *	usb_gadget_register_driver
+ */
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct s3c2410_udc *udc = the_controller;
+	int		retval;
+
+	dprintk(DEBUG_NORMAL, "usb_gadget_register_driver() '%s'\n",
+		driver->driver.name);
+
+	/* Sanity checks */
+	if (!udc)
+		return -ENODEV;
+
+	if (udc->driver)
+		return -EBUSY;
+
+	if (!driver->bind || !driver->setup
+			|| driver->speed != USB_SPEED_FULL) {
+		printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n",
+			driver->bind, driver->setup, driver->speed);
+		return -EINVAL;
+	}
+#if defined(MODULE)
+	if (!driver->unbind) {
+		printk(KERN_ERR "Invalid driver: no unbind method\n");
+		return -EINVAL;
+	}
+#endif
+
+	/* Hook the driver */
+	udc->driver = driver;
+	udc->gadget.dev.driver = &driver->driver;
+
+	/* Bind the driver */
+	if ((retval = device_add(&udc->gadget.dev)) != 0) {
+		printk(KERN_ERR "Error in device_add() : %d\n",retval);
+		goto register_error;
+	}
+
+	dprintk(DEBUG_NORMAL, "binding gadget driver '%s'\n",
+		driver->driver.name);
+
+	if ((retval = driver->bind (&udc->gadget)) != 0) {
+		device_del(&udc->gadget.dev);
+		goto register_error;
+	}
+
+	/* Enable udc */
+	s3c2410_udc_enable(udc);
+
+	return 0;
+
+register_error:
+	udc->driver = NULL;
+	udc->gadget.dev.driver = NULL;
+	return retval;
+}
+
+/*
+ *	usb_gadget_unregister_driver
+ */
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct s3c2410_udc *udc = the_controller;
+
+	if (!udc)
+		return -ENODEV;
+
+	if (!driver || driver != udc->driver || !driver->unbind)
+		return -EINVAL;
+
+	dprintk(DEBUG_NORMAL,"usb_gadget_register_driver() '%s'\n",
+		driver->driver.name);
+
+	if (driver->disconnect)
+		driver->disconnect(&udc->gadget);
+
+	device_del(&udc->gadget.dev);
+	udc->driver = NULL;
+
+	/* Disable udc */
+	s3c2410_udc_disable(udc);
+
+	return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+static struct s3c2410_udc memory = {
+	.gadget = {
+		.ops		= &s3c2410_ops,
+		.ep0		= &memory.ep[0].ep,
+		.name		= gadget_name,
+		.dev = {
+			.bus_id		= "gadget",
+		},
+	},
+
+	/* control endpoint */
+	.ep[0] = {
+		.num		= 0,
+		.ep = {
+			.name		= ep0name,
+			.ops		= &s3c2410_ep_ops,
+			.maxpacket	= EP0_FIFO_SIZE,
+		},
+		.dev		= &memory,
+	},
+
+	/* first group of endpoints */
+	.ep[1] = {
+		.num		= 1,
+		.ep = {
+			.name		= "ep1-bulk",
+			.ops		= &s3c2410_ep_ops,
+			.maxpacket	= EP_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= EP_FIFO_SIZE,
+		.bEndpointAddress = 1,
+		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
+	},
+	.ep[2] = {
+		.num		= 2,
+		.ep = {
+			.name		= "ep2-bulk",
+			.ops		= &s3c2410_ep_ops,
+			.maxpacket	= EP_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= EP_FIFO_SIZE,
+		.bEndpointAddress = 2,
+		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
+	},
+	.ep[3] = {
+		.num		= 3,
+		.ep = {
+			.name		= "ep3-bulk",
+			.ops		= &s3c2410_ep_ops,
+			.maxpacket	= EP_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= EP_FIFO_SIZE,
+		.bEndpointAddress = 3,
+		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
+	},
+	.ep[4] = {
+		.num		= 4,
+		.ep = {
+			.name		= "ep4-bulk",
+			.ops		= &s3c2410_ep_ops,
+			.maxpacket	= EP_FIFO_SIZE,
+		},
+		.dev		= &memory,
+		.fifo_size	= EP_FIFO_SIZE,
+		.bEndpointAddress = 4,
+		.bmAttributes	= USB_ENDPOINT_XFER_BULK,
+	}
+
+};
+
+/*
+ *	probe - binds to the platform device
+ */
+static int s3c2410_udc_probe(struct platform_device *pdev)
+{
+	struct s3c2410_udc *udc = &memory;
+	struct device *dev = &pdev->dev;
+	int retval;
+	unsigned int irq;
+
+	dev_dbg(dev, "%s()\n", __func__);
+
+	usb_bus_clock = clk_get(NULL, "usb-bus-gadget");
+	if (IS_ERR(usb_bus_clock)) {
+		dev_err(dev, "failed to get usb bus clock source\n");
+		return PTR_ERR(usb_bus_clock);
+	}
+
+	clk_enable(usb_bus_clock);
+
+	udc_clock = clk_get(NULL, "usb-device");
+	if (IS_ERR(udc_clock)) {
+		dev_err(dev, "failed to get udc clock source\n");
+		return PTR_ERR(udc_clock);
+	}
+
+	clk_enable(udc_clock);
+
+	mdelay(10);
+
+	dev_dbg(dev, "got and enabled clocks\n");
+
+	if (strncmp(pdev->name, "s3c2440", 7) == 0) {
+		dev_info(dev, "S3C2440: increasing FIFO to 128 bytes\n");
+		memory.ep[1].fifo_size = S3C2440_EP_FIFO_SIZE;
+		memory.ep[2].fifo_size = S3C2440_EP_FIFO_SIZE;
+		memory.ep[3].fifo_size = S3C2440_EP_FIFO_SIZE;
+		memory.ep[4].fifo_size = S3C2440_EP_FIFO_SIZE;
+	}
+
+	spin_lock_init (&udc->lock);
+	udc_info = pdev->dev.platform_data;
+
+	rsrc_start = S3C2410_PA_USBDEV;
+	rsrc_len   = S3C24XX_SZ_USBDEV;
+
+	if (!request_mem_region(rsrc_start, rsrc_len, gadget_name))
+		return -EBUSY;
+
+	base_addr = ioremap(rsrc_start, rsrc_len);
+	if (!base_addr) {
+		retval = -ENOMEM;
+		goto err_mem;
+	}
+
+	device_initialize(&udc->gadget.dev);
+	udc->gadget.dev.parent = &pdev->dev;
+	udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+	the_controller = udc;
+	platform_set_drvdata(pdev, udc);
+
+	s3c2410_udc_disable(udc);
+	s3c2410_udc_reinit(udc);
+
+	/* irq setup after old hardware state is cleaned up */
+	retval = request_irq(IRQ_USBD, s3c2410_udc_irq,
+			IRQF_DISABLED, gadget_name, udc);
+
+	if (retval != 0) {
+		dev_err(dev, "cannot get irq %i, err %d\n", IRQ_USBD, retval);
+		retval = -EBUSY;
+		goto err_map;
+	}
+
+	dev_dbg(dev, "got irq %i\n", IRQ_USBD);
+
+	if (udc_info && udc_info->vbus_pin > 0) {
+		irq = s3c2410_gpio_getirq(udc_info->vbus_pin);
+		retval = request_irq(irq, s3c2410_udc_vbus_irq,
+				IRQF_DISABLED | IRQF_TRIGGER_RISING
+				| IRQF_TRIGGER_FALLING,
+				gadget_name, udc);
+
+		if (retval != 0) {
+			dev_err(dev, "can't get vbus irq %i, err %d\n",
+				irq, retval);
+			retval = -EBUSY;
+			goto err_int;
+		}
+
+		dev_dbg(dev, "got irq %i\n", irq);
+	} else {
+		udc->vbus = 1;
+	}
+
+	if (s3c2410_udc_debugfs_root) {
+		udc->regs_info = debugfs_create_file("registers", S_IRUGO,
+				s3c2410_udc_debugfs_root,
+				udc, &s3c2410_udc_debugfs_fops);
+		if (IS_ERR(udc->regs_info)) {
+			dev_warn(dev, "debugfs file creation failed %ld\n",
+				 PTR_ERR(udc->regs_info));
+			udc->regs_info = NULL;
+		}
+	}
+
+	dev_dbg(dev, "probe ok\n");
+
+	return 0;
+
+err_int:
+	free_irq(IRQ_USBD, udc);
+err_map:
+	iounmap(base_addr);
+err_mem:
+	release_mem_region(rsrc_start, rsrc_len);
+
+	return retval;
+}
+
+/*
+ *	s3c2410_udc_remove
+ */
+static int s3c2410_udc_remove(struct platform_device *pdev)
+{
+	struct s3c2410_udc *udc = platform_get_drvdata(pdev);
+	unsigned int irq;
+
+	dev_dbg(&pdev->dev, "%s()\n", __func__);
+	if (udc->driver)
+		return -EBUSY;
+
+	debugfs_remove(udc->regs_info);
+
+	if (udc_info && udc_info->vbus_pin > 0) {
+		irq = s3c2410_gpio_getirq(udc_info->vbus_pin);
+		free_irq(irq, udc);
+	}
+
+	free_irq(IRQ_USBD, udc);
+
+	iounmap(base_addr);
+	release_mem_region(rsrc_start, rsrc_len);
+
+	platform_set_drvdata(pdev, NULL);
+
+	if (!IS_ERR(udc_clock) && udc_clock != NULL) {
+		clk_disable(udc_clock);
+		clk_put(udc_clock);
+		udc_clock = NULL;
+	}
+
+	if (!IS_ERR(usb_bus_clock) && usb_bus_clock != NULL) {
+		clk_disable(usb_bus_clock);
+		clk_put(usb_bus_clock);
+		usb_bus_clock = NULL;
+	}
+
+	dev_dbg(&pdev->dev, "%s: remove ok\n", __func__);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int s3c2410_udc_suspend(struct platform_device *pdev, pm_message_t message)
+{
+	if (udc_info && udc_info->udc_command)
+		udc_info->udc_command(S3C2410_UDC_P_DISABLE);
+
+	return 0;
+}
+
+static int s3c2410_udc_resume(struct platform_device *pdev)
+{
+	if (udc_info && udc_info->udc_command)
+		udc_info->udc_command(S3C2410_UDC_P_ENABLE);
+
+	return 0;
+}
+#else
+#define s3c2410_udc_suspend	NULL
+#define s3c2410_udc_resume	NULL
+#endif
+
+static struct platform_driver udc_driver_2410 = {
+	.driver		= {
+		.name	= "s3c2410-usbgadget",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= s3c2410_udc_probe,
+	.remove		= s3c2410_udc_remove,
+	.suspend	= s3c2410_udc_suspend,
+	.resume		= s3c2410_udc_resume,
+};
+
+static struct platform_driver udc_driver_2440 = {
+	.driver		= {
+		.name	= "s3c2440-usbgadget",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= s3c2410_udc_probe,
+	.remove		= s3c2410_udc_remove,
+	.suspend	= s3c2410_udc_suspend,
+	.resume		= s3c2410_udc_resume,
+};
+
+static int __init udc_init(void)
+{
+	int retval;
+
+	dprintk(DEBUG_NORMAL, "%s: version %s\n", gadget_name, DRIVER_VERSION);
+
+	s3c2410_udc_debugfs_root = debugfs_create_dir(gadget_name, NULL);
+	if (IS_ERR(s3c2410_udc_debugfs_root)) {
+		printk(KERN_ERR "%s: debugfs dir creation failed %ld\n",
+			gadget_name, PTR_ERR(s3c2410_udc_debugfs_root));
+		s3c2410_udc_debugfs_root = NULL;
+	}
+
+	retval = platform_driver_register(&udc_driver_2410);
+	if (retval)
+		goto err;
+
+	retval = platform_driver_register(&udc_driver_2440);
+	if (retval)
+		goto err;
+
+	return 0;
+
+err:
+	debugfs_remove(s3c2410_udc_debugfs_root);
+	return retval;
+}
+
+static void __exit udc_exit(void)
+{
+	platform_driver_unregister(&udc_driver_2410);
+	platform_driver_unregister(&udc_driver_2440);
+	debugfs_remove(s3c2410_udc_debugfs_root);
+}
+
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+module_init(udc_init);
+module_exit(udc_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");

+ 110 - 0
drivers/usb/gadget/s3c2410_udc.h

@@ -0,0 +1,110 @@
+/*
+ * linux/drivers/usb/gadget/s3c2410_udc.h
+ * Samsung on-chip full speed USB device controllers
+ *
+ * Copyright (C) 2004-2007 Herbert Pötzl - Arnaud Patard
+ *	Additional cleanups by Ben Dooks <ben-linux@fluff.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _S3C2410_UDC_H
+#define _S3C2410_UDC_H
+
+struct s3c2410_ep {
+	struct list_head		queue;
+	unsigned long			last_io;	/* jiffies timestamp */
+	struct usb_gadget		*gadget;
+	struct s3c2410_udc		*dev;
+	const struct usb_endpoint_descriptor *desc;
+	struct usb_ep			ep;
+	u8				num;
+
+	unsigned short			fifo_size;
+	u8				bEndpointAddress;
+	u8				bmAttributes;
+
+	unsigned			halted : 1;
+	unsigned			already_seen : 1;
+	unsigned			setup_stage : 1;
+};
+
+
+/* Warning : ep0 has a fifo of 16 bytes */
+/* Don't try to set 32 or 64            */
+/* also testusb 14 fails  wit 16 but is */
+/* fine with 8                          */
+#define EP0_FIFO_SIZE		 8
+#define EP_FIFO_SIZE		64
+#define DEFAULT_POWER_STATE	0x00
+
+#define S3C2440_EP_FIFO_SIZE	128
+
+static const char ep0name [] = "ep0";
+
+static const char *const ep_name[] = {
+	ep0name,                                /* everyone has ep0 */
+	/* s3c2410 four bidirectional bulk endpoints */
+	"ep1-bulk", "ep2-bulk", "ep3-bulk", "ep4-bulk",
+};
+
+#define S3C2410_ENDPOINTS       ARRAY_SIZE(ep_name)
+
+struct s3c2410_request {
+	struct list_head		queue;		/* ep's requests */
+	struct usb_request		req;
+};
+
+enum ep0_state {
+        EP0_IDLE,
+        EP0_IN_DATA_PHASE,
+        EP0_OUT_DATA_PHASE,
+        EP0_END_XFER,
+        EP0_STALL,
+};
+
+static const char *ep0states[]= {
+        "EP0_IDLE",
+        "EP0_IN_DATA_PHASE",
+        "EP0_OUT_DATA_PHASE",
+        "EP0_END_XFER",
+        "EP0_STALL",
+};
+
+struct s3c2410_udc {
+	spinlock_t			lock;
+
+	struct s3c2410_ep		ep[S3C2410_ENDPOINTS];
+	int				address;
+	struct usb_gadget		gadget;
+	struct usb_gadget_driver	*driver;
+	struct s3c2410_request		fifo_req;
+	u8				fifo_buf[EP_FIFO_SIZE];
+	u16				devstatus;
+
+	u32				port_status;
+	int				ep0state;
+
+	unsigned			got_irq : 1;
+
+	unsigned			req_std : 1;
+	unsigned			req_config : 1;
+	unsigned			req_pending : 1;
+	u8				vbus;
+	struct dentry			*regs_info;
+};
+
+#endif

+ 8 - 6
drivers/usb/gadget/serial.c

@@ -2215,7 +2215,7 @@ static struct gs_buf *gs_buf_alloc(unsigned int size, gfp_t kmalloc_flags)
  *
  *
  * Free the buffer and all associated memory.
  * Free the buffer and all associated memory.
  */
  */
-void gs_buf_free(struct gs_buf *gb)
+static void gs_buf_free(struct gs_buf *gb)
 {
 {
 	if (gb) {
 	if (gb) {
 		kfree(gb->buf_buf);
 		kfree(gb->buf_buf);
@@ -2228,7 +2228,7 @@ void gs_buf_free(struct gs_buf *gb)
  *
  *
  * Clear out all data in the circular buffer.
  * Clear out all data in the circular buffer.
  */
  */
-void gs_buf_clear(struct gs_buf *gb)
+static void gs_buf_clear(struct gs_buf *gb)
 {
 {
 	if (gb != NULL)
 	if (gb != NULL)
 		gb->buf_get = gb->buf_put;
 		gb->buf_get = gb->buf_put;
@@ -2241,7 +2241,7 @@ void gs_buf_clear(struct gs_buf *gb)
  * Return the number of bytes of data available in the circular
  * Return the number of bytes of data available in the circular
  * buffer.
  * buffer.
  */
  */
-unsigned int gs_buf_data_avail(struct gs_buf *gb)
+static unsigned int gs_buf_data_avail(struct gs_buf *gb)
 {
 {
 	if (gb != NULL)
 	if (gb != NULL)
 		return (gb->buf_size + gb->buf_put - gb->buf_get) % gb->buf_size;
 		return (gb->buf_size + gb->buf_put - gb->buf_get) % gb->buf_size;
@@ -2255,7 +2255,7 @@ unsigned int gs_buf_data_avail(struct gs_buf *gb)
  * Return the number of bytes of space available in the circular
  * Return the number of bytes of space available in the circular
  * buffer.
  * buffer.
  */
  */
-unsigned int gs_buf_space_avail(struct gs_buf *gb)
+static unsigned int gs_buf_space_avail(struct gs_buf *gb)
 {
 {
 	if (gb != NULL)
 	if (gb != NULL)
 		return (gb->buf_size + gb->buf_get - gb->buf_put - 1) % gb->buf_size;
 		return (gb->buf_size + gb->buf_get - gb->buf_put - 1) % gb->buf_size;
@@ -2271,7 +2271,8 @@ unsigned int gs_buf_space_avail(struct gs_buf *gb)
  *
  *
  * Return the number of bytes copied.
  * Return the number of bytes copied.
  */
  */
-unsigned int gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count)
+static unsigned int
+gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count)
 {
 {
 	unsigned int len;
 	unsigned int len;
 
 
@@ -2309,7 +2310,8 @@ unsigned int gs_buf_put(struct gs_buf *gb, const char *buf, unsigned int count)
  *
  *
  * Return the number of bytes copied.
  * Return the number of bytes copied.
  */
  */
-unsigned int gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count)
+static unsigned int
+gs_buf_get(struct gs_buf *gb, char *buf, unsigned int count)
 {
 {
 	unsigned int len;
 	unsigned int len;
 
 

+ 3 - 6
drivers/usb/gadget/zero.c

@@ -481,8 +481,7 @@ alloc_ep_req (struct usb_ep *ep, unsigned length)
 	req = usb_ep_alloc_request (ep, GFP_ATOMIC);
 	req = usb_ep_alloc_request (ep, GFP_ATOMIC);
 	if (req) {
 	if (req) {
 		req->length = length;
 		req->length = length;
-		req->buf = usb_ep_alloc_buffer (ep, length,
-				&req->dma, GFP_ATOMIC);
+		req->buf = kmalloc(length, GFP_ATOMIC);
 		if (!req->buf) {
 		if (!req->buf) {
 			usb_ep_free_request (ep, req);
 			usb_ep_free_request (ep, req);
 			req = NULL;
 			req = NULL;
@@ -493,8 +492,7 @@ alloc_ep_req (struct usb_ep *ep, unsigned length)
 
 
 static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
 static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
 {
 {
-	if (req->buf)
-		usb_ep_free_buffer (ep, req->buf, req->dma, req->length);
+	kfree(req->buf);
 	usb_ep_free_request (ep, req);
 	usb_ep_free_request (ep, req);
 }
 }
 
 
@@ -1199,8 +1197,7 @@ autoconf_fail:
 	dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
 	dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
 	if (!dev->req)
 	if (!dev->req)
 		goto enomem;
 		goto enomem;
-	dev->req->buf = usb_ep_alloc_buffer (gadget->ep0, USB_BUFSIZ,
-				&dev->req->dma, GFP_KERNEL);
+	dev->req->buf = kmalloc(USB_BUFSIZ, GFP_KERNEL);
 	if (!dev->req->buf)
 	if (!dev->req->buf)
 		goto enomem;
 		goto enomem;
 
 

+ 26 - 2
drivers/usb/host/Kconfig

@@ -69,8 +69,20 @@ config USB_EHCI_TT_NEWSCHED
 
 
 config USB_EHCI_BIG_ENDIAN_MMIO
 config USB_EHCI_BIG_ENDIAN_MMIO
 	bool
 	bool
-	depends on USB_EHCI_HCD
-	default n
+	depends on USB_EHCI_HCD && (PPC_CELLEB || PPC_PS3 || 440EPX)
+	default y
+
+config USB_EHCI_BIG_ENDIAN_DESC
+	bool
+	depends on USB_EHCI_HCD && 440EPX
+	default y
+
+config USB_EHCI_FSL
+	bool
+	select USB_EHCI_ROOT_HUB_TT
+	default y if MPC834x || PPC_MPC831x
+	---help---
+	  Variation of ARC USB block used in some Freescale chips.
 
 
 config USB_ISP116X_HCD
 config USB_ISP116X_HCD
 	tristate "ISP116X HCD support"
 	tristate "ISP116X HCD support"
@@ -224,3 +236,15 @@ config USB_SL811_CS
 	  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 "sl811_cs".
 	  module will be called "sl811_cs".
 
 
+config USB_R8A66597_HCD
+	tristate "R8A66597 HCD suppoort"
+	depends on USB
+	help
+	  The R8A66597 is a USB 2.0 host and peripheral controller.
+
+	  Enable this option if your board has this chip, and you want
+	  to use it as a host controller.  If unsure, say N.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called r8a66597-hcd.
+

+ 2 - 0
drivers/usb/host/Makefile

@@ -15,3 +15,5 @@ obj-$(CONFIG_USB_UHCI_HCD)	+= uhci-hcd.o
 obj-$(CONFIG_USB_SL811_HCD)	+= sl811-hcd.o
 obj-$(CONFIG_USB_SL811_HCD)	+= sl811-hcd.o
 obj-$(CONFIG_USB_SL811_CS)	+= sl811_cs.o
 obj-$(CONFIG_USB_SL811_CS)	+= sl811_cs.o
 obj-$(CONFIG_USB_U132_HCD)	+= u132-hcd.o
 obj-$(CONFIG_USB_U132_HCD)	+= u132-hcd.o
+obj-$(CONFIG_USB_R8A66597_HCD)	+= r8a66597-hcd.o
+

+ 96 - 87
drivers/usb/host/ehci-dbg.c

@@ -52,7 +52,7 @@ static void dbg_hcs_params (struct ehci_hcd *ehci, char *label)
 		HCS_INDICATOR (params) ? " ind" : "",
 		HCS_INDICATOR (params) ? " ind" : "",
 		HCS_N_CC (params),
 		HCS_N_CC (params),
 		HCS_N_PCC (params),
 		HCS_N_PCC (params),
-	        HCS_PORTROUTED (params) ? "" : " ordered",
+		HCS_PORTROUTED (params) ? "" : " ordered",
 		HCS_PPC (params) ? "" : " !ppc",
 		HCS_PPC (params) ? "" : " !ppc",
 		HCS_N_PORTS (params)
 		HCS_N_PORTS (params)
 		);
 		);
@@ -91,20 +91,20 @@ static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
 
 
 	if (HCC_ISOC_CACHE (params)) {
 	if (HCC_ISOC_CACHE (params)) {
 		ehci_dbg (ehci,
 		ehci_dbg (ehci,
-		     "%s hcc_params %04x caching frame %s%s%s\n",
-		     label, params,
-		     HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
-		     HCC_CANPARK (params) ? " park" : "",
-		     HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
+			"%s hcc_params %04x caching frame %s%s%s\n",
+			label, params,
+			HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",
+			HCC_CANPARK(params) ? " park" : "",
+			HCC_64BIT_ADDR(params) ? " 64 bit addr" : "");
 	} else {
 	} else {
 		ehci_dbg (ehci,
 		ehci_dbg (ehci,
-		     "%s hcc_params %04x thresh %d uframes %s%s%s\n",
-		     label,
-		     params,
-		     HCC_ISOC_THRES (params),
-		     HCC_PGM_FRAMELISTLEN (params) ? "256/512/1024" : "1024",
-		     HCC_CANPARK (params) ? " park" : "",
-		     HCC_64BIT_ADDR (params) ? " 64 bit addr" : "");
+			"%s hcc_params %04x thresh %d uframes %s%s%s\n",
+			label,
+			params,
+			HCC_ISOC_THRES(params),
+			HCC_PGM_FRAMELISTLEN(params) ? "256/512/1024" : "1024",
+			HCC_CANPARK(params) ? " park" : "",
+			HCC_64BIT_ADDR(params) ? " 64 bit addr" : "");
 	}
 	}
 }
 }
 #else
 #else
@@ -115,23 +115,23 @@ static inline void dbg_hcc_params (struct ehci_hcd *ehci, char *label) {}
 
 
 #ifdef	DEBUG
 #ifdef	DEBUG
 
 
-static void __attribute__((__unused__))
+static void __maybe_unused
 dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
 dbg_qtd (const char *label, struct ehci_hcd *ehci, struct ehci_qtd *qtd)
 {
 {
-	ehci_dbg (ehci, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd,
-		le32_to_cpup (&qtd->hw_next),
-		le32_to_cpup (&qtd->hw_alt_next),
-		le32_to_cpup (&qtd->hw_token),
-		le32_to_cpup (&qtd->hw_buf [0]));
+	ehci_dbg(ehci, "%s td %p n%08x %08x t%08x p0=%08x\n", label, qtd,
+		hc32_to_cpup(ehci, &qtd->hw_next),
+		hc32_to_cpup(ehci, &qtd->hw_alt_next),
+		hc32_to_cpup(ehci, &qtd->hw_token),
+		hc32_to_cpup(ehci, &qtd->hw_buf [0]));
 	if (qtd->hw_buf [1])
 	if (qtd->hw_buf [1])
-		ehci_dbg (ehci, "  p1=%08x p2=%08x p3=%08x p4=%08x\n",
-			le32_to_cpup (&qtd->hw_buf [1]),
-			le32_to_cpup (&qtd->hw_buf [2]),
-			le32_to_cpup (&qtd->hw_buf [3]),
-			le32_to_cpup (&qtd->hw_buf [4]));
+		ehci_dbg(ehci, "  p1=%08x p2=%08x p3=%08x p4=%08x\n",
+			hc32_to_cpup(ehci, &qtd->hw_buf[1]),
+			hc32_to_cpup(ehci, &qtd->hw_buf[2]),
+			hc32_to_cpup(ehci, &qtd->hw_buf[3]),
+			hc32_to_cpup(ehci, &qtd->hw_buf[4]));
 }
 }
 
 
-static void __attribute__((__unused__))
+static void __maybe_unused
 dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
 dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
 {
 	ehci_dbg (ehci, "%s qh %p n%08x info %x %x qtd %x\n", label,
 	ehci_dbg (ehci, "%s qh %p n%08x info %x %x qtd %x\n", label,
@@ -140,51 +140,53 @@ dbg_qh (const char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
 	dbg_qtd ("overlay", ehci, (struct ehci_qtd *) &qh->hw_qtd_next);
 	dbg_qtd ("overlay", ehci, (struct ehci_qtd *) &qh->hw_qtd_next);
 }
 }
 
 
-static void __attribute__((__unused__))
+static void __maybe_unused
 dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
 dbg_itd (const char *label, struct ehci_hcd *ehci, struct ehci_itd *itd)
 {
 {
 	ehci_dbg (ehci, "%s [%d] itd %p, next %08x, urb %p\n",
 	ehci_dbg (ehci, "%s [%d] itd %p, next %08x, urb %p\n",
-		label, itd->frame, itd, le32_to_cpu(itd->hw_next), itd->urb);
+		label, itd->frame, itd, hc32_to_cpu(ehci, itd->hw_next),
+		itd->urb);
 	ehci_dbg (ehci,
 	ehci_dbg (ehci,
 		"  trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
 		"  trans: %08x %08x %08x %08x %08x %08x %08x %08x\n",
-		le32_to_cpu(itd->hw_transaction[0]),
-		le32_to_cpu(itd->hw_transaction[1]),
-		le32_to_cpu(itd->hw_transaction[2]),
-		le32_to_cpu(itd->hw_transaction[3]),
-		le32_to_cpu(itd->hw_transaction[4]),
-		le32_to_cpu(itd->hw_transaction[5]),
-		le32_to_cpu(itd->hw_transaction[6]),
-		le32_to_cpu(itd->hw_transaction[7]));
+		hc32_to_cpu(ehci, itd->hw_transaction[0]),
+		hc32_to_cpu(ehci, itd->hw_transaction[1]),
+		hc32_to_cpu(ehci, itd->hw_transaction[2]),
+		hc32_to_cpu(ehci, itd->hw_transaction[3]),
+		hc32_to_cpu(ehci, itd->hw_transaction[4]),
+		hc32_to_cpu(ehci, itd->hw_transaction[5]),
+		hc32_to_cpu(ehci, itd->hw_transaction[6]),
+		hc32_to_cpu(ehci, itd->hw_transaction[7]));
 	ehci_dbg (ehci,
 	ehci_dbg (ehci,
 		"  buf:   %08x %08x %08x %08x %08x %08x %08x\n",
 		"  buf:   %08x %08x %08x %08x %08x %08x %08x\n",
-		le32_to_cpu(itd->hw_bufp[0]),
-		le32_to_cpu(itd->hw_bufp[1]),
-		le32_to_cpu(itd->hw_bufp[2]),
-		le32_to_cpu(itd->hw_bufp[3]),
-		le32_to_cpu(itd->hw_bufp[4]),
-		le32_to_cpu(itd->hw_bufp[5]),
-		le32_to_cpu(itd->hw_bufp[6]));
+		hc32_to_cpu(ehci, itd->hw_bufp[0]),
+		hc32_to_cpu(ehci, itd->hw_bufp[1]),
+		hc32_to_cpu(ehci, itd->hw_bufp[2]),
+		hc32_to_cpu(ehci, itd->hw_bufp[3]),
+		hc32_to_cpu(ehci, itd->hw_bufp[4]),
+		hc32_to_cpu(ehci, itd->hw_bufp[5]),
+		hc32_to_cpu(ehci, itd->hw_bufp[6]));
 	ehci_dbg (ehci, "  index: %d %d %d %d %d %d %d %d\n",
 	ehci_dbg (ehci, "  index: %d %d %d %d %d %d %d %d\n",
 		itd->index[0], itd->index[1], itd->index[2],
 		itd->index[0], itd->index[1], itd->index[2],
 		itd->index[3], itd->index[4], itd->index[5],
 		itd->index[3], itd->index[4], itd->index[5],
 		itd->index[6], itd->index[7]);
 		itd->index[6], itd->index[7]);
 }
 }
 
 
-static void __attribute__((__unused__))
+static void __maybe_unused
 dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd)
 dbg_sitd (const char *label, struct ehci_hcd *ehci, struct ehci_sitd *sitd)
 {
 {
 	ehci_dbg (ehci, "%s [%d] sitd %p, next %08x, urb %p\n",
 	ehci_dbg (ehci, "%s [%d] sitd %p, next %08x, urb %p\n",
-		label, sitd->frame, sitd, le32_to_cpu(sitd->hw_next), sitd->urb);
+		label, sitd->frame, sitd, hc32_to_cpu(ehci, sitd->hw_next),
+		sitd->urb);
 	ehci_dbg (ehci,
 	ehci_dbg (ehci,
 		"  addr %08x sched %04x result %08x buf %08x %08x\n",
 		"  addr %08x sched %04x result %08x buf %08x %08x\n",
-		le32_to_cpu(sitd->hw_fullspeed_ep),
-		le32_to_cpu(sitd->hw_uframe),
-		le32_to_cpu(sitd->hw_results),
-		le32_to_cpu(sitd->hw_buf [0]),
-		le32_to_cpu(sitd->hw_buf [1]));
+		hc32_to_cpu(ehci, sitd->hw_fullspeed_ep),
+		hc32_to_cpu(ehci, sitd->hw_uframe),
+		hc32_to_cpu(ehci, sitd->hw_results),
+		hc32_to_cpu(ehci, sitd->hw_buf[0]),
+		hc32_to_cpu(ehci, sitd->hw_buf[1]));
 }
 }
 
 
-static int __attribute__((__unused__))
+static int __maybe_unused
 dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
 dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
 {
 {
 	return scnprintf (buf, len,
 	return scnprintf (buf, len,
@@ -203,7 +205,7 @@ dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
 		);
 		);
 }
 }
 
 
-static int __attribute__((__unused__))
+static int __maybe_unused
 dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable)
 dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable)
 {
 {
 	return scnprintf (buf, len,
 	return scnprintf (buf, len,
@@ -267,28 +269,27 @@ dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
 		(status & PORT_PEC) ? " PEC" : "",
 		(status & PORT_PEC) ? " PEC" : "",
 		(status & PORT_PE) ? " PE" : "",
 		(status & PORT_PE) ? " PE" : "",
 		(status & PORT_CSC) ? " CSC" : "",
 		(status & PORT_CSC) ? " CSC" : "",
-		(status & PORT_CONNECT) ? " CONNECT" : ""
-	    );
+		(status & PORT_CONNECT) ? " CONNECT" : "");
 }
 }
 
 
 #else
 #else
-static inline void __attribute__((__unused__))
+static inline void __maybe_unused
 dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
 dbg_qh (char *label, struct ehci_hcd *ehci, struct ehci_qh *qh)
 {}
 {}
 
 
-static inline int __attribute__((__unused__))
+static inline int __maybe_unused
 dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
 dbg_status_buf (char *buf, unsigned len, const char *label, u32 status)
 { return 0; }
 { return 0; }
 
 
-static inline int __attribute__((__unused__))
+static inline int __maybe_unused
 dbg_command_buf (char *buf, unsigned len, const char *label, u32 command)
 dbg_command_buf (char *buf, unsigned len, const char *label, u32 command)
 { return 0; }
 { return 0; }
 
 
-static inline int __attribute__((__unused__))
+static inline int __maybe_unused
 dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable)
 dbg_intr_buf (char *buf, unsigned len, const char *label, u32 enable)
 { return 0; }
 { return 0; }
 
 
-static inline int __attribute__((__unused__))
+static inline int __maybe_unused
 dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
 dbg_port_buf (char *buf, unsigned len, const char *label, int port, u32 status)
 { return 0; }
 { return 0; }
 
 
@@ -332,9 +333,10 @@ static inline void remove_debug_files (struct ehci_hcd *bus) { }
 		default: tmp = '?'; break; \
 		default: tmp = '?'; break; \
 		}; tmp; })
 		}; tmp; })
 
 
-static inline char token_mark (__le32 token)
+static inline char token_mark(struct ehci_hcd *ehci, __hc32 token)
 {
 {
-	__u32 v = le32_to_cpu (token);
+	__u32 v = hc32_to_cpu(ehci, token);
+
 	if (v & QTD_STS_ACTIVE)
 	if (v & QTD_STS_ACTIVE)
 		return '*';
 		return '*';
 	if (v & QTD_STS_HALT)
 	if (v & QTD_STS_HALT)
@@ -360,46 +362,48 @@ static void qh_lines (
 	unsigned		size = *sizep;
 	unsigned		size = *sizep;
 	char			*next = *nextp;
 	char			*next = *nextp;
 	char			mark;
 	char			mark;
+	u32			list_end = EHCI_LIST_END(ehci);
 
 
-	if (qh->hw_qtd_next == EHCI_LIST_END)	/* NEC does this */
+	if (qh->hw_qtd_next == list_end)	/* NEC does this */
 		mark = '@';
 		mark = '@';
 	else
 	else
-		mark = token_mark (qh->hw_token);
+		mark = token_mark(ehci, qh->hw_token);
 	if (mark == '/') {	/* qh_alt_next controls qh advance? */
 	if (mark == '/') {	/* qh_alt_next controls qh advance? */
-		if ((qh->hw_alt_next & QTD_MASK) == ehci->async->hw_alt_next)
+		if ((qh->hw_alt_next & QTD_MASK(ehci))
+				== ehci->async->hw_alt_next)
 			mark = '#';	/* blocked */
 			mark = '#';	/* blocked */
-		else if (qh->hw_alt_next == EHCI_LIST_END)
+		else if (qh->hw_alt_next == list_end)
 			mark = '.';	/* use hw_qtd_next */
 			mark = '.';	/* use hw_qtd_next */
 		/* else alt_next points to some other qtd */
 		/* else alt_next points to some other qtd */
 	}
 	}
-	scratch = le32_to_cpup (&qh->hw_info1);
-	hw_curr = (mark == '*') ? le32_to_cpup (&qh->hw_current) : 0;
+	scratch = hc32_to_cpup(ehci, &qh->hw_info1);
+	hw_curr = (mark == '*') ? hc32_to_cpup(ehci, &qh->hw_current) : 0;
 	temp = scnprintf (next, size,
 	temp = scnprintf (next, size,
 			"qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)",
 			"qh/%p dev%d %cs ep%d %08x %08x (%08x%c %s nak%d)",
 			qh, scratch & 0x007f,
 			qh, scratch & 0x007f,
 			speed_char (scratch),
 			speed_char (scratch),
 			(scratch >> 8) & 0x000f,
 			(scratch >> 8) & 0x000f,
-			scratch, le32_to_cpup (&qh->hw_info2),
-			le32_to_cpup (&qh->hw_token), mark,
-			(__constant_cpu_to_le32 (QTD_TOGGLE) & qh->hw_token)
+			scratch, hc32_to_cpup(ehci, &qh->hw_info2),
+			hc32_to_cpup(ehci, &qh->hw_token), mark,
+			(cpu_to_hc32(ehci, QTD_TOGGLE) & qh->hw_token)
 				? "data1" : "data0",
 				? "data1" : "data0",
-			(le32_to_cpup (&qh->hw_alt_next) >> 1) & 0x0f);
+			(hc32_to_cpup(ehci, &qh->hw_alt_next) >> 1) & 0x0f);
 	size -= temp;
 	size -= temp;
 	next += temp;
 	next += temp;
 
 
 	/* hc may be modifying the list as we read it ... */
 	/* hc may be modifying the list as we read it ... */
 	list_for_each (entry, &qh->qtd_list) {
 	list_for_each (entry, &qh->qtd_list) {
 		td = list_entry (entry, struct ehci_qtd, qtd_list);
 		td = list_entry (entry, struct ehci_qtd, qtd_list);
-		scratch = le32_to_cpup (&td->hw_token);
+		scratch = hc32_to_cpup(ehci, &td->hw_token);
 		mark = ' ';
 		mark = ' ';
 		if (hw_curr == td->qtd_dma)
 		if (hw_curr == td->qtd_dma)
 			mark = '*';
 			mark = '*';
-		else if (qh->hw_qtd_next == cpu_to_le32(td->qtd_dma))
+		else if (qh->hw_qtd_next == cpu_to_hc32(ehci, td->qtd_dma))
 			mark = '+';
 			mark = '+';
 		else if (QTD_LENGTH (scratch)) {
 		else if (QTD_LENGTH (scratch)) {
 			if (td->hw_alt_next == ehci->async->hw_alt_next)
 			if (td->hw_alt_next == ehci->async->hw_alt_next)
 				mark = '#';
 				mark = '#';
-			else if (td->hw_alt_next != EHCI_LIST_END)
+			else if (td->hw_alt_next != list_end)
 				mark = '/';
 				mark = '/';
 		}
 		}
 		temp = snprintf (next, size,
 		temp = snprintf (next, size,
@@ -490,7 +494,7 @@ show_periodic (struct class_device *class_dev, char *buf)
 	unsigned		temp, size, seen_count;
 	unsigned		temp, size, seen_count;
 	char			*next;
 	char			*next;
 	unsigned		i;
 	unsigned		i;
-	__le32			tag;
+	__hc32			tag;
 
 
 	if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC)))
 	if (!(seen = kmalloc (DBG_SCHED_LIMIT * sizeof *seen, GFP_ATOMIC)))
 		return 0;
 		return 0;
@@ -514,18 +518,19 @@ show_periodic (struct class_device *class_dev, char *buf)
 		p = ehci->pshadow [i];
 		p = ehci->pshadow [i];
 		if (likely (!p.ptr))
 		if (likely (!p.ptr))
 			continue;
 			continue;
-		tag = Q_NEXT_TYPE (ehci->periodic [i]);
+		tag = Q_NEXT_TYPE(ehci, ehci->periodic [i]);
 
 
 		temp = scnprintf (next, size, "%4d: ", i);
 		temp = scnprintf (next, size, "%4d: ", i);
 		size -= temp;
 		size -= temp;
 		next += temp;
 		next += temp;
 
 
 		do {
 		do {
-			switch (tag) {
+			switch (hc32_to_cpu(ehci, tag)) {
 			case Q_TYPE_QH:
 			case Q_TYPE_QH:
 				temp = scnprintf (next, size, " qh%d-%04x/%p",
 				temp = scnprintf (next, size, " qh%d-%04x/%p",
 						p.qh->period,
 						p.qh->period,
-						le32_to_cpup (&p.qh->hw_info2)
+						hc32_to_cpup(ehci,
+								&p.qh->hw_info2)
 							/* uframe masks */
 							/* uframe masks */
 							& (QH_CMASK | QH_SMASK),
 							& (QH_CMASK | QH_SMASK),
 						p.qh);
 						p.qh);
@@ -543,7 +548,7 @@ show_periodic (struct class_device *class_dev, char *buf)
 				}
 				}
 				/* show more info the first time around */
 				/* show more info the first time around */
 				if (temp == seen_count && p.ptr) {
 				if (temp == seen_count && p.ptr) {
-					u32	scratch = le32_to_cpup (
+					u32	scratch = hc32_to_cpup(ehci,
 							&p.qh->hw_info1);
 							&p.qh->hw_info1);
 					struct ehci_qtd	*qtd;
 					struct ehci_qtd	*qtd;
 					char		*type = "";
 					char		*type = "";
@@ -554,7 +559,8 @@ show_periodic (struct class_device *class_dev, char *buf)
 							&p.qh->qtd_list,
 							&p.qh->qtd_list,
 							qtd_list) {
 							qtd_list) {
 						temp++;
 						temp++;
-						switch (0x03 & (le32_to_cpu (
+						switch (0x03 & (hc32_to_cpu(
+							ehci,
 							qtd->hw_token) >> 8)) {
 							qtd->hw_token) >> 8)) {
 						case 0: type = "out"; continue;
 						case 0: type = "out"; continue;
 						case 1: type = "in"; continue;
 						case 1: type = "in"; continue;
@@ -576,7 +582,7 @@ show_periodic (struct class_device *class_dev, char *buf)
 				} else
 				} else
 					temp = 0;
 					temp = 0;
 				if (p.qh) {
 				if (p.qh) {
-					tag = Q_NEXT_TYPE (p.qh->hw_next);
+					tag = Q_NEXT_TYPE(ehci, p.qh->hw_next);
 					p = p.qh->qh_next;
 					p = p.qh->qh_next;
 				}
 				}
 				break;
 				break;
@@ -584,23 +590,23 @@ show_periodic (struct class_device *class_dev, char *buf)
 				temp = scnprintf (next, size,
 				temp = scnprintf (next, size,
 					" fstn-%8x/%p", p.fstn->hw_prev,
 					" fstn-%8x/%p", p.fstn->hw_prev,
 					p.fstn);
 					p.fstn);
-				tag = Q_NEXT_TYPE (p.fstn->hw_next);
+				tag = Q_NEXT_TYPE(ehci, p.fstn->hw_next);
 				p = p.fstn->fstn_next;
 				p = p.fstn->fstn_next;
 				break;
 				break;
 			case Q_TYPE_ITD:
 			case Q_TYPE_ITD:
 				temp = scnprintf (next, size,
 				temp = scnprintf (next, size,
 					" itd/%p", p.itd);
 					" itd/%p", p.itd);
-				tag = Q_NEXT_TYPE (p.itd->hw_next);
+				tag = Q_NEXT_TYPE(ehci, p.itd->hw_next);
 				p = p.itd->itd_next;
 				p = p.itd->itd_next;
 				break;
 				break;
 			case Q_TYPE_SITD:
 			case Q_TYPE_SITD:
 				temp = scnprintf (next, size,
 				temp = scnprintf (next, size,
 					" sitd%d-%04x/%p",
 					" sitd%d-%04x/%p",
 					p.sitd->stream->interval,
 					p.sitd->stream->interval,
-					le32_to_cpup (&p.sitd->hw_uframe)
+					hc32_to_cpup(ehci, &p.sitd->hw_uframe)
 						& 0x0000ffff,
 						& 0x0000ffff,
 					p.sitd);
 					p.sitd);
-				tag = Q_NEXT_TYPE (p.sitd->hw_next);
+				tag = Q_NEXT_TYPE(ehci, p.sitd->hw_next);
 				p = p.sitd->sitd_next;
 				p = p.sitd->sitd_next;
 				break;
 				break;
 			}
 			}
@@ -673,7 +679,8 @@ 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 (ehci_readl(ehci, &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) {
@@ -740,14 +747,16 @@ show_registers (struct class_device *class_dev, char *buf)
 
 
 	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,
-				ehci_readl(ehci, &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",
-					ehci_readl(ehci, &ehci->debug->control));
+					ehci_readl(ehci,
+						&ehci->debug->control));
 			size -= temp;
 			size -= temp;
 			next += temp;
 			next += temp;
 		}
 		}

+ 7 - 3
drivers/usb/host/ehci-fsl.c

@@ -67,7 +67,8 @@ int usb_hcd_fsl_probe(const struct hc_driver *driver,
 	 * in host mode.
 	 * in host mode.
 	 */
 	 */
 	if (!((pdata->operating_mode == FSL_USB2_DR_HOST) ||
 	if (!((pdata->operating_mode == FSL_USB2_DR_HOST) ||
-	      (pdata->operating_mode == FSL_USB2_MPH_HOST))) {
+	      (pdata->operating_mode == FSL_USB2_MPH_HOST) ||
+	      (pdata->operating_mode == FSL_USB2_DR_OTG))) {
 		dev_err(&pdev->dev,
 		dev_err(&pdev->dev,
 			"Non Host Mode configured for %s. Wrong driver linked.\n",
 			"Non Host Mode configured for %s. Wrong driver linked.\n",
 			pdev->dev.bus_id);
 			pdev->dev.bus_id);
@@ -185,12 +186,14 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
 	struct fsl_usb2_platform_data *pdata;
 	struct fsl_usb2_platform_data *pdata;
 	void __iomem *non_ehci = hcd->regs;
 	void __iomem *non_ehci = hcd->regs;
+	u32 temp;
 
 
 	pdata =
 	pdata =
 	    (struct fsl_usb2_platform_data *)hcd->self.controller->
 	    (struct fsl_usb2_platform_data *)hcd->self.controller->
 	    platform_data;
 	    platform_data;
 	/* Enable PHY interface in the control reg. */
 	/* Enable PHY interface in the control reg. */
-	out_be32(non_ehci + FSL_SOC_USB_CTRL, 0x00000004);
+	temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
+	out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
 	out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
 	out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
 
 
 #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
 #if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
@@ -206,7 +209,8 @@ static void mpc83xx_usb_setup(struct usb_hcd *hcd)
 	out_be32(non_ehci + FSL_SOC_USB_SNOOP2, 0x80000000 | SNOOP_SIZE_2GB);
 	out_be32(non_ehci + FSL_SOC_USB_SNOOP2, 0x80000000 | SNOOP_SIZE_2GB);
 #endif
 #endif
 
 
-	if (pdata->operating_mode == FSL_USB2_DR_HOST)
+	if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
+			(pdata->operating_mode == FSL_USB2_DR_OTG))
 		mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
 		mpc83xx_setup_phy(ehci, pdata->phy_mode, 0);
 
 
 	if (pdata->operating_mode == FSL_USB2_MPH_HOST) {
 	if (pdata->operating_mode == FSL_USB2_MPH_HOST) {

+ 95 - 23
drivers/usb/host/ehci-hcd.c

@@ -41,10 +41,6 @@
 #include <asm/irq.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/system.h>
 #include <asm/unaligned.h>
 #include <asm/unaligned.h>
-#ifdef CONFIG_PPC_PS3
-#include <asm/firmware.h>
-#endif
-
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
@@ -201,9 +197,15 @@ static void tdi_reset (struct ehci_hcd *ehci)
 	u32 __iomem	*reg_ptr;
 	u32 __iomem	*reg_ptr;
 	u32		tmp;
 	u32		tmp;
 
 
-	reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + 0x68);
+	reg_ptr = (u32 __iomem *)(((u8 __iomem *)ehci->regs) + USBMODE);
 	tmp = ehci_readl(ehci, reg_ptr);
 	tmp = ehci_readl(ehci, reg_ptr);
-	tmp |= 0x3;
+	tmp |= USBMODE_CM_HC;
+	/* The default byte access to MMR space is LE after
+	 * controller reset. Set the required endian mode
+	 * for transfer buffers to match the host microprocessor
+	 */
+	if (ehci_big_endian_mmio(ehci))
+		tmp |= USBMODE_BE;
 	ehci_writel(ehci, tmp, reg_ptr);
 	ehci_writel(ehci, tmp, reg_ptr);
 }
 }
 
 
@@ -273,6 +275,58 @@ static void ehci_work(struct ehci_hcd *ehci);
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
+#ifdef CONFIG_CPU_FREQ
+
+#include <linux/cpufreq.h>
+
+static void ehci_cpufreq_pause (struct ehci_hcd *ehci)
+{
+	unsigned long	flags;
+
+	spin_lock_irqsave(&ehci->lock, flags);
+	if (!ehci->cpufreq_changing++)
+		qh_inactivate_split_intr_qhs(ehci);
+	spin_unlock_irqrestore(&ehci->lock, flags);
+}
+
+static void ehci_cpufreq_unpause (struct ehci_hcd *ehci)
+{
+	unsigned long	flags;
+
+	spin_lock_irqsave(&ehci->lock, flags);
+	if (!--ehci->cpufreq_changing)
+		qh_reactivate_split_intr_qhs(ehci);
+	spin_unlock_irqrestore(&ehci->lock, flags);
+}
+
+/*
+ * ehci_cpufreq_notifier is needed to avoid MMF errors that occur when
+ * EHCI controllers that don't cache many uframes get delayed trying to
+ * read main memory during CPU frequency transitions.  This can cause
+ * split interrupt transactions to not be completed in the required uframe.
+ * This has been observed on the Broadcom/ServerWorks HT1000 controller.
+ */
+static int ehci_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
+				 void *data)
+{
+	struct ehci_hcd *ehci = container_of(nb, struct ehci_hcd,
+					     cpufreq_transition);
+
+	switch (val) {
+	case CPUFREQ_PRECHANGE:
+		ehci_cpufreq_pause(ehci);
+		break;
+	case CPUFREQ_POSTCHANGE:
+		ehci_cpufreq_unpause(ehci);
+		break;
+	}
+	return 0;
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
 static void ehci_watchdog (unsigned long param)
 static void ehci_watchdog (unsigned long param)
 {
 {
 	struct ehci_hcd		*ehci = (struct ehci_hcd *) param;
 	struct ehci_hcd		*ehci = (struct ehci_hcd *) param;
@@ -347,6 +401,8 @@ static void ehci_port_power (struct ehci_hcd *ehci, int is_on)
 				is_on ? SetPortFeature : ClearPortFeature,
 				is_on ? SetPortFeature : ClearPortFeature,
 				USB_PORT_FEAT_POWER,
 				USB_PORT_FEAT_POWER,
 				port--, NULL, 0);
 				port--, NULL, 0);
+	/* Flush those writes */
+	ehci_readl(ehci, &ehci->regs->command);
 	msleep(20);
 	msleep(20);
 }
 }
 
 
@@ -404,6 +460,10 @@ static void ehci_stop (struct usb_hcd *hcd)
 	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
 	spin_unlock_irq(&ehci->lock);
 	spin_unlock_irq(&ehci->lock);
 
 
+#ifdef CONFIG_CPU_FREQ
+	cpufreq_unregister_notifier(&ehci->cpufreq_transition,
+				    CPUFREQ_TRANSITION_NOTIFIER);
+#endif
 	/* let companion controllers work when we aren't */
 	/* let companion controllers work when we aren't */
 	ehci_writel(ehci, 0, &ehci->regs->configured_flag);
 	ehci_writel(ehci, 0, &ehci->regs->configured_flag);
 
 
@@ -470,12 +530,12 @@ static int ehci_init(struct usb_hcd *hcd)
 	 * from automatically advancing to the next td after short reads.
 	 * from automatically advancing to the next td after short reads.
 	 */
 	 */
 	ehci->async->qh_next.qh = NULL;
 	ehci->async->qh_next.qh = NULL;
-	ehci->async->hw_next = QH_NEXT(ehci->async->qh_dma);
-	ehci->async->hw_info1 = cpu_to_le32(QH_HEAD);
-	ehci->async->hw_token = cpu_to_le32(QTD_STS_HALT);
-	ehci->async->hw_qtd_next = EHCI_LIST_END;
+	ehci->async->hw_next = QH_NEXT(ehci, ehci->async->qh_dma);
+	ehci->async->hw_info1 = cpu_to_hc32(ehci, QH_HEAD);
+	ehci->async->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
+	ehci->async->hw_qtd_next = EHCI_LIST_END(ehci);
 	ehci->async->qh_state = QH_STATE_LINKED;
 	ehci->async->qh_state = QH_STATE_LINKED;
-	ehci->async->hw_alt_next = QTD_NEXT(ehci->async->dummy->qtd_dma);
+	ehci->async->hw_alt_next = QTD_NEXT(ehci, ehci->async->dummy->qtd_dma);
 
 
 	/* clear interrupt enables, set irq latency */
 	/* clear interrupt enables, set irq latency */
 	if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
 	if (log2_irq_thresh < 0 || log2_irq_thresh > 6)
@@ -509,6 +569,17 @@ static int ehci_init(struct usb_hcd *hcd)
 	}
 	}
 	ehci->command = temp;
 	ehci->command = temp;
 
 
+#ifdef CONFIG_CPU_FREQ
+	INIT_LIST_HEAD(&ehci->split_intr_qhs);
+	/*
+	 * If the EHCI controller caches enough uframes, this probably
+	 * isn't needed unless there are so many low/full speed devices
+	 * that the controller's can't cache it all.
+	 */
+	ehci->cpufreq_transition.notifier_call = ehci_cpufreq_notifier;
+	cpufreq_register_notifier(&ehci->cpufreq_transition,
+				  CPUFREQ_TRANSITION_NOTIFIER);
+#endif
 	return 0;
 	return 0;
 }
 }
 
 
@@ -925,7 +996,7 @@ MODULE_LICENSE ("GPL");
 #define	PCI_DRIVER		ehci_pci_driver
 #define	PCI_DRIVER		ehci_pci_driver
 #endif
 #endif
 
 
-#ifdef CONFIG_MPC834x
+#ifdef CONFIG_USB_EHCI_FSL
 #include "ehci-fsl.c"
 #include "ehci-fsl.c"
 #define	PLATFORM_DRIVER		ehci_fsl_driver
 #define	PLATFORM_DRIVER		ehci_fsl_driver
 #endif
 #endif
@@ -937,7 +1008,12 @@ MODULE_LICENSE ("GPL");
 
 
 #ifdef CONFIG_PPC_PS3
 #ifdef CONFIG_PPC_PS3
 #include "ehci-ps3.c"
 #include "ehci-ps3.c"
-#define	PS3_SYSTEM_BUS_DRIVER	ps3_ehci_sb_driver
+#define	PS3_SYSTEM_BUS_DRIVER	ps3_ehci_driver
+#endif
+
+#ifdef CONFIG_440EPX
+#include "ehci-ppc-soc.c"
+#define	PLATFORM_DRIVER		ehci_ppc_soc_driver
 #endif
 #endif
 
 
 #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
 #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
@@ -971,18 +1047,15 @@ static int __init ehci_hcd_init(void)
 #endif
 #endif
 
 
 #ifdef PS3_SYSTEM_BUS_DRIVER
 #ifdef PS3_SYSTEM_BUS_DRIVER
-	if (firmware_has_feature(FW_FEATURE_PS3_LV1)) {
-		retval = ps3_system_bus_driver_register(
-				&PS3_SYSTEM_BUS_DRIVER);
-		if (retval < 0) {
+	retval = ps3_ehci_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+	if (retval < 0) {
 #ifdef PLATFORM_DRIVER
 #ifdef PLATFORM_DRIVER
-			platform_driver_unregister(&PLATFORM_DRIVER);
+		platform_driver_unregister(&PLATFORM_DRIVER);
 #endif
 #endif
 #ifdef PCI_DRIVER
 #ifdef PCI_DRIVER
-			pci_unregister_driver(&PCI_DRIVER);
+		pci_unregister_driver(&PCI_DRIVER);
 #endif
 #endif
-			return retval;
-		}
+		return retval;
 	}
 	}
 #endif
 #endif
 
 
@@ -999,8 +1072,7 @@ static void __exit ehci_hcd_cleanup(void)
 	pci_unregister_driver(&PCI_DRIVER);
 	pci_unregister_driver(&PCI_DRIVER);
 #endif
 #endif
 #ifdef PS3_SYSTEM_BUS_DRIVER
 #ifdef PS3_SYSTEM_BUS_DRIVER
-	if (firmware_has_feature(FW_FEATURE_PS3_LV1))
-		ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+	ps3_ehci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
 #endif
 #endif
 }
 }
 module_exit(ehci_hcd_cleanup);
 module_exit(ehci_hcd_cleanup);

+ 116 - 6
drivers/usb/host/ehci-hub.c

@@ -28,6 +28,89 @@
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
+#ifdef	CONFIG_USB_PERSIST
+
+static int ehci_hub_control(
+	struct usb_hcd	*hcd,
+	u16		typeReq,
+	u16		wValue,
+	u16		wIndex,
+	char		*buf,
+	u16		wLength
+);
+
+/* After a power loss, ports that were owned by the companion must be
+ * reset so that the companion can still own them.
+ */
+static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
+{
+	u32 __iomem	*reg;
+	u32		status;
+	int		port;
+	__le32		buf;
+	struct usb_hcd	*hcd = ehci_to_hcd(ehci);
+
+	if (!ehci->owned_ports)
+		return;
+
+	/* Give the connections some time to appear */
+	msleep(20);
+
+	port = HCS_N_PORTS(ehci->hcs_params);
+	while (port--) {
+		if (test_bit(port, &ehci->owned_ports)) {
+			reg = &ehci->regs->port_status[port];
+			status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
+
+			/* Port already owned by companion? */
+			if (status & PORT_OWNER)
+				clear_bit(port, &ehci->owned_ports);
+			else if (test_bit(port, &ehci->companion_ports))
+				ehci_writel(ehci, status & ~PORT_PE, reg);
+			else
+				ehci_hub_control(hcd, SetPortFeature,
+						USB_PORT_FEAT_RESET, port + 1,
+						NULL, 0);
+		}
+	}
+
+	if (!ehci->owned_ports)
+		return;
+	msleep(90);		/* Wait for resets to complete */
+
+	port = HCS_N_PORTS(ehci->hcs_params);
+	while (port--) {
+		if (test_bit(port, &ehci->owned_ports)) {
+			ehci_hub_control(hcd, GetPortStatus,
+					0, port + 1,
+					(char *) &buf, sizeof(buf));
+
+			/* The companion should now own the port,
+			 * but if something went wrong the port must not
+			 * remain enabled.
+			 */
+			reg = &ehci->regs->port_status[port];
+			status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
+			if (status & PORT_OWNER)
+				ehci_writel(ehci, status | PORT_CSC, reg);
+			else {
+				ehci_dbg(ehci, "failed handover port %d: %x\n",
+						port + 1, status);
+				ehci_writel(ehci, status & ~PORT_PE, reg);
+			}
+		}
+	}
+
+	ehci->owned_ports = 0;
+}
+
+#else	/* CONFIG_USB_PERSIST */
+
+static inline void ehci_handover_companion_ports(struct ehci_hcd *ehci)
+{ }
+
+#endif
+
 #ifdef	CONFIG_PM
 #ifdef	CONFIG_PM
 
 
 static int ehci_bus_suspend (struct usb_hcd *hcd)
 static int ehci_bus_suspend (struct usb_hcd *hcd)
@@ -60,14 +143,16 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
 	 * then manually resume them in the bus_resume() routine.
 	 * then manually resume them in the bus_resume() routine.
 	 */
 	 */
 	ehci->bus_suspended = 0;
 	ehci->bus_suspended = 0;
+	ehci->owned_ports = 0;
 	while (port--) {
 	while (port--) {
 		u32 __iomem	*reg = &ehci->regs->port_status [port];
 		u32 __iomem	*reg = &ehci->regs->port_status [port];
 		u32		t1 = ehci_readl(ehci, 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 */
-		if ((t1 & PORT_PE) && !(t1 & PORT_OWNER) &&
-				!(t1 & PORT_SUSPEND)) {
+		if (t1 & PORT_OWNER)
+			set_bit(port, &ehci->owned_ports);
+		else if ((t1 & PORT_PE) && !(t1 & PORT_SUSPEND)) {
 			t2 |= PORT_SUSPEND;
 			t2 |= PORT_SUSPEND;
 			set_bit(port, &ehci->bus_suspended);
 			set_bit(port, &ehci->bus_suspended);
 		}
 		}
@@ -108,11 +193,16 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
 {
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	u32			temp;
 	u32			temp;
+	u32			power_okay;
 	int			i;
 	int			i;
 
 
 	if (time_before (jiffies, ehci->next_statechange))
 	if (time_before (jiffies, ehci->next_statechange))
 		msleep(5);
 		msleep(5);
 	spin_lock_irq (&ehci->lock);
 	spin_lock_irq (&ehci->lock);
+	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+		spin_unlock_irq(&ehci->lock);
+		return -ESHUTDOWN;
+	}
 
 
 	/* Ideally and we've got a real resume here, and no port's power
 	/* Ideally and we've got a real resume here, and no port's power
 	 * was lost.  (For PCI, that means Vaux was maintained.)  But we
 	 * was lost.  (For PCI, that means Vaux was maintained.)  But we
@@ -120,8 +210,9 @@ 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 = ehci_readl(ehci, &ehci->regs->intr_enable);
-	ehci_dbg(ehci, "resume root hub%s\n", temp ? "" : " after power loss");
+	power_okay = ehci_readl(ehci, &ehci->regs->intr_enable);
+	ehci_dbg(ehci, "resume root hub%s\n",
+			power_okay ? "" : " 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.
@@ -184,6 +275,9 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
 	ehci_writel(ehci, 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);
+
+	if (!power_okay)
+		ehci_handover_companion_ports(ehci);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -448,7 +542,8 @@ 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 __iomem	*status_reg = &ehci->regs->port_status[
+				(wIndex & 0xff) - 1];
 	u32		temp, status;
 	u32		temp, status;
 	unsigned long	flags;
 	unsigned long	flags;
 	int		retval = 0;
 	int		retval = 0;
@@ -556,9 +651,24 @@ static int ehci_hub_control (
 			status |= 1 << USB_PORT_FEAT_C_CONNECTION;
 			status |= 1 << USB_PORT_FEAT_C_CONNECTION;
 		if (temp & PORT_PEC)
 		if (temp & PORT_PEC)
 			status |= 1 << USB_PORT_FEAT_C_ENABLE;
 			status |= 1 << USB_PORT_FEAT_C_ENABLE;
-		if ((temp & PORT_OCC) && !ignore_oc)
+
+		if ((temp & PORT_OCC) && !ignore_oc){
 			status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
 			status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT;
 
 
+			/*
+			 * Hubs should disable port power on over-current.
+			 * However, not all EHCI implementations do this
+			 * automatically, even if they _do_ support per-port
+			 * power switching; they're allowed to just limit the
+			 * current.  khubd will turn the power back on.
+			 */
+			if (HCS_PPC (ehci->hcs_params)){
+				ehci_writel(ehci,
+					temp & ~(PORT_RWC_BITS | PORT_POWER),
+					status_reg);
+			}
+		}
+
 		/* whoever resumes must GetPortStatus to complete it!! */
 		/* whoever resumes must GetPortStatus to complete it!! */
 		if (temp & PORT_RESUME) {
 		if (temp & PORT_RESUME) {
 
 

+ 16 - 11
drivers/usb/host/ehci-mem.c

@@ -27,7 +27,7 @@
  *	  need to use dma_pool or dma_alloc_coherent
  *	  need to use dma_pool or dma_alloc_coherent
  *	- driver buffers, read/written by HC ... single shot DMA mapped
  *	- driver buffers, read/written by HC ... single shot DMA mapped
  *
  *
- * There's also PCI "register" data, which is memory mapped.
+ * There's also "register" data (e.g. PCI or SOC), which is memory mapped.
  * No memory seen by this driver is pageable.
  * No memory seen by this driver is pageable.
  */
  */
 
 
@@ -35,13 +35,14 @@
 
 
 /* Allocate the key transfer structures from the previously allocated pool */
 /* Allocate the key transfer structures from the previously allocated pool */
 
 
-static inline void ehci_qtd_init (struct ehci_qtd *qtd, dma_addr_t dma)
+static inline void ehci_qtd_init(struct ehci_hcd *ehci, struct ehci_qtd *qtd,
+				  dma_addr_t dma)
 {
 {
 	memset (qtd, 0, sizeof *qtd);
 	memset (qtd, 0, sizeof *qtd);
 	qtd->qtd_dma = dma;
 	qtd->qtd_dma = dma;
 	qtd->hw_token = cpu_to_le32 (QTD_STS_HALT);
 	qtd->hw_token = cpu_to_le32 (QTD_STS_HALT);
-	qtd->hw_next = EHCI_LIST_END;
-	qtd->hw_alt_next = EHCI_LIST_END;
+	qtd->hw_next = EHCI_LIST_END(ehci);
+	qtd->hw_alt_next = EHCI_LIST_END(ehci);
 	INIT_LIST_HEAD (&qtd->qtd_list);
 	INIT_LIST_HEAD (&qtd->qtd_list);
 }
 }
 
 
@@ -52,7 +53,7 @@ static struct ehci_qtd *ehci_qtd_alloc (struct ehci_hcd *ehci, gfp_t flags)
 
 
 	qtd = dma_pool_alloc (ehci->qtd_pool, flags, &dma);
 	qtd = dma_pool_alloc (ehci->qtd_pool, flags, &dma);
 	if (qtd != NULL) {
 	if (qtd != NULL) {
-		ehci_qtd_init (qtd, dma);
+		ehci_qtd_init(ehci, qtd, dma);
 	}
 	}
 	return qtd;
 	return qtd;
 }
 }
@@ -63,9 +64,8 @@ static inline void ehci_qtd_free (struct ehci_hcd *ehci, struct ehci_qtd *qtd)
 }
 }
 
 
 
 
-static void qh_destroy (struct kref *kref)
+static void qh_destroy(struct ehci_qh *qh)
 {
 {
-	struct ehci_qh *qh = container_of(kref, struct ehci_qh, kref);
 	struct ehci_hcd *ehci = qh->ehci;
 	struct ehci_hcd *ehci = qh->ehci;
 
 
 	/* clean qtds first, and know this is not linked */
 	/* clean qtds first, and know this is not linked */
@@ -89,11 +89,14 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
 		return qh;
 		return qh;
 
 
 	memset (qh, 0, sizeof *qh);
 	memset (qh, 0, sizeof *qh);
-	kref_init(&qh->kref);
+	qh->refcount = 1;
 	qh->ehci = ehci;
 	qh->ehci = ehci;
 	qh->qh_dma = dma;
 	qh->qh_dma = dma;
 	// INIT_LIST_HEAD (&qh->qh_list);
 	// INIT_LIST_HEAD (&qh->qh_list);
 	INIT_LIST_HEAD (&qh->qtd_list);
 	INIT_LIST_HEAD (&qh->qtd_list);
+#ifdef CONFIG_CPU_FREQ
+	INIT_LIST_HEAD (&qh->split_intr_qhs);
+#endif
 
 
 	/* dummy td enables safe urb queuing */
 	/* dummy td enables safe urb queuing */
 	qh->dummy = ehci_qtd_alloc (ehci, flags);
 	qh->dummy = ehci_qtd_alloc (ehci, flags);
@@ -108,13 +111,15 @@ static struct ehci_qh *ehci_qh_alloc (struct ehci_hcd *ehci, gfp_t flags)
 /* to share a qh (cpu threads, or hc) */
 /* to share a qh (cpu threads, or hc) */
 static inline struct ehci_qh *qh_get (struct ehci_qh *qh)
 static inline struct ehci_qh *qh_get (struct ehci_qh *qh)
 {
 {
-	kref_get(&qh->kref);
+	WARN_ON(!qh->refcount);
+	qh->refcount++;
 	return qh;
 	return qh;
 }
 }
 
 
 static inline void qh_put (struct ehci_qh *qh)
 static inline void qh_put (struct ehci_qh *qh)
 {
 {
-	kref_put(&qh->kref, qh_destroy);
+	if (!--qh->refcount)
+		qh_destroy(qh);
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -217,7 +222,7 @@ static int ehci_mem_init (struct ehci_hcd *ehci, gfp_t flags)
 		goto fail;
 		goto fail;
 	}
 	}
 	for (i = 0; i < ehci->periodic_size; i++)
 	for (i = 0; i < ehci->periodic_size; i++)
-		ehci->periodic [i] = EHCI_LIST_END;
+		ehci->periodic [i] = EHCI_LIST_END(ehci);
 
 
 	/* software shadow of hardware table */
 	/* software shadow of hardware table */
 	ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags);
 	ehci->pshadow = kcalloc(ehci->periodic_size, sizeof(void *), flags);

+ 4 - 3
drivers/usb/host/ehci-pci.c

@@ -312,13 +312,14 @@ static int ehci_pci_resume(struct usb_hcd *hcd)
 	ehci_work(ehci);
 	ehci_work(ehci);
 	spin_unlock_irq(&ehci->lock);
 	spin_unlock_irq(&ehci->lock);
 
 
-	/* here we "know" root ports should always stay powered */
-	ehci_port_power(ehci, 1);
-
 	ehci_writel(ehci, ehci->command, &ehci->regs->command);
 	ehci_writel(ehci, ehci->command, &ehci->regs->command);
 	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
 	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
 	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
 	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
 
 
+	/* here we "know" root ports should always stay powered */
+	ehci_port_power(ehci, 1);
+	ehci_handover_companion_ports(ehci);
+
 	hcd->state = HC_STATE_SUSPENDED;
 	hcd->state = HC_STATE_SUSPENDED;
 	return 0;
 	return 0;
 }
 }

+ 182 - 0
drivers/usb/host/ehci-ppc-soc.c

@@ -0,0 +1,182 @@
+/*
+ * EHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 2006-2007 Stefan Roese <sr@denx.de>, DENX Software Engineering
+ *
+ * Bus Glue for PPC On-Chip EHCI driver
+ * Tested on AMCC 440EPx
+ *
+ * Based on "ehci-au12xx.c" by David Brownell <dbrownell@users.sourceforge.net>
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/platform_device.h>
+
+extern int usb_disabled(void);
+
+/**
+ * usb_ehci_ppc_soc_probe - initialize PPC-SoC-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ *
+ */
+int usb_ehci_ppc_soc_probe(const struct hc_driver *driver,
+			   struct usb_hcd **hcd_out,
+			   struct platform_device *dev)
+{
+	int retval;
+	struct usb_hcd *hcd;
+	struct ehci_hcd *ehci;
+
+	if (dev->resource[1].flags != IORESOURCE_IRQ) {
+		pr_debug("resource[1] is not IORESOURCE_IRQ");
+		retval = -ENOMEM;
+	}
+	hcd = usb_create_hcd(driver, &dev->dev, "PPC-SOC EHCI");
+	if (!hcd)
+		return -ENOMEM;
+	hcd->rsrc_start = dev->resource[0].start;
+	hcd->rsrc_len = dev->resource[0].end - dev->resource[0].start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		pr_debug("request_mem_region failed");
+		retval = -EBUSY;
+		goto err1;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		pr_debug("ioremap failed");
+		retval = -ENOMEM;
+		goto err2;
+	}
+
+	ehci = hcd_to_ehci(hcd);
+	ehci->big_endian_mmio = 1;
+	ehci->big_endian_desc = 1;
+	ehci->caps = hcd->regs;
+	ehci->regs = hcd->regs + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+
+	/* cache this readonly data; minimize chip reads */
+	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+#if defined(CONFIG_440EPX)
+	/*
+	 * 440EPx Errata USBH_3
+	 * Fix: Enable Break Memory Transfer (BMT) in INSNREG3
+	 */
+	out_be32((void *)((ulong)(&ehci->regs->command) + 0x8c), (1 << 0));
+	ehci_dbg(ehci, "Break Memory Transfer (BMT) has beed enabled!\n");
+#endif
+
+	retval = usb_add_hcd(hcd, dev->resource[1].start, IRQF_DISABLED);
+	if (retval == 0)
+		return retval;
+
+	iounmap(hcd->regs);
+err2:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err1:
+	usb_put_hcd(hcd);
+	return retval;
+}
+
+/* may be called without controller electrically present */
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_ehci_hcd_ppc_soc_remove - shutdown processing for PPC-SoC-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_ehci_hcd_ppc_soc_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ *
+ */
+void usb_ehci_ppc_soc_remove(struct usb_hcd *hcd, struct platform_device *dev)
+{
+	usb_remove_hcd(hcd);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+}
+
+static const struct hc_driver ehci_ppc_soc_hc_driver = {
+	.description = hcd_name,
+	.product_desc = "PPC-SOC EHCI",
+	.hcd_priv_size = sizeof(struct ehci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq = ehci_irq,
+	.flags = HCD_MEMORY | HCD_USB2,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset = ehci_init,
+	.start = ehci_run,
+	.stop = ehci_stop,
+	.shutdown = ehci_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue = ehci_urb_enqueue,
+	.urb_dequeue = ehci_urb_dequeue,
+	.endpoint_disable = ehci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number = ehci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data = ehci_hub_status_data,
+	.hub_control = ehci_hub_control,
+#ifdef	CONFIG_PM
+	.hub_suspend = ehci_hub_suspend,
+	.hub_resume = ehci_hub_resume,
+#endif
+};
+
+static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd = NULL;
+	int ret;
+
+	pr_debug("In ehci_hcd_ppc_soc_drv_probe\n");
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	ret = usb_ehci_ppc_soc_probe(&ehci_ppc_soc_hc_driver, &hcd, pdev);
+	return ret;
+}
+
+static int ehci_hcd_ppc_soc_drv_remove(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+	usb_ehci_ppc_soc_remove(hcd, pdev);
+	return 0;
+}
+
+MODULE_ALIAS("ppc-soc-ehci");
+static struct platform_driver ehci_ppc_soc_driver = {
+	.probe = ehci_hcd_ppc_soc_drv_probe,
+	.remove = ehci_hcd_ppc_soc_drv_remove,
+	.shutdown = usb_hcd_platform_shutdown,
+	.driver = {
+		.name = "ppc-soc-ehci",
+		.bus = &platform_bus_type
+	}
+};

+ 74 - 12
drivers/usb/host/ehci-ps3.c

@@ -18,6 +18,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
  */
 
 
+#include <asm/firmware.h>
 #include <asm/ps3.h>
 #include <asm/ps3.h>
 
 
 static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
 static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
@@ -73,7 +74,7 @@ static const struct hc_driver ps3_ehci_hc_driver = {
 #endif
 #endif
 };
 };
 
 
-static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
+static int ps3_ehci_probe(struct ps3_system_bus_device *dev)
 {
 {
 	int result;
 	int result;
 	struct usb_hcd *hcd;
 	struct usb_hcd *hcd;
@@ -85,13 +86,30 @@ static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
 		goto fail_start;
 		goto fail_start;
 	}
 	}
 
 
+	result = ps3_open_hv_device(dev);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: ps3_open_hv_device failed\n",
+			__func__, __LINE__);
+		goto fail_open;
+	}
+
+	result = ps3_dma_region_create(dev->d_region);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: ps3_dma_region_create failed: "
+			"(%d)\n", __func__, __LINE__, result);
+		BUG_ON("check region type");
+		goto fail_dma_region;
+	}
+
 	result = ps3_mmio_region_create(dev->m_region);
 	result = ps3_mmio_region_create(dev->m_region);
 
 
 	if (result) {
 	if (result) {
 		dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
 		dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
 			__func__, __LINE__);
 			__func__, __LINE__);
 		result = -EPERM;
 		result = -EPERM;
-		goto fail_mmio;
+		goto fail_mmio_region;
 	}
 	}
 
 
 	dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
 	dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
@@ -120,6 +138,11 @@ static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
 
 
 	hcd->rsrc_start = dev->m_region->lpar_addr;
 	hcd->rsrc_start = dev->m_region->lpar_addr;
 	hcd->rsrc_len = dev->m_region->len;
 	hcd->rsrc_len = dev->m_region->len;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name))
+		dev_dbg(&dev->core, "%s:%d: request_mem_region failed\n",
+			__func__, __LINE__);
+
 	hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
 	hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
 
 
 	if (!hcd->regs) {
 	if (!hcd->regs) {
@@ -153,34 +176,73 @@ static int ps3_ehci_sb_probe(struct ps3_system_bus_device *dev)
 fail_add_hcd:
 fail_add_hcd:
 	iounmap(hcd->regs);
 	iounmap(hcd->regs);
 fail_ioremap:
 fail_ioremap:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
 	usb_put_hcd(hcd);
 fail_create_hcd:
 fail_create_hcd:
 	ps3_io_irq_destroy(virq);
 	ps3_io_irq_destroy(virq);
 fail_irq:
 fail_irq:
 	ps3_free_mmio_region(dev->m_region);
 	ps3_free_mmio_region(dev->m_region);
-fail_mmio:
+fail_mmio_region:
+	ps3_dma_region_free(dev->d_region);
+fail_dma_region:
+	ps3_close_hv_device(dev);
+fail_open:
 fail_start:
 fail_start:
 	return result;
 	return result;
 }
 }
 
 
-static int ps3_ehci_sb_remove(struct ps3_system_bus_device *dev)
+static int ps3_ehci_remove(struct ps3_system_bus_device *dev)
 {
 {
+	unsigned int tmp;
 	struct usb_hcd *hcd =
 	struct usb_hcd *hcd =
 		(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
 		(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
 
 
-	usb_put_hcd(hcd);
+	BUG_ON(!hcd);
+
+	dev_dbg(&dev->core, "%s:%d: regs %p\n", __func__, __LINE__, hcd->regs);
+	dev_dbg(&dev->core, "%s:%d: irq %u\n", __func__, __LINE__, hcd->irq);
+
+	tmp = hcd->irq;
+
+	usb_remove_hcd(hcd);
+
 	ps3_system_bus_set_driver_data(dev, NULL);
 	ps3_system_bus_set_driver_data(dev, NULL);
 
 
+	BUG_ON(!hcd->regs);
+	iounmap(hcd->regs);
+
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+
+	ps3_io_irq_destroy(tmp);
+	ps3_free_mmio_region(dev->m_region);
+
+	ps3_dma_region_free(dev->d_region);
+	ps3_close_hv_device(dev);
+
 	return 0;
 	return 0;
 }
 }
 
 
-MODULE_ALIAS("ps3-ehci");
+static int ps3_ehci_driver_register(struct ps3_system_bus_driver *drv)
+{
+	return firmware_has_feature(FW_FEATURE_PS3_LV1)
+		? ps3_system_bus_driver_register(drv)
+		: 0;
+}
+
+static void ps3_ehci_driver_unregister(struct ps3_system_bus_driver *drv)
+{
+	if (firmware_has_feature(FW_FEATURE_PS3_LV1))
+		ps3_system_bus_driver_unregister(drv);
+}
+
+MODULE_ALIAS(PS3_MODULE_ALIAS_EHCI);
 
 
-static struct ps3_system_bus_driver ps3_ehci_sb_driver = {
+static struct ps3_system_bus_driver ps3_ehci_driver = {
+	.core.name = "ps3-ehci-driver",
+	.core.owner = THIS_MODULE,
 	.match_id = PS3_MATCH_ID_EHCI,
 	.match_id = PS3_MATCH_ID_EHCI,
-	.core = {
-		.name = "ps3-ehci-driver",
-	},
-	.probe = ps3_ehci_sb_probe,
-	.remove = ps3_ehci_sb_remove,
+	.probe = ps3_ehci_probe,
+	.remove = ps3_ehci_remove,
+	.shutdown = ps3_ehci_remove,
 };
 };

+ 51 - 45
drivers/usb/host/ehci-q.c

@@ -43,15 +43,15 @@
 /* fill a qtd, returning how much of the buffer we were able to queue up */
 /* fill a qtd, returning how much of the buffer we were able to queue up */
 
 
 static int
 static int
-qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len,
-		int token, int maxpacket)
+qtd_fill(struct ehci_hcd *ehci, struct ehci_qtd *qtd, dma_addr_t buf,
+		  size_t len, int token, int maxpacket)
 {
 {
 	int	i, count;
 	int	i, count;
 	u64	addr = buf;
 	u64	addr = buf;
 
 
 	/* one buffer entry per 4K ... first might be short or unaligned */
 	/* one buffer entry per 4K ... first might be short or unaligned */
-	qtd->hw_buf [0] = cpu_to_le32 ((u32)addr);
-	qtd->hw_buf_hi [0] = cpu_to_le32 ((u32)(addr >> 32));
+	qtd->hw_buf[0] = cpu_to_hc32(ehci, (u32)addr);
+	qtd->hw_buf_hi[0] = cpu_to_hc32(ehci, (u32)(addr >> 32));
 	count = 0x1000 - (buf & 0x0fff);	/* rest of that page */
 	count = 0x1000 - (buf & 0x0fff);	/* rest of that page */
 	if (likely (len < count))		/* ... iff needed */
 	if (likely (len < count))		/* ... iff needed */
 		count = len;
 		count = len;
@@ -62,8 +62,9 @@ qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len,
 		/* per-qtd limit: from 16K to 20K (best alignment) */
 		/* per-qtd limit: from 16K to 20K (best alignment) */
 		for (i = 1; count < len && i < 5; i++) {
 		for (i = 1; count < len && i < 5; i++) {
 			addr = buf;
 			addr = buf;
-			qtd->hw_buf [i] = cpu_to_le32 ((u32)addr);
-			qtd->hw_buf_hi [i] = cpu_to_le32 ((u32)(addr >> 32));
+			qtd->hw_buf[i] = cpu_to_hc32(ehci, (u32)addr);
+			qtd->hw_buf_hi[i] = cpu_to_hc32(ehci,
+					(u32)(addr >> 32));
 			buf += 0x1000;
 			buf += 0x1000;
 			if ((count + 0x1000) < len)
 			if ((count + 0x1000) < len)
 				count += 0x1000;
 				count += 0x1000;
@@ -75,7 +76,7 @@ qtd_fill (struct ehci_qtd *qtd, dma_addr_t buf, size_t len,
 		if (count != len)
 		if (count != len)
 			count -= (count % maxpacket);
 			count -= (count % maxpacket);
 	}
 	}
-	qtd->hw_token = cpu_to_le32 ((count << 16) | token);
+	qtd->hw_token = cpu_to_hc32(ehci, (count << 16) | token);
 	qtd->length = count;
 	qtd->length = count;
 
 
 	return count;
 	return count;
@@ -89,28 +90,28 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
 	/* writes to an active overlay are unsafe */
 	/* writes to an active overlay are unsafe */
 	BUG_ON(qh->qh_state != QH_STATE_IDLE);
 	BUG_ON(qh->qh_state != QH_STATE_IDLE);
 
 
-	qh->hw_qtd_next = QTD_NEXT (qtd->qtd_dma);
-	qh->hw_alt_next = EHCI_LIST_END;
+	qh->hw_qtd_next = QTD_NEXT(ehci, qtd->qtd_dma);
+	qh->hw_alt_next = EHCI_LIST_END(ehci);
 
 
 	/* Except for control endpoints, we make hardware maintain data
 	/* Except for control endpoints, we make hardware maintain data
 	 * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
 	 * toggle (like OHCI) ... here (re)initialize the toggle in the QH,
 	 * and set the pseudo-toggle in udev. Only usb_clear_halt() will
 	 * and set the pseudo-toggle in udev. Only usb_clear_halt() will
 	 * ever clear it.
 	 * ever clear it.
 	 */
 	 */
-	if (!(qh->hw_info1 & cpu_to_le32(1 << 14))) {
+	if (!(qh->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
 		unsigned	is_out, epnum;
 		unsigned	is_out, epnum;
 
 
-		is_out = !(qtd->hw_token & cpu_to_le32(1 << 8));
-		epnum = (le32_to_cpup(&qh->hw_info1) >> 8) & 0x0f;
+		is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8));
+		epnum = (hc32_to_cpup(ehci, &qh->hw_info1) >> 8) & 0x0f;
 		if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
 		if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
-			qh->hw_token &= ~__constant_cpu_to_le32 (QTD_TOGGLE);
+			qh->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
 			usb_settoggle (qh->dev, epnum, is_out, 1);
 			usb_settoggle (qh->dev, epnum, is_out, 1);
 		}
 		}
 	}
 	}
 
 
 	/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
 	/* HC must see latest qtd and qh data before we clear ACTIVE+HALT */
 	wmb ();
 	wmb ();
-	qh->hw_token &= __constant_cpu_to_le32 (QTD_TOGGLE | QTD_STS_PING);
+	qh->hw_token &= cpu_to_hc32(ehci, QTD_TOGGLE | QTD_STS_PING);
 }
 }
 
 
 /* if it weren't for a common silicon quirk (writing the dummy into the qh
 /* if it weren't for a common silicon quirk (writing the dummy into the qh
@@ -128,7 +129,7 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
 		qtd = list_entry (qh->qtd_list.next,
 		qtd = list_entry (qh->qtd_list.next,
 				struct ehci_qtd, qtd_list);
 				struct ehci_qtd, qtd_list);
 		/* first qtd may already be partially processed */
 		/* first qtd may already be partially processed */
-		if (cpu_to_le32 (qtd->qtd_dma) == qh->hw_current)
+		if (cpu_to_hc32(ehci, qtd->qtd_dma) == qh->hw_current)
 			qtd = NULL;
 			qtd = NULL;
 	}
 	}
 
 
@@ -222,7 +223,7 @@ __acquires(ehci->lock)
 		struct ehci_qh	*qh = (struct ehci_qh *) urb->hcpriv;
 		struct ehci_qh	*qh = (struct ehci_qh *) urb->hcpriv;
 
 
 		/* S-mask in a QH means it's an interrupt urb */
 		/* S-mask in a QH means it's an interrupt urb */
-		if ((qh->hw_info2 & __constant_cpu_to_le32 (QH_SMASK)) != 0) {
+		if ((qh->hw_info2 & cpu_to_hc32(ehci, QH_SMASK)) != 0) {
 
 
 			/* ... update hc-wide periodic stats (for usbfs) */
 			/* ... update hc-wide periodic stats (for usbfs) */
 			ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
 			ehci_to_hcd(ehci)->self.bandwidth_int_reqs--;
@@ -277,7 +278,6 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh);
  * Chases up to qh->hw_current.  Returns number of completions called,
  * Chases up to qh->hw_current.  Returns number of completions called,
  * indicating how much "real" work we did.
  * indicating how much "real" work we did.
  */
  */
-#define HALT_BIT __constant_cpu_to_le32(QTD_STS_HALT)
 static unsigned
 static unsigned
 qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
 qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
 {
@@ -287,6 +287,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
 	unsigned		count = 0;
 	unsigned		count = 0;
 	int			do_status = 0;
 	int			do_status = 0;
 	u8			state;
 	u8			state;
+	u32			halt = HALT_BIT(ehci);
 
 
 	if (unlikely (list_empty (&qh->qtd_list)))
 	if (unlikely (list_empty (&qh->qtd_list)))
 		return count;
 		return count;
@@ -311,6 +312,10 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
 		struct urb	*urb;
 		struct urb	*urb;
 		u32		token = 0;
 		u32		token = 0;
 
 
+		/* ignore QHs that are currently inactive */
+		if (qh->hw_info1 & __constant_cpu_to_le32(QH_INACTIVATE))
+			break;
+
 		qtd = list_entry (entry, struct ehci_qtd, qtd_list);
 		qtd = list_entry (entry, struct ehci_qtd, qtd_list);
 		urb = qtd->urb;
 		urb = qtd->urb;
 
 
@@ -330,7 +335,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
 
 		/* hardware copies qtd out of qh overlay */
 		/* hardware copies qtd out of qh overlay */
 		rmb ();
 		rmb ();
-		token = le32_to_cpu (qtd->hw_token);
+		token = hc32_to_cpu(ehci, qtd->hw_token);
 
 
 		/* always clean up qtds the hc de-activated */
 		/* always clean up qtds the hc de-activated */
 		if ((token & QTD_STS_ACTIVE) == 0) {
 		if ((token & QTD_STS_ACTIVE) == 0) {
@@ -342,7 +347,8 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
 			 * that silicon quirk can kick in with this dummy too.
 			 * that silicon quirk can kick in with this dummy too.
 			 */
 			 */
 			} else if (IS_SHORT_READ (token)
 			} else if (IS_SHORT_READ (token)
-					&& !(qtd->hw_alt_next & EHCI_LIST_END)) {
+					&& !(qtd->hw_alt_next
+						& EHCI_LIST_END(ehci))) {
 				stopped = 1;
 				stopped = 1;
 				goto halt;
 				goto halt;
 			}
 			}
@@ -374,17 +380,17 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
 
 			/* token in overlay may be most current */
 			/* token in overlay may be most current */
 			if (state == QH_STATE_IDLE
 			if (state == QH_STATE_IDLE
-					&& cpu_to_le32 (qtd->qtd_dma)
+					&& cpu_to_hc32(ehci, qtd->qtd_dma)
 						== qh->hw_current)
 						== qh->hw_current)
-				token = le32_to_cpu (qh->hw_token);
+				token = hc32_to_cpu(ehci, qh->hw_token);
 
 
 			/* force halt for unlinked or blocked qh, so we'll
 			/* force halt for unlinked or blocked qh, so we'll
 			 * patch the qh later and so that completions can't
 			 * patch the qh later and so that completions can't
 			 * activate it while we "know" it's stopped.
 			 * activate it while we "know" it's stopped.
 			 */
 			 */
-			if ((HALT_BIT & qh->hw_token) == 0) {
+			if ((halt & qh->hw_token) == 0) {
 halt:
 halt:
-				qh->hw_token |= HALT_BIT;
+				qh->hw_token |= halt;
 				wmb ();
 				wmb ();
 			}
 			}
 		}
 		}
@@ -419,7 +425,7 @@ halt:
 	 * it after fault cleanup, or recovering from silicon wrongly
 	 * it after fault cleanup, or recovering from silicon wrongly
 	 * overlaying the dummy qtd (which reduces DMA chatter).
 	 * overlaying the dummy qtd (which reduces DMA chatter).
 	 */
 	 */
-	if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END) {
+	if (stopped != 0 || qh->hw_qtd_next == EHCI_LIST_END(ehci)) {
 		switch (state) {
 		switch (state) {
 		case QH_STATE_IDLE:
 		case QH_STATE_IDLE:
 			qh_refresh(ehci, qh);
 			qh_refresh(ehci, qh);
@@ -428,7 +434,7 @@ halt:
 			/* should be rare for periodic transfers,
 			/* should be rare for periodic transfers,
 			 * except maybe high bandwidth ...
 			 * except maybe high bandwidth ...
 			 */
 			 */
-			if ((__constant_cpu_to_le32 (QH_SMASK)
+			if ((cpu_to_hc32(ehci, QH_SMASK)
 					& qh->hw_info2) != 0) {
 					& qh->hw_info2) != 0) {
 				intr_deschedule (ehci, qh);
 				intr_deschedule (ehci, qh);
 				(void) qh_schedule (ehci, qh);
 				(void) qh_schedule (ehci, qh);
@@ -502,8 +508,9 @@ qh_urb_transaction (
 	is_input = usb_pipein (urb->pipe);
 	is_input = usb_pipein (urb->pipe);
 	if (usb_pipecontrol (urb->pipe)) {
 	if (usb_pipecontrol (urb->pipe)) {
 		/* SETUP pid */
 		/* SETUP pid */
-		qtd_fill (qtd, urb->setup_dma, sizeof (struct usb_ctrlrequest),
-			token | (2 /* "setup" */ << 8), 8);
+		qtd_fill(ehci, qtd, urb->setup_dma,
+				sizeof (struct usb_ctrlrequest),
+				token | (2 /* "setup" */ << 8), 8);
 
 
 		/* ... and always at least one more pid */
 		/* ... and always at least one more pid */
 		token ^= QTD_TOGGLE;
 		token ^= QTD_TOGGLE;
@@ -512,7 +519,7 @@ qh_urb_transaction (
 		if (unlikely (!qtd))
 		if (unlikely (!qtd))
 			goto cleanup;
 			goto cleanup;
 		qtd->urb = urb;
 		qtd->urb = urb;
-		qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+		qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma);
 		list_add_tail (&qtd->qtd_list, head);
 		list_add_tail (&qtd->qtd_list, head);
 
 
 		/* for zero length DATA stages, STATUS is always IN */
 		/* for zero length DATA stages, STATUS is always IN */
@@ -539,7 +546,7 @@ qh_urb_transaction (
 	for (;;) {
 	for (;;) {
 		int this_qtd_len;
 		int this_qtd_len;
 
 
-		this_qtd_len = qtd_fill (qtd, buf, len, token, maxpacket);
+		this_qtd_len = qtd_fill(ehci, qtd, buf, len, token, maxpacket);
 		len -= this_qtd_len;
 		len -= this_qtd_len;
 		buf += this_qtd_len;
 		buf += this_qtd_len;
 		if (is_input)
 		if (is_input)
@@ -557,7 +564,7 @@ qh_urb_transaction (
 		if (unlikely (!qtd))
 		if (unlikely (!qtd))
 			goto cleanup;
 			goto cleanup;
 		qtd->urb = urb;
 		qtd->urb = urb;
-		qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+		qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma);
 		list_add_tail (&qtd->qtd_list, head);
 		list_add_tail (&qtd->qtd_list, head);
 	}
 	}
 
 
@@ -566,7 +573,7 @@ qh_urb_transaction (
 	 */
 	 */
 	if (likely ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0
 	if (likely ((urb->transfer_flags & URB_SHORT_NOT_OK) == 0
 				|| usb_pipecontrol (urb->pipe)))
 				|| usb_pipecontrol (urb->pipe)))
-		qtd->hw_alt_next = EHCI_LIST_END;
+		qtd->hw_alt_next = EHCI_LIST_END(ehci);
 
 
 	/*
 	/*
 	 * control requests may need a terminating data "status" ack;
 	 * control requests may need a terminating data "status" ack;
@@ -590,17 +597,17 @@ qh_urb_transaction (
 			if (unlikely (!qtd))
 			if (unlikely (!qtd))
 				goto cleanup;
 				goto cleanup;
 			qtd->urb = urb;
 			qtd->urb = urb;
-			qtd_prev->hw_next = QTD_NEXT (qtd->qtd_dma);
+			qtd_prev->hw_next = QTD_NEXT(ehci, qtd->qtd_dma);
 			list_add_tail (&qtd->qtd_list, head);
 			list_add_tail (&qtd->qtd_list, head);
 
 
 			/* never any data in such packets */
 			/* never any data in such packets */
-			qtd_fill (qtd, 0, 0, token, 0);
+			qtd_fill(ehci, qtd, 0, 0, token, 0);
 		}
 		}
 	}
 	}
 
 
 	/* by default, enable interrupt on urb completion */
 	/* by default, enable interrupt on urb completion */
 	if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))
 	if (likely (!(urb->transfer_flags & URB_NO_INTERRUPT)))
-		qtd->hw_token |= __constant_cpu_to_le32 (QTD_IOC);
+		qtd->hw_token |= cpu_to_hc32(ehci, QTD_IOC);
 	return head;
 	return head;
 
 
 cleanup:
 cleanup:
@@ -769,8 +776,8 @@ done:
 
 
 	/* init as live, toggle clear, advance to dummy */
 	/* init as live, toggle clear, advance to dummy */
 	qh->qh_state = QH_STATE_IDLE;
 	qh->qh_state = QH_STATE_IDLE;
-	qh->hw_info1 = cpu_to_le32 (info1);
-	qh->hw_info2 = cpu_to_le32 (info2);
+	qh->hw_info1 = cpu_to_hc32(ehci, info1);
+	qh->hw_info2 = cpu_to_hc32(ehci, info2);
 	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
 	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
 	qh_refresh (ehci, qh);
 	qh_refresh (ehci, qh);
 	return qh;
 	return qh;
@@ -782,7 +789,7 @@ done:
 
 
 static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
 {
-	__le32		dma = QH_NEXT (qh->qh_dma);
+	__hc32		dma = QH_NEXT(ehci, qh->qh_dma);
 	struct ehci_qh	*head;
 	struct ehci_qh	*head;
 
 
 	/* (re)start the async schedule? */
 	/* (re)start the async schedule? */
@@ -820,8 +827,6 @@ static void qh_link_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-#define	QH_ADDR_MASK	__constant_cpu_to_le32(0x7f)
-
 /*
 /*
  * For control/bulk/interrupt, return QH with these TDs appended.
  * For control/bulk/interrupt, return QH with these TDs appended.
  * Allocates and initializes the QH if necessary.
  * Allocates and initializes the QH if necessary.
@@ -837,6 +842,7 @@ static struct ehci_qh *qh_append_tds (
 )
 )
 {
 {
 	struct ehci_qh		*qh = NULL;
 	struct ehci_qh		*qh = NULL;
+	u32			qh_addr_mask = cpu_to_hc32(ehci, 0x7f);
 
 
 	qh = (struct ehci_qh *) *ptr;
 	qh = (struct ehci_qh *) *ptr;
 	if (unlikely (qh == NULL)) {
 	if (unlikely (qh == NULL)) {
@@ -858,7 +864,7 @@ static struct ehci_qh *qh_append_tds (
 
 
                         /* usb_reset_device() briefly reverts to address 0 */
                         /* usb_reset_device() briefly reverts to address 0 */
                         if (usb_pipedevice (urb->pipe) == 0)
                         if (usb_pipedevice (urb->pipe) == 0)
-                                qh->hw_info1 &= ~QH_ADDR_MASK;
+                                qh->hw_info1 &= ~qh_addr_mask;
 		}
 		}
 
 
 		/* just one way to queue requests: swap with the dummy qtd.
 		/* just one way to queue requests: swap with the dummy qtd.
@@ -867,7 +873,7 @@ static struct ehci_qh *qh_append_tds (
 		if (likely (qtd != NULL)) {
 		if (likely (qtd != NULL)) {
 			struct ehci_qtd		*dummy;
 			struct ehci_qtd		*dummy;
 			dma_addr_t		dma;
 			dma_addr_t		dma;
-			__le32			token;
+			__hc32			token;
 
 
 			/* to avoid racing the HC, use the dummy td instead of
 			/* to avoid racing the HC, use the dummy td instead of
 			 * the first td of our list (becomes new dummy).  both
 			 * the first td of our list (becomes new dummy).  both
@@ -875,7 +881,7 @@ static struct ehci_qh *qh_append_tds (
 			 * HC is allowed to fetch the old dummy (4.10.2).
 			 * HC is allowed to fetch the old dummy (4.10.2).
 			 */
 			 */
 			token = qtd->hw_token;
 			token = qtd->hw_token;
-			qtd->hw_token = HALT_BIT;
+			qtd->hw_token = HALT_BIT(ehci);
 			wmb ();
 			wmb ();
 			dummy = qh->dummy;
 			dummy = qh->dummy;
 
 
@@ -887,14 +893,14 @@ static struct ehci_qh *qh_append_tds (
 			list_add (&dummy->qtd_list, qtd_list);
 			list_add (&dummy->qtd_list, qtd_list);
 			__list_splice (qtd_list, qh->qtd_list.prev);
 			__list_splice (qtd_list, qh->qtd_list.prev);
 
 
-			ehci_qtd_init (qtd, qtd->qtd_dma);
+			ehci_qtd_init(ehci, qtd, qtd->qtd_dma);
 			qh->dummy = qtd;
 			qh->dummy = qtd;
 
 
 			/* hc must see the new dummy at list end */
 			/* hc must see the new dummy at list end */
 			dma = qtd->qtd_dma;
 			dma = qtd->qtd_dma;
 			qtd = list_entry (qh->qtd_list.prev,
 			qtd = list_entry (qh->qtd_list.prev,
 					struct ehci_qtd, qtd_list);
 					struct ehci_qtd, qtd_list);
-			qtd->hw_next = QTD_NEXT (dma);
+			qtd->hw_next = QTD_NEXT(ehci, dma);
 
 
 			/* let the hc process these next qtds */
 			/* let the hc process these next qtds */
 			wmb ();
 			wmb ();
@@ -970,7 +976,7 @@ static void end_unlink_async (struct ehci_hcd *ehci)
 
 
 	timer_action_done (ehci, TIMER_IAA_WATCHDOG);
 	timer_action_done (ehci, TIMER_IAA_WATCHDOG);
 
 
-	// qh->hw_next = cpu_to_le32 (qh->qh_dma);
+	// qh->hw_next = cpu_to_hc32(qh->qh_dma);
 	qh->qh_state = QH_STATE_IDLE;
 	qh->qh_state = QH_STATE_IDLE;
 	qh->qh_next.qh = NULL;
 	qh->qh_next.qh = NULL;
 	qh_put (qh);			// refcount from reclaim
 	qh_put (qh);			// refcount from reclaim

+ 240 - 99
drivers/usb/host/ehci-sched.c

@@ -44,9 +44,10 @@ static int ehci_get_frame (struct usb_hcd *hcd);
  * @tag: hardware tag for type of this record
  * @tag: hardware tag for type of this record
  */
  */
 static union ehci_shadow *
 static union ehci_shadow *
-periodic_next_shadow (union ehci_shadow *periodic, __le32 tag)
+periodic_next_shadow(struct ehci_hcd *ehci, union ehci_shadow *periodic,
+		__hc32 tag)
 {
 {
-	switch (tag) {
+	switch (hc32_to_cpu(ehci, tag)) {
 	case Q_TYPE_QH:
 	case Q_TYPE_QH:
 		return &periodic->qh->qh_next;
 		return &periodic->qh->qh_next;
 	case Q_TYPE_FSTN:
 	case Q_TYPE_FSTN:
@@ -62,13 +63,14 @@ periodic_next_shadow (union ehci_shadow *periodic, __le32 tag)
 /* caller must hold ehci->lock */
 /* caller must hold ehci->lock */
 static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
 static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
 {
 {
-	union ehci_shadow	*prev_p = &ehci->pshadow [frame];
-	__le32			*hw_p = &ehci->periodic [frame];
+	union ehci_shadow	*prev_p = &ehci->pshadow[frame];
+	__hc32			*hw_p = &ehci->periodic[frame];
 	union ehci_shadow	here = *prev_p;
 	union ehci_shadow	here = *prev_p;
 
 
 	/* find predecessor of "ptr"; hw and shadow lists are in sync */
 	/* find predecessor of "ptr"; hw and shadow lists are in sync */
 	while (here.ptr && here.ptr != ptr) {
 	while (here.ptr && here.ptr != ptr) {
-		prev_p = periodic_next_shadow (prev_p, Q_NEXT_TYPE (*hw_p));
+		prev_p = periodic_next_shadow(ehci, prev_p,
+				Q_NEXT_TYPE(ehci, *hw_p));
 		hw_p = here.hw_next;
 		hw_p = here.hw_next;
 		here = *prev_p;
 		here = *prev_p;
 	}
 	}
@@ -79,7 +81,8 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
 	/* update shadow and hardware lists ... the old "next" pointers
 	/* update shadow and hardware lists ... the old "next" pointers
 	 * from ptr may still be in use, the caller updates them.
 	 * from ptr may still be in use, the caller updates them.
 	 */
 	 */
-	*prev_p = *periodic_next_shadow (&here, Q_NEXT_TYPE (*hw_p));
+	*prev_p = *periodic_next_shadow(ehci, &here,
+			Q_NEXT_TYPE(ehci, *hw_p));
 	*hw_p = *here.hw_next;
 	*hw_p = *here.hw_next;
 }
 }
 
 
@@ -87,18 +90,19 @@ static void periodic_unlink (struct ehci_hcd *ehci, unsigned frame, void *ptr)
 static unsigned short
 static unsigned short
 periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
 periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
 {
 {
-	__le32			*hw_p = &ehci->periodic [frame];
+	__hc32			*hw_p = &ehci->periodic [frame];
 	union ehci_shadow	*q = &ehci->pshadow [frame];
 	union ehci_shadow	*q = &ehci->pshadow [frame];
 	unsigned		usecs = 0;
 	unsigned		usecs = 0;
 
 
 	while (q->ptr) {
 	while (q->ptr) {
-		switch (Q_NEXT_TYPE (*hw_p)) {
+		switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) {
 		case Q_TYPE_QH:
 		case Q_TYPE_QH:
 			/* is it in the S-mask? */
 			/* is it in the S-mask? */
-			if (q->qh->hw_info2 & cpu_to_le32 (1 << uframe))
+			if (q->qh->hw_info2 & cpu_to_hc32(ehci, 1 << uframe))
 				usecs += q->qh->usecs;
 				usecs += q->qh->usecs;
 			/* ... or C-mask? */
 			/* ... or C-mask? */
-			if (q->qh->hw_info2 & cpu_to_le32 (1 << (8 + uframe)))
+			if (q->qh->hw_info2 & cpu_to_hc32(ehci,
+					1 << (8 + uframe)))
 				usecs += q->qh->c_usecs;
 				usecs += q->qh->c_usecs;
 			hw_p = &q->qh->hw_next;
 			hw_p = &q->qh->hw_next;
 			q = &q->qh->qh_next;
 			q = &q->qh->qh_next;
@@ -108,7 +112,7 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
 			/* for "save place" FSTNs, count the relevant INTR
 			/* for "save place" FSTNs, count the relevant INTR
 			 * bandwidth from the previous frame
 			 * bandwidth from the previous frame
 			 */
 			 */
-			if (q->fstn->hw_prev != EHCI_LIST_END) {
+			if (q->fstn->hw_prev != EHCI_LIST_END(ehci)) {
 				ehci_dbg (ehci, "ignoring FSTN cost ...\n");
 				ehci_dbg (ehci, "ignoring FSTN cost ...\n");
 			}
 			}
 			hw_p = &q->fstn->hw_next;
 			hw_p = &q->fstn->hw_next;
@@ -121,9 +125,10 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
 			break;
 			break;
 		case Q_TYPE_SITD:
 		case Q_TYPE_SITD:
 			/* is it in the S-mask?  (count SPLIT, DATA) */
 			/* is it in the S-mask?  (count SPLIT, DATA) */
-			if (q->sitd->hw_uframe & cpu_to_le32 (1 << uframe)) {
+			if (q->sitd->hw_uframe & cpu_to_hc32(ehci,
+					1 << uframe)) {
 				if (q->sitd->hw_fullspeed_ep &
 				if (q->sitd->hw_fullspeed_ep &
-						__constant_cpu_to_le32 (1<<31))
+						cpu_to_hc32(ehci, 1<<31))
 					usecs += q->sitd->stream->usecs;
 					usecs += q->sitd->stream->usecs;
 				else	/* worst case for OUT start-split */
 				else	/* worst case for OUT start-split */
 					usecs += HS_USECS_ISO (188);
 					usecs += HS_USECS_ISO (188);
@@ -131,7 +136,7 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
 
 
 			/* ... C-mask?  (count CSPLIT, DATA) */
 			/* ... C-mask?  (count CSPLIT, DATA) */
 			if (q->sitd->hw_uframe &
 			if (q->sitd->hw_uframe &
-					cpu_to_le32 (1 << (8 + uframe))) {
+					cpu_to_hc32(ehci, 1 << (8 + uframe))) {
 				/* worst case for IN complete-split */
 				/* worst case for IN complete-split */
 				usecs += q->sitd->stream->c_usecs;
 				usecs += q->sitd->stream->c_usecs;
 			}
 			}
@@ -173,9 +178,9 @@ static int same_tt (struct usb_device *dev1, struct usb_device *dev2)
  * will cause a transfer in "B-frame" uframe 0.  "B-frames" lag
  * will cause a transfer in "B-frame" uframe 0.  "B-frames" lag
  * "H-frames" by 1 uframe.  See the EHCI spec sec 4.5 and figure 4.7.
  * "H-frames" by 1 uframe.  See the EHCI spec sec 4.5 and figure 4.7.
  */
  */
-static inline unsigned char tt_start_uframe(struct ehci_hcd *ehci, __le32 mask)
+static inline unsigned char tt_start_uframe(struct ehci_hcd *ehci, __hc32 mask)
 {
 {
-	unsigned char smask = QH_SMASK & le32_to_cpu(mask);
+	unsigned char smask = QH_SMASK & hc32_to_cpu(ehci, mask);
 	if (!smask) {
 	if (!smask) {
 		ehci_err(ehci, "invalid empty smask!\n");
 		ehci_err(ehci, "invalid empty smask!\n");
 		/* uframe 7 can't have bw so this will indicate failure */
 		/* uframe 7 can't have bw so this will indicate failure */
@@ -217,14 +222,14 @@ periodic_tt_usecs (
 	unsigned short tt_usecs[8]
 	unsigned short tt_usecs[8]
 )
 )
 {
 {
-	__le32			*hw_p = &ehci->periodic [frame];
+	__hc32			*hw_p = &ehci->periodic [frame];
 	union ehci_shadow	*q = &ehci->pshadow [frame];
 	union ehci_shadow	*q = &ehci->pshadow [frame];
 	unsigned char		uf;
 	unsigned char		uf;
 
 
 	memset(tt_usecs, 0, 16);
 	memset(tt_usecs, 0, 16);
 
 
 	while (q->ptr) {
 	while (q->ptr) {
-		switch (Q_NEXT_TYPE(*hw_p)) {
+		switch (hc32_to_cpu(ehci, Q_NEXT_TYPE(ehci, *hw_p))) {
 		case Q_TYPE_ITD:
 		case Q_TYPE_ITD:
 			hw_p = &q->itd->hw_next;
 			hw_p = &q->itd->hw_next;
 			q = &q->itd->itd_next;
 			q = &q->itd->itd_next;
@@ -247,8 +252,8 @@ periodic_tt_usecs (
 			continue;
 			continue;
 		// case Q_TYPE_FSTN:
 		// case Q_TYPE_FSTN:
 		default:
 		default:
-			ehci_dbg(ehci,
-				  "ignoring periodic frame %d FSTN\n", frame);
+			ehci_dbg(ehci, "ignoring periodic frame %d FSTN\n",
+					frame);
 			hw_p = &q->fstn->hw_next;
 			hw_p = &q->fstn->hw_next;
 			q = &q->fstn->fstn_next;
 			q = &q->fstn->fstn_next;
 		}
 		}
@@ -368,41 +373,42 @@ static int tt_no_collision (
 	 */
 	 */
 	for (; frame < ehci->periodic_size; frame += period) {
 	for (; frame < ehci->periodic_size; frame += period) {
 		union ehci_shadow	here;
 		union ehci_shadow	here;
-		__le32			type;
+		__hc32			type;
 
 
 		here = ehci->pshadow [frame];
 		here = ehci->pshadow [frame];
-		type = Q_NEXT_TYPE (ehci->periodic [frame]);
+		type = Q_NEXT_TYPE(ehci, ehci->periodic [frame]);
 		while (here.ptr) {
 		while (here.ptr) {
-			switch (type) {
+			switch (hc32_to_cpu(ehci, type)) {
 			case Q_TYPE_ITD:
 			case Q_TYPE_ITD:
-				type = Q_NEXT_TYPE (here.itd->hw_next);
+				type = Q_NEXT_TYPE(ehci, here.itd->hw_next);
 				here = here.itd->itd_next;
 				here = here.itd->itd_next;
 				continue;
 				continue;
 			case Q_TYPE_QH:
 			case Q_TYPE_QH:
 				if (same_tt (dev, here.qh->dev)) {
 				if (same_tt (dev, here.qh->dev)) {
 					u32		mask;
 					u32		mask;
 
 
-					mask = le32_to_cpu (here.qh->hw_info2);
+					mask = hc32_to_cpu(ehci,
+							here.qh->hw_info2);
 					/* "knows" no gap is needed */
 					/* "knows" no gap is needed */
 					mask |= mask >> 8;
 					mask |= mask >> 8;
 					if (mask & uf_mask)
 					if (mask & uf_mask)
 						break;
 						break;
 				}
 				}
-				type = Q_NEXT_TYPE (here.qh->hw_next);
+				type = Q_NEXT_TYPE(ehci, here.qh->hw_next);
 				here = here.qh->qh_next;
 				here = here.qh->qh_next;
 				continue;
 				continue;
 			case Q_TYPE_SITD:
 			case Q_TYPE_SITD:
 				if (same_tt (dev, here.sitd->urb->dev)) {
 				if (same_tt (dev, here.sitd->urb->dev)) {
 					u16		mask;
 					u16		mask;
 
 
-					mask = le32_to_cpu (here.sitd
+					mask = hc32_to_cpu(ehci, here.sitd
 								->hw_uframe);
 								->hw_uframe);
 					/* FIXME assumes no gap for IN! */
 					/* FIXME assumes no gap for IN! */
 					mask |= mask >> 8;
 					mask |= mask >> 8;
 					if (mask & uf_mask)
 					if (mask & uf_mask)
 						break;
 						break;
 				}
 				}
-				type = Q_NEXT_TYPE (here.sitd->hw_next);
+				type = Q_NEXT_TYPE(ehci, here.sitd->hw_next);
 				here = here.sitd->sitd_next;
 				here = here.sitd->sitd_next;
 				continue;
 				continue;
 			// case Q_TYPE_FSTN:
 			// case Q_TYPE_FSTN:
@@ -473,6 +479,109 @@ static int disable_periodic (struct ehci_hcd *ehci)
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
+#ifdef CONFIG_CPU_FREQ
+
+static int safe_to_modify_i (struct ehci_hcd *ehci, struct ehci_qh *qh)
+{
+	int now; /* current (frame * 8) + uframe */
+	int prev_start, next_start; /* uframes from/to split start */
+	int start_uframe = ffs(le32_to_cpup (&qh->hw_info2) & QH_SMASK);
+	int end_uframe = fls((le32_to_cpup (&qh->hw_info2) & QH_CMASK) >> 8);
+	int split_duration = end_uframe - start_uframe;
+
+	now = readl(&ehci->regs->frame_index) % (ehci->periodic_size << 3);
+
+	next_start = ((1024 << 3) + (qh->start << 3) + start_uframe - now)
+			% (qh->period << 3);
+	prev_start = (qh->period << 3) - next_start;
+
+	/*
+	 * Make sure there will be at least one uframe when qh is safe.
+	 */
+	if ((qh->period << 3) <= (ehci->i_thresh + 2 + split_duration))
+		/* never safe */
+		return -EINVAL;
+
+	/*
+	 * Wait 1 uframe after transaction should have started, to make
+	 * sure controller has time to write back overlay, so we can
+	 * check QTD_STS_STS to see if transaction is in progress.
+	 */
+	if ((next_start > ehci->i_thresh) && (prev_start > 1))
+		/* safe to set "i" bit if split isn't in progress */
+		return (qh->hw_token & STATUS_BIT(ehci)) ? 0 : 1;
+	else
+		return 0;
+}
+
+/* Set inactivate bit for all the split interrupt QHs. */
+static void qh_inactivate_split_intr_qhs (struct ehci_hcd *ehci)
+{
+	struct ehci_qh	*qh;
+	int		not_done, safe;
+	u32		inactivate = INACTIVATE_BIT(ehci);
+	u32		active = ACTIVE_BIT(ehci);
+
+	do {
+		not_done = 0;
+		list_for_each_entry(qh, &ehci->split_intr_qhs,
+				split_intr_qhs) {
+			if (qh->hw_info1 & inactivate)
+				/* already off */
+				continue;
+			/*
+			 * To avoid setting "I" after the start split happens,
+			 * don't set it if the QH might be cached in the
+			 * controller.  Some HCs (Broadcom/ServerWorks HT1000)
+			 * will stop in the middle of a split transaction when
+			 * the "I" bit is set.
+			 */
+			safe = safe_to_modify_i(ehci, qh);
+			if (safe == 0) {
+				not_done = 1;
+			} else if (safe > 0) {
+				qh->was_active = qh->hw_token & active;
+				qh->hw_info1 |= inactivate;
+			}
+		}
+	} while (not_done);
+	wmb();
+}
+
+static void qh_reactivate_split_intr_qhs (struct ehci_hcd *ehci)
+{
+	struct ehci_qh	*qh;
+	u32		token;
+	int		not_done, safe;
+	u32		inactivate = INACTIVATE_BIT(ehci);
+	u32		active = ACTIVE_BIT(ehci);
+	u32		halt = HALT_BIT(ehci);
+
+	do {
+		not_done = 0;
+		list_for_each_entry(qh, &ehci->split_intr_qhs, split_intr_qhs) {
+			if (!(qh->hw_info1 & inactivate)) /* already on */
+				continue;
+			/*
+			 * Don't reactivate if cached, or controller might
+			 * overwrite overlay after we modify it!
+			 */
+			safe = safe_to_modify_i(ehci, qh);
+			if (safe == 0) {
+				not_done = 1;
+			} else if (safe > 0) {
+				/* See EHCI 1.0 section 4.15.2.4. */
+				token = qh->hw_token;
+				qh->hw_token = (token | halt) & ~active;
+				wmb();
+				qh->hw_info1 &= ~inactivate;
+				wmb();
+				qh->hw_token = (token & ~halt) | qh->was_active;
+			}
+		}
+	} while (not_done);
+}
+#endif
 
 
 /* periodic schedule slots have iso tds (normal or split) first, then a
 /* periodic schedule slots have iso tds (normal or split) first, then a
  * sparse tree for active interrupt transfers.
  * sparse tree for active interrupt transfers.
@@ -487,25 +596,36 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
 
 	dev_dbg (&qh->dev->dev,
 	dev_dbg (&qh->dev->dev,
 		"link qh%d-%04x/%p start %d [%d/%d us]\n",
 		"link qh%d-%04x/%p start %d [%d/%d us]\n",
-		period, le32_to_cpup (&qh->hw_info2) & (QH_CMASK | QH_SMASK),
+		period, hc32_to_cpup(ehci, &qh->hw_info2) & (QH_CMASK | QH_SMASK),
 		qh, qh->start, qh->usecs, qh->c_usecs);
 		qh, qh->start, qh->usecs, qh->c_usecs);
 
 
+#ifdef CONFIG_CPU_FREQ
+	/*
+	 * If low/full speed interrupt QHs are inactive (because of
+	 * cpufreq changing processor speeds), start QH with I flag set--
+	 * it will automatically be cleared when cpufreq is done.
+	 */
+	if (ehci->cpufreq_changing)
+		if (!(qh->hw_info1 & (cpu_to_le32(1 << 13))))
+			qh->hw_info1 |= INACTIVATE_BIT(ehci);
+#endif
+
 	/* high bandwidth, or otherwise every microframe */
 	/* high bandwidth, or otherwise every microframe */
 	if (period == 0)
 	if (period == 0)
 		period = 1;
 		period = 1;
 
 
 	for (i = qh->start; i < ehci->periodic_size; i += period) {
 	for (i = qh->start; i < ehci->periodic_size; i += period) {
-		union ehci_shadow	*prev = &ehci->pshadow [i];
-		__le32			*hw_p = &ehci->periodic [i];
+		union ehci_shadow	*prev = &ehci->pshadow[i];
+		__hc32			*hw_p = &ehci->periodic[i];
 		union ehci_shadow	here = *prev;
 		union ehci_shadow	here = *prev;
-		__le32			type = 0;
+		__hc32			type = 0;
 
 
 		/* skip the iso nodes at list head */
 		/* skip the iso nodes at list head */
 		while (here.ptr) {
 		while (here.ptr) {
-			type = Q_NEXT_TYPE (*hw_p);
-			if (type == Q_TYPE_QH)
+			type = Q_NEXT_TYPE(ehci, *hw_p);
+			if (type == cpu_to_hc32(ehci, Q_TYPE_QH))
 				break;
 				break;
-			prev = periodic_next_shadow (prev, type);
+			prev = periodic_next_shadow(ehci, prev, type);
 			hw_p = &here.qh->hw_next;
 			hw_p = &here.qh->hw_next;
 			here = *prev;
 			here = *prev;
 		}
 		}
@@ -527,7 +647,7 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
 				qh->hw_next = *hw_p;
 				qh->hw_next = *hw_p;
 			wmb ();
 			wmb ();
 			prev->qh = qh;
 			prev->qh = qh;
-			*hw_p = QH_NEXT (qh->qh_dma);
+			*hw_p = QH_NEXT (ehci, qh->qh_dma);
 		}
 		}
 	}
 	}
 	qh->qh_state = QH_STATE_LINKED;
 	qh->qh_state = QH_STATE_LINKED;
@@ -538,6 +658,12 @@ static int qh_link_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
 		? ((qh->usecs + qh->c_usecs) / qh->period)
 		? ((qh->usecs + qh->c_usecs) / qh->period)
 		: (qh->usecs * 8);
 		: (qh->usecs * 8);
 
 
+#ifdef CONFIG_CPU_FREQ
+	/* add qh to list of low/full speed interrupt QHs, if applicable */
+	if (!(qh->hw_info1 & (cpu_to_le32(1 << 13)))) {
+		list_add(&qh->split_intr_qhs, &ehci->split_intr_qhs);
+	}
+#endif
 	/* maybe enable periodic schedule processing */
 	/* maybe enable periodic schedule processing */
 	if (!ehci->periodic_sched++)
 	if (!ehci->periodic_sched++)
 		return enable_periodic (ehci);
 		return enable_periodic (ehci);
@@ -555,7 +681,14 @@ static void qh_unlink_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
 	//   and this qh is active in the current uframe
 	//   and this qh is active in the current uframe
 	//   (and overlay token SplitXstate is false?)
 	//   (and overlay token SplitXstate is false?)
 	// THEN
 	// THEN
-	//   qh->hw_info1 |= __constant_cpu_to_le32 (1 << 7 /* "ignore" */);
+	//   qh->hw_info1 |= __constant_cpu_to_hc32(1 << 7 /* "ignore" */);
+
+#ifdef CONFIG_CPU_FREQ
+	/* remove qh from list of low/full speed interrupt QHs */
+	if (!(qh->hw_info1 & (cpu_to_le32(1 << 13)))) {
+		list_del_init(&qh->split_intr_qhs);
+	}
+#endif
 
 
 	/* high bandwidth, or otherwise part of every microframe */
 	/* high bandwidth, or otherwise part of every microframe */
 	if ((period = qh->period) == 0)
 	if ((period = qh->period) == 0)
@@ -572,7 +705,7 @@ static void qh_unlink_periodic (struct ehci_hcd *ehci, struct ehci_qh *qh)
 	dev_dbg (&qh->dev->dev,
 	dev_dbg (&qh->dev->dev,
 		"unlink qh%d-%04x/%p start %d [%d/%d us]\n",
 		"unlink qh%d-%04x/%p start %d [%d/%d us]\n",
 		qh->period,
 		qh->period,
-		le32_to_cpup (&qh->hw_info2) & (QH_CMASK | QH_SMASK),
+		hc32_to_cpup(ehci, &qh->hw_info2) & (QH_CMASK | QH_SMASK),
 		qh, qh->start, qh->usecs, qh->c_usecs);
 		qh, qh->start, qh->usecs, qh->c_usecs);
 
 
 	/* qh->qh_next still "live" to HC */
 	/* qh->qh_next still "live" to HC */
@@ -598,7 +731,7 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
 	 * active high speed queues may need bigger delays...
 	 * active high speed queues may need bigger delays...
 	 */
 	 */
 	if (list_empty (&qh->qtd_list)
 	if (list_empty (&qh->qtd_list)
-			|| (__constant_cpu_to_le32 (QH_CMASK)
+			|| (cpu_to_hc32(ehci, QH_CMASK)
 					& qh->hw_info2) != 0)
 					& qh->hw_info2) != 0)
 		wait = 2;
 		wait = 2;
 	else
 	else
@@ -606,7 +739,7 @@ static void intr_deschedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
 
 	udelay (wait);
 	udelay (wait);
 	qh->qh_state = QH_STATE_IDLE;
 	qh->qh_state = QH_STATE_IDLE;
-	qh->hw_next = EHCI_LIST_END;
+	qh->hw_next = EHCI_LIST_END(ehci);
 	wmb ();
 	wmb ();
 }
 }
 
 
@@ -663,7 +796,7 @@ static int check_intr_schedule (
 	unsigned		frame,
 	unsigned		frame,
 	unsigned		uframe,
 	unsigned		uframe,
 	const struct ehci_qh	*qh,
 	const struct ehci_qh	*qh,
-	__le32			*c_maskp
+	__hc32			*c_maskp
 )
 )
 {
 {
 	int		retval = -ENOSPC;
 	int		retval = -ENOSPC;
@@ -695,7 +828,7 @@ static int check_intr_schedule (
 
 
 		retval = 0;
 		retval = 0;
 
 
-		*c_maskp = cpu_to_le32 (mask << 8);
+		*c_maskp = cpu_to_hc32(ehci, mask << 8);
 	}
 	}
 #else
 #else
 	/* Make sure this tt's buffer is also available for CSPLITs.
 	/* Make sure this tt's buffer is also available for CSPLITs.
@@ -706,7 +839,7 @@ static int check_intr_schedule (
 	 * one smart pass...
 	 * one smart pass...
 	 */
 	 */
 	mask = 0x03 << (uframe + qh->gap_uf);
 	mask = 0x03 << (uframe + qh->gap_uf);
-	*c_maskp = cpu_to_le32 (mask << 8);
+	*c_maskp = cpu_to_hc32(ehci, mask << 8);
 
 
 	mask |= 1 << uframe;
 	mask |= 1 << uframe;
 	if (tt_no_collision (ehci, qh->period, qh->dev, frame, mask)) {
 	if (tt_no_collision (ehci, qh->period, qh->dev, frame, mask)) {
@@ -726,20 +859,20 @@ done:
 /* "first fit" scheduling policy used the first time through,
 /* "first fit" scheduling policy used the first time through,
  * or when the previous schedule slot can't be re-used.
  * or when the previous schedule slot can't be re-used.
  */
  */
-static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
+static int qh_schedule(struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
 {
 	int		status;
 	int		status;
 	unsigned	uframe;
 	unsigned	uframe;
-	__le32		c_mask;
+	__hc32		c_mask;
 	unsigned	frame;		/* 0..(qh->period - 1), or NO_FRAME */
 	unsigned	frame;		/* 0..(qh->period - 1), or NO_FRAME */
 
 
 	qh_refresh(ehci, qh);
 	qh_refresh(ehci, qh);
-	qh->hw_next = EHCI_LIST_END;
+	qh->hw_next = EHCI_LIST_END(ehci);
 	frame = qh->start;
 	frame = qh->start;
 
 
 	/* reuse the previous schedule slots, if we can */
 	/* reuse the previous schedule slots, if we can */
 	if (frame < qh->period) {
 	if (frame < qh->period) {
-		uframe = ffs (le32_to_cpup (&qh->hw_info2) & QH_SMASK);
+		uframe = ffs(hc32_to_cpup(ehci, &qh->hw_info2) & QH_SMASK);
 		status = check_intr_schedule (ehci, frame, --uframe,
 		status = check_intr_schedule (ehci, frame, --uframe,
 				qh, &c_mask);
 				qh, &c_mask);
 	} else {
 	} else {
@@ -775,10 +908,10 @@ static int qh_schedule (struct ehci_hcd *ehci, struct ehci_qh *qh)
 		qh->start = frame;
 		qh->start = frame;
 
 
 		/* reset S-frame and (maybe) C-frame masks */
 		/* reset S-frame and (maybe) C-frame masks */
-		qh->hw_info2 &= __constant_cpu_to_le32(~(QH_CMASK | QH_SMASK));
+		qh->hw_info2 &= cpu_to_hc32(ehci, ~(QH_CMASK | QH_SMASK));
 		qh->hw_info2 |= qh->period
 		qh->hw_info2 |= qh->period
-			? cpu_to_le32 (1 << uframe)
-			: __constant_cpu_to_le32 (QH_SMASK);
+			? cpu_to_hc32(ehci, 1 << uframe)
+			: cpu_to_hc32(ehci, QH_SMASK);
 		qh->hw_info2 |= c_mask;
 		qh->hw_info2 |= c_mask;
 	} else
 	} else
 		ehci_dbg (ehci, "reused qh %p schedule\n", qh);
 		ehci_dbg (ehci, "reused qh %p schedule\n", qh);
@@ -808,7 +941,7 @@ static int intr_submit (
 	spin_lock_irqsave (&ehci->lock, flags);
 	spin_lock_irqsave (&ehci->lock, flags);
 
 
 	if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
 	if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
-			       &ehci_to_hcd(ehci)->flags))) {
+			&ehci_to_hcd(ehci)->flags))) {
 		status = -ESHUTDOWN;
 		status = -ESHUTDOWN;
 		goto done;
 		goto done;
 	}
 	}
@@ -898,9 +1031,9 @@ iso_stream_init (
 		buf1 |= maxp;
 		buf1 |= maxp;
 		maxp *= multi;
 		maxp *= multi;
 
 
-		stream->buf0 = cpu_to_le32 ((epnum << 8) | dev->devnum);
-		stream->buf1 = cpu_to_le32 (buf1);
-		stream->buf2 = cpu_to_le32 (multi);
+		stream->buf0 = cpu_to_hc32(ehci, (epnum << 8) | dev->devnum);
+		stream->buf1 = cpu_to_hc32(ehci, buf1);
+		stream->buf2 = cpu_to_hc32(ehci, multi);
 
 
 		/* usbfs wants to report the average usecs per frame tied up
 		/* usbfs wants to report the average usecs per frame tied up
 		 * when transfers on this endpoint are scheduled ...
 		 * when transfers on this endpoint are scheduled ...
@@ -943,7 +1076,7 @@ iso_stream_init (
 		bandwidth /= 1 << (interval + 2);
 		bandwidth /= 1 << (interval + 2);
 
 
 		/* stream->splits gets created from raw_mask later */
 		/* stream->splits gets created from raw_mask later */
-		stream->address = cpu_to_le32 (addr);
+		stream->address = cpu_to_hc32(ehci, addr);
 	}
 	}
 	stream->bandwidth = bandwidth;
 	stream->bandwidth = bandwidth;
 
 
@@ -1077,7 +1210,8 @@ iso_sched_alloc (unsigned packets, gfp_t mem_flags)
 }
 }
 
 
 static inline void
 static inline void
-itd_sched_init (
+itd_sched_init(
+	struct ehci_hcd		*ehci,
 	struct ehci_iso_sched	*iso_sched,
 	struct ehci_iso_sched	*iso_sched,
 	struct ehci_iso_stream	*stream,
 	struct ehci_iso_stream	*stream,
 	struct urb		*urb
 	struct urb		*urb
@@ -1107,7 +1241,7 @@ itd_sched_init (
 				&& !(urb->transfer_flags & URB_NO_INTERRUPT))
 				&& !(urb->transfer_flags & URB_NO_INTERRUPT))
 			trans |= EHCI_ITD_IOC;
 			trans |= EHCI_ITD_IOC;
 		trans |= length << 16;
 		trans |= length << 16;
-		uframe->transaction = cpu_to_le32 (trans);
+		uframe->transaction = cpu_to_hc32(ehci, trans);
 
 
 		/* might need to cross a buffer page within a uframe */
 		/* might need to cross a buffer page within a uframe */
 		uframe->bufp = (buf & ~(u64)0x0fff);
 		uframe->bufp = (buf & ~(u64)0x0fff);
@@ -1149,7 +1283,7 @@ itd_urb_transaction (
 	if (unlikely (sched == NULL))
 	if (unlikely (sched == NULL))
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	itd_sched_init (sched, stream, urb);
+	itd_sched_init(ehci, sched, stream, urb);
 
 
 	if (urb->interval < 8)
 	if (urb->interval < 8)
 		num_itds = 1 + (sched->span + 7) / 8;
 		num_itds = 1 + (sched->span + 7) / 8;
@@ -1167,7 +1301,7 @@ itd_urb_transaction (
 		/* prefer previously-allocated itds */
 		/* prefer previously-allocated itds */
 		if (likely (!list_empty(&stream->free_list))) {
 		if (likely (!list_empty(&stream->free_list))) {
 			itd = list_entry (stream->free_list.prev,
 			itd = list_entry (stream->free_list.prev,
-					 struct ehci_itd, itd_list);
+					struct ehci_itd, itd_list);
 			list_del (&itd->itd_list);
 			list_del (&itd->itd_list);
 			itd_dma = itd->itd_dma;
 			itd_dma = itd->itd_dma;
 		} else
 		} else
@@ -1294,7 +1428,7 @@ sitd_slot_ok (
 		uframe += period_uframes;
 		uframe += period_uframes;
 	} while (uframe < mod);
 	} while (uframe < mod);
 
 
-	stream->splits = cpu_to_le32(stream->raw_mask << (uframe & 7));
+	stream->splits = cpu_to_hc32(ehci, stream->raw_mask << (uframe & 7));
 	return 1;
 	return 1;
 }
 }
 
 
@@ -1415,12 +1549,13 @@ ready:
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 static inline void
 static inline void
-itd_init (struct ehci_iso_stream *stream, struct ehci_itd *itd)
+itd_init(struct ehci_hcd *ehci, struct ehci_iso_stream *stream,
+		struct ehci_itd *itd)
 {
 {
 	int i;
 	int i;
 
 
 	/* it's been recently zeroed */
 	/* it's been recently zeroed */
-	itd->hw_next = EHCI_LIST_END;
+	itd->hw_next = EHCI_LIST_END(ehci);
 	itd->hw_bufp [0] = stream->buf0;
 	itd->hw_bufp [0] = stream->buf0;
 	itd->hw_bufp [1] = stream->buf1;
 	itd->hw_bufp [1] = stream->buf1;
 	itd->hw_bufp [2] = stream->buf2;
 	itd->hw_bufp [2] = stream->buf2;
@@ -1432,7 +1567,8 @@ itd_init (struct ehci_iso_stream *stream, struct ehci_itd *itd)
 }
 }
 
 
 static inline void
 static inline void
-itd_patch (
+itd_patch(
+	struct ehci_hcd		*ehci,
 	struct ehci_itd		*itd,
 	struct ehci_itd		*itd,
 	struct ehci_iso_sched	*iso_sched,
 	struct ehci_iso_sched	*iso_sched,
 	unsigned		index,
 	unsigned		index,
@@ -1447,17 +1583,18 @@ itd_patch (
 	uframe &= 0x07;
 	uframe &= 0x07;
 	itd->index [uframe] = index;
 	itd->index [uframe] = index;
 
 
-	itd->hw_transaction [uframe] = uf->transaction;
-	itd->hw_transaction [uframe] |= cpu_to_le32 (pg << 12);
-	itd->hw_bufp [pg] |= cpu_to_le32 (uf->bufp & ~(u32)0);
-	itd->hw_bufp_hi [pg] |= cpu_to_le32 ((u32)(uf->bufp >> 32));
+	itd->hw_transaction[uframe] = uf->transaction;
+	itd->hw_transaction[uframe] |= cpu_to_hc32(ehci, pg << 12);
+	itd->hw_bufp[pg] |= cpu_to_hc32(ehci, uf->bufp & ~(u32)0);
+	itd->hw_bufp_hi[pg] |= cpu_to_hc32(ehci, (u32)(uf->bufp >> 32));
 
 
 	/* iso_frame_desc[].offset must be strictly increasing */
 	/* iso_frame_desc[].offset must be strictly increasing */
 	if (unlikely (uf->cross)) {
 	if (unlikely (uf->cross)) {
 		u64	bufp = uf->bufp + 4096;
 		u64	bufp = uf->bufp + 4096;
+
 		itd->pg = ++pg;
 		itd->pg = ++pg;
-		itd->hw_bufp [pg] |= cpu_to_le32 (bufp & ~(u32)0);
-		itd->hw_bufp_hi [pg] |= cpu_to_le32 ((u32)(bufp >> 32));
+		itd->hw_bufp[pg] |= cpu_to_hc32(ehci, bufp & ~(u32)0);
+		itd->hw_bufp_hi[pg] |= cpu_to_hc32(ehci, (u32)(bufp >> 32));
 	}
 	}
 }
 }
 
 
@@ -1470,7 +1607,7 @@ itd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_itd *itd)
 	ehci->pshadow [frame].itd = itd;
 	ehci->pshadow [frame].itd = itd;
 	itd->frame = frame;
 	itd->frame = frame;
 	wmb ();
 	wmb ();
-	ehci->periodic [frame] = cpu_to_le32 (itd->itd_dma) | Q_TYPE_ITD;
+	ehci->periodic[frame] = cpu_to_hc32(ehci, itd->itd_dma | Q_TYPE_ITD);
 }
 }
 
 
 /* fit urb's itds into the selected schedule slot; activate as needed */
 /* fit urb's itds into the selected schedule slot; activate as needed */
@@ -1515,14 +1652,14 @@ itd_link_urb (
 			list_move_tail (&itd->itd_list, &stream->td_list);
 			list_move_tail (&itd->itd_list, &stream->td_list);
 			itd->stream = iso_stream_get (stream);
 			itd->stream = iso_stream_get (stream);
 			itd->urb = usb_get_urb (urb);
 			itd->urb = usb_get_urb (urb);
-			itd_init (stream, itd);
+			itd_init (ehci, stream, itd);
 		}
 		}
 
 
 		uframe = next_uframe & 0x07;
 		uframe = next_uframe & 0x07;
 		frame = next_uframe >> 3;
 		frame = next_uframe >> 3;
 
 
 		itd->usecs [uframe] = stream->usecs;
 		itd->usecs [uframe] = stream->usecs;
-		itd_patch (itd, iso_sched, packet, uframe);
+		itd_patch(ehci, itd, iso_sched, packet, uframe);
 
 
 		next_uframe += stream->interval;
 		next_uframe += stream->interval;
 		stream->depth += stream->interval;
 		stream->depth += stream->interval;
@@ -1570,7 +1707,7 @@ itd_complete (
 		urb_index = itd->index[uframe];
 		urb_index = itd->index[uframe];
 		desc = &urb->iso_frame_desc [urb_index];
 		desc = &urb->iso_frame_desc [urb_index];
 
 
-		t = le32_to_cpup (&itd->hw_transaction [uframe]);
+		t = hc32_to_cpup(ehci, &itd->hw_transaction [uframe]);
 		itd->hw_transaction [uframe] = 0;
 		itd->hw_transaction [uframe] = 0;
 		stream->depth -= stream->interval;
 		stream->depth -= stream->interval;
 
 
@@ -1700,7 +1837,8 @@ done:
  */
  */
 
 
 static inline void
 static inline void
-sitd_sched_init (
+sitd_sched_init(
+	struct ehci_hcd		*ehci,
 	struct ehci_iso_sched	*iso_sched,
 	struct ehci_iso_sched	*iso_sched,
 	struct ehci_iso_stream	*stream,
 	struct ehci_iso_stream	*stream,
 	struct urb		*urb
 	struct urb		*urb
@@ -1729,7 +1867,7 @@ sitd_sched_init (
 				&& !(urb->transfer_flags & URB_NO_INTERRUPT))
 				&& !(urb->transfer_flags & URB_NO_INTERRUPT))
 			trans |= SITD_IOC;
 			trans |= SITD_IOC;
 		trans |= length << 16;
 		trans |= length << 16;
-		packet->transaction = cpu_to_le32 (trans);
+		packet->transaction = cpu_to_hc32(ehci, trans);
 
 
 		/* might need to cross a buffer page within a td */
 		/* might need to cross a buffer page within a td */
 		packet->bufp = buf;
 		packet->bufp = buf;
@@ -1765,7 +1903,7 @@ sitd_urb_transaction (
 	if (iso_sched == NULL)
 	if (iso_sched == NULL)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	sitd_sched_init (iso_sched, stream, urb);
+	sitd_sched_init(ehci, iso_sched, stream, urb);
 
 
 	/* allocate/init sITDs */
 	/* allocate/init sITDs */
 	spin_lock_irqsave (&ehci->lock, flags);
 	spin_lock_irqsave (&ehci->lock, flags);
@@ -1817,7 +1955,8 @@ sitd_urb_transaction (
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 static inline void
 static inline void
-sitd_patch (
+sitd_patch(
+	struct ehci_hcd		*ehci,
 	struct ehci_iso_stream	*stream,
 	struct ehci_iso_stream	*stream,
 	struct ehci_sitd	*sitd,
 	struct ehci_sitd	*sitd,
 	struct ehci_iso_sched	*iso_sched,
 	struct ehci_iso_sched	*iso_sched,
@@ -1827,20 +1966,20 @@ sitd_patch (
 	struct ehci_iso_packet	*uf = &iso_sched->packet [index];
 	struct ehci_iso_packet	*uf = &iso_sched->packet [index];
 	u64			bufp = uf->bufp;
 	u64			bufp = uf->bufp;
 
 
-	sitd->hw_next = EHCI_LIST_END;
+	sitd->hw_next = EHCI_LIST_END(ehci);
 	sitd->hw_fullspeed_ep = stream->address;
 	sitd->hw_fullspeed_ep = stream->address;
 	sitd->hw_uframe = stream->splits;
 	sitd->hw_uframe = stream->splits;
 	sitd->hw_results = uf->transaction;
 	sitd->hw_results = uf->transaction;
-	sitd->hw_backpointer = EHCI_LIST_END;
+	sitd->hw_backpointer = EHCI_LIST_END(ehci);
 
 
 	bufp = uf->bufp;
 	bufp = uf->bufp;
-	sitd->hw_buf [0] = cpu_to_le32 (bufp);
-	sitd->hw_buf_hi [0] = cpu_to_le32 (bufp >> 32);
+	sitd->hw_buf[0] = cpu_to_hc32(ehci, bufp);
+	sitd->hw_buf_hi[0] = cpu_to_hc32(ehci, bufp >> 32);
 
 
-	sitd->hw_buf [1] = cpu_to_le32 (uf->buf1);
+	sitd->hw_buf[1] = cpu_to_hc32(ehci, uf->buf1);
 	if (uf->cross)
 	if (uf->cross)
 		bufp += 4096;
 		bufp += 4096;
-	sitd->hw_buf_hi [1] = cpu_to_le32 (bufp >> 32);
+	sitd->hw_buf_hi[1] = cpu_to_hc32(ehci, bufp >> 32);
 	sitd->index = index;
 	sitd->index = index;
 }
 }
 
 
@@ -1853,7 +1992,7 @@ sitd_link (struct ehci_hcd *ehci, unsigned frame, struct ehci_sitd *sitd)
 	ehci->pshadow [frame].sitd = sitd;
 	ehci->pshadow [frame].sitd = sitd;
 	sitd->frame = frame;
 	sitd->frame = frame;
 	wmb ();
 	wmb ();
-	ehci->periodic [frame] = cpu_to_le32 (sitd->sitd_dma) | Q_TYPE_SITD;
+	ehci->periodic[frame] = cpu_to_hc32(ehci, sitd->sitd_dma | Q_TYPE_SITD);
 }
 }
 
 
 /* fit urb's sitds into the selected schedule slot; activate as needed */
 /* fit urb's sitds into the selected schedule slot; activate as needed */
@@ -1881,7 +2020,7 @@ sitd_link_urb (
 			urb->dev->devpath, stream->bEndpointAddress & 0x0f,
 			urb->dev->devpath, stream->bEndpointAddress & 0x0f,
 			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
 			(stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
 			(next_uframe >> 3) % ehci->periodic_size,
 			(next_uframe >> 3) % ehci->periodic_size,
-			stream->interval, le32_to_cpu (stream->splits));
+			stream->interval, hc32_to_cpu(ehci, stream->splits));
 		stream->start = jiffies;
 		stream->start = jiffies;
 	}
 	}
 	ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
 	ehci_to_hcd(ehci)->self.bandwidth_isoc_reqs++;
@@ -1902,7 +2041,7 @@ sitd_link_urb (
 		sitd->stream = iso_stream_get (stream);
 		sitd->stream = iso_stream_get (stream);
 		sitd->urb = usb_get_urb (urb);
 		sitd->urb = usb_get_urb (urb);
 
 
-		sitd_patch (stream, sitd, sched, packet);
+		sitd_patch(ehci, stream, sitd, sched, packet);
 		sitd_link (ehci, (next_uframe >> 3) % ehci->periodic_size,
 		sitd_link (ehci, (next_uframe >> 3) % ehci->periodic_size,
 				sitd);
 				sitd);
 
 
@@ -1940,7 +2079,7 @@ sitd_complete (
 
 
 	urb_index = sitd->index;
 	urb_index = sitd->index;
 	desc = &urb->iso_frame_desc [urb_index];
 	desc = &urb->iso_frame_desc [urb_index];
-	t = le32_to_cpup (&sitd->hw_results);
+	t = hc32_to_cpup(ehci, &sitd->hw_results);
 
 
 	/* report transfer status */
 	/* report transfer status */
 	if (t & SITD_ERRS) {
 	if (t & SITD_ERRS) {
@@ -2095,7 +2234,7 @@ scan_periodic (struct ehci_hcd *ehci)
 
 
 	for (;;) {
 	for (;;) {
 		union ehci_shadow	q, *q_p;
 		union ehci_shadow	q, *q_p;
-		__le32			type, *hw_p;
+		__hc32			type, *hw_p;
 		unsigned		uframes;
 		unsigned		uframes;
 
 
 		/* don't scan past the live uframe */
 		/* don't scan past the live uframe */
@@ -2113,7 +2252,7 @@ restart:
 		q_p = &ehci->pshadow [frame];
 		q_p = &ehci->pshadow [frame];
 		hw_p = &ehci->periodic [frame];
 		hw_p = &ehci->periodic [frame];
 		q.ptr = q_p->ptr;
 		q.ptr = q_p->ptr;
-		type = Q_NEXT_TYPE (*hw_p);
+		type = Q_NEXT_TYPE(ehci, *hw_p);
 		modified = 0;
 		modified = 0;
 
 
 		while (q.ptr != NULL) {
 		while (q.ptr != NULL) {
@@ -2122,11 +2261,11 @@ restart:
 			int			live;
 			int			live;
 
 
 			live = HC_IS_RUNNING (ehci_to_hcd(ehci)->state);
 			live = HC_IS_RUNNING (ehci_to_hcd(ehci)->state);
-			switch (type) {
+			switch (hc32_to_cpu(ehci, type)) {
 			case Q_TYPE_QH:
 			case Q_TYPE_QH:
 				/* handle any completions */
 				/* handle any completions */
 				temp.qh = qh_get (q.qh);
 				temp.qh = qh_get (q.qh);
-				type = Q_NEXT_TYPE (q.qh->hw_next);
+				type = Q_NEXT_TYPE(ehci, q.qh->hw_next);
 				q = q.qh->qh_next;
 				q = q.qh->qh_next;
 				modified = qh_completions (ehci, temp.qh);
 				modified = qh_completions (ehci, temp.qh);
 				if (unlikely (list_empty (&temp.qh->qtd_list)))
 				if (unlikely (list_empty (&temp.qh->qtd_list)))
@@ -2137,10 +2276,10 @@ restart:
 				/* for "save place" FSTNs, look at QH entries
 				/* for "save place" FSTNs, look at QH entries
 				 * in the previous frame for completions.
 				 * in the previous frame for completions.
 				 */
 				 */
-				if (q.fstn->hw_prev != EHCI_LIST_END) {
+				if (q.fstn->hw_prev != EHCI_LIST_END(ehci)) {
 					dbg ("ignoring completions from FSTNs");
 					dbg ("ignoring completions from FSTNs");
 				}
 				}
-				type = Q_NEXT_TYPE (q.fstn->hw_next);
+				type = Q_NEXT_TYPE(ehci, q.fstn->hw_next);
 				q = q.fstn->fstn_next;
 				q = q.fstn->fstn_next;
 				break;
 				break;
 			case Q_TYPE_ITD:
 			case Q_TYPE_ITD:
@@ -2148,11 +2287,12 @@ restart:
 				rmb ();
 				rmb ();
 				for (uf = live ? uframes : 8; uf < 8; uf++) {
 				for (uf = live ? uframes : 8; uf < 8; uf++) {
 					if (0 == (q.itd->hw_transaction [uf]
 					if (0 == (q.itd->hw_transaction [uf]
-							& ITD_ACTIVE))
+							& ITD_ACTIVE(ehci)))
 						continue;
 						continue;
 					q_p = &q.itd->itd_next;
 					q_p = &q.itd->itd_next;
 					hw_p = &q.itd->hw_next;
 					hw_p = &q.itd->hw_next;
-					type = Q_NEXT_TYPE (q.itd->hw_next);
+					type = Q_NEXT_TYPE(ehci,
+							q.itd->hw_next);
 					q = *q_p;
 					q = *q_p;
 					break;
 					break;
 				}
 				}
@@ -2164,23 +2304,24 @@ restart:
 				 */
 				 */
 				*q_p = q.itd->itd_next;
 				*q_p = q.itd->itd_next;
 				*hw_p = q.itd->hw_next;
 				*hw_p = q.itd->hw_next;
-				type = Q_NEXT_TYPE (q.itd->hw_next);
+				type = Q_NEXT_TYPE(ehci, q.itd->hw_next);
 				wmb();
 				wmb();
 				modified = itd_complete (ehci, q.itd);
 				modified = itd_complete (ehci, q.itd);
 				q = *q_p;
 				q = *q_p;
 				break;
 				break;
 			case Q_TYPE_SITD:
 			case Q_TYPE_SITD:
-				if ((q.sitd->hw_results & SITD_ACTIVE)
+				if ((q.sitd->hw_results & SITD_ACTIVE(ehci))
 						&& live) {
 						&& live) {
 					q_p = &q.sitd->sitd_next;
 					q_p = &q.sitd->sitd_next;
 					hw_p = &q.sitd->hw_next;
 					hw_p = &q.sitd->hw_next;
-					type = Q_NEXT_TYPE (q.sitd->hw_next);
+					type = Q_NEXT_TYPE(ehci,
+							q.sitd->hw_next);
 					q = *q_p;
 					q = *q_p;
 					break;
 					break;
 				}
 				}
 				*q_p = q.sitd->sitd_next;
 				*q_p = q.sitd->sitd_next;
 				*hw_p = q.sitd->hw_next;
 				*hw_p = q.sitd->hw_next;
-				type = Q_NEXT_TYPE (q.sitd->hw_next);
+				type = Q_NEXT_TYPE(ehci, q.sitd->hw_next);
 				wmb();
 				wmb();
 				modified = sitd_complete (ehci, q.sitd);
 				modified = sitd_complete (ehci, q.sitd);
 				q = *q_p;
 				q = *q_p;

+ 181 - 53
drivers/usb/host/ehci.h

@@ -21,6 +21,22 @@
 
 
 /* definitions used for the EHCI driver */
 /* definitions used for the EHCI driver */
 
 
+/*
+ * __hc32 and __hc16 are "Host Controller" types, they may be equivalent to
+ * __leXX (normally) or __beXX (given EHCI_BIG_ENDIAN_DESC), depending on
+ * the host controller implementation.
+ *
+ * To facilitate the strongest possible byte-order checking from "sparse"
+ * and so on, we use __leXX unless that's not practical.
+ */
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
+typedef __u32 __bitwise __hc32;
+typedef __u16 __bitwise __hc16;
+#else
+#define __hc32	__le32
+#define __hc16	__le16
+#endif
+
 /* statistics can be kept for for tuning/monitoring */
 /* statistics can be kept for for tuning/monitoring */
 struct ehci_stats {
 struct ehci_stats {
 	/* irq usage */
 	/* irq usage */
@@ -55,6 +71,12 @@ struct ehci_hcd {			/* one per controller */
 	__u32			hcs_params;	/* cached register copy */
 	__u32			hcs_params;	/* cached register copy */
 	spinlock_t		lock;
 	spinlock_t		lock;
 
 
+#ifdef CONFIG_CPU_FREQ
+	struct notifier_block	cpufreq_transition;
+	int			cpufreq_changing;
+	struct list_head	split_intr_qhs;
+#endif
+
 	/* async schedule support */
 	/* async schedule support */
 	struct ehci_qh		*async;
 	struct ehci_qh		*async;
 	struct ehci_qh		*reclaim;
 	struct ehci_qh		*reclaim;
@@ -64,7 +86,7 @@ struct ehci_hcd {			/* one per controller */
 	/* periodic schedule support */
 	/* periodic schedule support */
 #define	DEFAULT_I_TDPS		1024		/* some HCs can do less */
 #define	DEFAULT_I_TDPS		1024		/* some HCs can do less */
 	unsigned		periodic_size;
 	unsigned		periodic_size;
-	__le32			*periodic;	/* hw periodic table */
+	__hc32			*periodic;	/* hw periodic table */
 	dma_addr_t		periodic_dma;
 	dma_addr_t		periodic_dma;
 	unsigned		i_thresh;	/* uframes HC might cache */
 	unsigned		i_thresh;	/* uframes HC might cache */
 
 
@@ -74,11 +96,14 @@ 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];
+
 	/* bit vectors (one bit per port) */
 	/* bit vectors (one bit per port) */
 	unsigned long		bus_suspended;		/* which ports were
 	unsigned long		bus_suspended;		/* which ports were
 			already suspended at the start of a bus suspend */
 			already suspended at the start of a bus suspend */
 	unsigned long		companion_ports;	/* which ports are
 	unsigned long		companion_ports;	/* which ports are
 			dedicated to the companion controller */
 			dedicated to the companion controller */
+	unsigned long		owned_ports;		/* which ports are
+			owned by the companion during a bus suspend */
 
 
 	/* 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 */
@@ -97,6 +122,7 @@ struct ehci_hcd {			/* one per controller */
 	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;
 	unsigned		big_endian_mmio:1;
+	unsigned		big_endian_desc:1;
 
 
 	u8			sbrn;		/* packed release number */
 	u8			sbrn;		/* packed release number */
 
 
@@ -276,6 +302,12 @@ struct ehci_regs {
 #define PORT_RWC_BITS   (PORT_CSC | PORT_PEC | PORT_OCC)
 #define PORT_RWC_BITS   (PORT_CSC | PORT_PEC | PORT_OCC)
 } __attribute__ ((packed));
 } __attribute__ ((packed));
 
 
+#define USBMODE		0x68		/* USB Device mode */
+#define USBMODE_SDIS	(1<<3)		/* Stream disable */
+#define USBMODE_BE	(1<<2)		/* BE/LE endianness select */
+#define USBMODE_CM_HC	(3<<0)		/* host controller mode */
+#define USBMODE_CM_IDLE	(0<<0)		/* idle state */
+
 /* Appendix C, Debug port ... intended for use with special "debug devices"
 /* Appendix C, Debug port ... intended for use with special "debug devices"
  * that can help if there's no serial console.  (nonstandard enumeration.)
  * that can help if there's no serial console.  (nonstandard enumeration.)
  */
  */
@@ -303,7 +335,7 @@ struct ehci_dbg_port {
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-#define	QTD_NEXT(dma)	cpu_to_le32((u32)dma)
+#define	QTD_NEXT(ehci, dma)	cpu_to_hc32(ehci, (u32)dma)
 
 
 /*
 /*
  * EHCI Specification 0.95 Section 3.5
  * EHCI Specification 0.95 Section 3.5
@@ -315,9 +347,9 @@ struct ehci_dbg_port {
  */
  */
 struct ehci_qtd {
 struct ehci_qtd {
 	/* first part defined by EHCI spec */
 	/* first part defined by EHCI spec */
-	__le32			hw_next;	  /* see EHCI 3.5.1 */
-	__le32			hw_alt_next;      /* see EHCI 3.5.2 */
-	__le32			hw_token;         /* see EHCI 3.5.3 */
+	__hc32			hw_next;	/* see EHCI 3.5.1 */
+	__hc32			hw_alt_next;    /* see EHCI 3.5.2 */
+	__hc32			hw_token;       /* see EHCI 3.5.3 */
 #define	QTD_TOGGLE	(1 << 31)	/* data toggle */
 #define	QTD_TOGGLE	(1 << 31)	/* data toggle */
 #define	QTD_LENGTH(tok)	(((tok)>>16) & 0x7fff)
 #define	QTD_LENGTH(tok)	(((tok)>>16) & 0x7fff)
 #define	QTD_IOC		(1 << 15)	/* interrupt on complete */
 #define	QTD_IOC		(1 << 15)	/* interrupt on complete */
@@ -331,8 +363,13 @@ struct ehci_qtd {
 #define	QTD_STS_MMF	(1 << 2)	/* incomplete split transaction */
 #define	QTD_STS_MMF	(1 << 2)	/* incomplete split transaction */
 #define	QTD_STS_STS	(1 << 1)	/* split transaction state */
 #define	QTD_STS_STS	(1 << 1)	/* split transaction state */
 #define	QTD_STS_PING	(1 << 0)	/* issue PING? */
 #define	QTD_STS_PING	(1 << 0)	/* issue PING? */
-	__le32			hw_buf [5];        /* see EHCI 3.5.4 */
-	__le32			hw_buf_hi [5];        /* Appendix B */
+
+#define ACTIVE_BIT(ehci)	cpu_to_hc32(ehci, QTD_STS_ACTIVE)
+#define HALT_BIT(ehci)		cpu_to_hc32(ehci, QTD_STS_HALT)
+#define STATUS_BIT(ehci)	cpu_to_hc32(ehci, QTD_STS_STS)
+
+	__hc32			hw_buf [5];        /* see EHCI 3.5.4 */
+	__hc32			hw_buf_hi [5];        /* Appendix B */
 
 
 	/* the rest is HCD-private */
 	/* the rest is HCD-private */
 	dma_addr_t		qtd_dma;		/* qtd address */
 	dma_addr_t		qtd_dma;		/* qtd address */
@@ -342,26 +379,33 @@ struct ehci_qtd {
 } __attribute__ ((aligned (32)));
 } __attribute__ ((aligned (32)));
 
 
 /* mask NakCnt+T in qh->hw_alt_next */
 /* mask NakCnt+T in qh->hw_alt_next */
-#define QTD_MASK __constant_cpu_to_le32 (~0x1f)
+#define QTD_MASK(ehci)	cpu_to_hc32 (ehci, ~0x1f)
 
 
 #define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1)
 #define IS_SHORT_READ(token) (QTD_LENGTH (token) != 0 && QTD_PID (token) == 1)
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 /* type tag from {qh,itd,sitd,fstn}->hw_next */
 /* type tag from {qh,itd,sitd,fstn}->hw_next */
-#define Q_NEXT_TYPE(dma) ((dma) & __constant_cpu_to_le32 (3 << 1))
+#define Q_NEXT_TYPE(ehci,dma)	((dma) & cpu_to_hc32(ehci, 3 << 1))
 
 
+/*
+ * Now the following defines are not converted using the
+ * __constant_cpu_to_le32() macro anymore, since we have to support
+ * "dynamic" switching between be and le support, so that the driver
+ * can be used on one system with SoC EHCI controller using big-endian
+ * descriptors as well as a normal little-endian PCI EHCI controller.
+ */
 /* values for that type tag */
 /* values for that type tag */
-#define Q_TYPE_ITD	__constant_cpu_to_le32 (0 << 1)
-#define Q_TYPE_QH	__constant_cpu_to_le32 (1 << 1)
-#define Q_TYPE_SITD	__constant_cpu_to_le32 (2 << 1)
-#define Q_TYPE_FSTN	__constant_cpu_to_le32 (3 << 1)
+#define Q_TYPE_ITD	(0 << 1)
+#define Q_TYPE_QH	(1 << 1)
+#define Q_TYPE_SITD	(2 << 1)
+#define Q_TYPE_FSTN	(3 << 1)
 
 
 /* next async queue entry, or pointer to interrupt/periodic QH */
 /* next async queue entry, or pointer to interrupt/periodic QH */
-#define	QH_NEXT(dma)	(cpu_to_le32(((u32)dma)&~0x01f)|Q_TYPE_QH)
+#define QH_NEXT(ehci,dma)	(cpu_to_hc32(ehci, (((u32)dma)&~0x01f)|Q_TYPE_QH))
 
 
 /* for periodic/async schedules and qtd lists, mark end of list */
 /* for periodic/async schedules and qtd lists, mark end of list */
-#define	EHCI_LIST_END	__constant_cpu_to_le32(1) /* "null pointer" to hw */
+#define EHCI_LIST_END(ehci)	cpu_to_hc32(ehci, 1) /* "null pointer" to hw */
 
 
 /*
 /*
  * Entries in periodic shadow table are pointers to one of four kinds
  * Entries in periodic shadow table are pointers to one of four kinds
@@ -376,7 +420,7 @@ union ehci_shadow {
 	struct ehci_itd		*itd;		/* Q_TYPE_ITD */
 	struct ehci_itd		*itd;		/* Q_TYPE_ITD */
 	struct ehci_sitd	*sitd;		/* Q_TYPE_SITD */
 	struct ehci_sitd	*sitd;		/* Q_TYPE_SITD */
 	struct ehci_fstn	*fstn;		/* Q_TYPE_FSTN */
 	struct ehci_fstn	*fstn;		/* Q_TYPE_FSTN */
-	__le32			*hw_next;	/* (all types) */
+	__hc32			*hw_next;	/* (all types) */
 	void			*ptr;
 	void			*ptr;
 };
 };
 
 
@@ -392,23 +436,27 @@ union ehci_shadow {
 
 
 struct ehci_qh {
 struct ehci_qh {
 	/* first part defined by EHCI spec */
 	/* first part defined by EHCI spec */
-	__le32			hw_next;	 /* see EHCI 3.6.1 */
-	__le32			hw_info1;        /* see EHCI 3.6.2 */
+	__hc32			hw_next;	/* see EHCI 3.6.1 */
+	__hc32			hw_info1;       /* see EHCI 3.6.2 */
 #define	QH_HEAD		0x00008000
 #define	QH_HEAD		0x00008000
-	__le32			hw_info2;        /* see EHCI 3.6.2 */
+#define	QH_INACTIVATE	0x00000080
+
+#define INACTIVATE_BIT(ehci)	cpu_to_hc32(ehci, QH_INACTIVATE)
+
+	__hc32			hw_info2;        /* see EHCI 3.6.2 */
 #define	QH_SMASK	0x000000ff
 #define	QH_SMASK	0x000000ff
 #define	QH_CMASK	0x0000ff00
 #define	QH_CMASK	0x0000ff00
 #define	QH_HUBADDR	0x007f0000
 #define	QH_HUBADDR	0x007f0000
 #define	QH_HUBPORT	0x3f800000
 #define	QH_HUBPORT	0x3f800000
 #define	QH_MULT		0xc0000000
 #define	QH_MULT		0xc0000000
-	__le32			hw_current;	 /* qtd list - see EHCI 3.6.4 */
+	__hc32			hw_current;	/* qtd list - see EHCI 3.6.4 */
 
 
 	/* qtd overlay (hardware parts of a struct ehci_qtd) */
 	/* qtd overlay (hardware parts of a struct ehci_qtd) */
-	__le32			hw_qtd_next;
-	__le32			hw_alt_next;
-	__le32			hw_token;
-	__le32			hw_buf [5];
-	__le32			hw_buf_hi [5];
+	__hc32			hw_qtd_next;
+	__hc32			hw_alt_next;
+	__hc32			hw_token;
+	__hc32			hw_buf [5];
+	__hc32			hw_buf_hi [5];
 
 
 	/* the rest is HCD-private */
 	/* the rest is HCD-private */
 	dma_addr_t		qh_dma;		/* address of qh */
 	dma_addr_t		qh_dma;		/* address of qh */
@@ -418,7 +466,14 @@ struct ehci_qh {
 	struct ehci_qh		*reclaim;	/* next to reclaim */
 	struct ehci_qh		*reclaim;	/* next to reclaim */
 
 
 	struct ehci_hcd		*ehci;
 	struct ehci_hcd		*ehci;
-	struct kref		kref;
+
+	/*
+	 * Do NOT use atomic operations for QH refcounting. On some CPUs
+	 * (PPC7448 for example), atomic operations cannot be performed on
+	 * memory that is cache-inhibited (i.e. being used for DMA).
+	 * Spinlocks are used to protect all QH fields.
+	 */
+	u32			refcount;
 	unsigned		stamp;
 	unsigned		stamp;
 
 
 	u8			qh_state;
 	u8			qh_state;
@@ -437,6 +492,10 @@ struct ehci_qh {
 	unsigned short		start;		/* where polling starts */
 	unsigned short		start;		/* where polling starts */
 #define NO_FRAME ((unsigned short)~0)			/* pick new start */
 #define NO_FRAME ((unsigned short)~0)			/* pick new start */
 	struct usb_device	*dev;		/* access to TT */
 	struct usb_device	*dev;		/* access to TT */
+#ifdef CONFIG_CPU_FREQ
+	struct list_head	split_intr_qhs; /* list of split qhs */
+	__le32			was_active;	/* active bit before "i" set */
+#endif
 } __attribute__ ((aligned (32)));
 } __attribute__ ((aligned (32)));
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -445,7 +504,7 @@ struct ehci_qh {
 struct ehci_iso_packet {
 struct ehci_iso_packet {
 	/* These will be copied to iTD when scheduling */
 	/* These will be copied to iTD when scheduling */
 	u64			bufp;		/* itd->hw_bufp{,_hi}[pg] |= */
 	u64			bufp;		/* itd->hw_bufp{,_hi}[pg] |= */
-	__le32			transaction;	/* itd->hw_transaction[i] |= */
+	__hc32			transaction;	/* itd->hw_transaction[i] |= */
 	u8			cross;		/* buf crosses pages */
 	u8			cross;		/* buf crosses pages */
 	/* for full speed OUT splits */
 	/* for full speed OUT splits */
 	u32			buf1;
 	u32			buf1;
@@ -467,8 +526,8 @@ struct ehci_iso_sched {
  */
  */
 struct ehci_iso_stream {
 struct ehci_iso_stream {
 	/* first two fields match QH, but info1 == 0 */
 	/* first two fields match QH, but info1 == 0 */
-	__le32			hw_next;
-	__le32			hw_info1;
+	__hc32			hw_next;
+	__hc32			hw_info1;
 
 
 	u32			refcount;
 	u32			refcount;
 	u8			bEndpointAddress;
 	u8			bEndpointAddress;
@@ -483,7 +542,7 @@ struct ehci_iso_stream {
 	unsigned long		start;		/* jiffies */
 	unsigned long		start;		/* jiffies */
 	unsigned long		rescheduled;
 	unsigned long		rescheduled;
 	int			next_uframe;
 	int			next_uframe;
-	__le32			splits;
+	__hc32			splits;
 
 
 	/* the rest is derived from the endpoint descriptor,
 	/* the rest is derived from the endpoint descriptor,
 	 * trusting urb->interval == f(epdesc->bInterval) and
 	 * trusting urb->interval == f(epdesc->bInterval) and
@@ -497,12 +556,12 @@ struct ehci_iso_stream {
 	unsigned		bandwidth;
 	unsigned		bandwidth;
 
 
 	/* This is used to initialize iTD's hw_bufp fields */
 	/* This is used to initialize iTD's hw_bufp fields */
-	__le32			buf0;
-	__le32			buf1;
-	__le32			buf2;
+	__hc32			buf0;
+	__hc32			buf1;
+	__hc32			buf2;
 
 
 	/* this is used to initialize sITD's tt info */
 	/* this is used to initialize sITD's tt info */
-	__le32			address;
+	__hc32			address;
 };
 };
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -515,8 +574,8 @@ struct ehci_iso_stream {
  */
  */
 struct ehci_itd {
 struct ehci_itd {
 	/* first part defined by EHCI spec */
 	/* first part defined by EHCI spec */
-	__le32			hw_next;           /* see EHCI 3.3.1 */
-	__le32			hw_transaction [8]; /* see EHCI 3.3.2 */
+	__hc32			hw_next;           /* see EHCI 3.3.1 */
+	__hc32			hw_transaction [8]; /* see EHCI 3.3.2 */
 #define EHCI_ISOC_ACTIVE        (1<<31)        /* activate transfer this slot */
 #define EHCI_ISOC_ACTIVE        (1<<31)        /* activate transfer this slot */
 #define EHCI_ISOC_BUF_ERR       (1<<30)        /* Data buffer error */
 #define EHCI_ISOC_BUF_ERR       (1<<30)        /* Data buffer error */
 #define EHCI_ISOC_BABBLE        (1<<29)        /* babble detected */
 #define EHCI_ISOC_BABBLE        (1<<29)        /* babble detected */
@@ -524,10 +583,10 @@ struct ehci_itd {
 #define	EHCI_ITD_LENGTH(tok)	(((tok)>>16) & 0x0fff)
 #define	EHCI_ITD_LENGTH(tok)	(((tok)>>16) & 0x0fff)
 #define	EHCI_ITD_IOC		(1 << 15)	/* interrupt on complete */
 #define	EHCI_ITD_IOC		(1 << 15)	/* interrupt on complete */
 
 
-#define ITD_ACTIVE	__constant_cpu_to_le32(EHCI_ISOC_ACTIVE)
+#define ITD_ACTIVE(ehci)	cpu_to_hc32(ehci, EHCI_ISOC_ACTIVE)
 
 
-	__le32			hw_bufp [7];	/* see EHCI 3.3.3 */
-	__le32			hw_bufp_hi [7];	/* Appendix B */
+	__hc32			hw_bufp [7];	/* see EHCI 3.3.3 */
+	__hc32			hw_bufp_hi [7];	/* Appendix B */
 
 
 	/* the rest is HCD-private */
 	/* the rest is HCD-private */
 	dma_addr_t		itd_dma;	/* for this itd */
 	dma_addr_t		itd_dma;	/* for this itd */
@@ -554,11 +613,11 @@ struct ehci_itd {
  */
  */
 struct ehci_sitd {
 struct ehci_sitd {
 	/* first part defined by EHCI spec */
 	/* first part defined by EHCI spec */
-	__le32			hw_next;
+	__hc32			hw_next;
 /* uses bit field macros above - see EHCI 0.95 Table 3-8 */
 /* uses bit field macros above - see EHCI 0.95 Table 3-8 */
-	__le32			hw_fullspeed_ep;	/* EHCI table 3-9 */
-	__le32			hw_uframe;		/* EHCI table 3-10 */
-	__le32			hw_results;		/* EHCI table 3-11 */
+	__hc32			hw_fullspeed_ep;	/* EHCI table 3-9 */
+	__hc32			hw_uframe;		/* EHCI table 3-10 */
+	__hc32			hw_results;		/* EHCI table 3-11 */
 #define	SITD_IOC	(1 << 31)	/* interrupt on completion */
 #define	SITD_IOC	(1 << 31)	/* interrupt on completion */
 #define	SITD_PAGE	(1 << 30)	/* buffer 0/1 */
 #define	SITD_PAGE	(1 << 30)	/* buffer 0/1 */
 #define	SITD_LENGTH(x)	(0x3ff & ((x)>>16))
 #define	SITD_LENGTH(x)	(0x3ff & ((x)>>16))
@@ -570,11 +629,11 @@ struct ehci_sitd {
 #define	SITD_STS_MMF	(1 << 2)	/* incomplete split transaction */
 #define	SITD_STS_MMF	(1 << 2)	/* incomplete split transaction */
 #define	SITD_STS_STS	(1 << 1)	/* split transaction state */
 #define	SITD_STS_STS	(1 << 1)	/* split transaction state */
 
 
-#define SITD_ACTIVE	__constant_cpu_to_le32(SITD_STS_ACTIVE)
+#define SITD_ACTIVE(ehci)	cpu_to_hc32(ehci, SITD_STS_ACTIVE)
 
 
-	__le32			hw_buf [2];		/* EHCI table 3-12 */
-	__le32			hw_backpointer;		/* EHCI table 3-13 */
-	__le32			hw_buf_hi [2];		/* Appendix B */
+	__hc32			hw_buf [2];		/* EHCI table 3-12 */
+	__hc32			hw_backpointer;		/* EHCI table 3-13 */
+	__hc32			hw_buf_hi [2];		/* Appendix B */
 
 
 	/* the rest is HCD-private */
 	/* the rest is HCD-private */
 	dma_addr_t		sitd_dma;
 	dma_addr_t		sitd_dma;
@@ -599,8 +658,8 @@ struct ehci_sitd {
  * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
  * it hits a "restore" FSTN; then it returns to finish other uframe 0/1 work.
  */
  */
 struct ehci_fstn {
 struct ehci_fstn {
-	__le32			hw_next;	/* any periodic q entry */
-	__le32			hw_prev;	/* qh or EHCI_LIST_END */
+	__hc32			hw_next;	/* any periodic q entry */
+	__hc32			hw_prev;	/* qh or EHCI_LIST_END */
 
 
 	/* the rest is HCD-private */
 	/* the rest is HCD-private */
 	dma_addr_t		fstn_dma;
 	dma_addr_t		fstn_dma;
@@ -672,8 +731,21 @@ ehci_port_speed(struct ehci_hcd *ehci, unsigned int portsc)
 #define ehci_big_endian_mmio(e)		0
 #define ehci_big_endian_mmio(e)		0
 #endif
 #endif
 
 
-static inline unsigned int ehci_readl (const struct ehci_hcd *ehci,
-				       __u32 __iomem * regs)
+/*
+ * Big-endian read/write functions are arch-specific.
+ * Other arches can be added if/when they're needed.
+ *
+ * REVISIT: arch/powerpc now has readl/writel_be, so the
+ * definition below can die once the 4xx support is
+ * finally ported over.
+ */
+#if defined(CONFIG_PPC)
+#define readl_be(addr)		in_be32((__force unsigned *)addr)
+#define writel_be(val, addr)	out_be32((__force unsigned *)addr, val)
+#endif
+
+static inline unsigned int ehci_readl(const struct ehci_hcd *ehci,
+		__u32 __iomem * regs)
 {
 {
 #ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
 #ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
 	return ehci_big_endian_mmio(ehci) ?
 	return ehci_big_endian_mmio(ehci) ?
@@ -684,8 +756,8 @@ static inline unsigned int ehci_readl (const struct ehci_hcd *ehci,
 #endif
 #endif
 }
 }
 
 
-static inline void ehci_writel (const struct ehci_hcd *ehci,
-				const unsigned int val, __u32 __iomem *regs)
+static inline void ehci_writel(const struct ehci_hcd *ehci,
+		const unsigned int val, __u32 __iomem *regs)
 {
 {
 #ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
 #ifdef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
 	ehci_big_endian_mmio(ehci) ?
 	ehci_big_endian_mmio(ehci) ?
@@ -698,6 +770,62 @@ static inline void ehci_writel (const struct ehci_hcd *ehci,
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
+/*
+ * The AMCC 440EPx not only implements its EHCI registers in big-endian
+ * format, but also its DMA data structures (descriptors).
+ *
+ * EHCI controllers accessed through PCI work normally (little-endian
+ * everywhere), so we won't bother supporting a BE-only mode for now.
+ */
+#ifdef CONFIG_USB_EHCI_BIG_ENDIAN_DESC
+#define ehci_big_endian_desc(e)		((e)->big_endian_desc)
+
+/* cpu to ehci */
+static inline __hc32 cpu_to_hc32 (const struct ehci_hcd *ehci, const u32 x)
+{
+	return ehci_big_endian_desc(ehci)
+		? (__force __hc32)cpu_to_be32(x)
+		: (__force __hc32)cpu_to_le32(x);
+}
+
+/* ehci to cpu */
+static inline u32 hc32_to_cpu (const struct ehci_hcd *ehci, const __hc32 x)
+{
+	return ehci_big_endian_desc(ehci)
+		? be32_to_cpu((__force __be32)x)
+		: le32_to_cpu((__force __le32)x);
+}
+
+static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)
+{
+	return ehci_big_endian_desc(ehci)
+		? be32_to_cpup((__force __be32 *)x)
+		: le32_to_cpup((__force __le32 *)x);
+}
+
+#else
+
+/* cpu to ehci */
+static inline __hc32 cpu_to_hc32 (const struct ehci_hcd *ehci, const u32 x)
+{
+	return cpu_to_le32(x);
+}
+
+/* ehci to cpu */
+static inline u32 hc32_to_cpu (const struct ehci_hcd *ehci, const __hc32 x)
+{
+	return le32_to_cpu(x);
+}
+
+static inline u32 hc32_to_cpup (const struct ehci_hcd *ehci, const __hc32 *x)
+{
+	return le32_to_cpup(x);
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
 #ifndef DEBUG
 #ifndef DEBUG
 #define STUB_DEBUG_FILES
 #define STUB_DEBUG_FILES
 #endif	/* DEBUG */
 #endif	/* DEBUG */

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

@@ -23,7 +23,7 @@
 /* debug| print the main components of an URB
 /* debug| print the main components of an URB
  * small: 0) header + data packets 1) just header
  * small: 0) header + data packets 1) just header
  */
  */
-static void __attribute__((unused))
+static void __maybe_unused
 urb_print (struct urb * urb, char * str, int small)
 urb_print (struct urb * urb, char * str, int small)
 {
 {
 	unsigned int pipe= urb->pipe;
 	unsigned int pipe= urb->pipe;
@@ -338,7 +338,7 @@ static void ohci_dump_td (const struct ohci_hcd *ohci, const char *label,
 }
 }
 
 
 /* caller MUST own hcd spinlock if verbose is set! */
 /* caller MUST own hcd spinlock if verbose is set! */
-static void __attribute__((unused))
+static void __maybe_unused
 ohci_dump_ed (const struct ohci_hcd *ohci, const char *label,
 ohci_dump_ed (const struct ohci_hcd *ohci, const char *label,
 		const struct ed *ed, int verbose)
 		const struct ed *ed, int verbose)
 {
 {

+ 47 - 45
drivers/usb/host/ohci-hcd.c

@@ -35,15 +35,13 @@
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>
 #include <linux/dmapool.h>
 #include <linux/dmapool.h>
 #include <linux/reboot.h>
 #include <linux/reboot.h>
+#include <linux/workqueue.h>
 
 
 #include <asm/io.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/system.h>
 #include <asm/unaligned.h>
 #include <asm/unaligned.h>
 #include <asm/byteorder.h>
 #include <asm/byteorder.h>
-#ifdef CONFIG_PPC_PS3
-#include <asm/firmware.h>
-#endif
 
 
 #include "../core/hcd.h"
 #include "../core/hcd.h"
 
 
@@ -82,6 +80,8 @@ static const char	hcd_name [] = "ohci_hcd";
 static void ohci_dump (struct ohci_hcd *ohci, int verbose);
 static void ohci_dump (struct ohci_hcd *ohci, int verbose);
 static int ohci_init (struct ohci_hcd *ohci);
 static int ohci_init (struct ohci_hcd *ohci);
 static void ohci_stop (struct usb_hcd *hcd);
 static void ohci_stop (struct usb_hcd *hcd);
+static int ohci_restart (struct ohci_hcd *ohci);
+static void ohci_quirk_nec_worker (struct work_struct *work);
 
 
 #include "ohci-hub.c"
 #include "ohci-hub.c"
 #include "ohci-dbg.c"
 #include "ohci-dbg.c"
@@ -510,15 +510,7 @@ static int ohci_run (struct ohci_hcd *ohci)
 	// flush the writes
 	// flush the writes
 	(void) ohci_readl (ohci, &ohci->regs->control);
 	(void) ohci_readl (ohci, &ohci->regs->control);
 	msleep(temp);
 	msleep(temp);
-	temp = roothub_a (ohci);
-	if (!(temp & RH_A_NPS)) {
-		/* power down each port */
-		for (temp = 0; temp < ohci->num_ports; temp++)
-			ohci_writel (ohci, RH_PS_LSDA,
-				&ohci->regs->roothub.portstatus [temp]);
-	}
-	// flush those writes
-	(void) ohci_readl (ohci, &ohci->regs->control);
+
 	memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
 	memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
 
 
 	/* 2msec timelimit here means no irqs/preempt */
 	/* 2msec timelimit here means no irqs/preempt */
@@ -659,9 +651,20 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
 	}
 	}
 
 
 	if (ints & OHCI_INTR_UE) {
 	if (ints & OHCI_INTR_UE) {
-		disable (ohci);
-		ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
 		// e.g. due to PCI Master/Target Abort
 		// e.g. due to PCI Master/Target Abort
+		if (ohci->flags & OHCI_QUIRK_NEC) {
+			/* Workaround for a silicon bug in some NEC chips used
+			 * in Apple's PowerBooks. Adapted from Darwin code.
+			 */
+			ohci_err (ohci, "OHCI Unrecoverable Error, scheduling NEC chip restart\n");
+
+			ohci_writel (ohci, OHCI_INTR_UE, &regs->intrdisable);
+
+			schedule_work (&ohci->nec_work);
+		} else {
+			disable (ohci);
+			ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
+		}
 
 
 		ohci_dump (ohci, 1);
 		ohci_dump (ohci, 1);
 		ohci_usb_reset (ohci);
 		ohci_usb_reset (ohci);
@@ -763,23 +766,16 @@ static void ohci_stop (struct usb_hcd *hcd)
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 /* must not be called from interrupt context */
 /* must not be called from interrupt context */
-
-#ifdef	CONFIG_PM
-
 static int ohci_restart (struct ohci_hcd *ohci)
 static int ohci_restart (struct ohci_hcd *ohci)
 {
 {
 	int temp;
 	int temp;
 	int i;
 	int i;
 	struct urb_priv *priv;
 	struct urb_priv *priv;
 
 
-	/* mark any devices gone, so they do nothing till khubd disconnects.
-	 * recycle any "live" eds/tds (and urbs) right away.
-	 * later, khubd disconnect processing will recycle the other state,
-	 * (either as disconnect/reconnect, or maybe someday as a reset).
-	 */
 	spin_lock_irq(&ohci->lock);
 	spin_lock_irq(&ohci->lock);
 	disable (ohci);
 	disable (ohci);
-	usb_root_hub_lost_power(ohci_to_hcd(ohci)->self.root_hub);
+
+	/* Recycle any "live" eds/tds (and urbs). */
 	if (!list_empty (&ohci->pending))
 	if (!list_empty (&ohci->pending))
 		ohci_dbg(ohci, "abort schedule...\n");
 		ohci_dbg(ohci, "abort schedule...\n");
 	list_for_each_entry (priv, &ohci->pending, pending) {
 	list_for_each_entry (priv, &ohci->pending, pending) {
@@ -826,20 +822,31 @@ static int ohci_restart (struct ohci_hcd *ohci)
 	if ((temp = ohci_run (ohci)) < 0) {
 	if ((temp = ohci_run (ohci)) < 0) {
 		ohci_err (ohci, "can't restart, %d\n", temp);
 		ohci_err (ohci, "can't restart, %d\n", temp);
 		return temp;
 		return temp;
-	} else {
-		/* here we "know" root ports should always stay powered,
-		 * and that if we try to turn them back on the root hub
-		 * will respond to CSC processing.
-		 */
-		i = ohci->num_ports;
-		while (i--)
-			ohci_writel (ohci, RH_PS_PSS,
-				&ohci->regs->roothub.portstatus [i]);
-		ohci_dbg (ohci, "restart complete\n");
 	}
 	}
+	ohci_dbg(ohci, "restart complete\n");
 	return 0;
 	return 0;
 }
 }
-#endif
+
+/*-------------------------------------------------------------------------*/
+
+/* NEC workaround */
+static void ohci_quirk_nec_worker(struct work_struct *work)
+{
+	struct ohci_hcd *ohci = container_of(work, struct ohci_hcd, nec_work);
+	int status;
+
+	status = ohci_init(ohci);
+	if (status != 0) {
+		ohci_err(ohci, "Restarting NEC controller failed "
+			 "in ohci_init, %d\n", status);
+		return;
+	}
+
+	status = ohci_restart(ohci);
+	if (status != 0)
+		ohci_err(ohci, "Restarting NEC controller failed "
+			 "in ohci_restart, %d\n", status);
+}
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
@@ -917,7 +924,7 @@ MODULE_LICENSE ("GPL");
 
 
 #ifdef CONFIG_PPC_PS3
 #ifdef CONFIG_PPC_PS3
 #include "ohci-ps3.c"
 #include "ohci-ps3.c"
-#define PS3_SYSTEM_BUS_DRIVER	ps3_ohci_sb_driver
+#define PS3_SYSTEM_BUS_DRIVER	ps3_ohci_driver
 #endif
 #endif
 
 
 #if	!defined(PCI_DRIVER) &&		\
 #if	!defined(PCI_DRIVER) &&		\
@@ -940,12 +947,9 @@ static int __init ohci_hcd_mod_init(void)
 		sizeof (struct ed), sizeof (struct td));
 		sizeof (struct ed), sizeof (struct td));
 
 
 #ifdef PS3_SYSTEM_BUS_DRIVER
 #ifdef PS3_SYSTEM_BUS_DRIVER
-	if (firmware_has_feature(FW_FEATURE_PS3_LV1)) {
-		retval = ps3_system_bus_driver_register(
-				&PS3_SYSTEM_BUS_DRIVER);
-		if (retval < 0)
-			goto error_ps3;
-	}
+	retval = ps3_ohci_driver_register(&PS3_SYSTEM_BUS_DRIVER);
+	if (retval < 0)
+		goto error_ps3;
 #endif
 #endif
 
 
 #ifdef PLATFORM_DRIVER
 #ifdef PLATFORM_DRIVER
@@ -991,8 +995,7 @@ static int __init ohci_hcd_mod_init(void)
  error_platform:
  error_platform:
 #endif
 #endif
 #ifdef PS3_SYSTEM_BUS_DRIVER
 #ifdef PS3_SYSTEM_BUS_DRIVER
-	if (firmware_has_feature(FW_FEATURE_PS3_LV1))
-		ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+	ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
  error_ps3:
  error_ps3:
 #endif
 #endif
 	return retval;
 	return retval;
@@ -1014,8 +1017,7 @@ static void __exit ohci_hcd_mod_exit(void)
 	platform_driver_unregister(&PLATFORM_DRIVER);
 	platform_driver_unregister(&PLATFORM_DRIVER);
 #endif
 #endif
 #ifdef PS3_SYSTEM_BUS_DRIVER
 #ifdef PS3_SYSTEM_BUS_DRIVER
-	if (firmware_has_feature(FW_FEATURE_PS3_LV1))
-		ps3_system_bus_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
+	ps3_ohci_driver_unregister(&PS3_SYSTEM_BUS_DRIVER);
 #endif
 #endif
 }
 }
 module_exit(ohci_hcd_mod_exit);
 module_exit(ohci_hcd_mod_exit);

+ 3 - 2
drivers/usb/host/ohci-hub.c

@@ -55,8 +55,6 @@ static void dl_done_list (struct ohci_hcd *);
 static void finish_unlinks (struct ohci_hcd *, u16);
 static void finish_unlinks (struct ohci_hcd *, u16);
 
 
 #ifdef	CONFIG_PM
 #ifdef	CONFIG_PM
-static int ohci_restart(struct ohci_hcd *ohci);
-
 static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop)
 static int ohci_rh_suspend (struct ohci_hcd *ohci, int autostop)
 __releases(ohci->lock)
 __releases(ohci->lock)
 __acquires(ohci->lock)
 __acquires(ohci->lock)
@@ -191,6 +189,9 @@ __acquires(ohci->lock)
 			spin_unlock_irq (&ohci->lock);
 			spin_unlock_irq (&ohci->lock);
 			(void) ohci_init (ohci);
 			(void) ohci_init (ohci);
 			status = ohci_restart (ohci);
 			status = ohci_restart (ohci);
+
+			usb_root_hub_lost_power(hcd->self.root_hub);
+
 			spin_lock_irq (&ohci->lock);
 			spin_lock_irq (&ohci->lock);
 		}
 		}
 		return status;
 		return status;

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

@@ -28,6 +28,7 @@ static void ohci_hcd_init (struct ohci_hcd *ohci)
 	ohci->next_statechange = jiffies;
 	ohci->next_statechange = jiffies;
 	spin_lock_init (&ohci->lock);
 	spin_lock_init (&ohci->lock);
 	INIT_LIST_HEAD (&ohci->pending);
 	INIT_LIST_HEAD (&ohci->pending);
+	INIT_WORK (&ohci->nec_work, ohci_quirk_nec_worker);
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/

+ 56 - 1
drivers/usb/host/ohci-pci.c

@@ -111,6 +111,18 @@ static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
 #endif
 #endif
 }
 }
 
 
+/* Check for NEC chip and apply quirk for allegedly lost interrupts.
+ */
+static int ohci_quirk_nec(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
+
+	ohci->flags |= OHCI_QUIRK_NEC;
+	ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n");
+
+	return 0;
+}
+
 /* List of quirks for OHCI */
 /* List of quirks for OHCI */
 static const struct pci_device_id ohci_pci_quirks[] = {
 static const struct pci_device_id ohci_pci_quirks[] = {
 	{
 	{
@@ -133,6 +145,10 @@ static const struct pci_device_id ohci_pci_quirks[] = {
 		PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6),
 		PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA_2, 0x01b6),
 		.driver_data = (unsigned long)ohci_quirk_toshiba_scc,
 		.driver_data = (unsigned long)ohci_quirk_toshiba_scc,
 	},
 	},
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_USB),
+		.driver_data = (unsigned long)ohci_quirk_nec,
+	},
 	{
 	{
 		/* Toshiba portege 4000 */
 		/* Toshiba portege 4000 */
 		.vendor		= PCI_VENDOR_ID_AL,
 		.vendor		= PCI_VENDOR_ID_AL,
@@ -202,6 +218,42 @@ static int __devinit ohci_pci_start (struct usb_hcd *hcd)
 	return ret;
 	return ret;
 }
 }
 
 
+#if	defined(CONFIG_USB_PERSIST) && (defined(CONFIG_USB_EHCI_HCD) || \
+		defined(CONFIG_USB_EHCI_HCD_MODULE))
+
+/* Following a power loss, we must prepare to regain control of the ports
+ * we used to own.  This means turning on the port power before ehci-hcd
+ * tries to switch ownership.
+ *
+ * This isn't a 100% perfect solution.  On most systems the OHCI controllers
+ * lie at lower PCI addresses than the EHCI controller, so they will be
+ * discovered (and hence resumed) first.  But there is no guarantee things
+ * will always work this way.  If the EHCI controller is resumed first and
+ * the OHCI ports are unpowered, then the handover will fail.
+ */
+static void prepare_for_handover(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
+	int		port;
+
+	/* Here we "know" root ports should always stay powered */
+	ohci_dbg(ohci, "powerup ports\n");
+	for (port = 0; port < ohci->num_ports; port++)
+		ohci_writel(ohci, RH_PS_PPS,
+				&ohci->regs->roothub.portstatus[port]);
+
+	/* Flush those writes */
+	ohci_readl(ohci, &ohci->regs->control);
+	msleep(20);
+}
+
+#else
+
+static inline void prepare_for_handover(struct usb_hcd *hcd)
+{ }
+
+#endif	/* CONFIG_USB_PERSIST etc. */
+
 #ifdef	CONFIG_PM
 #ifdef	CONFIG_PM
 
 
 static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
 static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
@@ -241,7 +293,10 @@ static int ohci_pci_suspend (struct usb_hcd *hcd, pm_message_t message)
 static int ohci_pci_resume (struct usb_hcd *hcd)
 static int ohci_pci_resume (struct usb_hcd *hcd)
 {
 {
 	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
-	usb_hcd_resume_root_hub(hcd);
+
+	/* FIXME: we should try to detect loss of VBUS power here */
+	prepare_for_handover(hcd);
+
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 1
drivers/usb/host/ohci-pnx4008.c

@@ -134,7 +134,7 @@ static int isp1301_attach(struct i2c_adapter *adap, int addr, int kind)
 {
 {
 	struct i2c_client *c;
 	struct i2c_client *c;
 
 
-	c = (struct i2c_client *)kzalloc(sizeof(*c), GFP_KERNEL);
+	c = kzalloc(sizeof(*c), GFP_KERNEL);
 
 
 	if (!c)
 	if (!c)
 		return -ENOMEM;
 		return -ENOMEM;

+ 75 - 12
drivers/usb/host/ohci-ps3.c

@@ -18,6 +18,7 @@
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
  */
 
 
+#include <asm/firmware.h>
 #include <asm/ps3.h>
 #include <asm/ps3.h>
 
 
 static int ps3_ohci_hc_reset(struct usb_hcd *hcd)
 static int ps3_ohci_hc_reset(struct usb_hcd *hcd)
@@ -75,7 +76,7 @@ static const struct hc_driver ps3_ohci_hc_driver = {
 #endif
 #endif
 };
 };
 
 
-static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
+static int ps3_ohci_probe(struct ps3_system_bus_device *dev)
 {
 {
 	int result;
 	int result;
 	struct usb_hcd *hcd;
 	struct usb_hcd *hcd;
@@ -87,13 +88,31 @@ static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
 		goto fail_start;
 		goto fail_start;
 	}
 	}
 
 
+	result = ps3_open_hv_device(dev);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: ps3_open_hv_device failed: %s\n",
+			__func__, __LINE__, ps3_result(result));
+		result = -EPERM;
+		goto fail_open;
+	}
+
+	result = ps3_dma_region_create(dev->d_region);
+
+	if (result) {
+		dev_dbg(&dev->core, "%s:%d: ps3_dma_region_create failed: "
+			"(%d)\n", __func__, __LINE__, result);
+		BUG_ON("check region type");
+		goto fail_dma_region;
+	}
+
 	result = ps3_mmio_region_create(dev->m_region);
 	result = ps3_mmio_region_create(dev->m_region);
 
 
 	if (result) {
 	if (result) {
 		dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
 		dev_dbg(&dev->core, "%s:%d: ps3_map_mmio_region failed\n",
 			__func__, __LINE__);
 			__func__, __LINE__);
 		result = -EPERM;
 		result = -EPERM;
-		goto fail_mmio;
+		goto fail_mmio_region;
 	}
 	}
 
 
 	dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
 	dev_dbg(&dev->core, "%s:%d: mmio mapped_addr %lxh\n", __func__,
@@ -122,6 +141,11 @@ static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
 
 
 	hcd->rsrc_start = dev->m_region->lpar_addr;
 	hcd->rsrc_start = dev->m_region->lpar_addr;
 	hcd->rsrc_len = dev->m_region->len;
 	hcd->rsrc_len = dev->m_region->len;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name))
+		dev_dbg(&dev->core, "%s:%d: request_mem_region failed\n",
+			__func__, __LINE__);
+
 	hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
 	hcd->regs = ioremap(dev->m_region->lpar_addr, dev->m_region->len);
 
 
 	if (!hcd->regs) {
 	if (!hcd->regs) {
@@ -155,34 +179,73 @@ static int ps3_ohci_sb_probe(struct ps3_system_bus_device *dev)
 fail_add_hcd:
 fail_add_hcd:
 	iounmap(hcd->regs);
 	iounmap(hcd->regs);
 fail_ioremap:
 fail_ioremap:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
 	usb_put_hcd(hcd);
 	usb_put_hcd(hcd);
 fail_create_hcd:
 fail_create_hcd:
 	ps3_io_irq_destroy(virq);
 	ps3_io_irq_destroy(virq);
 fail_irq:
 fail_irq:
 	ps3_free_mmio_region(dev->m_region);
 	ps3_free_mmio_region(dev->m_region);
-fail_mmio:
+fail_mmio_region:
+	ps3_dma_region_free(dev->d_region);
+fail_dma_region:
+	ps3_close_hv_device(dev);
+fail_open:
 fail_start:
 fail_start:
 	return result;
 	return result;
 }
 }
 
 
-static int ps3_ohci_sb_remove (struct ps3_system_bus_device *dev)
+static int ps3_ohci_remove (struct ps3_system_bus_device *dev)
 {
 {
+	unsigned int tmp;
 	struct usb_hcd *hcd =
 	struct usb_hcd *hcd =
 		(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
 		(struct usb_hcd *)ps3_system_bus_get_driver_data(dev);
 
 
-	usb_put_hcd(hcd);
+	BUG_ON(!hcd);
+
+	dev_dbg(&dev->core, "%s:%d: regs %p\n", __func__, __LINE__, hcd->regs);
+	dev_dbg(&dev->core, "%s:%d: irq %u\n", __func__, __LINE__, hcd->irq);
+
+	tmp = hcd->irq;
+
+	usb_remove_hcd(hcd);
+
 	ps3_system_bus_set_driver_data(dev, NULL);
 	ps3_system_bus_set_driver_data(dev, NULL);
 
 
+	BUG_ON(!hcd->regs);
+	iounmap(hcd->regs);
+
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+
+	ps3_io_irq_destroy(tmp);
+	ps3_free_mmio_region(dev->m_region);
+
+	ps3_dma_region_free(dev->d_region);
+	ps3_close_hv_device(dev);
+
 	return 0;
 	return 0;
 }
 }
 
 
-MODULE_ALIAS("ps3-ohci");
+static int ps3_ohci_driver_register(struct ps3_system_bus_driver *drv)
+{
+	return firmware_has_feature(FW_FEATURE_PS3_LV1)
+		? ps3_system_bus_driver_register(drv)
+		: 0;
+}
+
+static void ps3_ohci_driver_unregister(struct ps3_system_bus_driver *drv)
+{
+	if (firmware_has_feature(FW_FEATURE_PS3_LV1))
+		ps3_system_bus_driver_unregister(drv);
+}
+
+MODULE_ALIAS(PS3_MODULE_ALIAS_OHCI);
 
 
-static struct ps3_system_bus_driver ps3_ohci_sb_driver = {
+static struct ps3_system_bus_driver ps3_ohci_driver = {
+	.core.name = "ps3-ohci-driver",
+	.core.owner = THIS_MODULE,
 	.match_id = PS3_MATCH_ID_OHCI,
 	.match_id = PS3_MATCH_ID_OHCI,
-	.core = {
-		.name = "ps3-ohci-driver",
-	},
-	.probe = ps3_ohci_sb_probe,
-	.remove = ps3_ohci_sb_remove,
+	.probe = ps3_ohci_probe,
+	.remove = ps3_ohci_remove,
+	.shutdown = ps3_ohci_remove,
 };
 };

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

@@ -397,8 +397,10 @@ struct ohci_hcd {
 #define	OHCI_QUIRK_BE_DESC	0x08			/* BE descriptors */
 #define	OHCI_QUIRK_BE_DESC	0x08			/* BE descriptors */
 #define	OHCI_QUIRK_BE_MMIO	0x10			/* BE registers */
 #define	OHCI_QUIRK_BE_MMIO	0x10			/* BE registers */
 #define	OHCI_QUIRK_ZFMICRO	0x20			/* Compaq ZFMicro chipset*/
 #define	OHCI_QUIRK_ZFMICRO	0x20			/* Compaq ZFMicro chipset*/
+#define	OHCI_QUIRK_NEC		0x40			/* lost interrupts */
 	// there are also chip quirks/bugs in init logic
 	// there are also chip quirks/bugs in init logic
 
 
+	struct work_struct	nec_work;	/* Worker for NEC quirk */
 };
 };
 
 
 /* convert between an hcd pointer and the corresponding ohci_hcd */
 /* convert between an hcd pointer and the corresponding ohci_hcd */

+ 2244 - 0
drivers/usb/host/r8a66597-hcd.c

@@ -0,0 +1,2244 @@
+/*
+ * R8A66597 HCD (Host Controller Driver)
+ *
+ * Copyright (C) 2006-2007 Renesas Solutions Corp.
+ * Portions Copyright (C) 2004 Psion Teklogix (for NetBook PRO)
+ * Portions Copyright (C) 2004-2005 David Brownell
+ * Portions Copyright (C) 1999 Roman Weissgaerber
+ *
+ * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/usb.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "../core/hcd.h"
+#include "r8a66597.h"
+
+MODULE_DESCRIPTION("R8A66597 USB Host Controller Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Yoshihiro Shimoda");
+
+#define DRIVER_VERSION	"29 May 2007"
+
+static const char hcd_name[] = "r8a66597_hcd";
+
+/* module parameters */
+static unsigned short clock = XTAL12;
+module_param(clock, ushort, 0644);
+MODULE_PARM_DESC(clock, "input clock: 48MHz=32768, 24MHz=16384, 12MHz=0(default=0)");
+static unsigned short vif = LDRV;
+module_param(vif, ushort, 0644);
+MODULE_PARM_DESC(vif, "input VIF: 3.3V=32768, 1.5V=0(default=32768)");
+static unsigned short endian = 0;
+module_param(endian, ushort, 0644);
+MODULE_PARM_DESC(endian, "data endian: big=256, little=0(default=0)");
+static unsigned short irq_sense = INTL;
+module_param(irq_sense, ushort, 0644);
+MODULE_PARM_DESC(irq_sense, "IRQ sense: low level=32, falling edge=0(default=32)");
+
+static void packet_write(struct r8a66597 *r8a66597, u16 pipenum);
+static int r8a66597_get_frame(struct usb_hcd *hcd);
+
+/* this function must be called with interrupt disabled */
+static void enable_pipe_irq(struct r8a66597 *r8a66597, u16 pipenum,
+			    unsigned long reg)
+{
+	u16 tmp;
+
+	tmp = r8a66597_read(r8a66597, INTENB0);
+	r8a66597_bclr(r8a66597, BEMPE | NRDYE | BRDYE, INTENB0);
+	r8a66597_bset(r8a66597, 1 << pipenum, reg);
+	r8a66597_write(r8a66597, tmp, INTENB0);
+}
+
+/* this function must be called with interrupt disabled */
+static void disable_pipe_irq(struct r8a66597 *r8a66597, u16 pipenum,
+			     unsigned long reg)
+{
+	u16 tmp;
+
+	tmp = r8a66597_read(r8a66597, INTENB0);
+	r8a66597_bclr(r8a66597, BEMPE | NRDYE | BRDYE, INTENB0);
+	r8a66597_bclr(r8a66597, 1 << pipenum, reg);
+	r8a66597_write(r8a66597, tmp, INTENB0);
+}
+
+static void set_devadd_reg(struct r8a66597 *r8a66597, u8 r8a66597_address,
+			   u16 usbspd, u8 upphub, u8 hubport, int port)
+{
+	u16 val;
+	unsigned long devadd_reg = get_devadd_addr(r8a66597_address);
+
+	val = (upphub << 11) | (hubport << 8) | (usbspd << 6) | (port & 0x0001);
+	r8a66597_write(r8a66597, val, devadd_reg);
+}
+
+static int enable_controller(struct r8a66597 *r8a66597)
+{
+	u16 tmp;
+	int i = 0;
+
+	do {
+		r8a66597_write(r8a66597, USBE, SYSCFG0);
+		tmp = r8a66597_read(r8a66597, SYSCFG0);
+		if (i++ > 1000) {
+			err("register access fail.");
+			return -ENXIO;
+		}
+	} while ((tmp & USBE) != USBE);
+	r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+	r8a66597_mdfy(r8a66597, clock, XTAL, SYSCFG0);
+
+	i = 0;
+	r8a66597_bset(r8a66597, XCKE, SYSCFG0);
+	do {
+		msleep(1);
+		tmp = r8a66597_read(r8a66597, SYSCFG0);
+		if (i++ > 500) {
+			err("register access fail.");
+			return -ENXIO;
+		}
+	} while ((tmp & SCKE) != SCKE);
+
+	r8a66597_bset(r8a66597, DCFM | DRPD, SYSCFG0);
+	r8a66597_bset(r8a66597, DRPD, SYSCFG1);
+
+	r8a66597_bset(r8a66597, vif & LDRV, PINCFG);
+	r8a66597_bset(r8a66597, HSE, SYSCFG0);
+	r8a66597_bset(r8a66597, HSE, SYSCFG1);
+	r8a66597_bset(r8a66597, USBE, SYSCFG0);
+
+	r8a66597_bset(r8a66597, BEMPE | NRDYE | BRDYE, INTENB0);
+	r8a66597_bset(r8a66597, irq_sense & INTL, SOFCFG);
+	r8a66597_bset(r8a66597, BRDY0, BRDYENB);
+	r8a66597_bset(r8a66597, BEMP0, BEMPENB);
+
+	r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, DMA0CFG);
+	r8a66597_write(r8a66597, BURST | CPU_ADR_RD_WR, DMA1CFG);
+
+	r8a66597_bset(r8a66597, endian & BIGEND, CFIFOSEL);
+	r8a66597_bset(r8a66597, endian & BIGEND, D0FIFOSEL);
+	r8a66597_bset(r8a66597, endian & BIGEND, D1FIFOSEL);
+
+	r8a66597_bset(r8a66597, TRNENSEL, SOFCFG);
+
+	r8a66597_bset(r8a66597, SIGNE | SACKE, INTENB1);
+	r8a66597_bclr(r8a66597, DTCHE, INTENB1);
+	r8a66597_bset(r8a66597, ATTCHE, INTENB1);
+	r8a66597_bclr(r8a66597, DTCHE, INTENB2);
+	r8a66597_bset(r8a66597, ATTCHE, INTENB2);
+
+	return 0;
+}
+
+static void disable_controller(struct r8a66597 *r8a66597)
+{
+	u16 tmp;
+
+	r8a66597_write(r8a66597, 0, INTENB0);
+	r8a66597_write(r8a66597, 0, INTENB1);
+	r8a66597_write(r8a66597, 0, INTENB2);
+	r8a66597_write(r8a66597, 0, INTSTS0);
+	r8a66597_write(r8a66597, 0, INTSTS1);
+	r8a66597_write(r8a66597, 0, INTSTS2);
+
+	r8a66597_port_power(r8a66597, 0, 0);
+	r8a66597_port_power(r8a66597, 1, 0);
+
+	do {
+		tmp = r8a66597_read(r8a66597, SOFCFG) & EDGESTS;
+		udelay(640);
+	} while (tmp == EDGESTS);
+
+	r8a66597_bclr(r8a66597, DCFM | DRPD, SYSCFG0);
+	r8a66597_bclr(r8a66597, DRPD, SYSCFG1);
+	r8a66597_bclr(r8a66597, HSE, SYSCFG0);
+	r8a66597_bclr(r8a66597, HSE, SYSCFG1);
+
+	r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
+	udelay(1);
+	r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
+	r8a66597_bclr(r8a66597, XCKE, SYSCFG0);
+	r8a66597_bclr(r8a66597, USBE, SYSCFG0);
+}
+
+static int get_parent_r8a66597_address(struct r8a66597 *r8a66597,
+				       struct usb_device *udev)
+{
+	struct r8a66597_device *dev;
+
+	if (udev->parent && udev->parent->devnum != 1)
+		udev = udev->parent;
+
+	dev = dev_get_drvdata(&udev->dev);
+	if (dev)
+		return dev->address;
+	else
+		return 0;
+}
+
+static int is_child_device(char *devpath)
+{
+	return (devpath[2] ? 1 : 0);
+}
+
+static int is_hub_limit(char *devpath)
+{
+	return ((strlen(devpath) >= 4) ? 1 : 0);
+}
+
+static void get_port_number(char *devpath, u16 *root_port, u16 *hub_port)
+{
+	if (root_port) {
+		*root_port = (devpath[0] & 0x0F) - 1;
+		if (*root_port >= R8A66597_MAX_ROOT_HUB)
+			err("illegal root port number");
+	}
+	if (hub_port)
+		*hub_port = devpath[2] & 0x0F;
+}
+
+static u16 get_r8a66597_usb_speed(enum usb_device_speed speed)
+{
+	u16 usbspd = 0;
+
+	switch (speed) {
+	case USB_SPEED_LOW:
+		usbspd = LSMODE;
+		break;
+	case USB_SPEED_FULL:
+		usbspd = FSMODE;
+		break;
+	case USB_SPEED_HIGH:
+		usbspd = HSMODE;
+		break;
+	default:
+		err("unknown speed");
+		break;
+	}
+
+	return usbspd;
+}
+
+static void set_child_connect_map(struct r8a66597 *r8a66597, int address)
+{
+	int idx;
+
+	idx = address / 32;
+	r8a66597->child_connect_map[idx] |= 1 << (address % 32);
+}
+
+static void put_child_connect_map(struct r8a66597 *r8a66597, int address)
+{
+	int idx;
+
+	idx = address / 32;
+	r8a66597->child_connect_map[idx] &= ~(1 << (address % 32));
+}
+
+static void set_pipe_reg_addr(struct r8a66597_pipe *pipe, u8 dma_ch)
+{
+	u16 pipenum = pipe->info.pipenum;
+	unsigned long fifoaddr[] = {D0FIFO, D1FIFO, CFIFO};
+	unsigned long fifosel[] = {D0FIFOSEL, D1FIFOSEL, CFIFOSEL};
+	unsigned long fifoctr[] = {D0FIFOCTR, D1FIFOCTR, CFIFOCTR};
+
+	if (dma_ch > R8A66597_PIPE_NO_DMA)	/* dma fifo not use? */
+		dma_ch = R8A66597_PIPE_NO_DMA;
+
+	pipe->fifoaddr = fifoaddr[dma_ch];
+	pipe->fifosel = fifosel[dma_ch];
+	pipe->fifoctr = fifoctr[dma_ch];
+
+	if (pipenum == 0)
+		pipe->pipectr = DCPCTR;
+	else
+		pipe->pipectr = get_pipectr_addr(pipenum);
+
+	if (check_bulk_or_isoc(pipenum)) {
+		pipe->pipetre = get_pipetre_addr(pipenum);
+		pipe->pipetrn = get_pipetrn_addr(pipenum);
+	} else {
+		pipe->pipetre = 0;
+		pipe->pipetrn = 0;
+	}
+}
+
+static struct r8a66597_device *
+get_urb_to_r8a66597_dev(struct r8a66597 *r8a66597, struct urb *urb)
+{
+	if (usb_pipedevice(urb->pipe) == 0)
+		return &r8a66597->device0;
+
+	return dev_get_drvdata(&urb->dev->dev);
+}
+
+static int make_r8a66597_device(struct r8a66597 *r8a66597,
+				struct urb *urb, u8 addr)
+{
+	struct r8a66597_device *dev;
+	int usb_address = urb->setup_packet[2];	/* urb->pipe is address 0 */
+
+	dev = kzalloc(sizeof(struct r8a66597_device), GFP_KERNEL);
+	if (dev == NULL)
+		return -ENOMEM;
+
+	dev_set_drvdata(&urb->dev->dev, dev);
+	dev->udev = urb->dev;
+	dev->address = addr;
+	dev->usb_address = usb_address;
+	dev->state = USB_STATE_ADDRESS;
+	dev->ep_in_toggle = 0;
+	dev->ep_out_toggle = 0;
+	INIT_LIST_HEAD(&dev->device_list);
+	list_add_tail(&dev->device_list, &r8a66597->child_device);
+
+	get_port_number(urb->dev->devpath, &dev->root_port, &dev->hub_port);
+	if (!is_child_device(urb->dev->devpath))
+		r8a66597->root_hub[dev->root_port].dev = dev;
+
+	set_devadd_reg(r8a66597, dev->address,
+		       get_r8a66597_usb_speed(urb->dev->speed),
+		       get_parent_r8a66597_address(r8a66597, urb->dev),
+		       dev->hub_port, dev->root_port);
+
+	return 0;
+}
+
+/* this function must be called with interrupt disabled */
+static u8 alloc_usb_address(struct r8a66597 *r8a66597, struct urb *urb)
+{
+	u8 addr;	/* R8A66597's address */
+	struct r8a66597_device *dev;
+
+	if (is_hub_limit(urb->dev->devpath)) {
+		err("Externel hub limit reached.");
+		return 0;
+	}
+
+	dev = get_urb_to_r8a66597_dev(r8a66597, urb);
+	if (dev && dev->state >= USB_STATE_ADDRESS)
+		return dev->address;
+
+	for (addr = 1; addr <= R8A66597_MAX_DEVICE; addr++) {
+		if (r8a66597->address_map & (1 << addr))
+			continue;
+
+		dbg("alloc_address: r8a66597_addr=%d", addr);
+		r8a66597->address_map |= 1 << addr;
+
+		if (make_r8a66597_device(r8a66597, urb, addr) < 0)
+			return 0;
+
+		return addr;
+	}
+
+	err("cannot communicate with a USB device more than 10.(%x)",
+	    r8a66597->address_map);
+
+	return 0;
+}
+
+/* this function must be called with interrupt disabled */
+static void free_usb_address(struct r8a66597 *r8a66597,
+			     struct r8a66597_device *dev)
+{
+	int port;
+
+	if (!dev)
+		return;
+
+	dbg("free_addr: addr=%d", dev->address);
+
+	dev->state = USB_STATE_DEFAULT;
+	r8a66597->address_map &= ~(1 << dev->address);
+	dev->address = 0;
+	dev_set_drvdata(&dev->udev->dev, NULL);
+	list_del(&dev->device_list);
+	kfree(dev);
+
+	for (port = 0; port < R8A66597_MAX_ROOT_HUB; port++) {
+		if (r8a66597->root_hub[port].dev == dev) {
+			r8a66597->root_hub[port].dev = NULL;
+			break;
+		}
+	}
+}
+
+static void r8a66597_reg_wait(struct r8a66597 *r8a66597, unsigned long reg,
+			      u16 mask, u16 loop)
+{
+	u16 tmp;
+	int i = 0;
+
+	do {
+		tmp = r8a66597_read(r8a66597, reg);
+		if (i++ > 1000000) {
+			err("register%lx, loop %x is timeout", reg, loop);
+			break;
+		}
+		ndelay(1);
+	} while ((tmp & mask) != loop);
+}
+
+/* this function must be called with interrupt disabled */
+static void pipe_start(struct r8a66597 *r8a66597, struct r8a66597_pipe *pipe)
+{
+	u16 tmp;
+
+	tmp = r8a66597_read(r8a66597, pipe->pipectr) & PID;
+	if ((pipe->info.pipenum != 0) & ((tmp & PID_STALL) != 0)) /* stall? */
+		r8a66597_mdfy(r8a66597, PID_NAK, PID, pipe->pipectr);
+	r8a66597_mdfy(r8a66597, PID_BUF, PID, pipe->pipectr);
+}
+
+/* this function must be called with interrupt disabled */
+static void pipe_stop(struct r8a66597 *r8a66597, struct r8a66597_pipe *pipe)
+{
+	u16 tmp;
+
+	tmp = r8a66597_read(r8a66597, pipe->pipectr) & PID;
+	if ((tmp & PID_STALL11) != PID_STALL11)	/* force stall? */
+		r8a66597_mdfy(r8a66597, PID_STALL, PID, pipe->pipectr);
+	r8a66597_mdfy(r8a66597, PID_NAK, PID, pipe->pipectr);
+	r8a66597_reg_wait(r8a66597, pipe->pipectr, PBUSY, 0);
+}
+
+/* this function must be called with interrupt disabled */
+static void clear_all_buffer(struct r8a66597 *r8a66597,
+			     struct r8a66597_pipe *pipe)
+{
+	u16 tmp;
+
+	if (!pipe || pipe->info.pipenum == 0)
+		return;
+
+	pipe_stop(r8a66597, pipe);
+	r8a66597_bset(r8a66597, ACLRM, pipe->pipectr);
+	tmp = r8a66597_read(r8a66597, pipe->pipectr);
+	tmp = r8a66597_read(r8a66597, pipe->pipectr);
+	tmp = r8a66597_read(r8a66597, pipe->pipectr);
+	r8a66597_bclr(r8a66597, ACLRM, pipe->pipectr);
+}
+
+/* this function must be called with interrupt disabled */
+static void r8a66597_pipe_toggle(struct r8a66597 *r8a66597,
+				 struct r8a66597_pipe *pipe, int toggle)
+{
+	if (toggle)
+		r8a66597_bset(r8a66597, SQSET, pipe->pipectr);
+	else
+		r8a66597_bset(r8a66597, SQCLR, pipe->pipectr);
+}
+
+/* this function must be called with interrupt disabled */
+static inline void cfifo_change(struct r8a66597 *r8a66597, u16 pipenum)
+{
+	r8a66597_mdfy(r8a66597, MBW | pipenum, MBW | CURPIPE, CFIFOSEL);
+	r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, pipenum);
+}
+
+/* this function must be called with interrupt disabled */
+static inline void fifo_change_from_pipe(struct r8a66597 *r8a66597,
+					 struct r8a66597_pipe *pipe)
+{
+	cfifo_change(r8a66597, 0);
+	r8a66597_mdfy(r8a66597, MBW | 0, MBW | CURPIPE, D0FIFOSEL);
+	r8a66597_mdfy(r8a66597, MBW | 0, MBW | CURPIPE, D1FIFOSEL);
+
+	r8a66597_mdfy(r8a66597, MBW | pipe->info.pipenum, MBW | CURPIPE,
+		      pipe->fifosel);
+	r8a66597_reg_wait(r8a66597, pipe->fifosel, CURPIPE, pipe->info.pipenum);
+}
+
+static u16 r8a66597_get_pipenum(struct urb *urb, struct usb_host_endpoint *hep)
+{
+	struct r8a66597_pipe *pipe = hep->hcpriv;
+
+	if (usb_pipeendpoint(urb->pipe) == 0)
+		return 0;
+	else
+		return pipe->info.pipenum;
+}
+
+static u16 get_urb_to_r8a66597_addr(struct r8a66597 *r8a66597, struct urb *urb)
+{
+	struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb);
+
+	return (usb_pipedevice(urb->pipe) == 0) ? 0 : dev->address;
+}
+
+static unsigned short *get_toggle_pointer(struct r8a66597_device *dev,
+					  int urb_pipe)
+{
+	if (!dev)
+		return NULL;
+
+	return usb_pipein(urb_pipe) ? &dev->ep_in_toggle : &dev->ep_out_toggle;
+}
+
+/* this function must be called with interrupt disabled */
+static void pipe_toggle_set(struct r8a66597 *r8a66597,
+			    struct r8a66597_pipe *pipe,
+			    struct urb *urb, int set)
+{
+	struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb);
+	unsigned char endpoint = usb_pipeendpoint(urb->pipe);
+	unsigned short *toggle = get_toggle_pointer(dev, urb->pipe);
+
+	if (!toggle)
+		return;
+
+	if (set)
+		*toggle |= 1 << endpoint;
+	else
+		*toggle &= ~(1 << endpoint);
+}
+
+/* this function must be called with interrupt disabled */
+static void pipe_toggle_save(struct r8a66597 *r8a66597,
+			     struct r8a66597_pipe *pipe,
+			     struct urb *urb)
+{
+	if (r8a66597_read(r8a66597, pipe->pipectr) & SQMON)
+		pipe_toggle_set(r8a66597, pipe, urb, 1);
+	else
+		pipe_toggle_set(r8a66597, pipe, urb, 0);
+}
+
+/* this function must be called with interrupt disabled */
+static void pipe_toggle_restore(struct r8a66597 *r8a66597,
+				struct r8a66597_pipe *pipe,
+				struct urb *urb)
+{
+	struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb);
+	unsigned char endpoint = usb_pipeendpoint(urb->pipe);
+	unsigned short *toggle = get_toggle_pointer(dev, urb->pipe);
+
+	if (!toggle)
+		return;
+
+	r8a66597_pipe_toggle(r8a66597, pipe, *toggle & (1 << endpoint));
+}
+
+/* this function must be called with interrupt disabled */
+static void pipe_buffer_setting(struct r8a66597 *r8a66597,
+				struct r8a66597_pipe_info *info)
+{
+	u16 val = 0;
+
+	if (info->pipenum == 0)
+		return;
+
+	r8a66597_bset(r8a66597, ACLRM, get_pipectr_addr(info->pipenum));
+	r8a66597_bclr(r8a66597, ACLRM, get_pipectr_addr(info->pipenum));
+	r8a66597_write(r8a66597, info->pipenum, PIPESEL);
+	if (!info->dir_in)
+		val |= R8A66597_DIR;
+	if (info->type == R8A66597_BULK && info->dir_in)
+		val |= R8A66597_DBLB | R8A66597_SHTNAK;
+	val |= info->type | info->epnum;
+	r8a66597_write(r8a66597, val, PIPECFG);
+
+	r8a66597_write(r8a66597, (info->buf_bsize << 10) | (info->bufnum),
+		       PIPEBUF);
+	r8a66597_write(r8a66597, make_devsel(info->address) | info->maxpacket,
+		       PIPEMAXP);
+	if (info->interval)
+		info->interval--;
+	r8a66597_write(r8a66597, info->interval, PIPEPERI);
+}
+
+
+
+/* this function must be called with interrupt disabled */
+static void pipe_setting(struct r8a66597 *r8a66597, struct r8a66597_td *td)
+{
+	struct r8a66597_pipe_info *info;
+	struct urb *urb = td->urb;
+
+	if (td->pipenum > 0) {
+		info = &td->pipe->info;
+		cfifo_change(r8a66597, 0);
+		pipe_buffer_setting(r8a66597, info);
+
+		if (!usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+				   usb_pipeout(urb->pipe)) &&
+		    !usb_pipecontrol(urb->pipe)) {
+			r8a66597_pipe_toggle(r8a66597, td->pipe, 0);
+			pipe_toggle_set(r8a66597, td->pipe, urb, 0);
+			clear_all_buffer(r8a66597, td->pipe);
+			usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+				      usb_pipeout(urb->pipe), 1);
+		}
+		pipe_toggle_restore(r8a66597, td->pipe, urb);
+	}
+}
+
+/* this function must be called with interrupt disabled */
+static u16 get_empty_pipenum(struct r8a66597 *r8a66597,
+			     struct usb_endpoint_descriptor *ep)
+{
+	u16 array[R8A66597_MAX_NUM_PIPE], i = 0, min;
+
+	memset(array, 0, sizeof(array));
+        switch(ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+        case USB_ENDPOINT_XFER_BULK:
+		if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+			array[i++] = 4;
+		else {
+			array[i++] = 3;
+			array[i++] = 5;
+		}
+                break;
+        case USB_ENDPOINT_XFER_INT:
+		if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK) {
+			array[i++] = 6;
+			array[i++] = 7;
+			array[i++] = 8;
+		} else
+			array[i++] = 9;
+                break;
+        case USB_ENDPOINT_XFER_ISOC:
+		if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+			array[i++] = 2;
+		else
+			array[i++] = 1;
+                break;
+        default:
+                err("Illegal type");
+                return 0;
+        }
+
+	i = 1;
+	min = array[0];
+	while (array[i] != 0) {
+		if (r8a66597->pipe_cnt[min] > r8a66597->pipe_cnt[array[i]])
+			min = array[i];
+		i++;
+	}
+
+	return min;
+}
+
+static u16 get_r8a66597_type(__u8 type)
+{
+	u16 r8a66597_type;
+
+	switch(type) {
+	case USB_ENDPOINT_XFER_BULK:
+		r8a66597_type = R8A66597_BULK;
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		r8a66597_type = R8A66597_INT;
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		r8a66597_type = R8A66597_ISO;
+		break;
+	default:
+		err("Illegal type");
+		r8a66597_type = 0x0000;
+		break;
+	}
+
+	return r8a66597_type;
+}
+
+static u16 get_bufnum(u16 pipenum)
+{
+	u16 bufnum = 0;
+
+	if (pipenum == 0)
+		bufnum = 0;
+	else if (check_bulk_or_isoc(pipenum))
+		bufnum = 8 + (pipenum - 1) * R8A66597_BUF_BSIZE*2;
+	else if (check_interrupt(pipenum))
+		bufnum = 4 + (pipenum - 6);
+	else
+		err("Illegal pipenum (%d)", pipenum);
+
+	return bufnum;
+}
+
+static u16 get_buf_bsize(u16 pipenum)
+{
+	u16 buf_bsize = 0;
+
+	if (pipenum == 0)
+		buf_bsize = 3;
+	else if (check_bulk_or_isoc(pipenum))
+		buf_bsize = R8A66597_BUF_BSIZE - 1;
+	else if (check_interrupt(pipenum))
+		buf_bsize = 0;
+	else
+		err("Illegal pipenum (%d)", pipenum);
+
+	return buf_bsize;
+}
+
+/* this function must be called with interrupt disabled */
+static void enable_r8a66597_pipe_dma(struct r8a66597 *r8a66597,
+				     struct r8a66597_device *dev,
+				     struct r8a66597_pipe *pipe,
+				     struct urb *urb)
+{
+	int i;
+	struct r8a66597_pipe_info *info = &pipe->info;
+
+	if ((pipe->info.pipenum != 0) && (info->type != R8A66597_INT)) {
+		for (i = 0; i < R8A66597_MAX_DMA_CHANNEL; i++) {
+			if ((r8a66597->dma_map & (1 << i)) != 0)
+				continue;
+
+			info("address %d, EndpointAddress 0x%02x use DMA FIFO",
+			     usb_pipedevice(urb->pipe),
+			     info->dir_in ? USB_ENDPOINT_DIR_MASK + info->epnum
+					    : info->epnum);
+
+			r8a66597->dma_map |= 1 << i;
+			dev->dma_map |= 1 << i;
+			set_pipe_reg_addr(pipe, i);
+
+			cfifo_change(r8a66597, 0);
+			r8a66597_mdfy(r8a66597, MBW | pipe->info.pipenum,
+				      MBW | CURPIPE, pipe->fifosel);
+
+			r8a66597_reg_wait(r8a66597, pipe->fifosel, CURPIPE,
+					  pipe->info.pipenum);
+			r8a66597_bset(r8a66597, BCLR, pipe->fifoctr);
+			break;
+		}
+	}
+}
+
+/* this function must be called with interrupt disabled */
+static void enable_r8a66597_pipe(struct r8a66597 *r8a66597, struct urb *urb,
+				 struct usb_host_endpoint *hep,
+				 struct r8a66597_pipe_info *info)
+{
+	struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb);
+	struct r8a66597_pipe *pipe = hep->hcpriv;
+
+	dbg("enable_pipe:");
+
+	pipe->info = *info;
+	set_pipe_reg_addr(pipe, R8A66597_PIPE_NO_DMA);
+	r8a66597->pipe_cnt[pipe->info.pipenum]++;
+	dev->pipe_cnt[pipe->info.pipenum]++;
+
+	enable_r8a66597_pipe_dma(r8a66597, dev, pipe, urb);
+}
+
+/* this function must be called with interrupt disabled */
+static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address)
+{
+	struct r8a66597_td *td, *next;
+	struct urb *urb;
+	struct list_head *list = &r8a66597->pipe_queue[pipenum];
+
+	if (list_empty(list))
+		return;
+
+	list_for_each_entry_safe(td, next, list, queue) {
+		if (!td)
+			continue;
+		if (td->address != address)
+			continue;
+
+		urb = td->urb;
+		list_del(&td->queue);
+		kfree(td);
+
+		if (urb) {
+			urb->status = -ENODEV;
+			urb->hcpriv = NULL;
+			spin_unlock(&r8a66597->lock);
+			usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb);
+			spin_lock(&r8a66597->lock);
+		}
+		break;
+	}
+}
+
+/* this function must be called with interrupt disabled */
+static void disable_r8a66597_pipe_all(struct r8a66597 *r8a66597,
+				      struct r8a66597_device *dev)
+{
+	int check_ep0 = 0;
+	u16 pipenum;
+
+	if (!dev)
+		return;
+
+	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
+		if (!dev->pipe_cnt[pipenum])
+			continue;
+
+		if (!check_ep0) {
+			check_ep0 = 1;
+			force_dequeue(r8a66597, 0, dev->address);
+		}
+
+		r8a66597->pipe_cnt[pipenum] -= dev->pipe_cnt[pipenum];
+		dev->pipe_cnt[pipenum] = 0;
+		force_dequeue(r8a66597, pipenum, dev->address);
+	}
+
+	dbg("disable_pipe");
+
+	r8a66597->dma_map &= ~(dev->dma_map);
+	dev->dma_map = 0;
+}
+
+/* this function must be called with interrupt disabled */
+static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,
+			   struct usb_host_endpoint *hep,
+			   struct usb_endpoint_descriptor *ep)
+{
+	struct r8a66597_pipe_info info;
+
+	info.pipenum = get_empty_pipenum(r8a66597, ep);
+	info.address = get_urb_to_r8a66597_addr(r8a66597, urb);
+	info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+	info.maxpacket = ep->wMaxPacketSize;
+	info.type = get_r8a66597_type(ep->bmAttributes
+				      & USB_ENDPOINT_XFERTYPE_MASK);
+	info.bufnum = get_bufnum(info.pipenum);
+	info.buf_bsize = get_buf_bsize(info.pipenum);
+	info.interval = ep->bInterval;
+	if (ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+		info.dir_in = 1;
+	else
+		info.dir_in = 0;
+
+	enable_r8a66597_pipe(r8a66597, urb, hep, &info);
+}
+
+static void init_pipe_config(struct r8a66597 *r8a66597, struct urb *urb)
+{
+	struct r8a66597_device *dev;
+
+	dev = get_urb_to_r8a66597_dev(r8a66597, urb);
+	dev->state = USB_STATE_CONFIGURED;
+}
+
+static void pipe_irq_enable(struct r8a66597 *r8a66597, struct urb *urb,
+			    u16 pipenum)
+{
+	if (pipenum == 0 && usb_pipeout(urb->pipe))
+		enable_irq_empty(r8a66597, pipenum);
+	else
+		enable_irq_ready(r8a66597, pipenum);
+
+	if (!usb_pipeisoc(urb->pipe))
+		enable_irq_nrdy(r8a66597, pipenum);
+}
+
+static void pipe_irq_disable(struct r8a66597 *r8a66597, u16 pipenum)
+{
+	disable_irq_ready(r8a66597, pipenum);
+	disable_irq_nrdy(r8a66597, pipenum);
+}
+
+/* this function must be called with interrupt disabled */
+static void r8a66597_usb_preconnect(struct r8a66597 *r8a66597, int port)
+{
+	r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_CONNECTION)
+					 | (1 << USB_PORT_FEAT_C_CONNECTION);
+	r8a66597_write(r8a66597, (u16)~DTCH, get_intsts_reg(port));
+	r8a66597_bset(r8a66597, DTCHE, get_intenb_reg(port));
+}
+
+/* this function must be called with interrupt disabled */
+static void r8a66597_usb_connect(struct r8a66597 *r8a66597, int port)
+{
+	u16 speed = get_rh_usb_speed(r8a66597, port);
+	struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
+
+	if (speed == HSMODE)
+		rh->port |= (1 << USB_PORT_FEAT_HIGHSPEED);
+	else if (speed == LSMODE)
+		rh->port |= (1 << USB_PORT_FEAT_LOWSPEED);
+
+	rh->port &= ~(1 << USB_PORT_FEAT_RESET);
+	rh->port |= 1 << USB_PORT_FEAT_ENABLE;
+}
+
+/* this function must be called with interrupt disabled */
+static void r8a66597_usb_disconnect(struct r8a66597 *r8a66597, int port)
+{
+	struct r8a66597_device *dev = r8a66597->root_hub[port].dev;
+
+	r8a66597->root_hub[port].port &= ~(1 << USB_PORT_FEAT_CONNECTION);
+	r8a66597->root_hub[port].port |= (1 << USB_PORT_FEAT_C_CONNECTION);
+
+	disable_r8a66597_pipe_all(r8a66597, dev);
+	free_usb_address(r8a66597, dev);
+
+	r8a66597_bset(r8a66597, ATTCHE, get_intenb_reg(port));
+}
+
+/* this function must be called with interrupt disabled */
+static void prepare_setup_packet(struct r8a66597 *r8a66597,
+				 struct r8a66597_td *td)
+{
+	int i;
+	u16 *p = (u16 *)td->urb->setup_packet;
+	unsigned long setup_addr = USBREQ;
+
+	r8a66597_write(r8a66597, make_devsel(td->address) | td->maxpacket,
+		       DCPMAXP);
+	r8a66597_write(r8a66597, (u16)~(SIGN | SACK), INTSTS1);
+
+	for (i = 0; i < 4; i++) {
+		r8a66597_write(r8a66597, p[i], setup_addr);
+		setup_addr += 2;
+	}
+	r8a66597_write(r8a66597, SUREQ, DCPCTR);
+}
+
+/* this function must be called with interrupt disabled */
+static void prepare_packet_read(struct r8a66597 *r8a66597,
+				struct r8a66597_td *td)
+{
+	struct urb *urb = td->urb;
+
+	if (usb_pipecontrol(urb->pipe)) {
+		r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
+		r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
+		r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
+		if (urb->actual_length == 0) {
+			r8a66597_pipe_toggle(r8a66597, td->pipe, 1);
+			r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+		}
+		pipe_irq_disable(r8a66597, td->pipenum);
+		pipe_start(r8a66597, td->pipe);
+		pipe_irq_enable(r8a66597, urb, td->pipenum);
+	} else {
+		if (urb->actual_length == 0) {
+			pipe_irq_disable(r8a66597, td->pipenum);
+			pipe_setting(r8a66597, td);
+			pipe_stop(r8a66597, td->pipe);
+			r8a66597_write(r8a66597, (u16)~(1 << td->pipenum),
+				       BRDYSTS);
+
+			if (td->pipe->pipetre) {
+				r8a66597_write(r8a66597, TRCLR,
+					        td->pipe->pipetre);
+				r8a66597_write(r8a66597,
+					       (urb->transfer_buffer_length
+					       + td->maxpacket - 1)
+					       / td->maxpacket,
+					       td->pipe->pipetrn);
+				r8a66597_bset(r8a66597, TRENB,
+					      td->pipe->pipetre);
+			}
+
+			pipe_start(r8a66597, td->pipe);
+			pipe_irq_enable(r8a66597, urb, td->pipenum);
+		}
+	}
+}
+
+/* this function must be called with interrupt disabled */
+static void prepare_packet_write(struct r8a66597 *r8a66597,
+				 struct r8a66597_td *td)
+{
+	u16 tmp;
+	struct urb *urb = td->urb;
+
+	if (usb_pipecontrol(urb->pipe)) {
+		pipe_stop(r8a66597, td->pipe);
+		r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG);
+		r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
+		r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
+		if (urb->actual_length == 0) {
+			r8a66597_pipe_toggle(r8a66597, td->pipe, 1);
+			r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+		}
+	} else {
+		if (urb->actual_length == 0)
+			pipe_setting(r8a66597, td);
+		if (td->pipe->pipetre)
+			r8a66597_bclr(r8a66597, TRENB, td->pipe->pipetre);
+	}
+	r8a66597_write(r8a66597, (u16)~(1 << td->pipenum), BRDYSTS);
+
+	fifo_change_from_pipe(r8a66597, td->pipe);
+	tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
+	if (unlikely((tmp & FRDY) == 0))
+		pipe_irq_enable(r8a66597, urb, td->pipenum);
+	else
+		packet_write(r8a66597, td->pipenum);
+	pipe_start(r8a66597, td->pipe);
+}
+
+/* this function must be called with interrupt disabled */
+static void prepare_status_packet(struct r8a66597 *r8a66597,
+				  struct r8a66597_td *td)
+{
+	struct urb *urb = td->urb;
+
+	r8a66597_pipe_toggle(r8a66597, td->pipe, 1);
+
+	if (urb->setup_packet[0] & USB_ENDPOINT_DIR_MASK) {
+		r8a66597_bset(r8a66597, R8A66597_DIR, DCPCFG);
+		r8a66597_mdfy(r8a66597, ISEL, ISEL | CURPIPE, CFIFOSEL);
+		r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
+		r8a66597_write(r8a66597, BVAL | BCLR, CFIFOCTR);
+		r8a66597_write(r8a66597, (u16)~BEMP0, BEMPSTS);
+		enable_irq_empty(r8a66597, 0);
+	} else {
+		r8a66597_bclr(r8a66597, R8A66597_DIR, DCPCFG);
+		r8a66597_mdfy(r8a66597, 0, ISEL | CURPIPE, CFIFOSEL);
+		r8a66597_reg_wait(r8a66597, CFIFOSEL, CURPIPE, 0);
+		r8a66597_write(r8a66597, BCLR, CFIFOCTR);
+		r8a66597_write(r8a66597, (u16)~BRDY0, BRDYSTS);
+		r8a66597_write(r8a66597, (u16)~BEMP0, BEMPSTS);
+		enable_irq_ready(r8a66597, 0);
+	}
+	enable_irq_nrdy(r8a66597, 0);
+	pipe_start(r8a66597, td->pipe);
+}
+
+/* this function must be called with interrupt disabled */
+static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
+{
+	BUG_ON(!td);
+
+	switch (td->type) {
+	case USB_PID_SETUP:
+		if (td->urb->setup_packet[1] == USB_REQ_SET_ADDRESS) {
+			td->set_address = 1;
+			td->urb->setup_packet[2] = alloc_usb_address(r8a66597,
+								     td->urb);
+			if (td->urb->setup_packet[2] == 0)
+				return -EPIPE;
+		}
+		prepare_setup_packet(r8a66597, td);
+		break;
+	case USB_PID_IN:
+		prepare_packet_read(r8a66597, td);
+		break;
+	case USB_PID_OUT:
+		prepare_packet_write(r8a66597, td);
+		break;
+	case USB_PID_ACK:
+		prepare_status_packet(r8a66597, td);
+		break;
+	default:
+		err("invalid type.");
+		break;
+	}
+
+	return 0;
+}
+
+static int check_transfer_finish(struct r8a66597_td *td, struct urb *urb)
+{
+	if (usb_pipeisoc(urb->pipe)) {
+		if (urb->number_of_packets == td->iso_cnt)
+			return 1;
+	}
+
+	/* control or bulk or interrupt */
+	if ((urb->transfer_buffer_length <= urb->actual_length) ||
+	    (td->short_packet) || (td->zero_packet))
+		return 1;
+
+	return 0;
+}
+
+/* this function must be called with interrupt disabled */
+static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
+{
+	unsigned long time;
+
+	BUG_ON(!td);
+
+	if (!list_empty(&r8a66597->pipe_queue[td->pipenum]) &&
+	    !usb_pipecontrol(td->urb->pipe) && usb_pipein(td->urb->pipe)) {
+		r8a66597->timeout_map |= 1 << td->pipenum;
+		switch (usb_pipetype(td->urb->pipe)) {
+		case PIPE_INTERRUPT:
+		case PIPE_ISOCHRONOUS:
+			time = 30;
+			break;
+		default:
+			time = 300;
+			break;
+		}
+
+		mod_timer(&r8a66597->td_timer[td->pipenum],
+			  jiffies + msecs_to_jiffies(time));
+	}
+}
+
+/* this function must be called with interrupt disabled */
+static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
+		 u16 pipenum, struct urb *urb)
+{
+	int restart = 0;
+	struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
+
+	r8a66597->timeout_map &= ~(1 << pipenum);
+
+	if (likely(td)) {
+		if (td->set_address && urb->status != 0)
+			r8a66597->address_map &= ~(1 << urb->setup_packet[2]);
+
+		pipe_toggle_save(r8a66597, td->pipe, urb);
+		list_del(&td->queue);
+		kfree(td);
+	}
+
+	if (!list_empty(&r8a66597->pipe_queue[pipenum]))
+		restart = 1;
+
+	if (likely(urb)) {
+		if (usb_pipeisoc(urb->pipe))
+			urb->start_frame = r8a66597_get_frame(hcd);
+
+		urb->hcpriv = NULL;
+		spin_unlock(&r8a66597->lock);
+		usb_hcd_giveback_urb(hcd, urb);
+		spin_lock(&r8a66597->lock);
+	}
+
+	if (restart) {
+		td = r8a66597_get_td(r8a66597, pipenum);
+		if (unlikely(!td))
+			return;
+
+		start_transfer(r8a66597, td);
+		set_td_timer(r8a66597, td);
+	}
+}
+
+/* this function must be called with interrupt disabled */
+static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
+			   u16 pipenum, struct urb *urb)
+__releases(r8a66597->lock) __acquires(r8a66597->lock)
+{
+	done(r8a66597, td, pipenum, urb);
+}
+
+static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
+{
+	u16 tmp;
+	int rcv_len, bufsize, urb_len, size;
+	u16 *buf;
+	struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
+	struct urb *urb;
+	int finish = 0;
+
+	if (unlikely(!td))
+		return;
+	urb = td->urb;
+
+	fifo_change_from_pipe(r8a66597, td->pipe);
+	tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
+	if (unlikely((tmp & FRDY) == 0)) {
+		urb->status = -EPIPE;
+		pipe_stop(r8a66597, td->pipe);
+		pipe_irq_disable(r8a66597, pipenum);
+		err("in fifo not ready (%d)", pipenum);
+		finish_request(r8a66597, td, pipenum, td->urb);
+		return;
+	}
+
+	/* prepare parameters */
+	rcv_len = tmp & DTLN;
+	bufsize = td->maxpacket;
+	if (usb_pipeisoc(urb->pipe)) {
+		buf = (u16 *)(urb->transfer_buffer +
+				urb->iso_frame_desc[td->iso_cnt].offset);
+		urb_len = urb->iso_frame_desc[td->iso_cnt].length;
+	} else {
+		buf = (void *)urb->transfer_buffer + urb->actual_length;
+		urb_len = urb->transfer_buffer_length - urb->actual_length;
+	}
+	if (rcv_len < bufsize)
+		size = min(rcv_len, urb_len);
+	else
+		size = min(bufsize, urb_len);
+
+	/* update parameters */
+	urb->actual_length += size;
+	if (rcv_len == 0)
+		td->zero_packet = 1;
+	if ((size % td->maxpacket) > 0) {
+		td->short_packet = 1;
+		if (urb->transfer_buffer_length != urb->actual_length &&
+		    urb->transfer_flags & URB_SHORT_NOT_OK)
+			td->urb->status = -EREMOTEIO;
+	}
+	if (usb_pipeisoc(urb->pipe)) {
+		urb->iso_frame_desc[td->iso_cnt].actual_length = size;
+		urb->iso_frame_desc[td->iso_cnt].status = 0;
+		td->iso_cnt++;
+	}
+
+	/* check transfer finish */
+	if (check_transfer_finish(td, urb)) {
+		pipe_stop(r8a66597, td->pipe);
+		pipe_irq_disable(r8a66597, pipenum);
+		finish = 1;
+	}
+
+	/* read fifo */
+	if (urb->transfer_buffer) {
+		if (size == 0)
+			r8a66597_write(r8a66597, BCLR, td->pipe->fifoctr);
+		else
+			r8a66597_read_fifo(r8a66597, td->pipe->fifoaddr,
+					   buf, size);
+	}
+
+	if (finish && pipenum != 0) {
+		if (td->urb->status == -EINPROGRESS)
+			td->urb->status = 0;
+		finish_request(r8a66597, td, pipenum, urb);
+	}
+}
+
+static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
+{
+	u16 tmp;
+	int bufsize, size;
+	u16 *buf;
+	struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
+	struct urb *urb;
+
+	if (unlikely(!td))
+		return;
+	urb = td->urb;
+
+	fifo_change_from_pipe(r8a66597, td->pipe);
+	tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
+	if (unlikely((tmp & FRDY) == 0)) {
+		urb->status = -EPIPE;
+		pipe_stop(r8a66597, td->pipe);
+		pipe_irq_disable(r8a66597, pipenum);
+		err("out write fifo not ready. (%d)", pipenum);
+		finish_request(r8a66597, td, pipenum, td->urb);
+		return;
+	}
+
+	/* prepare parameters */
+	bufsize = td->maxpacket;
+	if (usb_pipeisoc(urb->pipe)) {
+		buf = (u16 *)(urb->transfer_buffer +
+				urb->iso_frame_desc[td->iso_cnt].offset);
+		size = min(bufsize,
+			   (int)urb->iso_frame_desc[td->iso_cnt].length);
+	} else {
+		buf = (u16 *)(urb->transfer_buffer + urb->actual_length);
+		size = min((int)bufsize,
+			   urb->transfer_buffer_length - urb->actual_length);
+	}
+
+	/* write fifo */
+	if (pipenum > 0)
+		r8a66597_write(r8a66597, (u16)~(1 << pipenum), BEMPSTS);
+	if (urb->transfer_buffer) {
+		r8a66597_write_fifo(r8a66597, td->pipe->fifoaddr, buf, size);
+		if (!usb_pipebulk(urb->pipe) || td->maxpacket != size)
+			r8a66597_write(r8a66597, BVAL, td->pipe->fifoctr);
+	}
+
+	/* update parameters */
+	urb->actual_length += size;
+	if (usb_pipeisoc(urb->pipe)) {
+		urb->iso_frame_desc[td->iso_cnt].actual_length = size;
+		urb->iso_frame_desc[td->iso_cnt].status = 0;
+		td->iso_cnt++;
+	}
+
+	/* check transfer finish */
+	if (check_transfer_finish(td, urb)) {
+		disable_irq_ready(r8a66597, pipenum);
+		enable_irq_empty(r8a66597, pipenum);
+		if (!usb_pipeisoc(urb->pipe))
+			enable_irq_nrdy(r8a66597, pipenum);
+	} else
+		pipe_irq_enable(r8a66597, urb, pipenum);
+}
+
+
+static void check_next_phase(struct r8a66597 *r8a66597)
+{
+	struct r8a66597_td *td = r8a66597_get_td(r8a66597, 0);
+	struct urb *urb;
+	u8 finish = 0;
+
+	if (unlikely(!td))
+		return;
+	urb = td->urb;
+
+	switch (td->type) {
+	case USB_PID_IN:
+	case USB_PID_OUT:
+		if (urb->status != -EINPROGRESS) {
+			finish = 1;
+			break;
+		}
+		if (check_transfer_finish(td, urb))
+			td->type = USB_PID_ACK;
+		break;
+	case USB_PID_SETUP:
+		if (urb->status != -EINPROGRESS)
+			finish = 1;
+		else if (urb->transfer_buffer_length == urb->actual_length) {
+			td->type = USB_PID_ACK;
+			urb->status = 0;
+		} else if (usb_pipeout(urb->pipe))
+			td->type = USB_PID_OUT;
+		else
+			td->type = USB_PID_IN;
+		break;
+	case USB_PID_ACK:
+		finish = 1;
+		if (urb->status == -EINPROGRESS)
+			urb->status = 0;
+		break;
+	}
+
+	if (finish)
+		finish_request(r8a66597, td, 0, urb);
+	else
+		start_transfer(r8a66597, td);
+}
+
+static void set_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
+{
+	struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
+
+	if (td && td->urb) {
+		u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID;
+
+		if (pid == PID_NAK)
+			td->urb->status = -ECONNRESET;
+		else
+			td->urb->status = -EPIPE;
+	}
+}
+
+static void irq_pipe_ready(struct r8a66597 *r8a66597)
+{
+	u16 check;
+	u16 pipenum;
+	u16 mask;
+	struct r8a66597_td *td;
+
+	mask = r8a66597_read(r8a66597, BRDYSTS)
+	       & r8a66597_read(r8a66597, BRDYENB);
+	r8a66597_write(r8a66597, (u16)~mask, BRDYSTS);
+	if (mask & BRDY0) {
+		td = r8a66597_get_td(r8a66597, 0);
+		if (td && td->type == USB_PID_IN)
+			packet_read(r8a66597, 0);
+		else
+			pipe_irq_disable(r8a66597, 0);
+		check_next_phase(r8a66597);
+	}
+
+	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
+		check = 1 << pipenum;
+		if (mask & check) {
+			td = r8a66597_get_td(r8a66597, pipenum);
+			if (unlikely(!td))
+				continue;
+
+			if (td->type == USB_PID_IN)
+				packet_read(r8a66597, pipenum);
+			else if (td->type == USB_PID_OUT)
+				packet_write(r8a66597, pipenum);
+		}
+	}
+}
+
+static void irq_pipe_empty(struct r8a66597 *r8a66597)
+{
+	u16 tmp;
+	u16 check;
+	u16 pipenum;
+	u16 mask;
+	struct r8a66597_td *td;
+
+	mask = r8a66597_read(r8a66597, BEMPSTS)
+	       & r8a66597_read(r8a66597, BEMPENB);
+	r8a66597_write(r8a66597, (u16)~mask, BEMPSTS);
+	if (mask & BEMP0) {
+		cfifo_change(r8a66597, 0);
+		td = r8a66597_get_td(r8a66597, 0);
+		if (td && td->type != USB_PID_OUT)
+			disable_irq_empty(r8a66597, 0);
+		check_next_phase(r8a66597);
+	}
+
+	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
+		check = 1 << pipenum;
+		if (mask &  check) {
+			struct r8a66597_td *td;
+			td = r8a66597_get_td(r8a66597, pipenum);
+			if (unlikely(!td))
+				continue;
+
+			tmp = r8a66597_read(r8a66597, td->pipe->pipectr);
+			if ((tmp & INBUFM) == 0) {
+				disable_irq_empty(r8a66597, pipenum);
+				pipe_irq_disable(r8a66597, pipenum);
+				if (td->urb->status == -EINPROGRESS)
+					td->urb->status = 0;
+				finish_request(r8a66597, td, pipenum, td->urb);
+			}
+		}
+	}
+}
+
+static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
+{
+	u16 check;
+	u16 pipenum;
+	u16 mask;
+
+	mask = r8a66597_read(r8a66597, NRDYSTS)
+	       & r8a66597_read(r8a66597, NRDYENB);
+	r8a66597_write(r8a66597, (u16)~mask, NRDYSTS);
+	if (mask & NRDY0) {
+		cfifo_change(r8a66597, 0);
+		set_urb_error(r8a66597, 0);
+		pipe_irq_disable(r8a66597, 0);
+		check_next_phase(r8a66597);
+	}
+
+	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
+		check = 1 << pipenum;
+		if (mask & check) {
+			struct r8a66597_td *td;
+			td = r8a66597_get_td(r8a66597, pipenum);
+			if (unlikely(!td))
+				continue;
+
+			set_urb_error(r8a66597, pipenum);
+			pipe_irq_disable(r8a66597, pipenum);
+			pipe_stop(r8a66597, td->pipe);
+			finish_request(r8a66597, td, pipenum, td->urb);
+		}
+	}
+}
+
+static void start_root_hub_sampling(struct r8a66597 *r8a66597, int port)
+{
+	struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
+
+	rh->old_syssts = r8a66597_read(r8a66597, get_syssts_reg(port)) & LNST;
+	rh->scount = R8A66597_MAX_SAMPLING;
+	mod_timer(&r8a66597->rh_timer, jiffies + msecs_to_jiffies(50));
+}
+
+static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
+{
+	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
+	u16 intsts0, intsts1, intsts2;
+	u16 intenb0, intenb1, intenb2;
+	u16 mask0, mask1, mask2;
+
+	spin_lock(&r8a66597->lock);
+
+	intsts0 = r8a66597_read(r8a66597, INTSTS0);
+	intsts1 = r8a66597_read(r8a66597, INTSTS1);
+	intsts2 = r8a66597_read(r8a66597, INTSTS2);
+	intenb0 = r8a66597_read(r8a66597, INTENB0);
+	intenb1 = r8a66597_read(r8a66597, INTENB1);
+	intenb2 = r8a66597_read(r8a66597, INTENB2);
+
+	mask2 = intsts2 & intenb2;
+	mask1 = intsts1 & intenb1;
+	mask0 = intsts0 & intenb0 & (BEMP | NRDY | BRDY);
+	if (mask2) {
+		if (mask2 & ATTCH) {
+			r8a66597_write(r8a66597, (u16)~ATTCH, INTSTS2);
+			r8a66597_bclr(r8a66597, ATTCHE, INTENB2);
+
+			/* start usb bus sampling */
+			start_root_hub_sampling(r8a66597, 1);
+		}
+		if (mask2 & DTCH) {
+			r8a66597_write(r8a66597, (u16)~DTCH, INTSTS2);
+			r8a66597_bclr(r8a66597, DTCHE, INTENB2);
+			r8a66597_usb_disconnect(r8a66597, 1);
+		}
+	}
+
+	if (mask1) {
+		if (mask1 & ATTCH) {
+			r8a66597_write(r8a66597, (u16)~ATTCH, INTSTS1);
+			r8a66597_bclr(r8a66597, ATTCHE, INTENB1);
+
+			/* start usb bus sampling */
+			start_root_hub_sampling(r8a66597, 0);
+		}
+		if (mask1 & DTCH) {
+			r8a66597_write(r8a66597, (u16)~DTCH, INTSTS1);
+			r8a66597_bclr(r8a66597, DTCHE, INTENB1);
+			r8a66597_usb_disconnect(r8a66597, 0);
+		}
+		if (mask1 & SIGN) {
+			r8a66597_write(r8a66597, (u16)~SIGN, INTSTS1);
+			set_urb_error(r8a66597, 0);
+			check_next_phase(r8a66597);
+		}
+		if (mask1 & SACK) {
+			r8a66597_write(r8a66597, (u16)~SACK, INTSTS1);
+			check_next_phase(r8a66597);
+		}
+	}
+	if (mask0) {
+		if (mask0 & BRDY)
+			irq_pipe_ready(r8a66597);
+		if (mask0 & BEMP)
+			irq_pipe_empty(r8a66597);
+		if (mask0 & NRDY)
+			irq_pipe_nrdy(r8a66597);
+	}
+
+	spin_unlock(&r8a66597->lock);
+	return IRQ_HANDLED;
+}
+
+/* this function must be called with interrupt disabled */
+static void r8a66597_root_hub_control(struct r8a66597 *r8a66597, int port)
+{
+	u16 tmp;
+	struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
+
+	if (rh->port & (1 << USB_PORT_FEAT_RESET)) {
+		unsigned long dvstctr_reg = get_dvstctr_reg(port);
+
+		tmp = r8a66597_read(r8a66597, dvstctr_reg);
+		if ((tmp & USBRST) == USBRST) {
+			r8a66597_mdfy(r8a66597, UACT, USBRST | UACT,
+				      dvstctr_reg);
+			mod_timer(&r8a66597->rh_timer,
+				  jiffies + msecs_to_jiffies(50));
+		} else
+			r8a66597_usb_connect(r8a66597, port);
+	}
+
+	if (rh->scount > 0) {
+		tmp = r8a66597_read(r8a66597, get_syssts_reg(port)) & LNST;
+		if (tmp == rh->old_syssts) {
+			rh->scount--;
+			if (rh->scount == 0) {
+				if (tmp == FS_JSTS) {
+					r8a66597_bset(r8a66597, HSE,
+						      get_syscfg_reg(port));
+					r8a66597_usb_preconnect(r8a66597, port);
+				} else if (tmp == LS_JSTS) {
+					r8a66597_bclr(r8a66597, HSE,
+						      get_syscfg_reg(port));
+					r8a66597_usb_preconnect(r8a66597, port);
+				} else if (tmp == SE0)
+					r8a66597_bset(r8a66597, ATTCHE,
+						      get_intenb_reg(port));
+			} else {
+				mod_timer(&r8a66597->rh_timer,
+					  jiffies + msecs_to_jiffies(50));
+			}
+		} else {
+			rh->scount = R8A66597_MAX_SAMPLING;
+			rh->old_syssts = tmp;
+			mod_timer(&r8a66597->rh_timer,
+				  jiffies + msecs_to_jiffies(50));
+		}
+	}
+}
+
+static void r8a66597_td_timer(unsigned long _r8a66597)
+{
+	struct r8a66597 *r8a66597 = (struct r8a66597 *)_r8a66597;
+	unsigned long flags;
+	u16 pipenum;
+	struct r8a66597_td *td, *new_td = NULL;
+	struct r8a66597_pipe *pipe;
+
+	spin_lock_irqsave(&r8a66597->lock, flags);
+	for (pipenum = 0; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
+		if (!(r8a66597->timeout_map & (1 << pipenum)))
+			continue;
+		if (timer_pending(&r8a66597->td_timer[pipenum]))
+			continue;
+
+		td = r8a66597_get_td(r8a66597, pipenum);
+		if (!td) {
+			r8a66597->timeout_map &= ~(1 << pipenum);
+			continue;
+		}
+
+		if (td->urb->actual_length) {
+			set_td_timer(r8a66597, td);
+			break;
+		}
+
+		pipe = td->pipe;
+		pipe_stop(r8a66597, pipe);
+
+		new_td = td;
+		do {
+			list_move_tail(&new_td->queue,
+				       &r8a66597->pipe_queue[pipenum]);
+			new_td = r8a66597_get_td(r8a66597, pipenum);
+			if (!new_td) {
+				new_td = td;
+				break;
+			}
+		} while (td != new_td && td->address == new_td->address);
+
+		start_transfer(r8a66597, new_td);
+
+		if (td == new_td)
+			r8a66597->timeout_map &= ~(1 << pipenum);
+		else
+			set_td_timer(r8a66597, new_td);
+		break;
+	}
+	spin_unlock_irqrestore(&r8a66597->lock, flags);
+}
+
+static void r8a66597_timer(unsigned long _r8a66597)
+{
+	struct r8a66597 *r8a66597 = (struct r8a66597 *)_r8a66597;
+	unsigned long flags;
+
+	spin_lock_irqsave(&r8a66597->lock, flags);
+
+	r8a66597_root_hub_control(r8a66597, 0);
+	r8a66597_root_hub_control(r8a66597, 1);
+
+	spin_unlock_irqrestore(&r8a66597->lock, flags);
+}
+
+static int check_pipe_config(struct r8a66597 *r8a66597, struct urb *urb)
+{
+	struct r8a66597_device *dev = get_urb_to_r8a66597_dev(r8a66597, urb);
+
+	if (dev && dev->address && dev->state != USB_STATE_CONFIGURED &&
+	    (urb->dev->state == USB_STATE_CONFIGURED))
+		return 1;
+	else
+		return 0;
+}
+
+static int r8a66597_start(struct usb_hcd *hcd)
+{
+	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
+	int ret;
+
+	hcd->state = HC_STATE_RUNNING;
+	if ((ret = enable_controller(r8a66597)) < 0)
+		return ret;
+
+	return 0;
+}
+
+static void r8a66597_stop(struct usb_hcd *hcd)
+{
+	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
+
+	disable_controller(r8a66597);
+}
+
+static void set_address_zero(struct r8a66597 *r8a66597, struct urb *urb)
+{
+	unsigned int usb_address = usb_pipedevice(urb->pipe);
+	u16 root_port, hub_port;
+
+	if (usb_address == 0) {
+		get_port_number(urb->dev->devpath,
+				&root_port, &hub_port);
+		set_devadd_reg(r8a66597, 0,
+			       get_r8a66597_usb_speed(urb->dev->speed),
+			       get_parent_r8a66597_address(r8a66597, urb->dev),
+			       hub_port, root_port);
+	}
+}
+
+static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597,
+					    struct urb *urb,
+					    struct usb_host_endpoint *hep,
+					    gfp_t mem_flags)
+{
+	struct r8a66597_td *td;
+	u16 pipenum;
+
+	td = kzalloc(sizeof(struct r8a66597_td), mem_flags);
+	if (td == NULL)
+		return NULL;
+
+	pipenum = r8a66597_get_pipenum(urb, hep);
+	td->pipenum = pipenum;
+	td->pipe = hep->hcpriv;
+	td->urb = urb;
+	td->address = get_urb_to_r8a66597_addr(r8a66597, urb);
+	td->maxpacket = usb_maxpacket(urb->dev, urb->pipe,
+				      !usb_pipein(urb->pipe));
+	if (usb_pipecontrol(urb->pipe))
+		td->type = USB_PID_SETUP;
+	else if (usb_pipein(urb->pipe))
+		td->type = USB_PID_IN;
+	else
+		td->type = USB_PID_OUT;
+	INIT_LIST_HEAD(&td->queue);
+
+	return td;
+}
+
+static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
+				struct usb_host_endpoint *hep,
+				struct urb *urb,
+				gfp_t mem_flags)
+{
+	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
+	struct r8a66597_td *td = NULL;
+	int ret = 0, request = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&r8a66597->lock, flags);
+	if (!get_urb_to_r8a66597_dev(r8a66597, urb)) {
+		ret = -ENODEV;
+		goto error;
+	}
+
+	if (!hep->hcpriv) {
+		hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe), mem_flags);
+		if (!hep->hcpriv) {
+			ret = -ENOMEM;
+			goto error;
+		}
+		set_pipe_reg_addr(hep->hcpriv, R8A66597_PIPE_NO_DMA);
+		if (usb_pipeendpoint(urb->pipe))
+			init_pipe_info(r8a66597, urb, hep, &hep->desc);
+	}
+
+	if (unlikely(check_pipe_config(r8a66597, urb)))
+		init_pipe_config(r8a66597, urb);
+
+	set_address_zero(r8a66597, urb);
+	td = r8a66597_make_td(r8a66597, urb, hep, mem_flags);
+	if (td == NULL) {
+		ret = -ENOMEM;
+		goto error;
+	}
+	if (list_empty(&r8a66597->pipe_queue[td->pipenum]))
+		request = 1;
+	list_add_tail(&td->queue, &r8a66597->pipe_queue[td->pipenum]);
+
+	spin_lock(&urb->lock);
+	if (urb->status != -EINPROGRESS) {
+		spin_unlock(&urb->lock);
+		ret = -EPIPE;
+		goto error;
+	}
+	urb->hcpriv = td;
+	spin_unlock(&urb->lock);
+
+	if (request) {
+		ret = start_transfer(r8a66597, td);
+		if (ret < 0) {
+			list_del(&td->queue);
+			kfree(td);
+		}
+	} else
+		set_td_timer(r8a66597, td);
+
+error:
+	spin_unlock_irqrestore(&r8a66597->lock, flags);
+	return ret;
+}
+
+static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+{
+	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
+	struct r8a66597_td *td;
+	unsigned long flags;
+
+	spin_lock_irqsave(&r8a66597->lock, flags);
+	if (urb->hcpriv) {
+		td = urb->hcpriv;
+		pipe_stop(r8a66597, td->pipe);
+		pipe_irq_disable(r8a66597, td->pipenum);
+		disable_irq_empty(r8a66597, td->pipenum);
+		done(r8a66597, td, td->pipenum, urb);
+	}
+	spin_unlock_irqrestore(&r8a66597->lock, flags);
+	return 0;
+}
+
+static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
+				      struct usb_host_endpoint *hep)
+{
+	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
+	struct r8a66597_pipe *pipe = (struct r8a66597_pipe *)hep->hcpriv;
+	struct r8a66597_td *td;
+	struct urb *urb = NULL;
+	u16 pipenum;
+	unsigned long flags;
+
+	if (pipe == NULL)
+		return;
+	pipenum = pipe->info.pipenum;
+
+	if (pipenum == 0) {
+		kfree(hep->hcpriv);
+		hep->hcpriv = NULL;
+		return;
+	}
+
+	spin_lock_irqsave(&r8a66597->lock, flags);
+	pipe_stop(r8a66597, pipe);
+	pipe_irq_disable(r8a66597, pipenum);
+	disable_irq_empty(r8a66597, pipenum);
+	td = r8a66597_get_td(r8a66597, pipenum);
+	if (td)
+		urb = td->urb;
+	done(r8a66597, td, pipenum, urb);
+	kfree(hep->hcpriv);
+	hep->hcpriv = NULL;
+	spin_unlock_irqrestore(&r8a66597->lock, flags);
+}
+
+static int r8a66597_get_frame(struct usb_hcd *hcd)
+{
+	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
+	return r8a66597_read(r8a66597, FRMNUM) & 0x03FF;
+}
+
+static void collect_usb_address_map(struct usb_device *udev, unsigned long *map)
+{
+	int chix;
+
+	if (udev->state == USB_STATE_CONFIGURED &&
+	    udev->parent && udev->parent->devnum > 1 &&
+	    udev->parent->descriptor.bDeviceClass == USB_CLASS_HUB)
+		map[udev->devnum/32] |= (1 << (udev->devnum % 32));
+
+	for (chix = 0; chix < udev->maxchild; chix++) {
+		struct usb_device *childdev = udev->children[chix];
+
+		if (childdev)
+			collect_usb_address_map(childdev, map);
+	}
+}
+
+/* this function must be called with interrupt disabled */
+static struct r8a66597_device *get_r8a66597_device(struct r8a66597 *r8a66597,
+						   int addr)
+{
+	struct r8a66597_device *dev;
+	struct list_head *list = &r8a66597->child_device;
+
+	list_for_each_entry(dev, list, device_list) {
+		if (!dev)
+			continue;
+		if (dev->usb_address != addr)
+			continue;
+
+		return dev;
+	}
+
+	err("get_r8a66597_device fail.(%d)\n", addr);
+	return NULL;
+}
+
+static void update_usb_address_map(struct r8a66597 *r8a66597,
+				   struct usb_device *root_hub,
+				   unsigned long *map)
+{
+	int i, j, addr;
+	unsigned long diff;
+	unsigned long flags;
+
+	for (i = 0; i < 4; i++) {
+		diff = r8a66597->child_connect_map[i] ^ map[i];
+		if (!diff)
+			continue;
+
+		for (j = 0; j < 32; j++) {
+			if (!(diff & (1 << j)))
+				continue;
+
+			addr = i * 32 + j;
+			if (map[i] & (1 << j))
+				set_child_connect_map(r8a66597, addr);
+			else {
+				struct r8a66597_device *dev;
+
+				spin_lock_irqsave(&r8a66597->lock, flags);
+				dev = get_r8a66597_device(r8a66597, addr);
+				disable_r8a66597_pipe_all(r8a66597, dev);
+				free_usb_address(r8a66597, dev);
+				put_child_connect_map(r8a66597, addr);
+				spin_unlock_irqrestore(&r8a66597->lock, flags);
+			}
+		}
+	}
+}
+
+static void r8a66597_check_detect_child(struct r8a66597 *r8a66597,
+					struct usb_hcd *hcd)
+{
+	struct usb_bus *bus;
+	unsigned long now_map[4];
+
+	memset(now_map, 0, sizeof(now_map));
+
+	list_for_each_entry(bus, &usb_bus_list, bus_list) {
+		if (!bus->root_hub)
+			continue;
+
+		if (bus->busnum != hcd->self.busnum)
+			continue;
+
+		collect_usb_address_map(bus->root_hub, now_map);
+		update_usb_address_map(r8a66597, bus->root_hub, now_map);
+	}
+}
+
+static int r8a66597_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
+	unsigned long flags;
+	int i;
+
+	r8a66597_check_detect_child(r8a66597, hcd);
+
+	spin_lock_irqsave(&r8a66597->lock, flags);
+
+	*buf = 0;	/* initialize (no change) */
+
+	for (i = 0; i < R8A66597_MAX_ROOT_HUB; i++) {
+		if (r8a66597->root_hub[i].port & 0xffff0000)
+			*buf |= 1 << (i + 1);
+	}
+
+	spin_unlock_irqrestore(&r8a66597->lock, flags);
+
+	return (*buf != 0);
+}
+
+static void r8a66597_hub_descriptor(struct r8a66597 *r8a66597,
+				    struct usb_hub_descriptor *desc)
+{
+	desc->bDescriptorType = 0x29;
+	desc->bHubContrCurrent = 0;
+	desc->bNbrPorts = R8A66597_MAX_ROOT_HUB;
+	desc->bDescLength = 9;
+	desc->bPwrOn2PwrGood = 0;
+	desc->wHubCharacteristics = cpu_to_le16(0x0011);
+	desc->bitmap[0] = ((1 << R8A66597_MAX_ROOT_HUB) - 1) << 1;
+	desc->bitmap[1] = ~0;
+}
+
+static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+				u16 wIndex, char *buf, u16 wLength)
+{
+	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
+	int ret;
+	int port = (wIndex & 0x00FF) - 1;
+	struct r8a66597_root_hub *rh = &r8a66597->root_hub[port];
+	unsigned long flags;
+
+	ret = 0;
+
+	spin_lock_irqsave(&r8a66597->lock, flags);
+	switch (typeReq) {
+	case ClearHubFeature:
+	case SetHubFeature:
+		switch (wValue) {
+		case C_HUB_OVER_CURRENT:
+		case C_HUB_LOCAL_POWER:
+			break;
+		default:
+			goto error;
+		}
+		break;
+	case ClearPortFeature:
+		if (wIndex > R8A66597_MAX_ROOT_HUB)
+			goto error;
+		if (wLength != 0)
+			goto error;
+
+		switch (wValue) {
+		case USB_PORT_FEAT_ENABLE:
+			rh->port &= (1 << USB_PORT_FEAT_POWER);
+			break;
+		case USB_PORT_FEAT_SUSPEND:
+			break;
+		case USB_PORT_FEAT_POWER:
+			r8a66597_port_power(r8a66597, port, 0);
+			break;
+		case USB_PORT_FEAT_C_ENABLE:
+		case USB_PORT_FEAT_C_SUSPEND:
+		case USB_PORT_FEAT_C_CONNECTION:
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+		case USB_PORT_FEAT_C_RESET:
+			break;
+		default:
+			goto error;
+		}
+		rh->port &= ~(1 << wValue);
+		break;
+	case GetHubDescriptor:
+		r8a66597_hub_descriptor(r8a66597,
+					(struct usb_hub_descriptor *)buf);
+		break;
+	case GetHubStatus:
+		*buf = 0x00;
+		break;
+	case GetPortStatus:
+		if (wIndex > R8A66597_MAX_ROOT_HUB)
+			goto error;
+		*(u32 *)buf = rh->port;
+		break;
+	case SetPortFeature:
+		if (wIndex > R8A66597_MAX_ROOT_HUB)
+			goto error;
+		if (wLength != 0)
+			goto error;
+
+		switch (wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+			break;
+		case USB_PORT_FEAT_POWER:
+			r8a66597_port_power(r8a66597, port, 1);
+			rh->port |= (1 << USB_PORT_FEAT_POWER);
+			break;
+		case USB_PORT_FEAT_RESET: {
+			struct r8a66597_device *dev = rh->dev;
+
+			rh->port |= (1 << USB_PORT_FEAT_RESET);
+
+			disable_r8a66597_pipe_all(r8a66597, dev);
+			free_usb_address(r8a66597, dev);
+
+			r8a66597_mdfy(r8a66597, USBRST, USBRST | UACT,
+				      get_dvstctr_reg(port));
+			mod_timer(&r8a66597->rh_timer,
+				  jiffies + msecs_to_jiffies(50));
+			}
+			break;
+		default:
+			goto error;
+		}
+		rh->port |= 1 << wValue;
+		break;
+	default:
+error:
+		ret = -EPIPE;
+		break;
+	}
+
+	spin_unlock_irqrestore(&r8a66597->lock, flags);
+	return ret;
+}
+
+static struct hc_driver r8a66597_hc_driver = {
+	.description =		hcd_name,
+	.hcd_priv_size =	sizeof(struct r8a66597),
+	.irq =			r8a66597_irq,
+
+	/*
+	 * generic hardware linkage
+	 */
+	.flags =		HCD_USB2,
+
+	.start =		r8a66597_start,
+	.stop =			r8a66597_stop,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		r8a66597_urb_enqueue,
+	.urb_dequeue =		r8a66597_urb_dequeue,
+	.endpoint_disable =	r8a66597_endpoint_disable,
+
+	/*
+	 * periodic schedule support
+	 */
+	.get_frame_number =	r8a66597_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	r8a66597_hub_status_data,
+	.hub_control =		r8a66597_hub_control,
+};
+
+#if defined(CONFIG_PM)
+static int r8a66597_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	pdev->dev.power.power_state = state;
+	return 0;
+}
+
+static int r8a66597_resume(struct platform_device *pdev)
+{
+	pdev->dev.power.power_state = PMSG_ON;
+	return 0;
+}
+#else	/* if defined(CONFIG_PM) */
+#define r8a66597_suspend	NULL
+#define r8a66597_resume		NULL
+#endif
+
+static int __init_or_module r8a66597_remove(struct platform_device *pdev)
+{
+	struct r8a66597		*r8a66597 = dev_get_drvdata(&pdev->dev);
+	struct usb_hcd		*hcd = r8a66597_to_hcd(r8a66597);
+
+	del_timer_sync(&r8a66597->rh_timer);
+	iounmap((void *)r8a66597->reg);
+	usb_remove_hcd(hcd);
+	usb_put_hcd(hcd);
+	return 0;
+}
+
+#define resource_len(r) (((r)->end - (r)->start) + 1)
+static int __init r8a66597_probe(struct platform_device *pdev)
+{
+	struct resource *res = NULL;
+	int irq = -1;
+	void __iomem *reg = NULL;
+	struct usb_hcd *hcd = NULL;
+	struct r8a66597 *r8a66597;
+	int ret = 0;
+	int i;
+
+	if (pdev->dev.dma_mask) {
+		ret = -EINVAL;
+		err("dma not support");
+		goto clean_up;
+	}
+
+	res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+					   (char *)hcd_name);
+	if (!res) {
+		ret = -ENODEV;
+		err("platform_get_resource_byname error.");
+		goto clean_up;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		ret = -ENODEV;
+		err("platform_get_irq error.");
+		goto clean_up;
+	}
+
+	reg = ioremap(res->start, resource_len(res));
+	if (reg == NULL) {
+		ret = -ENOMEM;
+		err("ioremap error.");
+		goto clean_up;
+	}
+
+	/* initialize hcd */
+	hcd = usb_create_hcd(&r8a66597_hc_driver, &pdev->dev, (char *)hcd_name);
+	if (!hcd) {
+		ret = -ENOMEM;
+		err("Failed to create hcd");
+		goto clean_up;
+	}
+	r8a66597 = hcd_to_r8a66597(hcd);
+	memset(r8a66597, 0, sizeof(struct r8a66597));
+	dev_set_drvdata(&pdev->dev, r8a66597);
+
+	spin_lock_init(&r8a66597->lock);
+	init_timer(&r8a66597->rh_timer);
+	r8a66597->rh_timer.function = r8a66597_timer;
+	r8a66597->rh_timer.data = (unsigned long)r8a66597;
+	r8a66597->reg = (unsigned long)reg;
+
+	for (i = 0; i < R8A66597_MAX_NUM_PIPE; i++) {
+		INIT_LIST_HEAD(&r8a66597->pipe_queue[i]);
+		init_timer(&r8a66597->td_timer[i]);
+		r8a66597->td_timer[i].function = r8a66597_td_timer;
+		r8a66597->td_timer[i].data = (unsigned long)r8a66597;
+	}
+	INIT_LIST_HEAD(&r8a66597->child_device);
+
+	hcd->rsrc_start = res->start;
+	ret = usb_add_hcd(hcd, irq, 0);
+	if (ret != 0) {
+		err("Failed to add hcd");
+		goto clean_up;
+	}
+
+	return 0;
+
+clean_up:
+	if (reg)
+		iounmap(reg);
+	if (res)
+		release_mem_region(res->start, 1);
+
+	return ret;
+}
+
+static struct platform_driver r8a66597_driver = {
+	.probe =	r8a66597_probe,
+	.remove =	r8a66597_remove,
+	.suspend =	r8a66597_suspend,
+	.resume =	r8a66597_resume,
+	.driver		= {
+		.name = (char *) hcd_name,
+	},
+};
+
+static int __init r8a66597_init(void)
+{
+	if (usb_disabled())
+		return -ENODEV;
+
+	info("driver %s, %s", hcd_name, DRIVER_VERSION);
+	return platform_driver_register(&r8a66597_driver);
+}
+module_init(r8a66597_init);
+
+static void __exit r8a66597_cleanup(void)
+{
+	platform_driver_unregister(&r8a66597_driver);
+}
+module_exit(r8a66597_cleanup);
+

+ 634 - 0
drivers/usb/host/r8a66597.h

@@ -0,0 +1,634 @@
+/*
+ * R8A66597 HCD (Host Controller Driver)
+ *
+ * Copyright (C) 2006-2007 Renesas Solutions Corp.
+ * Portions Copyright (C) 2004 Psion Teklogix (for NetBook PRO)
+ * Portions Copyright (C) 2004-2005 David Brownell
+ * Portions Copyright (C) 1999 Roman Weissgaerber
+ *
+ * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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 St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __R8A66597_H__
+#define __R8A66597_H__
+
+#define SYSCFG0		0x00
+#define SYSCFG1		0x02
+#define SYSSTS0		0x04
+#define SYSSTS1		0x06
+#define DVSTCTR0	0x08
+#define DVSTCTR1	0x0A
+#define TESTMODE	0x0C
+#define PINCFG		0x0E
+#define DMA0CFG		0x10
+#define DMA1CFG		0x12
+#define CFIFO		0x14
+#define D0FIFO		0x18
+#define D1FIFO		0x1C
+#define CFIFOSEL	0x20
+#define CFIFOCTR	0x22
+#define CFIFOSIE	0x24
+#define D0FIFOSEL	0x28
+#define D0FIFOCTR	0x2A
+#define D1FIFOSEL	0x2C
+#define D1FIFOCTR	0x2E
+#define INTENB0		0x30
+#define INTENB1		0x32
+#define INTENB2		0x34
+#define BRDYENB		0x36
+#define NRDYENB		0x38
+#define BEMPENB		0x3A
+#define SOFCFG		0x3C
+#define INTSTS0		0x40
+#define INTSTS1		0x42
+#define INTSTS2		0x44
+#define BRDYSTS		0x46
+#define NRDYSTS		0x48
+#define BEMPSTS		0x4A
+#define FRMNUM		0x4C
+#define UFRMNUM		0x4E
+#define USBADDR		0x50
+#define USBREQ		0x54
+#define USBVAL		0x56
+#define USBINDX		0x58
+#define USBLENG		0x5A
+#define DCPCFG		0x5C
+#define DCPMAXP		0x5E
+#define DCPCTR		0x60
+#define PIPESEL		0x64
+#define PIPECFG		0x68
+#define PIPEBUF		0x6A
+#define PIPEMAXP	0x6C
+#define PIPEPERI	0x6E
+#define PIPE1CTR	0x70
+#define PIPE2CTR	0x72
+#define PIPE3CTR	0x74
+#define PIPE4CTR	0x76
+#define PIPE5CTR	0x78
+#define PIPE6CTR	0x7A
+#define PIPE7CTR	0x7C
+#define PIPE8CTR	0x7E
+#define PIPE9CTR	0x80
+#define PIPE1TRE	0x90
+#define PIPE1TRN	0x92
+#define PIPE2TRE	0x94
+#define PIPE2TRN	0x96
+#define PIPE3TRE	0x98
+#define PIPE3TRN	0x9A
+#define PIPE4TRE	0x9C
+#define	PIPE4TRN	0x9E
+#define	PIPE5TRE	0xA0
+#define	PIPE5TRN	0xA2
+#define DEVADD0		0xD0
+#define DEVADD1		0xD2
+#define DEVADD2		0xD4
+#define DEVADD3		0xD6
+#define DEVADD4		0xD8
+#define DEVADD5		0xDA
+#define DEVADD6		0xDC
+#define DEVADD7		0xDE
+#define DEVADD8		0xE0
+#define DEVADD9		0xE2
+#define DEVADDA		0xE4
+
+/* System Configuration Control Register */
+#define	XTAL		0xC000	/* b15-14: Crystal selection */
+#define	  XTAL48	 0x8000	  /* 48MHz */
+#define	  XTAL24	 0x4000	  /* 24MHz */
+#define	  XTAL12	 0x0000	  /* 12MHz */
+#define	XCKE		0x2000	/* b13: External clock enable */
+#define	PLLC		0x0800	/* b11: PLL control */
+#define	SCKE		0x0400	/* b10: USB clock enable */
+#define	PCSDIS		0x0200	/* b9: not CS wakeup */
+#define	LPSME		0x0100	/* b8: Low power sleep mode */
+#define	HSE		0x0080	/* b7: Hi-speed enable */
+#define	DCFM		0x0040	/* b6: Controller function select  */
+#define	DRPD		0x0020	/* b5: D+/- pull down control */
+#define	DPRPU		0x0010	/* b4: D+ pull up control */
+#define	USBE		0x0001	/* b0: USB module operation enable */
+
+/* System Configuration Status Register */
+#define	OVCBIT		0x8000	/* b15-14: Over-current bit */
+#define	OVCMON		0xC000	/* b15-14: Over-current monitor */
+#define	SOFEA		0x0020	/* b5: SOF monitor */
+#define	IDMON		0x0004	/* b3: ID-pin monitor */
+#define	LNST		0x0003	/* b1-0: D+, D- line status */
+#define	  SE1		 0x0003	  /* SE1 */
+#define	  FS_KSTS	 0x0002	  /* Full-Speed K State */
+#define	  FS_JSTS	 0x0001	  /* Full-Speed J State */
+#define	  LS_JSTS	 0x0002	  /* Low-Speed J State */
+#define	  LS_KSTS	 0x0001	  /* Low-Speed K State */
+#define	  SE0		 0x0000	  /* SE0 */
+
+/* Device State Control Register */
+#define	EXTLP0		0x0400	/* b10: External port */
+#define	VBOUT		0x0200	/* b9: VBUS output */
+#define	WKUP		0x0100	/* b8: Remote wakeup */
+#define	RWUPE		0x0080	/* b7: Remote wakeup sense */
+#define	USBRST		0x0040	/* b6: USB reset enable */
+#define	RESUME		0x0020	/* b5: Resume enable */
+#define	UACT		0x0010	/* b4: USB bus enable */
+#define	RHST		0x0007	/* b1-0: Reset handshake status */
+#define	  HSPROC	 0x0004	  /* HS handshake is processing */
+#define	  HSMODE	 0x0003	  /* Hi-Speed mode */
+#define	  FSMODE	 0x0002	  /* Full-Speed mode */
+#define	  LSMODE	 0x0001	  /* Low-Speed mode */
+#define	  UNDECID	 0x0000	  /* Undecided */
+
+/* Test Mode Register */
+#define	UTST			0x000F	/* b3-0: Test select */
+#define	  H_TST_PACKET		 0x000C	  /* HOST TEST Packet */
+#define	  H_TST_SE0_NAK		 0x000B	  /* HOST TEST SE0 NAK */
+#define	  H_TST_K		 0x000A	  /* HOST TEST K */
+#define	  H_TST_J		 0x0009	  /* HOST TEST J */
+#define	  H_TST_NORMAL		 0x0000	  /* HOST Normal Mode */
+#define	  P_TST_PACKET		 0x0004	  /* PERI TEST Packet */
+#define	  P_TST_SE0_NAK		 0x0003	  /* PERI TEST SE0 NAK */
+#define	  P_TST_K		 0x0002	  /* PERI TEST K */
+#define	  P_TST_J		 0x0001	  /* PERI TEST J */
+#define	  P_TST_NORMAL		 0x0000	  /* PERI Normal Mode */
+
+/* Data Pin Configuration Register */
+#define	LDRV			0x8000	/* b15: Drive Current Adjust */
+#define	  VIF1			  0x0000		/* VIF = 1.8V */
+#define	  VIF3			  0x8000		/* VIF = 3.3V */
+#define	INTA			0x0001	/* b1: USB INT-pin active */
+
+/* DMAx Pin Configuration Register */
+#define	DREQA			0x4000	/* b14: Dreq active select */
+#define	BURST			0x2000	/* b13: Burst mode */
+#define	DACKA			0x0400	/* b10: Dack active select */
+#define	DFORM			0x0380	/* b9-7: DMA mode select */
+#define	  CPU_ADR_RD_WR		 0x0000	  /* Address + RD/WR mode (CPU bus) */
+#define	  CPU_DACK_RD_WR	 0x0100	  /* DACK + RD/WR mode (CPU bus) */
+#define	  CPU_DACK_ONLY		 0x0180	  /* DACK only mode (CPU bus) */
+#define	  SPLIT_DACK_ONLY	 0x0200	  /* DACK only mode (SPLIT bus) */
+#define	DENDA			0x0040	/* b6: Dend active select */
+#define	PKTM			0x0020	/* b5: Packet mode */
+#define	DENDE			0x0010	/* b4: Dend enable */
+#define	OBUS			0x0004	/* b2: OUTbus mode */
+
+/* CFIFO/DxFIFO Port Select Register */
+#define	RCNT		0x8000	/* b15: Read count mode */
+#define	REW		0x4000	/* b14: Buffer rewind */
+#define	DCLRM		0x2000	/* b13: DMA buffer clear mode */
+#define	DREQE		0x1000	/* b12: DREQ output enable */
+#define	MBW		0x0400	/* b10: Maximum bit width for FIFO access */
+#define	  MBW_8		 0x0000	  /*  8bit */
+#define	  MBW_16	 0x0400	  /* 16bit */
+#define	BIGEND		0x0100	/* b8: Big endian mode */
+#define	  BYTE_LITTLE	 0x0000		/* little dendian */
+#define	  BYTE_BIG	 0x0100		/* big endifan */
+#define	ISEL		0x0020	/* b5: DCP FIFO port direction select */
+#define	CURPIPE		0x000F	/* b2-0: PIPE select */
+
+/* CFIFO/DxFIFO Port Control Register */
+#define	BVAL		0x8000	/* b15: Buffer valid flag */
+#define	BCLR		0x4000	/* b14: Buffer clear */
+#define	FRDY		0x2000	/* b13: FIFO ready */
+#define	DTLN		0x0FFF	/* b11-0: FIFO received data length */
+
+/* Interrupt Enable Register 0 */
+#define	VBSE		0x8000	/* b15: VBUS interrupt */
+#define	RSME		0x4000	/* b14: Resume interrupt */
+#define	SOFE		0x2000	/* b13: Frame update interrupt */
+#define	DVSE		0x1000	/* b12: Device state transition interrupt */
+#define	CTRE		0x0800	/* b11: Control transfer stage transition interrupt */
+#define	BEMPE		0x0400	/* b10: Buffer empty interrupt */
+#define	NRDYE		0x0200	/* b9: Buffer not ready interrupt */
+#define	BRDYE		0x0100	/* b8: Buffer ready interrupt */
+
+/* Interrupt Enable Register 1 */
+#define	OVRCRE		0x8000	/* b15: Over-current interrupt */
+#define	BCHGE		0x4000	/* b14: USB us chenge interrupt */
+#define	DTCHE		0x1000	/* b12: Detach sense interrupt */
+#define	ATTCHE		0x0800	/* b11: Attach sense interrupt */
+#define	EOFERRE		0x0040	/* b6: EOF error interrupt */
+#define	SIGNE		0x0020	/* b5: SETUP IGNORE interrupt */
+#define	SACKE		0x0010	/* b4: SETUP ACK interrupt */
+
+/* BRDY Interrupt Enable/Status Register */
+#define	BRDY9		0x0200	/* b9: PIPE9 */
+#define	BRDY8		0x0100	/* b8: PIPE8 */
+#define	BRDY7		0x0080	/* b7: PIPE7 */
+#define	BRDY6		0x0040	/* b6: PIPE6 */
+#define	BRDY5		0x0020	/* b5: PIPE5 */
+#define	BRDY4		0x0010	/* b4: PIPE4 */
+#define	BRDY3		0x0008	/* b3: PIPE3 */
+#define	BRDY2		0x0004	/* b2: PIPE2 */
+#define	BRDY1		0x0002	/* b1: PIPE1 */
+#define	BRDY0		0x0001	/* b1: PIPE0 */
+
+/* NRDY Interrupt Enable/Status Register */
+#define	NRDY9		0x0200	/* b9: PIPE9 */
+#define	NRDY8		0x0100	/* b8: PIPE8 */
+#define	NRDY7		0x0080	/* b7: PIPE7 */
+#define	NRDY6		0x0040	/* b6: PIPE6 */
+#define	NRDY5		0x0020	/* b5: PIPE5 */
+#define	NRDY4		0x0010	/* b4: PIPE4 */
+#define	NRDY3		0x0008	/* b3: PIPE3 */
+#define	NRDY2		0x0004	/* b2: PIPE2 */
+#define	NRDY1		0x0002	/* b1: PIPE1 */
+#define	NRDY0		0x0001	/* b1: PIPE0 */
+
+/* BEMP Interrupt Enable/Status Register */
+#define	BEMP9		0x0200	/* b9: PIPE9 */
+#define	BEMP8		0x0100	/* b8: PIPE8 */
+#define	BEMP7		0x0080	/* b7: PIPE7 */
+#define	BEMP6		0x0040	/* b6: PIPE6 */
+#define	BEMP5		0x0020	/* b5: PIPE5 */
+#define	BEMP4		0x0010	/* b4: PIPE4 */
+#define	BEMP3		0x0008	/* b3: PIPE3 */
+#define	BEMP2		0x0004	/* b2: PIPE2 */
+#define	BEMP1		0x0002	/* b1: PIPE1 */
+#define	BEMP0		0x0001	/* b0: PIPE0 */
+
+/* SOF Pin Configuration Register */
+#define	TRNENSEL	0x0100	/* b8: Select transaction enable period */
+#define	BRDYM		0x0040	/* b6: BRDY clear timing */
+#define	INTL		0x0020	/* b5: Interrupt sense select */
+#define	EDGESTS		0x0010	/* b4:  */
+#define	SOFMODE		0x000C	/* b3-2: SOF pin select */
+#define	  SOF_125US	 0x0008	  /* SOF OUT 125us Frame Signal */
+#define	  SOF_1MS	 0x0004	  /* SOF OUT 1ms Frame Signal */
+#define	  SOF_DISABLE	 0x0000	  /* SOF OUT Disable */
+
+/* Interrupt Status Register 0 */
+#define	VBINT		0x8000	/* b15: VBUS interrupt */
+#define	RESM		0x4000	/* b14: Resume interrupt */
+#define	SOFR		0x2000	/* b13: SOF frame update interrupt */
+#define	DVST		0x1000	/* b12: Device state transition interrupt */
+#define	CTRT		0x0800	/* b11: Control transfer stage transition interrupt */
+#define	BEMP		0x0400	/* b10: Buffer empty interrupt */
+#define	NRDY		0x0200	/* b9: Buffer not ready interrupt */
+#define	BRDY		0x0100	/* b8: Buffer ready interrupt */
+#define	VBSTS		0x0080	/* b7: VBUS input port */
+#define	DVSQ		0x0070	/* b6-4: Device state */
+#define	  DS_SPD_CNFG	 0x0070	  /* Suspend Configured */
+#define	  DS_SPD_ADDR	 0x0060	  /* Suspend Address */
+#define	  DS_SPD_DFLT	 0x0050	  /* Suspend Default */
+#define	  DS_SPD_POWR	 0x0040	  /* Suspend Powered */
+#define	  DS_SUSP	 0x0040	  /* Suspend */
+#define	  DS_CNFG	 0x0030	  /* Configured */
+#define	  DS_ADDS	 0x0020	  /* Address */
+#define	  DS_DFLT	 0x0010	  /* Default */
+#define	  DS_POWR	 0x0000	  /* Powered */
+#define	DVSQS		0x0030	/* b5-4: Device state */
+#define	VALID		0x0008	/* b3: Setup packet detected flag */
+#define	CTSQ		0x0007	/* b2-0: Control transfer stage */
+#define	  CS_SQER	 0x0006	  /* Sequence error */
+#define	  CS_WRND	 0x0005	  /* Control write nodata status stage */
+#define	  CS_WRSS	 0x0004	  /* Control write status stage */
+#define	  CS_WRDS	 0x0003	  /* Control write data stage */
+#define	  CS_RDSS	 0x0002	  /* Control read status stage */
+#define	  CS_RDDS	 0x0001	  /* Control read data stage */
+#define	  CS_IDST	 0x0000	  /* Idle or setup stage */
+
+/* Interrupt Status Register 1 */
+#define	OVRCR		0x8000	/* b15: Over-current interrupt */
+#define	BCHG		0x4000	/* b14: USB bus chenge interrupt */
+#define	DTCH		0x1000	/* b12: Detach sense interrupt */
+#define	ATTCH		0x0800	/* b11: Attach sense interrupt */
+#define	EOFERR		0x0040	/* b6: EOF-error interrupt */
+#define	SIGN		0x0020	/* b5: Setup ignore interrupt */
+#define	SACK		0x0010	/* b4: Setup acknowledge interrupt */
+
+/* Frame Number Register */
+#define	OVRN		0x8000	/* b15: Overrun error */
+#define	CRCE		0x4000	/* b14: Received data error */
+#define	FRNM		0x07FF	/* b10-0: Frame number */
+
+/* Micro Frame Number Register */
+#define	UFRNM		0x0007	/* b2-0: Micro frame number */
+
+/* USB Address / Low Power Status Recovery Register */
+//#define	USBADDR		0x007F	/* b6-0: USB address */
+
+/* Default Control Pipe Maxpacket Size Register */
+/* Pipe Maxpacket Size Register */
+#define	DEVSEL		0xF000	/* b15-14: Device address select */
+#define	MAXP		0x007F	/* b6-0: Maxpacket size of default control pipe */
+
+/* Default Control Pipe Control Register */
+#define	BSTS		0x8000	/* b15: Buffer status */
+#define	SUREQ		0x4000	/* b14: Send USB request  */
+#define	CSCLR		0x2000	/* b13: complete-split status clear */
+#define	CSSTS		0x1000	/* b12: complete-split status */
+#define	SUREQCLR	0x0800	/* b11: stop setup request */
+#define	SQCLR		0x0100	/* b8: Sequence toggle bit clear */
+#define	SQSET		0x0080	/* b7: Sequence toggle bit set */
+#define	SQMON		0x0040	/* b6: Sequence toggle bit monitor */
+#define	PBUSY		0x0020	/* b5: pipe busy */
+#define	PINGE		0x0010	/* b4: ping enable */
+#define	CCPL		0x0004	/* b2: Enable control transfer complete */
+#define	PID		0x0003	/* b1-0: Response PID */
+#define	  PID_STALL11	 0x0003	  /* STALL */
+#define	  PID_STALL	 0x0002	  /* STALL */
+#define	  PID_BUF	 0x0001	  /* BUF */
+#define	  PID_NAK	 0x0000	  /* NAK */
+
+/* Pipe Window Select Register */
+#define	PIPENM		0x0007	/* b2-0: Pipe select */
+
+/* Pipe Configuration Register */
+#define	R8A66597_TYP	0xC000	/* b15-14: Transfer type */
+#define	  R8A66597_ISO	 0xC000		  /* Isochronous */
+#define	  R8A66597_INT	 0x8000		  /* Interrupt */
+#define	  R8A66597_BULK	 0x4000		  /* Bulk */
+#define	R8A66597_BFRE	0x0400	/* b10: Buffer ready interrupt mode select */
+#define	R8A66597_DBLB	0x0200	/* b9: Double buffer mode select */
+#define	R8A66597_CNTMD	0x0100	/* b8: Continuous transfer mode select */
+#define	R8A66597_SHTNAK	0x0080	/* b7: Transfer end NAK */
+#define	R8A66597_DIR	0x0010	/* b4: Transfer direction select */
+#define	R8A66597_EPNUM	0x000F	/* b3-0: Eendpoint number select */
+
+/* Pipe Buffer Configuration Register */
+#define	BUFSIZE		0x7C00	/* b14-10: Pipe buffer size */
+#define	BUFNMB		0x007F	/* b6-0: Pipe buffer number */
+#define	PIPE0BUF	256
+#define	PIPExBUF	64
+
+/* Pipe Maxpacket Size Register */
+#define	MXPS		0x07FF	/* b10-0: Maxpacket size */
+
+/* Pipe Cycle Configuration Register */
+#define	IFIS		0x1000	/* b12: Isochronous in-buffer flush mode select */
+#define	IITV		0x0007	/* b2-0: Isochronous interval */
+
+/* Pipex Control Register */
+#define	BSTS		0x8000	/* b15: Buffer status */
+#define	INBUFM		0x4000	/* b14: IN buffer monitor (Only for PIPE1 to 5) */
+#define	CSCLR		0x2000	/* b13: complete-split status clear */
+#define	CSSTS		0x1000	/* b12: complete-split status */
+#define	ATREPM		0x0400	/* b10: Auto repeat mode */
+#define	ACLRM		0x0200	/* b9: Out buffer auto clear mode */
+#define	SQCLR		0x0100	/* b8: Sequence toggle bit clear */
+#define	SQSET		0x0080	/* b7: Sequence toggle bit set */
+#define	SQMON		0x0040	/* b6: Sequence toggle bit monitor */
+#define	PBUSY		0x0020	/* b5: pipe busy */
+#define	PID		0x0003	/* b1-0: Response PID */
+
+/* PIPExTRE */
+#define	TRENB		0x0200	/* b9: Transaction counter enable */
+#define	TRCLR		0x0100	/* b8: Transaction counter clear */
+
+/* PIPExTRN */
+#define	TRNCNT		0xFFFF	/* b15-0: Transaction counter */
+
+/* DEVADDx */
+#define	UPPHUB		0x7800
+#define	HUBPORT		0x0700
+#define	USBSPD		0x00C0
+#define	RTPORT		0x0001
+
+#define R8A66597_MAX_NUM_PIPE		10
+#define R8A66597_BUF_BSIZE		8
+#define R8A66597_MAX_DEVICE		10
+#define R8A66597_MAX_ROOT_HUB		2
+#define R8A66597_MAX_SAMPLING		10
+#define R8A66597_MAX_DMA_CHANNEL	2
+#define R8A66597_PIPE_NO_DMA		R8A66597_MAX_DMA_CHANNEL
+#define check_bulk_or_isoc(pipenum)	((pipenum >= 1 && pipenum <= 5))
+#define check_interrupt(pipenum)	((pipenum >= 6 && pipenum <= 9))
+#define make_devsel(addr)		(addr << 12)
+
+struct r8a66597_pipe_info {
+        u16 pipenum;
+        u16 address;	/* R8A66597 HCD usb addres */
+        u16 epnum;
+        u16 maxpacket;
+        u16 type;
+        u16 bufnum;
+        u16 buf_bsize;
+        u16 interval;
+        u16 dir_in;
+};
+
+struct r8a66597_pipe {
+	struct r8a66597_pipe_info info;
+
+	unsigned long fifoaddr;
+	unsigned long fifosel;
+	unsigned long fifoctr;
+	unsigned long pipectr;
+	unsigned long pipetre;
+	unsigned long pipetrn;
+};
+
+struct r8a66597_td {
+	struct r8a66597_pipe *pipe;
+	struct urb *urb;
+	struct list_head queue;
+
+	u16 type;
+	u16 pipenum;
+	int iso_cnt;
+
+	u16 address;		/* R8A66597's USB address */
+	u16 maxpacket;
+
+	unsigned zero_packet:1;
+	unsigned short_packet:1;
+	unsigned set_address:1;
+};
+
+struct r8a66597_device {
+	u16	address;	/* R8A66597's USB address */
+	u16	hub_port;
+	u16	root_port;
+
+	unsigned short ep_in_toggle;
+	unsigned short ep_out_toggle;
+	unsigned char pipe_cnt[R8A66597_MAX_NUM_PIPE];
+	unsigned char dma_map;
+
+	enum usb_device_state state;
+
+	struct usb_device *udev;
+	int usb_address;
+	struct list_head device_list;
+};
+
+struct r8a66597_root_hub {
+	u32 port;
+	u16 old_syssts;
+	int scount;
+
+	struct r8a66597_device	*dev;
+};
+
+struct r8a66597 {
+	spinlock_t lock;
+	unsigned long reg;
+
+	struct r8a66597_device		device0;
+	struct r8a66597_root_hub	root_hub[R8A66597_MAX_ROOT_HUB];
+	struct list_head		pipe_queue[R8A66597_MAX_NUM_PIPE];
+
+	struct timer_list rh_timer;
+	struct timer_list td_timer[R8A66597_MAX_NUM_PIPE];
+
+	unsigned short address_map;
+	unsigned short timeout_map;
+	unsigned char pipe_cnt[R8A66597_MAX_NUM_PIPE];
+	unsigned char dma_map;
+
+	struct list_head child_device;
+	unsigned long child_connect_map[4];
+};
+
+static inline struct r8a66597 *hcd_to_r8a66597(struct usb_hcd *hcd)
+{
+	return (struct r8a66597 *)(hcd->hcd_priv);
+}
+
+static inline struct usb_hcd *r8a66597_to_hcd(struct r8a66597 *r8a66597)
+{
+	return container_of((void *)r8a66597, struct usb_hcd, hcd_priv);
+}
+
+static inline struct r8a66597_td *r8a66597_get_td(struct r8a66597 *r8a66597,
+						  u16 pipenum)
+{
+	if (unlikely(list_empty(&r8a66597->pipe_queue[pipenum])))
+		return NULL;
+
+	return list_entry(r8a66597->pipe_queue[pipenum].next,
+			  struct r8a66597_td, queue);
+}
+
+static inline struct urb *r8a66597_get_urb(struct r8a66597 *r8a66597,
+					   u16 pipenum)
+{
+	struct r8a66597_td *td;
+
+	td = r8a66597_get_td(r8a66597, pipenum);
+	return (td ? td->urb : NULL);
+}
+
+static inline u16 r8a66597_read(struct r8a66597 *r8a66597, unsigned long offset)
+{
+	return inw(r8a66597->reg + offset);
+}
+
+static inline void r8a66597_read_fifo(struct r8a66597 *r8a66597,
+				      unsigned long offset, u16 *buf,
+				      int len)
+{
+	len = (len + 1) / 2;
+	insw(r8a66597->reg + offset, buf, len);
+}
+
+static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
+				  unsigned long offset)
+{
+	outw(val, r8a66597->reg + offset);
+}
+
+static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
+				       unsigned long offset, u16 *buf,
+				       int len)
+{
+	unsigned long fifoaddr = r8a66597->reg + offset;
+	int odd = len & 0x0001;
+
+	len = len / 2;
+	outsw(fifoaddr, buf, len);
+	if (unlikely(odd)) {
+		buf = &buf[len];
+		outb((unsigned char)*buf, fifoaddr);
+	}
+}
+
+static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
+				 u16 val, u16 pat, unsigned long offset)
+{
+	u16 tmp;
+	tmp = r8a66597_read(r8a66597, offset);
+	tmp = tmp & (~pat);
+	tmp = tmp | val;
+	r8a66597_write(r8a66597, tmp, offset);
+}
+
+#define r8a66597_bclr(r8a66597, val, offset)	\
+			r8a66597_mdfy(r8a66597, 0, val, offset)
+#define r8a66597_bset(r8a66597, val, offset)	\
+			r8a66597_mdfy(r8a66597, val, 0, offset)
+
+static inline unsigned long get_syscfg_reg(int port)
+{
+	return port == 0 ? SYSCFG0 : SYSCFG1;
+}
+
+static inline unsigned long get_syssts_reg(int port)
+{
+	return port == 0 ? SYSSTS0 : SYSSTS1;
+}
+
+static inline unsigned long get_dvstctr_reg(int port)
+{
+	return port == 0 ? DVSTCTR0 : DVSTCTR1;
+}
+
+static inline unsigned long get_intenb_reg(int port)
+{
+	return port == 0 ? INTENB1 : INTENB2;
+}
+
+static inline unsigned long get_intsts_reg(int port)
+{
+	return port == 0 ? INTSTS1 : INTSTS2;
+}
+
+static inline u16 get_rh_usb_speed(struct r8a66597 *r8a66597, int port)
+{
+	unsigned long dvstctr_reg = get_dvstctr_reg(port);
+
+	return r8a66597_read(r8a66597, dvstctr_reg) & RHST;
+}
+
+static inline void r8a66597_port_power(struct r8a66597 *r8a66597, int port,
+				       int power)
+{
+	unsigned long dvstctr_reg = get_dvstctr_reg(port);
+
+	if (power)
+		r8a66597_bset(r8a66597, VBOUT, dvstctr_reg);
+	else
+		r8a66597_bclr(r8a66597, VBOUT, dvstctr_reg);
+}
+
+#define get_pipectr_addr(pipenum)	(PIPE1CTR + (pipenum - 1) * 2)
+#define get_pipetre_addr(pipenum)	(PIPE1TRE + (pipenum - 1) * 4)
+#define get_pipetrn_addr(pipenum)	(PIPE1TRN + (pipenum - 1) * 4)
+#define get_devadd_addr(address)	(DEVADD0 + address * 2)
+
+#define enable_irq_ready(r8a66597, pipenum)	\
+	enable_pipe_irq(r8a66597, pipenum, BRDYENB)
+#define disable_irq_ready(r8a66597, pipenum)	\
+	disable_pipe_irq(r8a66597, pipenum, BRDYENB)
+#define enable_irq_empty(r8a66597, pipenum)	\
+	enable_pipe_irq(r8a66597, pipenum, BEMPENB)
+#define disable_irq_empty(r8a66597, pipenum)	\
+	disable_pipe_irq(r8a66597, pipenum, BEMPENB)
+#define enable_irq_nrdy(r8a66597, pipenum)	\
+	enable_pipe_irq(r8a66597, pipenum, NRDYENB)
+#define disable_irq_nrdy(r8a66597, pipenum)	\
+	disable_pipe_irq(r8a66597, pipenum, NRDYENB)
+
+#endif	/* __R8A66597_H__ */
+

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

@@ -730,10 +730,9 @@ static int uhci_rh_resume(struct usb_hcd *hcd)
 	int rc = 0;
 	int rc = 0;
 
 
 	spin_lock_irq(&uhci->lock);
 	spin_lock_irq(&uhci->lock);
-	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
-		dev_warn(&hcd->self.root_hub->dev, "HC isn't running!\n");
+	if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags))
 		rc = -ESHUTDOWN;
 		rc = -ESHUTDOWN;
-	} else if (!uhci->dead)
+	else if (!uhci->dead)
 		wakeup_rh(uhci);
 		wakeup_rh(uhci);
 	spin_unlock_irq(&uhci->lock);
 	spin_unlock_irq(&uhci->lock);
 	return rc;
 	return rc;

+ 11 - 20
drivers/usb/misc/adutux.c

@@ -108,8 +108,6 @@ struct adu_device {
 	struct urb*		interrupt_out_urb;
 	struct urb*		interrupt_out_urb;
 };
 };
 
 
-/* prevent races between open() and disconnect */
-static DEFINE_MUTEX(disconnect_mutex);
 static struct usb_driver adu_driver;
 static struct usb_driver adu_driver;
 
 
 static void adu_debug_data(int level, const char *function, int size,
 static void adu_debug_data(int level, const char *function, int size,
@@ -256,8 +254,6 @@ static int adu_open(struct inode *inode, struct file *file)
 
 
 	subminor = iminor(inode);
 	subminor = iminor(inode);
 
 
-	mutex_lock(&disconnect_mutex);
-
 	interface = usb_find_interface(&adu_driver, subminor);
 	interface = usb_find_interface(&adu_driver, subminor);
 	if (!interface) {
 	if (!interface) {
 		err("%s - error, can't find device for minor %d",
 		err("%s - error, can't find device for minor %d",
@@ -306,7 +302,6 @@ static int adu_open(struct inode *inode, struct file *file)
 	up(&dev->sem);
 	up(&dev->sem);
 
 
 exit_no_device:
 exit_no_device:
-	mutex_unlock(&disconnect_mutex);
 	dbg(2,"%s : leave, return value %d ", __FUNCTION__, retval);
 	dbg(2,"%s : leave, return value %d ", __FUNCTION__, retval);
 
 
 	return retval;
 	return retval;
@@ -318,12 +313,6 @@ static int adu_release_internal(struct adu_device *dev)
 
 
 	dbg(2," %s : enter", __FUNCTION__);
 	dbg(2," %s : enter", __FUNCTION__);
 
 
-	if (dev->udev == NULL) {
-		/* the device was unplugged before the file was released */
-		adu_delete(dev);
-		goto exit;
-	}
-
 	/* decrement our usage count for the device */
 	/* decrement our usage count for the device */
 	--dev->open_count;
 	--dev->open_count;
 	dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
 	dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
@@ -332,7 +321,6 @@ static int adu_release_internal(struct adu_device *dev)
 		dev->open_count = 0;
 		dev->open_count = 0;
 	}
 	}
 
 
-exit:
 	dbg(2," %s : leave", __FUNCTION__);
 	dbg(2," %s : leave", __FUNCTION__);
 	return retval;
 	return retval;
 }
 }
@@ -367,8 +355,15 @@ static int adu_release(struct inode *inode, struct file *file)
 		goto exit;
 		goto exit;
 	}
 	}
 
 
-	/* do the work */
-	retval = adu_release_internal(dev);
+	if (dev->udev == NULL) {
+		/* the device was unplugged before the file was released */
+		up(&dev->sem);
+		adu_delete(dev);
+		dev = NULL;
+	} else {
+		/* do the work */
+		retval = adu_release_internal(dev);
+	}
 
 
 exit:
 exit:
 	if (dev)
 	if (dev)
@@ -831,19 +826,17 @@ static void adu_disconnect(struct usb_interface *interface)
 
 
 	dbg(2," %s : enter", __FUNCTION__);
 	dbg(2," %s : enter", __FUNCTION__);
 
 
-	mutex_lock(&disconnect_mutex); /* not interruptible */
-
 	dev = usb_get_intfdata(interface);
 	dev = usb_get_intfdata(interface);
 	usb_set_intfdata(interface, NULL);
 	usb_set_intfdata(interface, NULL);
 
 
-	down(&dev->sem); /* not interruptible */
-
 	minor = dev->minor;
 	minor = dev->minor;
 
 
 	/* give back our minor */
 	/* give back our minor */
 	usb_deregister_dev(interface, &adu_class);
 	usb_deregister_dev(interface, &adu_class);
 	dev->minor = 0;
 	dev->minor = 0;
 
 
+	down(&dev->sem); /* not interruptible */
+
 	/* if the device is not opened, then we clean up right now */
 	/* if the device is not opened, then we clean up right now */
 	dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
 	dbg(2," %s : open count %d", __FUNCTION__, dev->open_count);
 	if (!dev->open_count) {
 	if (!dev->open_count) {
@@ -854,8 +847,6 @@ static void adu_disconnect(struct usb_interface *interface)
 		up(&dev->sem);
 		up(&dev->sem);
 	}
 	}
 
 
-	mutex_unlock(&disconnect_mutex);
-
 	dev_info(&interface->dev, "ADU device adutux%d now disconnected",
 	dev_info(&interface->dev, "ADU device adutux%d now disconnected",
 		 (minor - ADU_MINOR_BASE));
 		 (minor - ADU_MINOR_BASE));
 
 

+ 3 - 3
drivers/usb/misc/auerswald.c

@@ -2034,12 +2034,12 @@ static void auerswald_disconnect (struct usb_interface *intf)
 	if (!cp)
 	if (!cp)
 		return;
 		return;
 
 
-	down (&cp->mutex);
-	info ("device /dev/%s now disconnecting", cp->name);
-
 	/* give back our USB minor number */
 	/* give back our USB minor number */
 	usb_deregister_dev(intf, &auerswald_class);
 	usb_deregister_dev(intf, &auerswald_class);
 
 
+	down (&cp->mutex);
+	info ("device /dev/%s now disconnecting", cp->name);
+
 	/* Stop the interrupt endpoint */
 	/* Stop the interrupt endpoint */
 	auerswald_int_release (cp);
 	auerswald_int_release (cp);
 
 

+ 35 - 0
drivers/usb/misc/berry_charge.c

@@ -26,8 +26,11 @@
 
 
 #define RIM_VENDOR		0x0fca
 #define RIM_VENDOR		0x0fca
 #define BLACKBERRY		0x0001
 #define BLACKBERRY		0x0001
+#define BLACKBERRY_PEARL_DUAL   0x0004
+#define BLACKBERRY_PEARL        0x0006
 
 
 static int debug;
 static int debug;
+static int pearl_dual_mode = 1;
 
 
 #ifdef dbg
 #ifdef dbg
 #undef dbg
 #undef dbg
@@ -38,6 +41,8 @@ static int debug;
 
 
 static struct usb_device_id id_table [] = {
 static struct usb_device_id id_table [] = {
 	{ USB_DEVICE(RIM_VENDOR, BLACKBERRY) },
 	{ USB_DEVICE(RIM_VENDOR, BLACKBERRY) },
+	{ USB_DEVICE(RIM_VENDOR, BLACKBERRY_PEARL) },
+	{ USB_DEVICE(RIM_VENDOR, BLACKBERRY_PEARL_DUAL) },
 	{ },					/* Terminating entry */
 	{ },					/* Terminating entry */
 };
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 MODULE_DEVICE_TABLE(usb, id_table);
@@ -86,6 +91,30 @@ static int magic_charge(struct usb_device *udev)
 	return retval;
 	return retval;
 }
 }
 
 
+static int magic_dual_mode(struct usb_device *udev)
+{
+	char *dummy_buffer = kzalloc(2, GFP_KERNEL);
+	int retval;
+
+	if (!dummy_buffer)
+		return -ENOMEM;
+
+	/* send magic command so that the Blackberry Pearl device exposes
+	 * two interfaces: both the USB mass-storage one and one which can
+	 * be used for database access. */
+	dbg(&udev->dev, "Sending magic pearl command\n");
+	retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
+				 0xa9, 0xc0, 1, 1, dummy_buffer, 2, 100);
+	dbg(&udev->dev, "Magic pearl command returned %d\n", retval);
+
+	dbg(&udev->dev, "Calling set_configuration\n");
+	retval = usb_driver_set_configuration(udev, 1);
+	if (retval)
+		dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
+
+	return retval;
+}
+
 static int berry_probe(struct usb_interface *intf,
 static int berry_probe(struct usb_interface *intf,
 		       const struct usb_device_id *id)
 		       const struct usb_device_id *id)
 {
 {
@@ -105,6 +134,10 @@ static int berry_probe(struct usb_interface *intf,
 	/* turn the power on */
 	/* turn the power on */
 	magic_charge(udev);
 	magic_charge(udev);
 
 
+	if ((le16_to_cpu(udev->descriptor.idProduct) == BLACKBERRY_PEARL) &&
+	    (pearl_dual_mode))
+		magic_dual_mode(udev);
+
 	/* we don't really want to bind to the device, userspace programs can
 	/* we don't really want to bind to the device, userspace programs can
 	 * handle the syncing just fine, so get outta here. */
 	 * handle the syncing just fine, so get outta here. */
 	return -ENODEV;
 	return -ENODEV;
@@ -138,3 +171,5 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
 MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 module_param(debug, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug enabled or not");
 MODULE_PARM_DESC(debug, "Debug enabled or not");
+module_param(pearl_dual_mode, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(pearl_dual_mode, "Change Blackberry Pearl to run in dual mode");

+ 15 - 39
drivers/usb/misc/idmouse.c

@@ -119,9 +119,6 @@ static struct usb_driver idmouse_driver = {
 	.id_table = idmouse_table,
 	.id_table = idmouse_table,
 };
 };
 
 
-/* prevent races between open() and disconnect() */
-static DEFINE_MUTEX(disconnect_mutex);
-
 static int idmouse_create_image(struct usb_idmouse *dev)
 static int idmouse_create_image(struct usb_idmouse *dev)
 {
 {
 	int bytes_read;
 	int bytes_read;
@@ -211,21 +208,15 @@ static int idmouse_open(struct inode *inode, struct file *file)
 	struct usb_interface *interface;
 	struct usb_interface *interface;
 	int result;
 	int result;
 
 
-	/* prevent disconnects */
-	mutex_lock(&disconnect_mutex);
-
 	/* get the interface from minor number and driver information */
 	/* get the interface from minor number and driver information */
 	interface = usb_find_interface (&idmouse_driver, iminor (inode));
 	interface = usb_find_interface (&idmouse_driver, iminor (inode));
-	if (!interface) {
-		mutex_unlock(&disconnect_mutex);
+	if (!interface)
 		return -ENODEV;
 		return -ENODEV;
-	}
+
 	/* get the device information block from the interface */
 	/* get the device information block from the interface */
 	dev = usb_get_intfdata(interface);
 	dev = usb_get_intfdata(interface);
-	if (!dev) {
-		mutex_unlock(&disconnect_mutex);
+	if (!dev)
 		return -ENODEV;
 		return -ENODEV;
-	}
 
 
 	/* lock this device */
 	/* lock this device */
 	down(&dev->sem);
 	down(&dev->sem);
@@ -255,9 +246,6 @@ error:
 
 
 	/* unlock this device */
 	/* unlock this device */
 	up(&dev->sem);
 	up(&dev->sem);
-
-	/* unlock the disconnect semaphore */
-	mutex_unlock(&disconnect_mutex);
 	return result;
 	return result;
 }
 }
 
 
@@ -265,15 +253,10 @@ static int idmouse_release(struct inode *inode, struct file *file)
 {
 {
 	struct usb_idmouse *dev;
 	struct usb_idmouse *dev;
 
 
-	/* prevent a race condition with open() */
-	mutex_lock(&disconnect_mutex);
-
 	dev = file->private_data;
 	dev = file->private_data;
 
 
-	if (dev == NULL) {
-		mutex_unlock(&disconnect_mutex);
+	if (dev == NULL)
 		return -ENODEV;
 		return -ENODEV;
-	}
 
 
 	/* lock our device */
 	/* lock our device */
 	down(&dev->sem);
 	down(&dev->sem);
@@ -281,7 +264,6 @@ static int idmouse_release(struct inode *inode, struct file *file)
 	/* are we really open? */
 	/* are we really open? */
 	if (dev->open <= 0) {
 	if (dev->open <= 0) {
 		up(&dev->sem);
 		up(&dev->sem);
-		mutex_unlock(&disconnect_mutex);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
@@ -291,12 +273,9 @@ static int idmouse_release(struct inode *inode, struct file *file)
 		/* the device was unplugged before the file was released */
 		/* the device was unplugged before the file was released */
 		up(&dev->sem);
 		up(&dev->sem);
 		idmouse_delete(dev);
 		idmouse_delete(dev);
-		mutex_unlock(&disconnect_mutex);
-		return 0;
+	} else {
+		up(&dev->sem);
 	}
 	}
-
-	up(&dev->sem);
-	mutex_unlock(&disconnect_mutex);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -391,30 +370,27 @@ static void idmouse_disconnect(struct usb_interface *interface)
 {
 {
 	struct usb_idmouse *dev;
 	struct usb_idmouse *dev;
 
 
-	/* prevent races with open() */
-	mutex_lock(&disconnect_mutex);
-
 	/* get device structure */
 	/* get device structure */
 	dev = usb_get_intfdata(interface);
 	dev = usb_get_intfdata(interface);
 	usb_set_intfdata(interface, NULL);
 	usb_set_intfdata(interface, NULL);
 
 
-	/* lock it */
-	down(&dev->sem);
-
 	/* give back our minor */
 	/* give back our minor */
 	usb_deregister_dev(interface, &idmouse_class);
 	usb_deregister_dev(interface, &idmouse_class);
 
 
+	/* lock it */
+	down(&dev->sem);
+
 	/* prevent device read, write and ioctl */
 	/* prevent device read, write and ioctl */
 	dev->present = 0;
 	dev->present = 0;
 
 
-	/* unlock */
-	up(&dev->sem);
-
 	/* if the device is opened, idmouse_release will clean this up */
 	/* if the device is opened, idmouse_release will clean this up */
-	if (!dev->open)
+	if (!dev->open) {
+		up(&dev->sem);
 		idmouse_delete(dev);
 		idmouse_delete(dev);
-
-	mutex_unlock(&disconnect_mutex);
+	} else {
+		/* unlock */
+		up(&dev->sem);
+	}
 
 
 	info("%s disconnected", DRIVER_DESC);
 	info("%s disconnected", DRIVER_DESC);
 }
 }

+ 8 - 18
drivers/usb/misc/iowarrior.c

@@ -100,8 +100,6 @@ struct iowarrior {
 /*--------------*/
 /*--------------*/
 /*    globals   */
 /*    globals   */
 /*--------------*/
 /*--------------*/
-/* prevent races between open() and disconnect() */
-static DECLARE_MUTEX(disconnect_sem);
 
 
 /*
 /*
  *  USB spec identifies 5 second timeouts.
  *  USB spec identifies 5 second timeouts.
@@ -600,22 +598,18 @@ static int iowarrior_open(struct inode *inode, struct file *file)
 
 
 	subminor = iminor(inode);
 	subminor = iminor(inode);
 
 
-	/* prevent disconnects */
-	down(&disconnect_sem);
-
 	interface = usb_find_interface(&iowarrior_driver, subminor);
 	interface = usb_find_interface(&iowarrior_driver, subminor);
 	if (!interface) {
 	if (!interface) {
 		err("%s - error, can't find device for minor %d", __FUNCTION__,
 		err("%s - error, can't find device for minor %d", __FUNCTION__,
 		    subminor);
 		    subminor);
-		retval = -ENODEV;
-		goto out;
+		return -ENODEV;
 	}
 	}
 
 
 	dev = usb_get_intfdata(interface);
 	dev = usb_get_intfdata(interface);
-	if (!dev) {
-		retval = -ENODEV;
-		goto out;
-	}
+	if (!dev)
+		return -ENODEV;
+
+	mutex_lock(&dev->mutex);
 
 
 	/* Only one process can open each device, no sharing. */
 	/* Only one process can open each device, no sharing. */
 	if (dev->opened) {
 	if (dev->opened) {
@@ -636,7 +630,7 @@ static int iowarrior_open(struct inode *inode, struct file *file)
 	retval = 0;
 	retval = 0;
 
 
 out:
 out:
-	up(&disconnect_sem);
+	mutex_unlock(&dev->mutex);
 	return retval;
 	return retval;
 }
 }
 
 
@@ -868,19 +862,16 @@ static void iowarrior_disconnect(struct usb_interface *interface)
 	struct iowarrior *dev;
 	struct iowarrior *dev;
 	int minor;
 	int minor;
 
 
-	/* prevent races with open() */
-	down(&disconnect_sem);
-
 	dev = usb_get_intfdata(interface);
 	dev = usb_get_intfdata(interface);
 	usb_set_intfdata(interface, NULL);
 	usb_set_intfdata(interface, NULL);
 
 
-	mutex_lock(&dev->mutex);
-
 	minor = dev->minor;
 	minor = dev->minor;
 
 
 	/* give back our minor */
 	/* give back our minor */
 	usb_deregister_dev(interface, &iowarrior_class);
 	usb_deregister_dev(interface, &iowarrior_class);
 
 
+	mutex_lock(&dev->mutex);
+
 	/* prevent device read, write and ioctl */
 	/* prevent device read, write and ioctl */
 	dev->present = 0;
 	dev->present = 0;
 
 
@@ -898,7 +889,6 @@ static void iowarrior_disconnect(struct usb_interface *interface)
 		/* no process is using the device, cleanup now */
 		/* no process is using the device, cleanup now */
 		iowarrior_delete(dev);
 		iowarrior_delete(dev);
 	}
 	}
-	up(&disconnect_sem);
 
 
 	dev_info(&interface->dev, "I/O-Warror #%d now disconnected\n",
 	dev_info(&interface->dev, "I/O-Warror #%d now disconnected\n",
 		 minor - IOWARRIOR_MINOR_BASE);
 		 minor - IOWARRIOR_MINOR_BASE);

+ 8 - 25
drivers/usb/misc/ldusb.c

@@ -176,9 +176,6 @@ struct ld_usb {
 	int			interrupt_out_busy;
 	int			interrupt_out_busy;
 };
 };
 
 
-/* prevent races between open() and disconnect() */
-static DEFINE_MUTEX(disconnect_mutex);
-
 static struct usb_driver ld_usb_driver;
 static struct usb_driver ld_usb_driver;
 
 
 /**
 /**
@@ -298,35 +295,28 @@ static int ld_usb_open(struct inode *inode, struct file *file)
 {
 {
 	struct ld_usb *dev;
 	struct ld_usb *dev;
 	int subminor;
 	int subminor;
-	int retval = 0;
+	int retval;
 	struct usb_interface *interface;
 	struct usb_interface *interface;
 
 
 	nonseekable_open(inode, file);
 	nonseekable_open(inode, file);
 	subminor = iminor(inode);
 	subminor = iminor(inode);
 
 
-	mutex_lock(&disconnect_mutex);
-
 	interface = usb_find_interface(&ld_usb_driver, subminor);
 	interface = usb_find_interface(&ld_usb_driver, subminor);
 
 
 	if (!interface) {
 	if (!interface) {
 		err("%s - error, can't find device for minor %d\n",
 		err("%s - error, can't find device for minor %d\n",
 		     __FUNCTION__, subminor);
 		     __FUNCTION__, subminor);
-		retval = -ENODEV;
-		goto unlock_disconnect_exit;
+		return -ENODEV;
 	}
 	}
 
 
 	dev = usb_get_intfdata(interface);
 	dev = usb_get_intfdata(interface);
 
 
-	if (!dev) {
-		retval = -ENODEV;
-		goto unlock_disconnect_exit;
-	}
+	if (!dev)
+		return -ENODEV;
 
 
 	/* lock this device */
 	/* lock this device */
-	if (down_interruptible(&dev->sem)) {
-		retval = -ERESTARTSYS;
-		goto unlock_disconnect_exit;
-	}
+	if (down_interruptible(&dev->sem))
+		return -ERESTARTSYS;
 
 
 	/* allow opening only once */
 	/* allow opening only once */
 	if (dev->open_count) {
 	if (dev->open_count) {
@@ -366,9 +356,6 @@ static int ld_usb_open(struct inode *inode, struct file *file)
 unlock_exit:
 unlock_exit:
 	up(&dev->sem);
 	up(&dev->sem);
 
 
-unlock_disconnect_exit:
-	mutex_unlock(&disconnect_mutex);
-
 	return retval;
 	return retval;
 }
 }
 
 
@@ -766,18 +753,16 @@ static void ld_usb_disconnect(struct usb_interface *intf)
 	struct ld_usb *dev;
 	struct ld_usb *dev;
 	int minor;
 	int minor;
 
 
-	mutex_lock(&disconnect_mutex);
-
 	dev = usb_get_intfdata(intf);
 	dev = usb_get_intfdata(intf);
 	usb_set_intfdata(intf, NULL);
 	usb_set_intfdata(intf, NULL);
 
 
-	down(&dev->sem);
-
 	minor = intf->minor;
 	minor = intf->minor;
 
 
 	/* give back our minor */
 	/* give back our minor */
 	usb_deregister_dev(intf, &ld_usb_class);
 	usb_deregister_dev(intf, &ld_usb_class);
 
 
+	down(&dev->sem);
+
 	/* if the device is not opened, then we clean up right now */
 	/* if the device is not opened, then we clean up right now */
 	if (!dev->open_count) {
 	if (!dev->open_count) {
 		up(&dev->sem);
 		up(&dev->sem);
@@ -787,8 +772,6 @@ static void ld_usb_disconnect(struct usb_interface *intf)
 		up(&dev->sem);
 		up(&dev->sem);
 	}
 	}
 
 
-	mutex_unlock(&disconnect_mutex);
-
 	dev_info(&intf->dev, "LD USB Device #%d now disconnected\n",
 	dev_info(&intf->dev, "LD USB Device #%d now disconnected\n",
 		 (minor - USB_LD_MINOR_BASE));
 		 (minor - USB_LD_MINOR_BASE));
 }
 }

+ 6 - 18
drivers/usb/misc/legousbtower.c

@@ -254,9 +254,6 @@ static int  tower_probe	(struct usb_interface *interface, const struct usb_devic
 static void tower_disconnect	(struct usb_interface *interface);
 static void tower_disconnect	(struct usb_interface *interface);
 
 
 
 
-/* prevent races between open() and disconnect */
-static DEFINE_MUTEX (disconnect_mutex);
-
 /* file operations needed when we register this driver */
 /* file operations needed when we register this driver */
 static const struct file_operations tower_fops = {
 static const struct file_operations tower_fops = {
 	.owner =	THIS_MODULE,
 	.owner =	THIS_MODULE,
@@ -344,28 +341,26 @@ static int tower_open (struct inode *inode, struct file *file)
 	nonseekable_open(inode, file);
 	nonseekable_open(inode, file);
 	subminor = iminor(inode);
 	subminor = iminor(inode);
 
 
-	mutex_lock (&disconnect_mutex);
-
 	interface = usb_find_interface (&tower_driver, subminor);
 	interface = usb_find_interface (&tower_driver, subminor);
 
 
 	if (!interface) {
 	if (!interface) {
 		err ("%s - error, can't find device for minor %d",
 		err ("%s - error, can't find device for minor %d",
 		     __FUNCTION__, subminor);
 		     __FUNCTION__, subminor);
 		retval = -ENODEV;
 		retval = -ENODEV;
-		goto unlock_disconnect_exit;
+		goto exit;
 	}
 	}
 
 
 	dev = usb_get_intfdata(interface);
 	dev = usb_get_intfdata(interface);
 
 
 	if (!dev) {
 	if (!dev) {
 		retval = -ENODEV;
 		retval = -ENODEV;
-		goto unlock_disconnect_exit;
+		goto exit;
 	}
 	}
 
 
 	/* lock this device */
 	/* lock this device */
 	if (down_interruptible (&dev->sem)) {
 	if (down_interruptible (&dev->sem)) {
 	        retval = -ERESTARTSYS;
 	        retval = -ERESTARTSYS;
-		goto unlock_disconnect_exit;
+		goto exit;
 	}
 	}
 
 
 	/* allow opening only once */
 	/* allow opening only once */
@@ -421,9 +416,7 @@ static int tower_open (struct inode *inode, struct file *file)
 unlock_exit:
 unlock_exit:
 	up (&dev->sem);
 	up (&dev->sem);
 
 
-unlock_disconnect_exit:
-	mutex_unlock (&disconnect_mutex);
-
+exit:
 	dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval);
 	dbg(2, "%s: leave, return value %d ", __FUNCTION__, retval);
 
 
 	return retval;
 	return retval;
@@ -993,19 +986,16 @@ static void tower_disconnect (struct usb_interface *interface)
 
 
 	dbg(2, "%s: enter", __FUNCTION__);
 	dbg(2, "%s: enter", __FUNCTION__);
 
 
-	mutex_lock (&disconnect_mutex);
-
 	dev = usb_get_intfdata (interface);
 	dev = usb_get_intfdata (interface);
 	usb_set_intfdata (interface, NULL);
 	usb_set_intfdata (interface, NULL);
 
 
-
-	down (&dev->sem);
-
 	minor = dev->minor;
 	minor = dev->minor;
 
 
 	/* give back our minor */
 	/* give back our minor */
 	usb_deregister_dev (interface, &tower_class);
 	usb_deregister_dev (interface, &tower_class);
 
 
+	down (&dev->sem);
+
 	/* if the device is not opened, then we clean up right now */
 	/* if the device is not opened, then we clean up right now */
 	if (!dev->open_count) {
 	if (!dev->open_count) {
 		up (&dev->sem);
 		up (&dev->sem);
@@ -1015,8 +1005,6 @@ static void tower_disconnect (struct usb_interface *interface)
 		up (&dev->sem);
 		up (&dev->sem);
 	}
 	}
 
 
-	mutex_unlock (&disconnect_mutex);
-
 	info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE));
 	info("LEGO USB Tower #%d now disconnected", (minor - LEGO_USB_TOWER_MINOR_BASE));
 
 
 	dbg(2, "%s: leave", __FUNCTION__);
 	dbg(2, "%s: leave", __FUNCTION__);

+ 5 - 33
drivers/usb/misc/sisusbvga/sisusb.c

@@ -72,8 +72,6 @@ MODULE_PARM_DESC(last, "Number of last console to take over (1 - MAX_NR_CONSOLES
 
 
 static struct usb_driver sisusb_driver;
 static struct usb_driver sisusb_driver;
 
 
-DEFINE_MUTEX(disconnect_mutex);
-
 static void
 static void
 sisusb_free_buffers(struct sisusb_usb_data *sisusb)
 sisusb_free_buffers(struct sisusb_usb_data *sisusb)
 {
 {
@@ -2511,31 +2509,24 @@ sisusb_open(struct inode *inode, struct file *file)
 	struct usb_interface *interface;
 	struct usb_interface *interface;
 	int subminor = iminor(inode);
 	int subminor = iminor(inode);
 
 
-	mutex_lock(&disconnect_mutex);
-
 	if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
 	if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
 		printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
 		printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
 				subminor);
 				subminor);
-		mutex_unlock(&disconnect_mutex);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
-	if (!(sisusb = usb_get_intfdata(interface))) {
-		mutex_unlock(&disconnect_mutex);
+	if (!(sisusb = usb_get_intfdata(interface)))
 		return -ENODEV;
 		return -ENODEV;
-	}
 
 
 	mutex_lock(&sisusb->lock);
 	mutex_lock(&sisusb->lock);
 
 
 	if (!sisusb->present || !sisusb->ready) {
 	if (!sisusb->present || !sisusb->ready) {
 		mutex_unlock(&sisusb->lock);
 		mutex_unlock(&sisusb->lock);
-		mutex_unlock(&disconnect_mutex);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
 	if (sisusb->isopen) {
 	if (sisusb->isopen) {
 		mutex_unlock(&sisusb->lock);
 		mutex_unlock(&sisusb->lock);
-		mutex_unlock(&disconnect_mutex);
 		return -EBUSY;
 		return -EBUSY;
 	}
 	}
 
 
@@ -2543,7 +2534,6 @@ sisusb_open(struct inode *inode, struct file *file)
 		if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
 		if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
 			if (sisusb_init_gfxdevice(sisusb, 0)) {
 			if (sisusb_init_gfxdevice(sisusb, 0)) {
 				mutex_unlock(&sisusb->lock);
 				mutex_unlock(&sisusb->lock);
-				mutex_unlock(&disconnect_mutex);
 				printk(KERN_ERR
 				printk(KERN_ERR
 					"sisusbvga[%d]: Failed to initialize "
 					"sisusbvga[%d]: Failed to initialize "
 					"device\n",
 					"device\n",
@@ -2552,7 +2542,6 @@ sisusb_open(struct inode *inode, struct file *file)
 			}
 			}
 		} else {
 		} else {
 			mutex_unlock(&sisusb->lock);
 			mutex_unlock(&sisusb->lock);
-			mutex_unlock(&disconnect_mutex);
 			printk(KERN_ERR
 			printk(KERN_ERR
 				"sisusbvga[%d]: Device not attached to "
 				"sisusbvga[%d]: Device not attached to "
 				"USB 2.0 hub\n",
 				"USB 2.0 hub\n",
@@ -2570,8 +2559,6 @@ sisusb_open(struct inode *inode, struct file *file)
 
 
 	mutex_unlock(&sisusb->lock);
 	mutex_unlock(&sisusb->lock);
 
 
-	mutex_unlock(&disconnect_mutex);
-
 	return 0;
 	return 0;
 }
 }
 
 
@@ -2601,12 +2588,8 @@ sisusb_release(struct inode *inode, struct file *file)
 	struct sisusb_usb_data *sisusb;
 	struct sisusb_usb_data *sisusb;
 	int myminor;
 	int myminor;
 
 
-	mutex_lock(&disconnect_mutex);
-
-	if (!(sisusb = (struct sisusb_usb_data *)file->private_data)) {
-		mutex_unlock(&disconnect_mutex);
+	if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
 		return -ENODEV;
 		return -ENODEV;
-	}
 
 
 	mutex_lock(&sisusb->lock);
 	mutex_lock(&sisusb->lock);
 
 
@@ -2626,8 +2609,6 @@ sisusb_release(struct inode *inode, struct file *file)
 	/* decrement the usage count on our device */
 	/* decrement the usage count on our device */
 	kref_put(&sisusb->kref, sisusb_delete);
 	kref_put(&sisusb->kref, sisusb_delete);
 
 
-	mutex_unlock(&disconnect_mutex);
-
 	return 0;
 	return 0;
 }
 }
 
 
@@ -3383,12 +3364,9 @@ static void sisusb_disconnect(struct usb_interface *intf)
 	sisusb_console_exit(sisusb);
 	sisusb_console_exit(sisusb);
 #endif
 #endif
 
 
-	/* The above code doesn't need the disconnect
-	 * semaphore to be down; its meaning is to
-	 * protect all other routines from the disconnect
-	 * case, not the other way round.
-	 */
-	mutex_lock(&disconnect_mutex);
+	minor = sisusb->minor;
+
+	usb_deregister_dev(intf, &usb_sisusb_class);
 
 
 	mutex_lock(&sisusb->lock);
 	mutex_lock(&sisusb->lock);
 
 
@@ -3396,12 +3374,8 @@ static void sisusb_disconnect(struct usb_interface *intf)
 	if (!sisusb_wait_all_out_complete(sisusb))
 	if (!sisusb_wait_all_out_complete(sisusb))
 		sisusb_kill_all_busy(sisusb);
 		sisusb_kill_all_busy(sisusb);
 
 
-	minor = sisusb->minor;
-
 	usb_set_intfdata(intf, NULL);
 	usb_set_intfdata(intf, NULL);
 
 
-	usb_deregister_dev(intf, &usb_sisusb_class);
-
 #ifdef SISUSB_OLD_CONFIG_COMPAT
 #ifdef SISUSB_OLD_CONFIG_COMPAT
 	if (sisusb->ioctl32registered) {
 	if (sisusb->ioctl32registered) {
 		int ret;
 		int ret;
@@ -3426,8 +3400,6 @@ static void sisusb_disconnect(struct usb_interface *intf)
 	/* decrement our usage count */
 	/* decrement our usage count */
 	kref_put(&sisusb->kref, sisusb_delete);
 	kref_put(&sisusb->kref, sisusb_delete);
 
 
-	mutex_unlock(&disconnect_mutex);
-
 	printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
 	printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
 }
 }
 
 

+ 2 - 23
drivers/usb/misc/sisusbvga/sisusb_con.c

@@ -214,18 +214,13 @@ sisusbcon_init(struct vc_data *c, int init)
 	 * are set up/restored.
 	 * are set up/restored.
 	 */
 	 */
 
 
-	mutex_lock(&disconnect_mutex);
-
-	if (!(sisusb = sisusb_get_sisusb(c->vc_num))) {
-		mutex_unlock(&disconnect_mutex);
+	if (!(sisusb = sisusb_get_sisusb(c->vc_num)))
 		return;
 		return;
-	}
 
 
 	mutex_lock(&sisusb->lock);
 	mutex_lock(&sisusb->lock);
 
 
 	if (!sisusb_sisusb_valid(sisusb)) {
 	if (!sisusb_sisusb_valid(sisusb)) {
 		mutex_unlock(&sisusb->lock);
 		mutex_unlock(&sisusb->lock);
-		mutex_unlock(&disconnect_mutex);
 		return;
 		return;
 	}
 	}
 
 
@@ -264,8 +259,6 @@ sisusbcon_init(struct vc_data *c, int init)
 
 
 	mutex_unlock(&sisusb->lock);
 	mutex_unlock(&sisusb->lock);
 
 
-	mutex_unlock(&disconnect_mutex);
-
 	if (init) {
 	if (init) {
 		c->vc_cols = cols;
 		c->vc_cols = cols;
 		c->vc_rows = rows;
 		c->vc_rows = rows;
@@ -284,12 +277,8 @@ sisusbcon_deinit(struct vc_data *c)
 	 * and others, ie not under our control.
 	 * and others, ie not under our control.
 	 */
 	 */
 
 
-	mutex_lock(&disconnect_mutex);
-
-	if (!(sisusb = sisusb_get_sisusb(c->vc_num))) {
-		mutex_unlock(&disconnect_mutex);
+	if (!(sisusb = sisusb_get_sisusb(c->vc_num)))
 		return;
 		return;
-	}
 
 
 	mutex_lock(&sisusb->lock);
 	mutex_lock(&sisusb->lock);
 
 
@@ -314,8 +303,6 @@ sisusbcon_deinit(struct vc_data *c)
 
 
 	/* decrement the usage count on our sisusb */
 	/* decrement the usage count on our sisusb */
 	kref_put(&sisusb->kref, sisusb_delete);
 	kref_put(&sisusb->kref, sisusb_delete);
-
-	mutex_unlock(&disconnect_mutex);
 }
 }
 
 
 /* interface routine */
 /* interface routine */
@@ -1490,14 +1477,11 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
 {
 {
 	int i, ret, minor = sisusb->minor;
 	int i, ret, minor = sisusb->minor;
 
 
-	mutex_lock(&disconnect_mutex);
-
 	mutex_lock(&sisusb->lock);
 	mutex_lock(&sisusb->lock);
 
 
 	/* Erm.. that should not happen */
 	/* Erm.. that should not happen */
 	if (sisusb->haveconsole || !sisusb->SiS_Pr) {
 	if (sisusb->haveconsole || !sisusb->SiS_Pr) {
 		mutex_unlock(&sisusb->lock);
 		mutex_unlock(&sisusb->lock);
-		mutex_unlock(&disconnect_mutex);
 		return 1;
 		return 1;
 	}
 	}
 
 
@@ -1508,14 +1492,12 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
 	    first > MAX_NR_CONSOLES ||
 	    first > MAX_NR_CONSOLES ||
 	    last > MAX_NR_CONSOLES) {
 	    last > MAX_NR_CONSOLES) {
 		mutex_unlock(&sisusb->lock);
 		mutex_unlock(&sisusb->lock);
-		mutex_unlock(&disconnect_mutex);
 		return 1;
 		return 1;
 	}
 	}
 
 
 	/* If gfxcore not initialized or no consoles given, quit graciously */
 	/* If gfxcore not initialized or no consoles given, quit graciously */
 	if (!sisusb->gfxinit || first < 1 || last < 1) {
 	if (!sisusb->gfxinit || first < 1 || last < 1) {
 		mutex_unlock(&sisusb->lock);
 		mutex_unlock(&sisusb->lock);
-		mutex_unlock(&disconnect_mutex);
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -1526,7 +1508,6 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
 	/* Set up text mode (and upload  default font) */
 	/* Set up text mode (and upload  default font) */
 	if (sisusb_reset_text_mode(sisusb, 1)) {
 	if (sisusb_reset_text_mode(sisusb, 1)) {
 		mutex_unlock(&sisusb->lock);
 		mutex_unlock(&sisusb->lock);
-		mutex_unlock(&disconnect_mutex);
 		printk(KERN_ERR
 		printk(KERN_ERR
 			"sisusbvga[%d]: Failed to set up text mode\n",
 			"sisusbvga[%d]: Failed to set up text mode\n",
 			minor);
 			minor);
@@ -1550,7 +1531,6 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
 	/* Allocate screen buffer */
 	/* Allocate screen buffer */
 	if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
 	if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
 		mutex_unlock(&sisusb->lock);
 		mutex_unlock(&sisusb->lock);
-		mutex_unlock(&disconnect_mutex);
 		printk(KERN_ERR
 		printk(KERN_ERR
 			"sisusbvga[%d]: Failed to allocate screen buffer\n",
 			"sisusbvga[%d]: Failed to allocate screen buffer\n",
 			minor);
 			minor);
@@ -1558,7 +1538,6 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
 	}
 	}
 
 
 	mutex_unlock(&sisusb->lock);
 	mutex_unlock(&sisusb->lock);
-	mutex_unlock(&disconnect_mutex);
 
 
 	/* Now grab the desired console(s) */
 	/* Now grab the desired console(s) */
 	ret = take_over_console(&sisusb_con, first - 1, last - 1, 0);
 	ret = take_over_console(&sisusb_con, first - 1, last - 1, 0);

+ 0 - 2
drivers/usb/misc/sisusbvga/sisusb_init.h

@@ -808,8 +808,6 @@ static const struct SiS_VCLKData SiSUSB_VCLKData[] =
 	{ 0x2b,0xc2, 35}  /* 0x71 768@576@60 */
 	{ 0x2b,0xc2, 35}  /* 0x71 768@576@60 */
 };
 };
 
 
-extern struct mutex disconnect_mutex;
-
 int		SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
 int		SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo);
 int		SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
 int		SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo);
 
 

+ 47 - 20
drivers/usb/misc/usblcd.c

@@ -45,13 +45,13 @@ struct usb_lcd {
 	struct kref		kref;
 	struct kref		kref;
 	struct semaphore	limit_sem;		/* to stop writes at full throttle from
 	struct semaphore	limit_sem;		/* to stop writes at full throttle from
 							 * using up all RAM */
 							 * using up all RAM */
+	struct usb_anchor	submitted;		/* URBs to wait for before suspend */
 };
 };
 #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref)
 #define to_lcd_dev(d) container_of(d, struct usb_lcd, kref)
 
 
 #define USB_LCD_CONCURRENT_WRITES	5
 #define USB_LCD_CONCURRENT_WRITES	5
 
 
 static struct usb_driver lcd_driver;
 static struct usb_driver lcd_driver;
-static DEFINE_MUTEX(usb_lcd_open_mutex);
 
 
 
 
 static void lcd_delete(struct kref *kref)
 static void lcd_delete(struct kref *kref)
@@ -68,35 +68,35 @@ static int lcd_open(struct inode *inode, struct file *file)
 {
 {
 	struct usb_lcd *dev;
 	struct usb_lcd *dev;
 	struct usb_interface *interface;
 	struct usb_interface *interface;
-	int subminor;
-	int retval = 0;
+	int subminor, r;
 
 
 	subminor = iminor(inode);
 	subminor = iminor(inode);
 
 
-	mutex_lock(&usb_lcd_open_mutex);
 	interface = usb_find_interface(&lcd_driver, subminor);
 	interface = usb_find_interface(&lcd_driver, subminor);
 	if (!interface) {
 	if (!interface) {
 		err ("USBLCD: %s - error, can't find device for minor %d",
 		err ("USBLCD: %s - error, can't find device for minor %d",
 		     __FUNCTION__, subminor);
 		     __FUNCTION__, subminor);
-		retval = -ENODEV;
-		goto exit;
+		return -ENODEV;
 	}
 	}
 
 
 	dev = usb_get_intfdata(interface);
 	dev = usb_get_intfdata(interface);
-	if (!dev) {
-		retval = -ENODEV;
-		goto exit;
-	}
+	if (!dev)
+		return -ENODEV;
 
 
 	/* increment our usage count for the device */
 	/* increment our usage count for the device */
 	kref_get(&dev->kref);
 	kref_get(&dev->kref);
 
 
+	/* grab a power reference */
+	r = usb_autopm_get_interface(interface);
+	if (r < 0) {
+		kref_put(&dev->kref, lcd_delete);
+		return r;
+	}
+
 	/* save our object in the file's private structure */
 	/* save our object in the file's private structure */
 	file->private_data = dev;
 	file->private_data = dev;
 
 
-exit:
-	mutex_unlock(&usb_lcd_open_mutex);
-	return retval;
+	return 0;
 }
 }
 
 
 static int lcd_release(struct inode *inode, struct file *file)
 static int lcd_release(struct inode *inode, struct file *file)
@@ -108,6 +108,7 @@ static int lcd_release(struct inode *inode, struct file *file)
 		return -ENODEV;
 		return -ENODEV;
 
 
 	/* decrement the count on our device */
 	/* decrement the count on our device */
+	usb_autopm_put_interface(dev->interface);
 	kref_put(&dev->kref, lcd_delete);
 	kref_put(&dev->kref, lcd_delete);
 	return 0;
 	return 0;
 }
 }
@@ -233,12 +234,14 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz
 			  usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
 			  usb_sndbulkpipe(dev->udev, dev->bulk_out_endpointAddr),
 			  buf, count, lcd_write_bulk_callback, dev);
 			  buf, count, lcd_write_bulk_callback, dev);
 	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
 	urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+	usb_anchor_urb(urb, &dev->submitted);
 	
 	
 	/* send the data out the bulk port */
 	/* send the data out the bulk port */
 	retval = usb_submit_urb(urb, GFP_KERNEL);
 	retval = usb_submit_urb(urb, GFP_KERNEL);
 	if (retval) {
 	if (retval) {
 		err("USBLCD: %s - failed submitting write urb, error %d", __FUNCTION__, retval);
 		err("USBLCD: %s - failed submitting write urb, error %d", __FUNCTION__, retval);
-		goto error;
+		goto error_unanchor;
 	}
 	}
 	
 	
 	/* release our reference to this urb, the USB core will eventually free it entirely */
 	/* release our reference to this urb, the USB core will eventually free it entirely */
@@ -246,7 +249,8 @@ static ssize_t lcd_write(struct file *file, const char __user * user_buffer, siz
 
 
 exit:
 exit:
 	return count;
 	return count;
-
+error_unanchor:
+	usb_unanchor_urb(urb);
 error:
 error:
 	usb_buffer_free(dev->udev, count, buf, urb->transfer_dma);
 	usb_buffer_free(dev->udev, count, buf, urb->transfer_dma);
 	usb_free_urb(urb);
 	usb_free_urb(urb);
@@ -291,6 +295,7 @@ static int lcd_probe(struct usb_interface *interface, const struct usb_device_id
 	}
 	}
 	kref_init(&dev->kref);
 	kref_init(&dev->kref);
 	sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES);
 	sema_init(&dev->limit_sem, USB_LCD_CONCURRENT_WRITES);
+	init_usb_anchor(&dev->submitted);
 
 
 	dev->udev = usb_get_dev(interface_to_usbdev(interface));
 	dev->udev = usb_get_dev(interface_to_usbdev(interface));
 	dev->interface = interface;
 	dev->interface = interface;
@@ -358,22 +363,41 @@ error:
 	return retval;
 	return retval;
 }
 }
 
 
+static void lcd_draw_down(struct usb_lcd *dev)
+{
+	int time;
+
+	time = usb_wait_anchor_empty_timeout(&dev->submitted, 1000);
+	if (!time)
+		usb_kill_anchored_urbs(&dev->submitted);
+}
+
+static int lcd_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct usb_lcd *dev = usb_get_intfdata(intf);
+
+	if (!dev)
+		return 0;
+	lcd_draw_down(dev);
+	return 0;
+}
+
+static int lcd_resume (struct usb_interface *intf)
+{
+	return 0;
+}
+
 static void lcd_disconnect(struct usb_interface *interface)
 static void lcd_disconnect(struct usb_interface *interface)
 {
 {
 	struct usb_lcd *dev;
 	struct usb_lcd *dev;
         int minor = interface->minor;
         int minor = interface->minor;
 
 
-        /* prevent skel_open() from racing skel_disconnect() */
-        mutex_lock(&usb_lcd_open_mutex);
-
         dev = usb_get_intfdata(interface);
         dev = usb_get_intfdata(interface);
         usb_set_intfdata(interface, NULL);
         usb_set_intfdata(interface, NULL);
 
 
         /* give back our minor */
         /* give back our minor */
         usb_deregister_dev(interface, &lcd_class);
         usb_deregister_dev(interface, &lcd_class);
  
  
-	mutex_unlock(&usb_lcd_open_mutex);
-
 	/* decrement our usage count */
 	/* decrement our usage count */
 	kref_put(&dev->kref, lcd_delete);
 	kref_put(&dev->kref, lcd_delete);
 
 
@@ -384,7 +408,10 @@ static struct usb_driver lcd_driver = {
 	.name =		"usblcd",
 	.name =		"usblcd",
 	.probe =	lcd_probe,
 	.probe =	lcd_probe,
 	.disconnect =	lcd_disconnect,
 	.disconnect =	lcd_disconnect,
+	.suspend =	lcd_suspend,
+	.resume =	lcd_resume,
 	.id_table =	id_table,
 	.id_table =	id_table,
+	.supports_autosuspend = 1,
 };
 };
 
 
 static int __init usb_lcd_init(void)
 static int __init usb_lcd_init(void)

+ 33 - 1
drivers/usb/mon/mon_bin.c

@@ -4,7 +4,7 @@
  * This is a binary format reader.
  * This is a binary format reader.
  *
  *
  * Copyright (C) 2006 Paolo Abeni (paolo.abeni@email.it)
  * Copyright (C) 2006 Paolo Abeni (paolo.abeni@email.it)
- * Copyright (C) 2006 Pete Zaitcev (zaitcev@redhat.com)
+ * Copyright (C) 2006,2007 Pete Zaitcev (zaitcev@redhat.com)
  */
  */
 
 
 #include <linux/kernel.h>
 #include <linux/kernel.h>
@@ -172,6 +172,7 @@ static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp,
 
 
 #define MON_RING_EMPTY(rp)	((rp)->b_cnt == 0)
 #define MON_RING_EMPTY(rp)	((rp)->b_cnt == 0)
 
 
+static struct class *mon_bin_class;
 static dev_t mon_bin_dev0;
 static dev_t mon_bin_dev0;
 static struct cdev mon_bin_cdev;
 static struct cdev mon_bin_cdev;
 
 
@@ -1144,10 +1145,38 @@ static void mon_free_buff(struct mon_pgmap *map, int npages)
 		free_page((unsigned long) map[n].ptr);
 		free_page((unsigned long) map[n].ptr);
 }
 }
 
 
+int mon_bin_add(struct mon_bus *mbus, const struct usb_bus *ubus)
+{
+	struct device *dev;
+	unsigned minor = ubus? ubus->busnum: 0;
+
+	if (minor >= MON_BIN_MAX_MINOR)
+		return 0;
+
+	dev = device_create(mon_bin_class, ubus? ubus->controller: NULL,
+			MKDEV(MAJOR(mon_bin_dev0), minor), "usbmon%d", minor);
+	if (IS_ERR(dev))
+		return 0;
+
+	mbus->classdev = dev;
+	return 1;
+}
+
+void mon_bin_del(struct mon_bus *mbus)
+{
+	device_destroy(mon_bin_class, mbus->classdev->devt);
+}
+
 int __init mon_bin_init(void)
 int __init mon_bin_init(void)
 {
 {
 	int rc;
 	int rc;
 
 
+	mon_bin_class = class_create(THIS_MODULE, "usbmon");
+	if (IS_ERR(mon_bin_class)) {
+		rc = PTR_ERR(mon_bin_class);
+		goto err_class;
+	}
+
 	rc = alloc_chrdev_region(&mon_bin_dev0, 0, MON_BIN_MAX_MINOR, "usbmon");
 	rc = alloc_chrdev_region(&mon_bin_dev0, 0, MON_BIN_MAX_MINOR, "usbmon");
 	if (rc < 0)
 	if (rc < 0)
 		goto err_dev;
 		goto err_dev;
@@ -1164,6 +1193,8 @@ int __init mon_bin_init(void)
 err_add:
 err_add:
 	unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
 	unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
 err_dev:
 err_dev:
+	class_destroy(mon_bin_class);
+err_class:
 	return rc;
 	return rc;
 }
 }
 
 
@@ -1171,4 +1202,5 @@ void mon_bin_exit(void)
 {
 {
 	cdev_del(&mon_bin_cdev);
 	cdev_del(&mon_bin_cdev);
 	unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
 	unregister_chrdev_region(mon_bin_dev0, MON_BIN_MAX_MINOR);
+	class_destroy(mon_bin_class);
 }
 }

+ 10 - 4
drivers/usb/mon/mon_main.c

@@ -220,6 +220,8 @@ static void mon_bus_remove(struct usb_bus *ubus)
 	list_del(&mbus->bus_link);
 	list_del(&mbus->bus_link);
 	if (mbus->text_inited)
 	if (mbus->text_inited)
 		mon_text_del(mbus);
 		mon_text_del(mbus);
+	if (mbus->bin_inited)
+		mon_bin_del(mbus);
 
 
 	mon_dissolve(mbus, ubus);
 	mon_dissolve(mbus, ubus);
 	kref_put(&mbus->ref, mon_bus_drop);
 	kref_put(&mbus->ref, mon_bus_drop);
@@ -301,8 +303,8 @@ static void mon_bus_init(struct usb_bus *ubus)
 	mbus->u_bus = ubus;
 	mbus->u_bus = ubus;
 	ubus->mon_bus = mbus;
 	ubus->mon_bus = mbus;
 
 
-	mbus->text_inited = mon_text_add(mbus, ubus->busnum);
-	// mon_bin_add(...)
+	mbus->text_inited = mon_text_add(mbus, ubus);
+	mbus->bin_inited = mon_bin_add(mbus, ubus);
 
 
 	mutex_lock(&mon_lock);
 	mutex_lock(&mon_lock);
 	list_add_tail(&mbus->bus_link, &mon_buses);
 	list_add_tail(&mbus->bus_link, &mon_buses);
@@ -321,8 +323,8 @@ static void mon_bus0_init(void)
 	spin_lock_init(&mbus->lock);
 	spin_lock_init(&mbus->lock);
 	INIT_LIST_HEAD(&mbus->r_list);
 	INIT_LIST_HEAD(&mbus->r_list);
 
 
-	mbus->text_inited = mon_text_add(mbus, 0);
-	// mbus->bin_inited = mon_bin_add(mbus, 0);
+	mbus->text_inited = mon_text_add(mbus, NULL);
+	mbus->bin_inited = mon_bin_add(mbus, NULL);
 }
 }
 
 
 /*
 /*
@@ -403,6 +405,8 @@ static void __exit mon_exit(void)
 
 
 		if (mbus->text_inited)
 		if (mbus->text_inited)
 			mon_text_del(mbus);
 			mon_text_del(mbus);
+		if (mbus->bin_inited)
+			mon_bin_del(mbus);
 
 
 		/*
 		/*
 		 * This never happens, because the open/close paths in
 		 * This never happens, because the open/close paths in
@@ -423,6 +427,8 @@ static void __exit mon_exit(void)
 	mbus = &mon_bus0;
 	mbus = &mon_bus0;
 	if (mbus->text_inited)
 	if (mbus->text_inited)
 		mon_text_del(mbus);
 		mon_text_del(mbus);
+	if (mbus->bin_inited)
+		mon_bin_del(mbus);
 
 
 	mutex_unlock(&mon_lock);
 	mutex_unlock(&mon_lock);
 
 

+ 18 - 11
drivers/usb/mon/mon_text.c

@@ -655,20 +655,24 @@ static const struct file_operations mon_fops_text_u = {
 	.release =	mon_text_release,
 	.release =	mon_text_release,
 };
 };
 
 
-int mon_text_add(struct mon_bus *mbus, int busnum)
+int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
 {
 {
 	struct dentry *d;
 	struct dentry *d;
 	enum { NAMESZ = 10 };
 	enum { NAMESZ = 10 };
 	char name[NAMESZ];
 	char name[NAMESZ];
+	int busnum = ubus? ubus->busnum: 0;
 	int rc;
 	int rc;
 
 
-	rc = snprintf(name, NAMESZ, "%dt", busnum);
-	if (rc <= 0 || rc >= NAMESZ)
-		goto err_print_t;
-	d = debugfs_create_file(name, 0600, mon_dir, mbus, &mon_fops_text_t);
-	if (d == NULL)
-		goto err_create_t;
-	mbus->dent_t = d;
+	if (ubus != NULL) {
+		rc = snprintf(name, NAMESZ, "%dt", busnum);
+		if (rc <= 0 || rc >= NAMESZ)
+			goto err_print_t;
+		d = debugfs_create_file(name, 0600, mon_dir, mbus,
+							     &mon_fops_text_t);
+		if (d == NULL)
+			goto err_create_t;
+		mbus->dent_t = d;
+	}
 
 
 	rc = snprintf(name, NAMESZ, "%du", busnum);
 	rc = snprintf(name, NAMESZ, "%du", busnum);
 	if (rc <= 0 || rc >= NAMESZ)
 	if (rc <= 0 || rc >= NAMESZ)
@@ -694,8 +698,10 @@ err_print_s:
 	mbus->dent_u = NULL;
 	mbus->dent_u = NULL;
 err_create_u:
 err_create_u:
 err_print_u:
 err_print_u:
-	debugfs_remove(mbus->dent_t);
-	mbus->dent_t = NULL;
+	if (ubus != NULL) {
+		debugfs_remove(mbus->dent_t);
+		mbus->dent_t = NULL;
+	}
 err_create_t:
 err_create_t:
 err_print_t:
 err_print_t:
 	return 0;
 	return 0;
@@ -704,7 +710,8 @@ err_print_t:
 void mon_text_del(struct mon_bus *mbus)
 void mon_text_del(struct mon_bus *mbus)
 {
 {
 	debugfs_remove(mbus->dent_u);
 	debugfs_remove(mbus->dent_u);
-	debugfs_remove(mbus->dent_t);
+	if (mbus->dent_t != NULL)
+		debugfs_remove(mbus->dent_t);
 	debugfs_remove(mbus->dent_s);
 	debugfs_remove(mbus->dent_s);
 }
 }
 
 

+ 5 - 2
drivers/usb/mon/usb_mon.h

@@ -20,9 +20,11 @@ struct mon_bus {
 	struct usb_bus *u_bus;
 	struct usb_bus *u_bus;
 
 
 	int text_inited;
 	int text_inited;
+	int bin_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 dentry *dent_u;		/* Second text interface file */
 	struct dentry *dent_u;		/* Second text interface file */
+	struct device *classdev;	/* Device in usbmon class */
 
 
 	/* Ref */
 	/* Ref */
 	int nreaders;			/* Under mon_lock AND mbus->lock */
 	int nreaders;			/* Under mon_lock AND mbus->lock */
@@ -52,9 +54,10 @@ void mon_reader_del(struct mon_bus *mbus, struct mon_reader *r);
 
 
 struct mon_bus *mon_bus_lookup(unsigned int num);
 struct mon_bus *mon_bus_lookup(unsigned int num);
 
 
-int /*bool*/ mon_text_add(struct mon_bus *mbus, int busnum);
+int /*bool*/ mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus);
 void mon_text_del(struct mon_bus *mbus);
 void mon_text_del(struct mon_bus *mbus);
-// void mon_bin_add(struct mon_bus *);
+int /*bool*/ mon_bin_add(struct mon_bus *mbus, const struct usb_bus *ubus);
+void mon_bin_del(struct mon_bus *mbus);
 
 
 int __init mon_text_init(void);
 int __init mon_text_init(void);
 void mon_text_exit(void);
 void mon_text_exit(void);

+ 10 - 0
drivers/usb/serial/Kconfig

@@ -464,6 +464,16 @@ config USB_SERIAL_PL2303
 	  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 pl2303.
 	  module will be called pl2303.
 
 
+config USB_SERIAL_OTI6858
+	tristate "USB Ours Technology Inc. OTi-6858 USB To RS232 Bridge Controller (EXPERIMENTAL)"
+	depends on USB_SERIAL
+	help
+	  Say Y here if you want to use the OTi-6858 single port USB to serial
+          converter device.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called oti6858.
+
 config USB_SERIAL_HP4X
 config USB_SERIAL_HP4X
         tristate "USB HP4x Calculators support"
         tristate "USB HP4x Calculators support"
         depends on USB_SERIAL
         depends on USB_SERIAL

+ 1 - 0
drivers/usb/serial/Makefile

@@ -40,6 +40,7 @@ obj-$(CONFIG_USB_SERIAL_MOS7840)		+= mos7840.o
 obj-$(CONFIG_USB_SERIAL_NAVMAN)			+= navman.o
 obj-$(CONFIG_USB_SERIAL_NAVMAN)			+= navman.o
 obj-$(CONFIG_USB_SERIAL_OMNINET)		+= omninet.o
 obj-$(CONFIG_USB_SERIAL_OMNINET)		+= omninet.o
 obj-$(CONFIG_USB_SERIAL_OPTION)			+= option.o
 obj-$(CONFIG_USB_SERIAL_OPTION)			+= option.o
+obj-$(CONFIG_USB_SERIAL_OTI6858)		+= oti6858.o
 obj-$(CONFIG_USB_SERIAL_PL2303)			+= pl2303.o
 obj-$(CONFIG_USB_SERIAL_PL2303)			+= pl2303.o
 obj-$(CONFIG_USB_SERIAL_SAFE)			+= safe_serial.o
 obj-$(CONFIG_USB_SERIAL_SAFE)			+= safe_serial.o
 obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS)		+= sierra.o
 obj-$(CONFIG_USB_SERIAL_SIERRAWIRELESS)		+= sierra.o

+ 9 - 7
drivers/usb/serial/aircable.c

@@ -411,12 +411,13 @@ static int aircable_write(struct usb_serial_port *port,
 static void aircable_write_bulk_callback(struct urb *urb)
 static void aircable_write_bulk_callback(struct urb *urb)
 {
 {
 	struct usb_serial_port *port = urb->context;
 	struct usb_serial_port *port = urb->context;
+	int status = urb->status;
 	int result;
 	int result;
 
 
-	dbg("%s - urb->status: %d", __FUNCTION__ , urb->status);
+	dbg("%s - urb status: %d", __FUNCTION__ , status);
 
 
 	/* This has been taken from cypress_m8.c cypress_write_int_callback */
 	/* This has been taken from cypress_m8.c cypress_write_int_callback */
-	switch (urb->status) {
+	switch (status) {
 		case 0:
 		case 0:
 			/* success */
 			/* success */
 			break;
 			break;
@@ -425,14 +426,14 @@ static void aircable_write_bulk_callback(struct urb *urb)
 		case -ESHUTDOWN:
 		case -ESHUTDOWN:
 			/* this urb is terminated, clean up */
 			/* this urb is terminated, clean up */
 			dbg("%s - urb shutting down with status: %d",
 			dbg("%s - urb shutting down with status: %d",
-			    __FUNCTION__, urb->status);
+			    __FUNCTION__, status);
 			port->write_urb_busy = 0;
 			port->write_urb_busy = 0;
 			return;
 			return;
 		default:
 		default:
 			/* error in the urb, so we have to resubmit it */
 			/* error in the urb, so we have to resubmit it */
 			dbg("%s - Overflow in write", __FUNCTION__);
 			dbg("%s - Overflow in write", __FUNCTION__);
 			dbg("%s - nonzero write bulk status received: %d",
 			dbg("%s - nonzero write bulk status received: %d",
-			    __FUNCTION__, urb->status);
+			    __FUNCTION__, status);
 			port->write_urb->transfer_buffer_length = 1;
 			port->write_urb->transfer_buffer_length = 1;
 			port->write_urb->dev = port->serial->dev;
 			port->write_urb->dev = port->serial->dev;
 			result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
 			result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
@@ -457,16 +458,17 @@ static void aircable_read_bulk_callback(struct urb *urb)
 	unsigned long no_packages, remaining, package_length, i;
 	unsigned long no_packages, remaining, package_length, i;
 	int result, shift = 0;
 	int result, shift = 0;
 	unsigned char *temp;
 	unsigned char *temp;
+	int status = urb->status;
 
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
 
-	if (urb->status) {
-		dbg("%s - urb->status = %d", __FUNCTION__, urb->status);
+	if (status) {
+		dbg("%s - urb status = %d", __FUNCTION__, status);
 		if (!port->open_count) {
 		if (!port->open_count) {
 			dbg("%s - port is closed, exiting.", __FUNCTION__);
 			dbg("%s - port is closed, exiting.", __FUNCTION__);
 			return;
 			return;
 		}
 		}
-		if (urb->status == -EPROTO) {
+		if (status == -EPROTO) {
 			dbg("%s - caught -EPROTO, resubmitting the urb",
 			dbg("%s - caught -EPROTO, resubmitting the urb",
 			    __FUNCTION__);
 			    __FUNCTION__);
 			usb_fill_bulk_urb(port->read_urb, port->serial->dev,
 			usb_fill_bulk_urb(port->read_urb, port->serial->dev,

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

@@ -82,12 +82,13 @@ static void airprime_read_bulk_callback(struct urb *urb)
 	unsigned char *data = urb->transfer_buffer;
 	unsigned char *data = urb->transfer_buffer;
 	struct tty_struct *tty;
 	struct tty_struct *tty;
 	int result;
 	int result;
+	int status = urb->status;
 
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
 
-	if (urb->status) {
+	if (status) {
 		dbg("%s - nonzero read bulk status received: %d",
 		dbg("%s - nonzero read bulk status received: %d",
-		    __FUNCTION__, urb->status);
+		    __FUNCTION__, status);
 		return;
 		return;
 	}
 	}
 	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
 	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
@@ -109,6 +110,7 @@ static void airprime_write_bulk_callback(struct urb *urb)
 {
 {
 	struct usb_serial_port *port = urb->context;
 	struct usb_serial_port *port = urb->context;
 	struct airprime_private *priv = usb_get_serial_port_data(port);
 	struct airprime_private *priv = usb_get_serial_port_data(port);
+	int status = urb->status;
 	unsigned long flags;
 	unsigned long flags;
 
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 	dbg("%s - port %d", __FUNCTION__, port->number);
@@ -116,9 +118,9 @@ static void airprime_write_bulk_callback(struct urb *urb)
 	/* free up the transfer buffer, as usb_free_urb() does not do this */
 	/* free up the transfer buffer, as usb_free_urb() does not do this */
 	kfree (urb->transfer_buffer);
 	kfree (urb->transfer_buffer);
 
 
-	if (urb->status)
+	if (status)
 		dbg("%s - nonzero write bulk status received: %d",
 		dbg("%s - nonzero write bulk status received: %d",
-		    __FUNCTION__, urb->status);
+		    __FUNCTION__, status);
 	spin_lock_irqsave(&priv->lock, flags);
 	spin_lock_irqsave(&priv->lock, flags);
 	--priv->outstanding_urbs;
 	--priv->outstanding_urbs;
 	spin_unlock_irqrestore(&priv->lock, flags);
 	spin_unlock_irqrestore(&priv->lock, flags);

+ 23 - 38
drivers/usb/serial/ark3116.c

@@ -172,7 +172,7 @@ static void ark3116_set_termios(struct usb_serial_port *port,
 
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
 
-	if ((!port->tty) || (!port->tty->termios)) {
+	if (!port->tty || !port->tty->termios) {
 		dbg("%s - no tty structures", __FUNCTION__);
 		dbg("%s - no tty structures", __FUNCTION__);
 		return;
 		return;
 	}
 	}
@@ -188,16 +188,6 @@ static void ark3116_set_termios(struct usb_serial_port *port,
 
 
 	cflag = port->tty->termios->c_cflag;
 	cflag = port->tty->termios->c_cflag;
 
 
-	/* check that they really want us to change something: */
-	if (old_termios) {
-		if ((cflag == old_termios->c_cflag) &&
-		    (RELEVANT_IFLAG(port->tty->termios->c_iflag) ==
-		     RELEVANT_IFLAG(old_termios->c_iflag))) {
-			dbg("%s - nothing to change...", __FUNCTION__);
-			return;
-		}
-	}
-
 	buf = kmalloc(1, GFP_KERNEL);
 	buf = kmalloc(1, GFP_KERNEL);
 	if (!buf) {
 	if (!buf) {
 		dbg("error kmalloc");
 		dbg("error kmalloc");
@@ -220,7 +210,7 @@ static void ark3116_set_termios(struct usb_serial_port *port,
 			dbg("setting CS7");
 			dbg("setting CS7");
 			break;
 			break;
 		default:
 		default:
-			err("CSIZE was set but not CS5-CS8, using CS8!");
+			dbg("CSIZE was set but not CS5-CS8, using CS8!");
 			/* fall through */
 			/* fall through */
 		case CS8:
 		case CS8:
 			config |= 0x03;
 			config |= 0x03;
@@ -251,38 +241,33 @@ static void ark3116_set_termios(struct usb_serial_port *port,
 	}
 	}
 
 
 	/* set baudrate */
 	/* set baudrate */
-	baud = 0;
-	switch (cflag & CBAUD) {
-		case B0:
-			err("can't set 0 baud, using 9600 instead");
+	baud = tty_get_baud_rate(port->tty);
+
+	switch (baud) {
+		case 75:
+		case 150:
+		case 300:
+		case 600:
+		case 1200:
+		case 1800:
+		case 2400:
+		case 4800:
+		case 9600:
+		case 19200:
+		case 38400:
+		case 57600:
+		case 115200:
+		case 230400:
+		case 460800:
 			break;
 			break;
-		case B75:	baud = 75;	break;
-		case B150:	baud = 150;	break;
-		case B300:	baud = 300;	break;
-		case B600:	baud = 600;	break;
-		case B1200:	baud = 1200;	break;
-		case B1800:	baud = 1800;	break;
-		case B2400:	baud = 2400;	break;
-		case B4800:	baud = 4800;	break;
-		case B9600:	baud = 9600;	break;
-		case B19200:	baud = 19200;	break;
-		case B38400:	baud = 38400;	break;
-		case B57600:	baud = 57600;	break;
-		case B115200:	baud = 115200;	break;
-		case B230400:	baud = 230400;	break;
-		case B460800:	baud = 460800;	break;
+		/* set 9600 as default (if given baudrate is invalid for example) */
 		default:
 		default:
-			dbg("does not support the baudrate requested (fix it)");
-			break;
+			baud = 9600;
 	}
 	}
 
 
-	/* set 9600 as default (if given baudrate is invalid for example) */
-	if (baud == 0)
-		baud = 9600;
-
 	/*
 	/*
 	 * found by try'n'error, be careful, maybe there are other options
 	 * found by try'n'error, be careful, maybe there are other options
-	 * for multiplicator etc!
+	 * for multiplicator etc! (3.5 for example)
 	 */
 	 */
 	if (baud == 460800)
 	if (baud == 460800)
 		/* strange, for 460800 the formula is wrong
 		/* strange, for 460800 the formula is wrong

+ 33 - 45
drivers/usb/serial/belkin_sa.c

@@ -255,9 +255,10 @@ static void belkin_sa_read_int_callback (struct urb *urb)
 	struct belkin_sa_private *priv;
 	struct belkin_sa_private *priv;
 	unsigned char *data = urb->transfer_buffer;
 	unsigned char *data = urb->transfer_buffer;
 	int retval;
 	int retval;
+	int status = urb->status;
 	unsigned long flags;
 	unsigned long flags;
 
 
-	switch (urb->status) {
+	switch (status) {
 	case 0:
 	case 0:
 		/* success */
 		/* success */
 		break;
 		break;
@@ -265,10 +266,12 @@ static void belkin_sa_read_int_callback (struct urb *urb)
 	case -ENOENT:
 	case -ENOENT:
 	case -ESHUTDOWN:
 	case -ESHUTDOWN:
 		/* this urb is terminated, clean up */
 		/* this urb is terminated, clean up */
-		dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+		dbg("%s - urb shutting down with status: %d",
+		    __FUNCTION__, status);
 		return;
 		return;
 	default:
 	default:
-		dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+		dbg("%s - nonzero urb status received: %d",
+		    __FUNCTION__, status);
 		goto exit;
 		goto exit;
 	}
 	}
 
 
@@ -346,6 +349,7 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
 	unsigned long flags;
 	unsigned long flags;
 	unsigned long control_state;
 	unsigned long control_state;
 	int bad_flow_control;
 	int bad_flow_control;
+	speed_t baud;
 	
 	
 	if ((!port->tty) || (!port->tty->termios)) {
 	if ((!port->tty) || (!port->tty->termios)) {
 		dbg ("%s - no tty or termios structure", __FUNCTION__);
 		dbg ("%s - no tty or termios structure", __FUNCTION__);
@@ -361,16 +365,8 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
 	bad_flow_control = priv->bad_flow_control;
 	bad_flow_control = priv->bad_flow_control;
 	spin_unlock_irqrestore(&priv->lock, flags);
 	spin_unlock_irqrestore(&priv->lock, flags);
 	
 	
-	/* check that they really want us to change something */
-	if (old_termios) {
-		if ((cflag == old_termios->c_cflag) &&
-		    (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
-			dbg("%s - nothing to change...", __FUNCTION__);
-			return;
-		}
-		old_iflag = old_termios->c_iflag;
-		old_cflag = old_termios->c_cflag;
-	}
+	old_iflag = old_termios->c_iflag;
+	old_cflag = old_termios->c_cflag;
 
 
 	/* Set the baud rate */
 	/* Set the baud rate */
 	if( (cflag&CBAUD) != (old_cflag&CBAUD) ) {
 	if( (cflag&CBAUD) != (old_cflag&CBAUD) ) {
@@ -384,38 +380,30 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
 				if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 1) < 0)
 				if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 1) < 0)
 					err("Set RTS error");
 					err("Set RTS error");
 		}
 		}
+	}
 
 
-		switch(cflag & CBAUD) {
-			case B0: /* handled below */ break;
-			case B300: urb_value = BELKIN_SA_BAUD(300); break;
-			case B600: urb_value = BELKIN_SA_BAUD(600); break;
-			case B1200: urb_value = BELKIN_SA_BAUD(1200); break;
-			case B2400: urb_value = BELKIN_SA_BAUD(2400); break;
-			case B4800: urb_value = BELKIN_SA_BAUD(4800); break;
-			case B9600: urb_value = BELKIN_SA_BAUD(9600); break;
-			case B19200: urb_value = BELKIN_SA_BAUD(19200); break;
-			case B38400: urb_value = BELKIN_SA_BAUD(38400); break;
-			case B57600: urb_value = BELKIN_SA_BAUD(57600); break;
-			case B115200: urb_value = BELKIN_SA_BAUD(115200); break;
-			case B230400: urb_value = BELKIN_SA_BAUD(230400); break;
-			default: err("BELKIN USB Serial Adapter: unsupported baudrate request, using default of 9600");
-				urb_value = BELKIN_SA_BAUD(9600); break;
-		}
-		if ((cflag & CBAUD) != B0 ) {
-			if (BSA_USB_CMD(BELKIN_SA_SET_BAUDRATE_REQUEST, urb_value) < 0)
-				err("Set baudrate error");
-		} else {
-			/* Disable flow control */
-			if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, BELKIN_SA_FLOW_NONE) < 0)
-				err("Disable flowcontrol error");
-
-			/* Drop RTS and DTR */
-			control_state &= ~(TIOCM_DTR | TIOCM_RTS);
-			if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 0) < 0)
-				err("DTR LOW error");
-			if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 0) < 0)
-				err("RTS LOW error");
-		}
+	baud = tty_get_baud_rate(port->tty);
+	urb_value = BELKIN_SA_BAUD(baud);
+	/* Clip to maximum speed */
+	if (urb_value == 0)
+		urb_value = 1;
+	/* Turn it back into a resulting real baud rate */
+	baud = BELKIN_SA_BAUD(urb_value);
+	/* FIXME: Once the tty updates are done then push this back to the tty */
+
+	if ((cflag & CBAUD) != B0 ) {
+		if (BSA_USB_CMD(BELKIN_SA_SET_BAUDRATE_REQUEST, urb_value) < 0)
+			err("Set baudrate error");
+	} else {
+		/* Disable flow control */
+		if (BSA_USB_CMD(BELKIN_SA_SET_FLOW_CTRL_REQUEST, BELKIN_SA_FLOW_NONE) < 0)
+			err("Disable flowcontrol error");
+		/* Drop RTS and DTR */
+		control_state &= ~(TIOCM_DTR | TIOCM_RTS);
+		if (BSA_USB_CMD(BELKIN_SA_SET_DTR_REQUEST, 0) < 0)
+			err("DTR LOW error");
+		if (BSA_USB_CMD(BELKIN_SA_SET_RTS_REQUEST, 0) < 0)
+			err("RTS LOW error");
 	}
 	}
 
 
 	/* set the parity */
 	/* set the parity */
@@ -435,7 +423,7 @@ static void belkin_sa_set_termios (struct usb_serial_port *port, struct ktermios
 			case CS6: urb_value = BELKIN_SA_DATA_BITS(6); break;
 			case CS6: urb_value = BELKIN_SA_DATA_BITS(6); break;
 			case CS7: urb_value = BELKIN_SA_DATA_BITS(7); break;
 			case CS7: urb_value = BELKIN_SA_DATA_BITS(7); break;
 			case CS8: urb_value = BELKIN_SA_DATA_BITS(8); break;
 			case CS8: urb_value = BELKIN_SA_DATA_BITS(8); break;
-			default: err("CSIZE was not CS5-CS8, using default of 8");
+			default: dbg("CSIZE was not CS5-CS8, using default of 8");
 				urb_value = BELKIN_SA_DATA_BITS(8);
 				urb_value = BELKIN_SA_DATA_BITS(8);
 				break;
 				break;
 		}
 		}

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

@@ -305,12 +305,13 @@ static void cyberjack_read_int_callback( struct urb *urb )
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 	struct cyberjack_private *priv = usb_get_serial_port_data(port);
 	struct cyberjack_private *priv = usb_get_serial_port_data(port);
 	unsigned char *data = urb->transfer_buffer;
 	unsigned char *data = urb->transfer_buffer;
+	int status = urb->status;
 	int result;
 	int result;
 
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
 
 	/* the urb might have been killed. */
 	/* the urb might have been killed. */
-	if (urb->status)
+	if (status)
 		return;
 		return;
 
 
 	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
 	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
@@ -365,12 +366,14 @@ static void cyberjack_read_bulk_callback (struct urb *urb)
 	unsigned char *data = urb->transfer_buffer;
 	unsigned char *data = urb->transfer_buffer;
 	short todo;
 	short todo;
 	int result;
 	int result;
+	int status = urb->status;
 
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 	dbg("%s - port %d", __FUNCTION__, port->number);
-	
+
 	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
 	usb_serial_debug_data(debug, &port->dev, __FUNCTION__, urb->actual_length, data);
-	if (urb->status) {
-		dbg("%s - nonzero read bulk status received: %d", __FUNCTION__, urb->status);
+	if (status) {
+		dbg("%s - nonzero read bulk status received: %d",
+		    __FUNCTION__, status);
 		return;
 		return;
 	}
 	}
 
 
@@ -411,12 +414,14 @@ static void cyberjack_write_bulk_callback (struct urb *urb)
 {
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 	struct cyberjack_private *priv = usb_get_serial_port_data(port);
 	struct cyberjack_private *priv = usb_get_serial_port_data(port);
+	int status = urb->status;
 
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
 
 	port->write_urb_busy = 0;
 	port->write_urb_busy = 0;
-	if (urb->status) {
-		dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
+	if (status) {
+		dbg("%s - nonzero write bulk status received: %d",
+		    __FUNCTION__, status);
 		return;
 		return;
 	}
 	}
 
 

+ 11 - 7
drivers/usb/serial/cypress_m8.c

@@ -1275,10 +1275,11 @@ static void cypress_read_int_callback(struct urb *urb)
 	int bytes = 0;
 	int bytes = 0;
 	int result;
 	int result;
 	int i = 0;
 	int i = 0;
+	int status = urb->status;
 
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
 
-	switch (urb->status) {
+	switch (status) {
 	case 0: /* success */
 	case 0: /* success */
 		break;
 		break;
 	case -ECONNRESET:
 	case -ECONNRESET:
@@ -1292,7 +1293,7 @@ static void cypress_read_int_callback(struct urb *urb)
 	default:
 	default:
 		/* something ugly is going on... */
 		/* something ugly is going on... */
 		dev_err(&urb->dev->dev,"%s - unexpected nonzero read status received: %d\n",
 		dev_err(&urb->dev->dev,"%s - unexpected nonzero read status received: %d\n",
-			__FUNCTION__,urb->status);
+			__FUNCTION__, status);
 		cypress_set_dead(port);
 		cypress_set_dead(port);
 		return;
 		return;
 	}
 	}
@@ -1419,10 +1420,11 @@ static void cypress_write_int_callback(struct urb *urb)
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
 	struct cypress_private *priv = usb_get_serial_port_data(port);
 	struct cypress_private *priv = usb_get_serial_port_data(port);
 	int result;
 	int result;
+	int status = urb->status;
 
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 	dbg("%s - port %d", __FUNCTION__, port->number);
-	
-	switch (urb->status) {
+
+	switch (status) {
 		case 0:
 		case 0:
 			/* success */
 			/* success */
 			break;
 			break;
@@ -1430,7 +1432,8 @@ static void cypress_write_int_callback(struct urb *urb)
 		case -ENOENT:
 		case -ENOENT:
 		case -ESHUTDOWN:
 		case -ESHUTDOWN:
 			/* this urb is terminated, clean up */
 			/* this urb is terminated, clean up */
-			dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+			dbg("%s - urb shutting down with status: %d",
+			    __FUNCTION__, status);
 			priv->write_urb_in_use = 0;
 			priv->write_urb_in_use = 0;
 			return;
 			return;
 		case -EPIPE: /* no break needed; clear halt and resubmit */
 		case -EPIPE: /* no break needed; clear halt and resubmit */
@@ -1438,7 +1441,8 @@ static void cypress_write_int_callback(struct urb *urb)
 				break;
 				break;
 			usb_clear_halt(port->serial->dev, 0x02);
 			usb_clear_halt(port->serial->dev, 0x02);
 			/* error in the urb, so we have to resubmit it */
 			/* error in the urb, so we have to resubmit it */
-			dbg("%s - nonzero write bulk status received: %d", __FUNCTION__, urb->status);
+			dbg("%s - nonzero write bulk status received: %d",
+			    __FUNCTION__, status);
 			port->interrupt_out_urb->transfer_buffer_length = 1;
 			port->interrupt_out_urb->transfer_buffer_length = 1;
 			port->interrupt_out_urb->dev = port->serial->dev;
 			port->interrupt_out_urb->dev = port->serial->dev;
 			result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
 			result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
@@ -1450,7 +1454,7 @@ static void cypress_write_int_callback(struct urb *urb)
 			break;
 			break;
 		default:
 		default:
 			dev_err(&urb->dev->dev,"%s - unexpected nonzero write status received: %d\n",
 			dev_err(&urb->dev->dev,"%s - unexpected nonzero write status received: %d\n",
-				__FUNCTION__,urb->status);
+				__FUNCTION__, status);
 			cypress_set_dead(port);
 			cypress_set_dead(port);
 			break;
 			break;
 	}
 	}

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