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

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: (142 commits)
  USB: fix race in autosuspend reschedule
  atmel_usba_udc: Keep track of the device status
  USB: Nikon D40X unusual_devs entry
  USB: serial core should respect driver requirements
  USB: documentation for USB power management
  USB: skip autosuspended devices during system resume
  USB: mutual exclusion for EHCI init and port resets
  USB: allow usbstorage to have LUNS greater than 2Tb
  USB: Adding support for SHARP WS011SH to ipaq.c
  USB: add atmel_usba_udc driver
  USB: ohci SSB bus glue
  USB: ehci build fixes on au1xxx, ppc-soc
  USB: add runtime frame_no quirk for big-endian OHCI
  USB: funsoft: Fix termios
  USB: visor: termios bits
  USB: unusual_devs entry for Nikon DSC D2Xs
  USB: re-remove <linux/usb_sl811.h>
  USB: move <linux/usb_gadget.h> to <linux/usb/gadget.h>
  USB: Export URB statistics for powertop
  USB: serial gadget: Disable endpoints on unload
  ...
Linus Torvalds 17 жил өмнө
parent
commit
117494a1b6
100 өөрчлөгдсөн 7945 нэмэгдсэн , 3553 устгасан
  1. 92 0
      Documentation/usb/authorization.txt
  2. 517 0
      Documentation/usb/power-management.txt
  3. 11 0
      Documentation/usb/usb-serial.txt
  4. 8 1
      Documentation/usb/usbmon.txt
  5. 7 0
      MAINTAINERS
  6. 1 1
      arch/blackfin/mach-bf537/boards/generic_board.c
  7. 1 1
      arch/blackfin/mach-bf537/boards/pnav10.c
  8. 1 1
      arch/blackfin/mach-bf537/boards/stamp.c
  9. 1 21
      drivers/usb/Makefile
  10. 28 15
      drivers/usb/atm/cxacru.c
  11. 1 2
      drivers/usb/atm/speedtch.c
  12. 691 148
      drivers/usb/atm/ueagle-atm.c
  13. 70 46
      drivers/usb/class/usblp.c
  14. 19 5
      drivers/usb/core/config.c
  15. 46 31
      drivers/usb/core/devio.c
  16. 57 33
      drivers/usb/core/driver.c
  17. 0 1
      drivers/usb/core/endpoint.c
  18. 17 9
      drivers/usb/core/generic.c
  19. 420 298
      drivers/usb/core/hcd.c
  20. 34 12
      drivers/usb/core/hcd.h
  21. 204 72
      drivers/usb/core/hub.c
  22. 29 21
      drivers/usb/core/message.c
  23. 1 80
      drivers/usb/core/quirks.c
  24. 50 0
      drivers/usb/core/sysfs.c
  25. 61 45
      drivers/usb/core/urb.c
  26. 30 11
      drivers/usb/core/usb.c
  27. 5 0
      drivers/usb/core/usb.h
  28. 25 1
      drivers/usb/gadget/Kconfig
  29. 1 0
      drivers/usb/gadget/Makefile
  30. 3 6
      drivers/usb/gadget/amd5536udc.c
  31. 1 1
      drivers/usb/gadget/at91_udc.c
  32. 2077 0
      drivers/usb/gadget/atmel_usba_udc.c
  33. 352 0
      drivers/usb/gadget/atmel_usba_udc.h
  34. 1 1
      drivers/usb/gadget/config.c
  35. 46 47
      drivers/usb/gadget/dummy_hcd.c
  36. 1 1
      drivers/usb/gadget/epautoconf.c
  37. 67 88
      drivers/usb/gadget/ether.c
  38. 108 141
      drivers/usb/gadget/file_storage.c
  39. 5 8
      drivers/usb/gadget/fsl_usb2_udc.c
  40. 33 49
      drivers/usb/gadget/gmidi.c
  41. 1 1
      drivers/usb/gadget/goku_udc.c
  42. 21 25
      drivers/usb/gadget/inode.c
  43. 1 1
      drivers/usb/gadget/lh7a40x_udc.h
  44. 1 1
      drivers/usb/gadget/m66592-udc.c
  45. 1 1
      drivers/usb/gadget/net2280.c
  46. 4 8
      drivers/usb/gadget/omap_udc.c
  47. 1 1
      drivers/usb/gadget/pxa2xx_udc.c
  48. 1 1
      drivers/usb/gadget/s3c2410_udc.c
  49. 80 94
      drivers/usb/gadget/serial.c
  50. 1 1
      drivers/usb/gadget/usbstring.c
  51. 97 142
      drivers/usb/gadget/zero.c
  52. 13 0
      drivers/usb/host/Kconfig
  53. 2 4
      drivers/usb/host/ehci-au1xxx.c
  54. 17 5
      drivers/usb/host/ehci-hcd.c
  55. 1 4
      drivers/usb/host/ehci-pci.c
  56. 2 4
      drivers/usb/host/ehci-ppc-soc.c
  57. 1 1
      drivers/usb/host/ehci-ps3.c
  58. 51 48
      drivers/usb/host/ehci-q.c
  59. 33 14
      drivers/usb/host/ehci-sched.c
  60. 27 34
      drivers/usb/host/isp116x-hcd.c
  61. 4 4
      drivers/usb/host/ohci-dbg.c
  62. 180 54
      drivers/usb/host/ohci-hcd.c
  63. 0 1
      drivers/usb/host/ohci-mem.c
  64. 21 1
      drivers/usb/host/ohci-pci.c
  65. 4 1
      drivers/usb/host/ohci-ppc-of.c
  66. 5 0
      drivers/usb/host/ohci-ppc-soc.c
  67. 92 95
      drivers/usb/host/ohci-q.c
  68. 247 0
      drivers/usb/host/ohci-ssb.c
  69. 32 7
      drivers/usb/host/ohci.h
  70. 86 86
      drivers/usb/host/r8a66597-hcd.c
  71. 27 47
      drivers/usb/host/sl811-hcd.c
  72. 215 155
      drivers/usb/host/u132-hcd.c
  73. 2 2
      drivers/usb/host/uhci-debug.c
  74. 0 16
      drivers/usb/host/uhci-hcd.h
  75. 26 44
      drivers/usb/host/uhci-q.c
  76. 2 1
      drivers/usb/misc/adutux.c
  77. 5 2
      drivers/usb/misc/berry_charge.c
  78. 5 3
      drivers/usb/misc/ftdi-elan.c
  79. 41 159
      drivers/usb/misc/sisusbvga/sisusb.c
  80. 63 67
      drivers/usb/misc/sisusbvga/sisusb.h
  81. 5 55
      drivers/usb/misc/sisusbvga/sisusb_con.c
  82. 134 220
      drivers/usb/misc/sisusbvga/sisusb_init.c
  83. 657 657
      drivers/usb/misc/sisusbvga/sisusb_init.h
  84. 68 76
      drivers/usb/misc/sisusbvga/sisusb_struct.h
  85. 23 19
      drivers/usb/mon/mon_bin.c
  86. 8 17
      drivers/usb/mon/mon_main.c
  87. 37 35
      drivers/usb/mon/mon_text.c
  88. 1 1
      drivers/usb/mon/usb_mon.h
  89. 10 0
      drivers/usb/serial/Kconfig
  90. 1 0
      drivers/usb/serial/Makefile
  91. 0 5
      drivers/usb/serial/ark3116.c
  92. 16 0
      drivers/usb/serial/bus.c
  93. 354 0
      drivers/usb/serial/ch341.c
  94. 2 1
      drivers/usb/serial/cp2101.c
  95. 4 1
      drivers/usb/serial/ftdi_sio.c
  96. 0 21
      drivers/usb/serial/funsoft.c
  97. 3 0
      drivers/usb/serial/ipaq.c
  98. 18 10
      drivers/usb/serial/kl5kusb105.c
  99. 55 89
      drivers/usb/serial/kobil_sct.c
  100. 14 14
      drivers/usb/serial/mct_u232.c

+ 92 - 0
Documentation/usb/authorization.txt

@@ -0,0 +1,92 @@
+
+Authorizing (or not) your USB devices to connect to the system
+
+(C) 2007 Inaky Perez-Gonzalez <inaky@linux.intel.com> Intel Corporation
+
+This feature allows you to control if a USB device can be used (or
+not) in a system. This feature will allow you to implement a lock-down
+of USB devices, fully controlled by user space.
+
+As of now, when a USB device is connected it is configured and
+it's interfaces inmediately made available to the users. With this
+modification, only if root authorizes the device to be configured will
+then it be possible to use it.
+
+Usage:
+
+Authorize a device to connect:
+
+$ echo 1 > /sys/usb/devices/DEVICE/authorized
+
+Deauthorize a device:
+
+$ echo 0 > /sys/usb/devices/DEVICE/authorized
+
+Set new devices connected to hostX to be deauthorized by default (ie:
+lock down):
+
+$ echo 0 > /sys/bus/devices/usbX/authorized_default
+
+Remove the lock down:
+
+$ echo 1 > /sys/bus/devices/usbX/authorized_default
+
+By default, Wired USB devices are authorized by default to
+connect. Wireless USB hosts deauthorize by default all new connected
+devices (this is so because we need to do an authentication phase
+before authorizing).
+
+
+Example system lockdown (lame)
+-----------------------
+
+Imagine you want to implement a lockdown so only devices of type XYZ
+can be connected (for example, it is a kiosk machine with a visible
+USB port):
+
+boot up
+rc.local ->
+
+ for host in /sys/bus/devices/usb*
+ do
+    echo 0 > $host/authorized_default
+ done
+
+Hookup an script to udev, for new USB devices
+
+ if device_is_my_type $DEV
+ then
+   echo 1 > $device_path/authorized
+ done
+
+
+Now, device_is_my_type() is where the juice for a lockdown is. Just
+checking if the class, type and protocol match something is the worse
+security verification you can make (or the best, for someone willing
+to break it). If you need something secure, use crypto and Certificate
+Authentication or stuff like that. Something simple for an storage key
+could be:
+
+function device_is_my_type()
+{
+   echo 1 > authorized		# temporarily authorize it
+                                # FIXME: make sure none can mount it
+   mount DEVICENODE /mntpoint
+   sum=$(md5sum /mntpoint/.signature)
+   if [ $sum = $(cat /etc/lockdown/keysum) ]
+   then
+        echo "We are good, connected"
+        umount /mntpoint
+        # Other stuff so others can use it
+   else
+        echo 0 > authorized
+   fi
+}
+
+
+Of course, this is lame, you'd want to do a real certificate
+verification stuff with PKI, so you don't depend on a shared secret,
+etc, but you get the idea. Anybody with access to a device gadget kit
+can fake descriptors and device info. Don't trust that. You are
+welcome.
+

+ 517 - 0
Documentation/usb/power-management.txt

@@ -0,0 +1,517 @@
+			Power Management for USB
+
+		 Alan Stern <stern@rowland.harvard.edu>
+
+			    October 5, 2007
+
+
+
+	What is Power Management?
+	-------------------------
+
+Power Management (PM) is the practice of saving energy by suspending
+parts of a computer system when they aren't being used.  While a
+component is "suspended" it is in a nonfunctional low-power state; it
+might even be turned off completely.  A suspended component can be
+"resumed" (returned to a functional full-power state) when the kernel
+needs to use it.  (There also are forms of PM in which components are
+placed in a less functional but still usable state instead of being
+suspended; an example would be reducing the CPU's clock rate.  This
+document will not discuss those other forms.)
+
+When the parts being suspended include the CPU and most of the rest of
+the system, we speak of it as a "system suspend".  When a particular
+device is turned off while the system as a whole remains running, we
+call it a "dynamic suspend" (also known as a "runtime suspend" or
+"selective suspend").  This document concentrates mostly on how
+dynamic PM is implemented in the USB subsystem, although system PM is
+covered to some extent (see Documentation/power/*.txt for more
+information about system PM).
+
+Note: Dynamic PM support for USB is present only if the kernel was
+built with CONFIG_USB_SUSPEND enabled.  System PM support is present
+only if the kernel was built with CONFIG_SUSPEND or CONFIG_HIBERNATION
+enabled.
+
+
+	What is Remote Wakeup?
+	----------------------
+
+When a device has been suspended, it generally doesn't resume until
+the computer tells it to.  Likewise, if the entire computer has been
+suspended, it generally doesn't resume until the user tells it to, say
+by pressing a power button or opening the cover.
+
+However some devices have the capability of resuming by themselves, or
+asking the kernel to resume them, or even telling the entire computer
+to resume.  This capability goes by several names such as "Wake On
+LAN"; we will refer to it generically as "remote wakeup".  When a
+device is enabled for remote wakeup and it is suspended, it may resume
+itself (or send a request to be resumed) in response to some external
+event.  Examples include a suspended keyboard resuming when a key is
+pressed, or a suspended USB hub resuming when a device is plugged in.
+
+
+	When is a USB device idle?
+	--------------------------
+
+A device is idle whenever the kernel thinks it's not busy doing
+anything important and thus is a candidate for being suspended.  The
+exact definition depends on the device's driver; drivers are allowed
+to declare that a device isn't idle even when there's no actual
+communication taking place.  (For example, a hub isn't considered idle
+unless all the devices plugged into that hub are already suspended.)
+In addition, a device isn't considered idle so long as a program keeps
+its usbfs file open, whether or not any I/O is going on.
+
+If a USB device has no driver, its usbfs file isn't open, and it isn't
+being accessed through sysfs, then it definitely is idle.
+
+
+	Forms of dynamic PM
+	-------------------
+
+Dynamic suspends can occur in two ways: manual and automatic.
+"Manual" means that the user has told the kernel to suspend a device,
+whereas "automatic" means that the kernel has decided all by itself to
+suspend a device.  Automatic suspend is called "autosuspend" for
+short.  In general, a device won't be autosuspended unless it has been
+idle for some minimum period of time, the so-called idle-delay time.
+
+Of course, nothing the kernel does on its own initiative should
+prevent the computer or its devices from working properly.  If a
+device has been autosuspended and a program tries to use it, the
+kernel will automatically resume the device (autoresume).  For the
+same reason, an autosuspended device will usually have remote wakeup
+enabled, if the device supports remote wakeup.
+
+It is worth mentioning that many USB drivers don't support
+autosuspend.  In fact, at the time of this writing (Linux 2.6.23) the
+only drivers which do support it are the hub driver, kaweth, asix,
+usblp, usblcd, and usb-skeleton (which doesn't count).  If a
+non-supporting driver is bound to a device, the device won't be
+autosuspended.  In effect, the kernel pretends the device is never
+idle.
+
+We can categorize power management events in two broad classes:
+external and internal.  External events are those triggered by some
+agent outside the USB stack: system suspend/resume (triggered by
+userspace), manual dynamic suspend/resume (also triggered by
+userspace), and remote wakeup (triggered by the device).  Internal
+events are those triggered within the USB stack: autosuspend and
+autoresume.
+
+
+	The user interface for dynamic PM
+	---------------------------------
+
+The user interface for controlling dynamic PM is located in the power/
+subdirectory of each USB device's sysfs directory, that is, in
+/sys/bus/usb/devices/.../power/ where "..." is the device's ID.  The
+relevant attribute files are: wakeup, level, and autosuspend.
+
+	power/wakeup
+
+		This file is empty if the device does not support
+		remote wakeup.  Otherwise the file contains either the
+		word "enabled" or the word "disabled", and you can
+		write those words to the file.  The setting determines
+		whether or not remote wakeup will be enabled when the
+		device is next suspended.  (If the setting is changed
+		while the device is suspended, the change won't take
+		effect until the following suspend.)
+
+	power/level
+
+		This file contains one of three words: "on", "auto",
+		or "suspend".  You can write those words to the file
+		to change the device's setting.
+
+		"on" means that the device should be resumed and
+		autosuspend is not allowed.  (Of course, system
+		suspends are still allowed.)
+
+		"auto" is the normal state in which the kernel is
+		allowed to autosuspend and autoresume the device.
+
+		"suspend" means that the device should remain
+		suspended, and autoresume is not allowed.  (But remote
+		wakeup may still be allowed, since it is controlled
+		separately by the power/wakeup attribute.)
+
+	power/autosuspend
+
+		This file contains an integer value, which is the
+		number of seconds the device should remain idle before
+		the kernel will autosuspend it (the idle-delay time).
+		The default is 2.  0 means to autosuspend as soon as
+		the device becomes idle, and -1 means never to
+		autosuspend.  You can write a number to the file to
+		change the autosuspend idle-delay time.
+
+Writing "-1" to power/autosuspend and writing "on" to power/level do
+essentially the same thing -- they both prevent the device from being
+autosuspended.  Yes, this is a redundancy in the API.
+
+(In 2.6.21 writing "0" to power/autosuspend would prevent the device
+from being autosuspended; the behavior was changed in 2.6.22.  The
+power/autosuspend attribute did not exist prior to 2.6.21, and the
+power/level attribute did not exist prior to 2.6.22.)
+
+
+	Changing the default idle-delay time
+	------------------------------------
+
+The default autosuspend idle-delay time is controlled by a module
+parameter in usbcore.  You can specify the value when usbcore is
+loaded.  For example, to set it to 5 seconds instead of 2 you would
+do:
+
+	modprobe usbcore autosuspend=5
+
+Equivalently, you could add to /etc/modprobe.conf a line saying:
+
+	options usbcore autosuspend=5
+
+Some distributions load the usbcore module very early during the boot
+process, by means of a program or script running from an initramfs
+image.  To alter the parameter value you would have to rebuild that
+image.
+
+If usbcore is compiled into the kernel rather than built as a loadable
+module, you can add
+
+	usbcore.autosuspend=5
+
+to the kernel's boot command line.
+
+Finally, the parameter value can be changed while the system is
+running.  If you do:
+
+	echo 5 >/sys/module/usbcore/parameters/autosuspend
+
+then each new USB device will have its autosuspend idle-delay
+initialized to 5.  (The idle-delay values for already existing devices
+will not be affected.)
+
+Setting the initial default idle-delay to -1 will prevent any
+autosuspend of any USB device.  This is a simple alternative to
+disabling CONFIG_USB_SUSPEND and rebuilding the kernel, and it has the
+added benefit of allowing you to enable autosuspend for selected
+devices.
+
+
+	Warnings
+	--------
+
+The USB specification states that all USB devices must support power
+management.  Nevertheless, the sad fact is that many devices do not
+support it very well.  You can suspend them all right, but when you
+try to resume them they disconnect themselves from the USB bus or
+they stop working entirely.  This seems to be especially prevalent
+among printers and scanners, but plenty of other types of device have
+the same deficiency.
+
+For this reason, by default the kernel disables autosuspend (the
+power/level attribute is initialized to "on") for all devices other
+than hubs.  Hubs, at least, appear to be reasonably well-behaved in
+this regard.
+
+(In 2.6.21 and 2.6.22 this wasn't the case.  Autosuspend was enabled
+by default for almost all USB devices.  A number of people experienced
+problems as a result.)
+
+This means that non-hub devices won't be autosuspended unless the user
+or a program explicitly enables it.  As of this writing there aren't
+any widespread programs which will do this; we hope that in the near
+future device managers such as HAL will take on this added
+responsibility.  In the meantime you can always carry out the
+necessary operations by hand or add them to a udev script.  You can
+also change the idle-delay time; 2 seconds is not the best choice for
+every device.
+
+Sometimes it turns out that even when a device does work okay with
+autosuspend there are still problems.  For example, there are
+experimental patches adding autosuspend support to the usbhid driver,
+which manages keyboards and mice, among other things.  Tests with a
+number of keyboards showed that typing on a suspended keyboard, while
+causing the keyboard to do a remote wakeup all right, would
+nonetheless frequently result in lost keystrokes.  Tests with mice
+showed that some of them would issue a remote-wakeup request in
+response to button presses but not to motion, and some in response to
+neither.
+
+The kernel will not prevent you from enabling autosuspend on devices
+that can't handle it.  It is even possible in theory to damage a
+device by suspending it at the wrong time -- for example, suspending a
+USB hard disk might cause it to spin down without parking the heads.
+(Highly unlikely, but possible.)  Take care.
+
+
+	The driver interface for Power Management
+	-----------------------------------------
+
+The requirements for a USB driver to support external power management
+are pretty modest; the driver need only define
+
+	.suspend
+	.resume
+	.reset_resume
+
+methods in its usb_driver structure, and the reset_resume method is
+optional.  The methods' jobs are quite simple:
+
+	The suspend method is called to warn the driver that the
+	device is going to be suspended.  If the driver returns a
+	negative error code, the suspend will be aborted.  Normally
+	the driver will return 0, in which case it must cancel all
+	outstanding URBs (usb_kill_urb()) and not submit any more.
+
+	The resume method is called to tell the driver that the
+	device has been resumed and the driver can return to normal
+	operation.  URBs may once more be submitted.
+
+	The reset_resume method is called to tell the driver that
+	the device has been resumed and it also has been reset.
+	The driver should redo any necessary device initialization,
+	since the device has probably lost most or all of its state
+	(although the interfaces will be in the same altsettings as
+	before the suspend).
+
+The reset_resume method is used by the USB Persist facility (see
+Documentation/usb/persist.txt) and it can also be used under certain
+circumstances when CONFIG_USB_PERSIST is not enabled.  Currently, if a
+device is reset during a resume and the driver does not have a
+reset_resume method, the driver won't receive any notification about
+the resume.  Later kernels will call the driver's disconnect method;
+2.6.23 doesn't do this.
+
+USB drivers are bound to interfaces, so their suspend and resume
+methods get called when the interfaces are suspended or resumed.  In
+principle one might want to suspend some interfaces on a device (i.e.,
+force the drivers for those interface to stop all activity) without
+suspending the other interfaces.  The USB core doesn't allow this; all
+interfaces are suspended when the device itself is suspended and all
+interfaces are resumed when the device is resumed.  It isn't possible
+to suspend or resume some but not all of a device's interfaces.  The
+closest you can come is to unbind the interfaces' drivers.
+
+
+	The driver interface for autosuspend and autoresume
+	---------------------------------------------------
+
+To support autosuspend and autoresume, a driver should implement all
+three of the methods listed above.  In addition, a driver indicates
+that it supports autosuspend by setting the .supports_autosuspend flag
+in its usb_driver structure.  It is then responsible for informing the
+USB core whenever one of its interfaces becomes busy or idle.  The
+driver does so by calling these three functions:
+
+	int  usb_autopm_get_interface(struct usb_interface *intf);
+	void usb_autopm_put_interface(struct usb_interface *intf);
+	int  usb_autopm_set_interface(struct usb_interface *intf);
+
+The functions work by maintaining a counter in the usb_interface
+structure.  When intf->pm_usage_count is > 0 then the interface is
+deemed to be busy, and the kernel will not autosuspend the interface's
+device.  When intf->pm_usage_count is <= 0 then the interface is
+considered to be idle, and the kernel may autosuspend the device.
+
+(There is a similar pm_usage_count field in struct usb_device,
+associated with the device itself rather than any of its interfaces.
+This field is used only by the USB core.)
+
+The driver owns intf->pm_usage_count; it can modify the value however
+and whenever it likes.  A nice aspect of the usb_autopm_* routines is
+that the changes they make are protected by the usb_device structure's
+PM mutex (udev->pm_mutex); however drivers may change pm_usage_count
+without holding the mutex.
+
+	usb_autopm_get_interface() increments pm_usage_count and
+	attempts an autoresume if the new value is > 0 and the
+	device is suspended.
+
+	usb_autopm_put_interface() decrements pm_usage_count and
+	attempts an autosuspend if the new value is <= 0 and the
+	device isn't suspended.
+
+	usb_autopm_set_interface() leaves pm_usage_count alone.
+	It attempts an autoresume if the value is > 0 and the device
+	is suspended, and it attempts an autosuspend if the value is
+	<= 0 and the device isn't suspended.
+
+There also are a couple of utility routines drivers can use:
+
+	usb_autopm_enable() sets pm_usage_cnt to 1 and then calls
+	usb_autopm_set_interface(), which will attempt an autoresume.
+
+	usb_autopm_disable() sets pm_usage_cnt to 0 and then calls
+	usb_autopm_set_interface(), which will attempt an autosuspend.
+
+The conventional usage pattern is that a driver calls
+usb_autopm_get_interface() in its open routine and
+usb_autopm_put_interface() in its close or release routine.  But
+other patterns are possible.
+
+The autosuspend attempts mentioned above will often fail for one
+reason or another.  For example, the power/level attribute might be
+set to "on", or another interface in the same device might not be
+idle.  This is perfectly normal.  If the reason for failure was that
+the device hasn't been idle for long enough, a delayed workqueue
+routine is automatically set up to carry out the operation when the
+autosuspend idle-delay has expired.
+
+Autoresume attempts also can fail.  This will happen if power/level is
+set to "suspend" or if the device doesn't manage to resume properly.
+Unlike autosuspend, there's no delay for an autoresume.
+
+
+	Other parts of the driver interface
+	-----------------------------------
+
+Sometimes a driver needs to make sure that remote wakeup is enabled
+during autosuspend.  For example, there's not much point
+autosuspending a keyboard if the user can't cause the keyboard to do a
+remote wakeup by typing on it.  If the driver sets
+intf->needs_remote_wakeup to 1, the kernel won't autosuspend the
+device if remote wakeup isn't available or has been disabled through
+the power/wakeup attribute.  (If the device is already autosuspended,
+though, setting this flag won't cause the kernel to autoresume it.
+Normally a driver would set this flag in its probe method, at which
+time the device is guaranteed not to be autosuspended.)
+
+The usb_autopm_* routines have to run in a sleepable process context;
+they must not be called from an interrupt handler or while holding a
+spinlock.  In fact, the entire autosuspend mechanism is not well geared
+toward interrupt-driven operation.  However there is one thing a
+driver can do in an interrupt handler:
+
+	usb_mark_last_busy(struct usb_device *udev);
+
+This sets udev->last_busy to the current time.  udev->last_busy is the
+field used for idle-delay calculations; updating it will cause any
+pending autosuspend to be moved back.  The usb_autopm_* routines will
+also set the last_busy field to the current time.
+
+Calling urb_mark_last_busy() from within an URB completion handler is
+subject to races: The kernel may have just finished deciding the
+device has been idle for long enough but not yet gotten around to
+calling the driver's suspend method.  The driver would have to be
+responsible for synchronizing its suspend method with its URB
+completion handler and causing the autosuspend to fail with -EBUSY if
+an URB had completed too recently.
+
+External suspend calls should never be allowed to fail in this way,
+only autosuspend calls.  The driver can tell them apart by checking
+udev->auto_pm; this flag will be set to 1 for internal PM events
+(autosuspend or autoresume) and 0 for external PM events.
+
+Many of the ingredients in the autosuspend framework are oriented
+towards interfaces: The usb_interface structure contains the
+pm_usage_cnt field, and the usb_autopm_* routines take an interface
+pointer as their argument.  But somewhat confusingly, a few of the
+pieces (usb_mark_last_busy() and udev->auto_pm) use the usb_device
+structure instead.  Drivers need to keep this straight; they can call
+interface_to_usbdev() to find the device structure for a given
+interface.
+
+
+	Locking requirements
+	--------------------
+
+All three suspend/resume methods are always called while holding the
+usb_device's PM mutex.  For external events -- but not necessarily for
+autosuspend or autoresume -- the device semaphore (udev->dev.sem) will
+also be held.  This implies that external suspend/resume events are
+mutually exclusive with calls to probe, disconnect, pre_reset, and
+post_reset; the USB core guarantees that this is true of internal
+suspend/resume events as well.
+
+If a driver wants to block all suspend/resume calls during some
+critical section, it can simply acquire udev->pm_mutex.
+Alternatively, if the critical section might call some of the
+usb_autopm_* routines, the driver can avoid deadlock by doing:
+
+	down(&udev->dev.sem);
+	rc = usb_autopm_get_interface(intf);
+
+and at the end of the critical section:
+
+	if (!rc)
+		usb_autopm_put_interface(intf);
+	up(&udev->dev.sem);
+
+Holding the device semaphore will block all external PM calls, and the
+usb_autopm_get_interface() will prevent any internal PM calls, even if
+it fails.  (Exercise: Why?)
+
+The rules for locking order are:
+
+	Never acquire any device semaphore while holding any PM mutex.
+
+	Never acquire udev->pm_mutex while holding the PM mutex for
+	a device that isn't a descendant of udev.
+
+In other words, PM mutexes should only be acquired going up the device
+tree, and they should be acquired only after locking all the device
+semaphores you need to hold.  These rules don't matter to drivers very
+much; they usually affect just the USB core.
+
+Still, drivers do need to be careful.  For example, many drivers use a
+private mutex to synchronize their normal I/O activities with their
+disconnect method.  Now if the driver supports autosuspend then it
+must call usb_autopm_put_interface() from somewhere -- maybe from its
+close method.  It should make the call while holding the private mutex,
+since a driver shouldn't call any of the usb_autopm_* functions for an
+interface from which it has been unbound.
+
+But the usb_autpm_* routines always acquire the device's PM mutex, and
+consequently the locking order has to be: private mutex first, PM
+mutex second.  Since the suspend method is always called with the PM
+mutex held, it mustn't try to acquire the private mutex.  It has to
+synchronize with the driver's I/O activities in some other way.
+
+
+	Interaction between dynamic PM and system PM
+	--------------------------------------------
+
+Dynamic power management and system power management can interact in
+a couple of ways.
+
+Firstly, a device may already be manually suspended or autosuspended
+when a system suspend occurs.  Since system suspends are supposed to
+be as transparent as possible, the device should remain suspended
+following the system resume.  The 2.6.23 kernel obeys this principle
+for manually suspended devices but not for autosuspended devices; they
+do get resumed when the system wakes up.  (Presumably they will be
+autosuspended again after their idle-delay time expires.)  In later
+kernels this behavior will be fixed.
+
+(There is an exception.  If a device would undergo a reset-resume
+instead of a normal resume, and the device is enabled for remote
+wakeup, then the reset-resume takes place even if the device was
+already suspended when the system suspend began.  The justification is
+that a reset-resume is a kind of remote-wakeup event.  Or to put it
+another way, a device which needs a reset won't be able to generate
+normal remote-wakeup signals, so it ought to be resumed immediately.)
+
+Secondly, a dynamic power-management event may occur as a system
+suspend is underway.  The window for this is short, since system
+suspends don't take long (a few seconds usually), but it can happen.
+For example, a suspended device may send a remote-wakeup signal while
+the system is suspending.  The remote wakeup may succeed, which would
+cause the system suspend to abort.  If the remote wakeup doesn't
+succeed, it may still remain active and thus cause the system to
+resume as soon as the system suspend is complete.  Or the remote
+wakeup may fail and get lost.  Which outcome occurs depends on timing
+and on the hardware and firmware design.
+
+More interestingly, a device might undergo a manual resume or
+autoresume during system suspend.  With current kernels this shouldn't
+happen, because manual resumes must be initiated by userspace and
+autoresumes happen in response to I/O requests, but all user processes
+and I/O should be quiescent during a system suspend -- thanks to the
+freezer.  However there are plans to do away with the freezer, which
+would mean these things would become possible.  If and when this comes
+about, the USB core will carefully arrange matters so that either type
+of resume will block until the entire system has resumed.

+ 11 - 0
Documentation/usb/usb-serial.txt

@@ -428,6 +428,17 @@ Options supported:
   See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
   information on this driver.
 
+Winchiphead CH341 Driver
+
+  This driver is for the Winchiphead CH341 USB-RS232 Converter. This chip
+  also implements an IEEE 1284 parallel port, I2C and SPI, but that is not
+  supported by the driver. The protocol was analyzed from the behaviour
+  of the Windows driver, no datasheet is available at present.
+  The manufacturer's website: http://www.winchiphead.com/.
+  For any questions or problems with this driver, please contact
+  frank@kingswood-consulting.co.uk.
+
+
 Generic Serial driver
 
   If your device is not one of the above listed devices, compatible with

+ 8 - 1
Documentation/usb/usbmon.txt

@@ -34,9 +34,12 @@ if usbmon is built into the kernel.
 Verify that bus sockets are present.
 
 # ls /sys/kernel/debug/usbmon
-1s  1t  1u  2s  2t  2u  3s  3t  3u  4s  4t  4u
+0s  0t  0u  1s  1t  1u  2s  2t  2u  3s  3t  3u  4s  4t  4u
 #
 
+Now you can choose to either use the sockets numbered '0' (to capture packets on
+all buses), and skip to step #3, or find the bus used by your device with step #2.
+
 2. Find which bus connects to the desired device
 
 Run "cat /proc/bus/usb/devices", and find the T-line which corresponds to
@@ -56,6 +59,10 @@ Bus=03 means it's bus 3.
 
 # cat /sys/kernel/debug/usbmon/3u > /tmp/1.mon.out
 
+to listen on a single bus, otherwise, to listen on all buses, type:
+
+# cat /sys/kernel/debug/usbmon/0u > /tmp/1.mon.out
+
 This process will be reading until killed. Naturally, the output can be
 redirected to a desirable location. This is preferred, because it is going
 to be quite long.

+ 7 - 0
MAINTAINERS

@@ -677,6 +677,13 @@ P:	Haavard Skinnemoen
 M:	hskinnemoen@atmel.com
 S:	Supported
 
+ATMEL USBA UDC DRIVER
+P:	Haavard Skinnemoen
+M:	hskinnemoen@atmel.com
+L:	kernel@avr32linux.org
+W:	http://avr32linux.org/twiki/bin/view/Main/AtmelUsbDeviceDriver
+S:	Supported
+
 ATMEL WIRELESS DRIVER
 P:	Simon Kelley
 M:	simon@thekelleys.org.uk

+ 1 - 1
arch/blackfin/mach-bf537/boards/generic_board.c

@@ -40,7 +40,7 @@
 #include <linux/pata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.h>

+ 1 - 1
arch/blackfin/mach-bf537/boards/pnav10.c

@@ -40,7 +40,7 @@
 #include <linux/irq.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 
 #include <linux/spi/ad7877.h>
 

+ 1 - 1
arch/blackfin/mach-bf537/boards/stamp.c

@@ -40,7 +40,7 @@
 #include <linux/pata_platform.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.h>

+ 1 - 21
drivers/usb/Makefile

@@ -28,27 +28,7 @@ obj-$(CONFIG_USB_MICROTEK)	+= image/
 
 obj-$(CONFIG_USB_SERIAL)	+= serial/
 
-obj-$(CONFIG_USB_ADUTUX)	+= misc/
-obj-$(CONFIG_USB_APPLEDISPLAY)	+= misc/
-obj-$(CONFIG_USB_AUERSWALD)	+= misc/
-obj-$(CONFIG_USB_BERRY_CHARGE)	+= misc/
-obj-$(CONFIG_USB_CYPRESS_CY7C63)+= misc/
-obj-$(CONFIG_USB_CYTHERM)	+= misc/
-obj-$(CONFIG_USB_EMI26)		+= misc/
-obj-$(CONFIG_USB_EMI62)		+= misc/
-obj-$(CONFIG_USB_FTDI_ELAN)	+= misc/
-obj-$(CONFIG_USB_IDMOUSE)	+= misc/
-obj-$(CONFIG_USB_LCD)		+= misc/
-obj-$(CONFIG_USB_LD)		+= misc/
-obj-$(CONFIG_USB_LED)		+= misc/
-obj-$(CONFIG_USB_LEGOTOWER)	+= misc/
-obj-$(CONFIG_USB_PHIDGETSERVO)	+= misc/
-obj-$(CONFIG_USB_RIO500)	+= misc/
-obj-$(CONFIG_USB_SISUSBVGA)	+= misc/
-obj-$(CONFIG_USB_TEST)		+= misc/
-obj-$(CONFIG_USB_TRANCEVIBRATOR)+= misc/
-obj-$(CONFIG_USB_USS720)	+= misc/
-obj-$(CONFIG_USB_IOWARRIOR)	+= misc/
+obj-$(CONFIG_USB)		+= misc/
 
 obj-$(CONFIG_USB_ATM)		+= atm/
 obj-$(CONFIG_USB_SPEEDTOUCH)	+= atm/

+ 28 - 15
drivers/usb/atm/cxacru.c

@@ -482,7 +482,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
 	int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE;
 
 	if (wbuflen > PAGE_SIZE || rbuflen > PAGE_SIZE) {
-		dbg("too big transfer requested");
+		if (printk_ratelimit())
+			usb_err(instance->usbatm, "requested transfer size too large (%d, %d)\n",
+				wbuflen, rbuflen);
 		ret = -ENOMEM;
 		goto fail;
 	}
@@ -493,8 +495,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
 	init_completion(&instance->rcv_done);
 	ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL);
 	if (ret < 0) {
-		dbg("submitting read urb for cm %#x failed", cm);
-		ret = ret;
+		if (printk_ratelimit())
+			usb_err(instance->usbatm, "submit of read urb for cm %#x failed (%d)\n",
+				cm, ret);
 		goto fail;
 	}
 
@@ -510,27 +513,29 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
 	init_completion(&instance->snd_done);
 	ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL);
 	if (ret < 0) {
-		dbg("submitting write urb for cm %#x failed", cm);
-		ret = ret;
+		if (printk_ratelimit())
+			usb_err(instance->usbatm, "submit of write urb for cm %#x failed (%d)\n",
+				cm, ret);
 		goto fail;
 	}
 
 	ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL);
 	if (ret < 0) {
-		dbg("sending cm %#x failed", cm);
-		ret = ret;
+		if (printk_ratelimit())
+			usb_err(instance->usbatm, "send of cm %#x failed (%d)\n", cm, ret);
 		goto fail;
 	}
 
 	ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen);
 	if (ret < 0) {
-		dbg("receiving cm %#x failed", cm);
-		ret = ret;
+		if (printk_ratelimit())
+			usb_err(instance->usbatm, "receive of cm %#x failed (%d)\n", cm, ret);
 		goto fail;
 	}
 	if (actlen % CMD_PACKET_SIZE || !actlen) {
-		dbg("response is not a positive multiple of %d: %#x",
-				CMD_PACKET_SIZE, actlen);
+		if (printk_ratelimit())
+			usb_err(instance->usbatm, "invalid response length to cm %#x: %d\n",
+				cm, actlen);
 		ret = -EIO;
 		goto fail;
 	}
@@ -538,12 +543,16 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
 	/* check the return status and copy the data to the output buffer, if needed */
 	for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) {
 		if (rbuf[offb] != cm) {
-			dbg("wrong cm %#x in response", rbuf[offb]);
+			if (printk_ratelimit())
+				usb_err(instance->usbatm, "wrong cm %#x in response to cm %#x\n",
+					rbuf[offb], cm);
 			ret = -EIO;
 			goto fail;
 		}
 		if (rbuf[offb + 1] != CM_STATUS_SUCCESS) {
-			dbg("response failed: %#x", rbuf[offb + 1]);
+			if (printk_ratelimit())
+				usb_err(instance->usbatm, "response to cm %#x failed: %#x\n",
+					cm, rbuf[offb + 1]);
 			ret = -EIO;
 			goto fail;
 		}
@@ -582,14 +591,18 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ
 	for (offb = 0; offb < len; ) {
 		int l = le32_to_cpu(buf[offb++]);
 		if (l > stride || l > (len - offb) / 2) {
-			dbg("wrong data length %#x in response", l);
+			if (printk_ratelimit())
+				usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n",
+					cm, l);
 			ret = -EIO;
 			goto cleanup;
 		}
 		while (l--) {
 			offd = le32_to_cpu(buf[offb++]);
 			if (offd >= size) {
-				dbg("wrong index %#x in response", offd);
+				if (printk_ratelimit())
+					usb_err(instance->usbatm, "wrong index #%x in response to cm #%x\n",
+						offd, cm);
 				ret = -EIO;
 				goto cleanup;
 			}

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

@@ -251,7 +251,6 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
 {
 	unsigned char *buffer;
 	struct usbatm_data *usbatm = instance->usbatm;
-	struct usb_interface *intf;
 	struct usb_device *usb_dev = usbatm->usb_dev;
 	int actual_length;
 	int ret = 0;
@@ -265,7 +264,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
 		goto out;
 	}
 
-	if (!(intf = usb_ifnum_to_if(usb_dev, 2))) {
+	if (!usb_ifnum_to_if(usb_dev, 2)) {
 		ret = -ENODEV;
 		usb_dbg(usbatm, "%s: interface not found!\n", __func__);
 		goto out_free;

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 691 - 148
drivers/usb/atm/ueagle-atm.c


+ 70 - 46
drivers/usb/class/usblp.c

@@ -28,6 +28,7 @@
  *	v0.12 - add hpoj.sourceforge.net ioctls (David Paschal)
  *	v0.13 - alloc space for statusbuf (<status> not on stack);
  *		use usb_buffer_alloc() for read buf & write buf;
+ *      none  - Maintained in Linux kernel after v0.13
  */
 
 /*
@@ -69,7 +70,6 @@
 #define USBLP_DEVICE_ID_SIZE	1024
 
 /* ioctls: */
-#define LPGETSTATUS		0x060b		/* same as in drivers/char/lp.c */
 #define IOCNR_GET_DEVICE_ID		1
 #define IOCNR_GET_PROTOCOLS		2
 #define IOCNR_SET_PROTOCOL		3
@@ -115,7 +115,7 @@ MFG:HEWLETT-PACKARD;MDL:DESKJET 970C;CMD:MLC,PCL,PML;CLASS:PRINTER;DESCRIPTION:H
 #define USBLP_MINORS		16
 #define USBLP_MINOR_BASE	0
 
-#define USBLP_WRITE_TIMEOUT	(5000)			/* 5 seconds */
+#define USBLP_CTL_TIMEOUT	5000			/* 5 seconds */
 
 #define USBLP_FIRST_PROTOCOL	1
 #define USBLP_LAST_PROTOCOL	3
@@ -159,10 +159,12 @@ struct usblp {
 	int			wstatus;	/* bytes written or error */
 	int			rstatus;	/* bytes ready or error */
 	unsigned int		quirks;			/* quirks flags */
+	unsigned int		flags;			/* mode flags */
 	unsigned char		used;			/* True if open */
 	unsigned char		present;		/* True if not disconnected */
 	unsigned char		bidir;			/* interface is bidirectional */
 	unsigned char		sleeping;		/* interface is suspended */
+	unsigned char		no_paper;		/* Paper Out happened */
 	unsigned char		*device_id_string;	/* IEEE 1284 DEVICE ID string (ptr) */
 							/* first 2 bytes are (big-endian) length */
 };
@@ -259,7 +261,7 @@ static int usblp_ctrl_msg(struct usblp *usblp, int request, int type, int dir, i
 
 	retval = usb_control_msg(usblp->dev,
 		dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
-		request, type | dir | recip, value, index, buf, len, USBLP_WRITE_TIMEOUT);
+		request, type | dir | recip, value, index, buf, len, USBLP_CTL_TIMEOUT);
 	dbg("usblp_control_msg: rq: 0x%02x dir: %d recip: %d value: %d idx: %d len: %#x result: %d",
 		request, !!dir, recip, value, index, len, retval);
 	return retval < 0 ? retval : 0;
@@ -325,13 +327,11 @@ static void usblp_bulk_write(struct urb *urb)
 		usblp->wstatus = status;
 	else
 		usblp->wstatus = urb->actual_length;
+	usblp->no_paper = 0;
 	usblp->wcomplete = 1;
 	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);
 }
 
@@ -346,16 +346,17 @@ static int usblp_check_status(struct usblp *usblp, int err)
 	unsigned char status, newerr = 0;
 	int error;
 
-	error = usblp_read_status (usblp, usblp->statusbuf);
-	if (error < 0) {
+	mutex_lock(&usblp->mut);
+	if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) {
+		mutex_unlock(&usblp->mut);
 		if (printk_ratelimit())
 			printk(KERN_ERR
 				"usblp%d: error %d reading printer status\n",
 				usblp->minor, error);
 		return 0;
 	}
-
 	status = *usblp->statusbuf;
+	mutex_unlock(&usblp->mut);
 
 	if (~status & LP_PERRORP)
 		newerr = 3;
@@ -411,18 +412,10 @@ static int usblp_open(struct inode *inode, struct file *file)
 		goto out;
 
 	/*
-	 * TODO: need to implement LP_ABORTOPEN + O_NONBLOCK as in drivers/char/lp.c ???
-	 * This is #if 0-ed because we *don't* want to fail an open
-	 * just because the printer is off-line.
+	 * We do not implement LP_ABORTOPEN/LPABORTOPEN for two reasons:
+	 *  - We do not want persistent state which close(2) does not clear
+	 *  - It is not used anyway, according to CUPS people
 	 */
-#if 0
-	if ((retval = usblp_check_status(usblp, 0))) {
-		retval = retval > 1 ? -EIO : -ENOSPC;
-		goto out;
-	}
-#else
-	retval = 0;
-#endif
 
 	retval = usb_autopm_get_interface(intf);
 	if (retval < 0)
@@ -463,6 +456,8 @@ static int usblp_release(struct inode *inode, struct file *file)
 {
 	struct usblp *usblp = file->private_data;
 
+	usblp->flags &= ~LP_ABORT;
+
 	mutex_lock (&usblp_mutex);
 	usblp->used = 0;
 	if (usblp->present) {
@@ -485,8 +480,8 @@ static unsigned int usblp_poll(struct file *file, struct poll_table_struct *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);
+	ret = ((usblp->bidir && usblp->rcomplete) ? POLLIN  | POLLRDNORM : 0) |
+	   ((usblp->no_paper || usblp->wcomplete) ? POLLOUT | POLLWRNORM : 0);
 	spin_unlock_irqrestore(&usblp->lock, flags);
 	return ret;
 }
@@ -675,6 +670,13 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 					retval = -EFAULT;
 				break;
 
+			case LPABORT:
+				if (arg)
+					usblp->flags |= LP_ABORT;
+				else
+					usblp->flags &= ~LP_ABORT;
+				break;
+
 			default:
 				retval = -ENOTTY;
 		}
@@ -684,10 +686,30 @@ done:
 	return retval;
 }
 
+static struct urb *usblp_new_writeurb(struct usblp *usblp, int transfer_length)
+{
+	struct urb *urb;
+	char *writebuf;
+
+	if ((writebuf = kmalloc(transfer_length, GFP_KERNEL)) == NULL)
+		return NULL;
+	if ((urb = usb_alloc_urb(0, GFP_KERNEL)) == NULL) {
+		kfree(writebuf);
+		return NULL;
+	}
+
+	usb_fill_bulk_urb(urb, usblp->dev,
+		usb_sndbulkpipe(usblp->dev,
+		 usblp->protocol[usblp->current_protocol].epwrite->bEndpointAddress),
+		writebuf, transfer_length, usblp_bulk_write, usblp);
+	urb->transfer_flags |= URB_FREE_BUFFER;
+
+	return urb;
+}
+
 static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 {
 	struct usblp *usblp = file->private_data;
-	char *writebuf;
 	struct urb *writeurb;
 	int rv;
 	int transfer_length;
@@ -708,17 +730,11 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
 			transfer_length = USBLP_BUF_SIZE;
 
 		rv = -ENOMEM;
-		if ((writebuf = kmalloc(USBLP_BUF_SIZE, GFP_KERNEL)) == NULL)
-			goto raise_buf;
-		if ((writeurb = usb_alloc_urb(0, GFP_KERNEL)) == NULL)
+		if ((writeurb = usblp_new_writeurb(usblp, transfer_length)) == 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,
+		if (copy_from_user(writeurb->transfer_buffer,
 				   buffer + writecount, transfer_length)) {
 			rv = -EFAULT;
 			goto raise_badaddr;
@@ -730,6 +746,7 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
 		if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) {
 			usblp->wstatus = 0;
 			spin_lock_irq(&usblp->lock);
+			usblp->no_paper = 0;
 			usblp->wcomplete = 1;
 			wake_up(&usblp->wwait);
 			spin_unlock_irq(&usblp->lock);
@@ -747,12 +764,17 @@ static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t
 				/* Presume that it's going to complete well. */
 				writecount += transfer_length;
 			}
+			if (rv == -ENOSPC) {
+				spin_lock_irq(&usblp->lock);
+				usblp->no_paper = 1;	/* Mark for poll(2) */
+				spin_unlock_irq(&usblp->lock);
+				writecount += transfer_length;
+			}
 			/* Leave URB dangling, to be cleaned on close. */
 			goto collect_error;
 		}
 
 		if (usblp->wstatus < 0) {
-			usblp_check_status(usblp, 0);
 			rv = -EIO;
 			goto collect_error;
 		}
@@ -771,8 +793,6 @@ 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);
@@ -838,32 +858,36 @@ done:
  * 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;
+	int err = 0;
 
 	add_wait_queue(&usblp->wwait, &waita);
 	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
 		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;
-		}
+		rc = usblp_wtest(usblp, nonblock);
 		mutex_unlock(&usblp->mut);
-		if (rc == 0)
+		if (rc <= 0)
 			break;
-		schedule();
+
+		if (usblp->flags & LP_ABORT) {
+			if (schedule_timeout(msecs_to_jiffies(5000)) == 0) {
+				err = usblp_check_status(usblp, err);
+				if (err == 1) {	/* Paper out */
+					rc = -ENOSPC;
+					break;
+				}
+			}
+		} else {
+			schedule();
+		}
 	}
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&usblp->wwait, &waita);

+ 19 - 5
drivers/usb/core/config.c

@@ -507,18 +507,30 @@ void usb_destroy_configuration(struct usb_device *dev)
 }
 
 
-// hub-only!! ... and only in reset path, or usb_new_device()
-// (used by real hubs and virtual root hubs)
+/*
+ * Get the USB config descriptors, cache and parse'em
+ *
+ * hub-only!! ... and only in reset path, or usb_new_device()
+ * (used by real hubs and virtual root hubs)
+ *
+ * NOTE: if this is a WUSB device and is not authorized, we skip the
+ *       whole thing. A non-authorized USB device has no
+ *       configurations.
+ */
 int usb_get_configuration(struct usb_device *dev)
 {
 	struct device *ddev = &dev->dev;
 	int ncfg = dev->descriptor.bNumConfigurations;
-	int result = -ENOMEM;
+	int result = 0;
 	unsigned int cfgno, length;
 	unsigned char *buffer;
 	unsigned char *bigbuffer;
  	struct usb_config_descriptor *desc;
 
+	cfgno = 0;
+	if (dev->authorized == 0)	/* Not really an error */
+		goto out_not_authorized;
+	result = -ENOMEM;
 	if (ncfg > USB_MAXCONFIG) {
 		dev_warn(ddev, "too many configurations: %d, "
 		    "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
@@ -545,14 +557,15 @@ int usb_get_configuration(struct usb_device *dev)
 		goto err2;
 	desc = (struct usb_config_descriptor *)buffer;
 
-	for (cfgno = 0; cfgno < ncfg; cfgno++) {
+	result = 0;
+	for (; cfgno < ncfg; cfgno++) {
 		/* We grab just the first descriptor so we know how long
 		 * the whole configuration is */
 		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
 		    buffer, USB_DT_CONFIG_SIZE);
 		if (result < 0) {
 			dev_err(ddev, "unable to read config index %d "
-			    "descriptor/%s\n", cfgno, "start");
+			    "descriptor/%s: %d\n", cfgno, "start", result);
 			dev_err(ddev, "chopping to %d config(s)\n", cfgno);
 			dev->descriptor.bNumConfigurations = cfgno;
 			break;
@@ -599,6 +612,7 @@ int usb_get_configuration(struct usb_device *dev)
 
 err:
 	kfree(buffer);
+out_not_authorized:
 	dev->descriptor.bNumConfigurations = cfgno;
 err2:
 	if (result == -ENOMEM)

+ 46 - 31
drivers/usb/core/devio.c

@@ -71,6 +71,7 @@ struct async {
 	void __user *userbuffer;
 	void __user *userurb;
 	struct urb *urb;
+	int status;
 	u32 secid;
 };
 
@@ -289,10 +290,8 @@ static void snoop_urb(struct urb *urb, void __user *userurb)
 	if (!usbfs_snoop)
 		return;
 
-	if (urb->pipe & USB_DIR_IN)
-		dev_info(&urb->dev->dev, "direction=IN\n");
-	else
-		dev_info(&urb->dev->dev, "direction=OUT\n");
+	dev_info(&urb->dev->dev, "direction=%s\n",
+			usb_urb_dir_in(urb) ? "IN" : "OUT");
 	dev_info(&urb->dev->dev, "userurb=%p\n", userurb);
 	dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n",
 		 urb->transfer_buffer_length);
@@ -312,9 +311,10 @@ static void async_completed(struct urb *urb)
         spin_lock(&ps->lock);
         list_move_tail(&as->asynclist, &ps->async_completed);
         spin_unlock(&ps->lock);
+	as->status = urb->status;
 	if (as->signr) {
 		sinfo.si_signo = as->signr;
-		sinfo.si_errno = as->urb->status;
+		sinfo.si_errno = as->status;
 		sinfo.si_code = SI_ASYNCIO;
 		sinfo.si_addr = as->userurb;
 		kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
@@ -910,6 +910,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 	struct usb_ctrlrequest *dr = NULL;
 	unsigned int u, totlen, isofrmlen;
 	int ret, ifnum = -1;
+	int is_in;
 
 	if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
 			   URB_NO_FSBR|URB_ZERO_PACKET))
@@ -924,16 +925,18 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 		if ((ret = checkintf(ps, ifnum)))
 			return ret;
 	}
-	if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0)
-		ep = ps->dev->ep_in [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
-	else
-		ep = ps->dev->ep_out [uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+	if ((uurb->endpoint & USB_ENDPOINT_DIR_MASK) != 0) {
+		is_in = 1;
+		ep = ps->dev->ep_in[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+	} else {
+		is_in = 0;
+		ep = ps->dev->ep_out[uurb->endpoint & USB_ENDPOINT_NUMBER_MASK];
+	}
 	if (!ep)
 		return -ENOENT;
 	switch(uurb->type) {
 	case USBDEVFS_URB_TYPE_CONTROL:
-		if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-				!= USB_ENDPOINT_XFER_CONTROL)
+		if (!usb_endpoint_xfer_control(&ep->desc))
 			return -EINVAL;
 		/* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */
 		if (uurb->buffer_length < 8 || uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
@@ -952,23 +955,32 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 			kfree(dr);
 			return ret;
 		}
-		uurb->endpoint = (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK);
 		uurb->number_of_packets = 0;
 		uurb->buffer_length = le16_to_cpup(&dr->wLength);
 		uurb->buffer += 8;
-		if (!access_ok((uurb->endpoint & USB_DIR_IN) ?  VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length)) {
+		if ((dr->bRequestType & USB_DIR_IN) && uurb->buffer_length) {
+			is_in = 1;
+			uurb->endpoint |= USB_DIR_IN;
+		} else {
+			is_in = 0;
+			uurb->endpoint &= ~USB_DIR_IN;
+		}
+		if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+				uurb->buffer, uurb->buffer_length)) {
 			kfree(dr);
 			return -EFAULT;
 		}
 		snoop(&ps->dev->dev, "control urb: bRequest=%02x "
 			"bRrequestType=%02x wValue=%04x "
 			"wIndex=%04x wLength=%04x\n",
-			dr->bRequest, dr->bRequestType, dr->wValue,
-			dr->wIndex, dr->wLength);
+			dr->bRequest, dr->bRequestType,
+			__le16_to_cpup(&dr->wValue),
+			__le16_to_cpup(&dr->wIndex),
+			__le16_to_cpup(&dr->wLength));
 		break;
 
 	case USBDEVFS_URB_TYPE_BULK:
-		switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+		switch (usb_endpoint_type(&ep->desc)) {
 		case USB_ENDPOINT_XFER_CONTROL:
 		case USB_ENDPOINT_XFER_ISOC:
 			return -EINVAL;
@@ -977,7 +989,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 		uurb->number_of_packets = 0;
 		if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
 			return -EINVAL;
-		if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
+		if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+				uurb->buffer, uurb->buffer_length))
 			return -EFAULT;
 		snoop(&ps->dev->dev, "bulk urb\n");
 		break;
@@ -986,8 +999,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 		/* arbitrary limit */
 		if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128)
 			return -EINVAL;
-		if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-				!= USB_ENDPOINT_XFER_ISOC)
+		if (!usb_endpoint_xfer_isoc(&ep->desc))
 			return -EINVAL;
 		isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets;
 		if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
@@ -1014,12 +1026,12 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 
 	case USBDEVFS_URB_TYPE_INTERRUPT:
 		uurb->number_of_packets = 0;
-		if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-				!= USB_ENDPOINT_XFER_INT)
+		if (!usb_endpoint_xfer_int(&ep->desc))
 			return -EINVAL;
 		if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
 			return -EINVAL;
-		if (!access_ok((uurb->endpoint & USB_DIR_IN) ? VERIFY_WRITE : VERIFY_READ, uurb->buffer, uurb->buffer_length))
+		if (!access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
+				uurb->buffer, uurb->buffer_length))
 			return -EFAULT;
 		snoop(&ps->dev->dev, "interrupt urb\n");
 		break;
@@ -1039,8 +1051,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 		return -ENOMEM;
 	}
         as->urb->dev = ps->dev;
-        as->urb->pipe = (uurb->type << 30) | __create_pipe(ps->dev, uurb->endpoint & 0xf) | (uurb->endpoint & USB_DIR_IN);
-        as->urb->transfer_flags = uurb->flags;
+        as->urb->pipe = (uurb->type << 30) |
+			__create_pipe(ps->dev, uurb->endpoint & 0xf) |
+			(uurb->endpoint & USB_DIR_IN);
+        as->urb->transfer_flags = uurb->flags |
+			(is_in ? URB_DIR_IN : URB_DIR_OUT);
 	as->urb->transfer_buffer_length = uurb->buffer_length;
 	as->urb->setup_packet = (unsigned char*)dr;
 	as->urb->start_frame = uurb->start_frame;
@@ -1070,13 +1085,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 	as->uid = current->uid;
 	as->euid = current->euid;
 	security_task_getsecid(current, &as->secid);
-	if (!(uurb->endpoint & USB_DIR_IN)) {
-		if (copy_from_user(as->urb->transfer_buffer, uurb->buffer, as->urb->transfer_buffer_length)) {
+	if (!is_in) {
+		if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
+				as->urb->transfer_buffer_length)) {
 			free_async(as);
 			return -EFAULT;
 		}
 	}
-	snoop(&as->urb->dev->dev, "submit urb\n");
 	snoop_urb(as->urb, as->userurb);
         async_newpending(as);
         if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
@@ -1119,14 +1134,14 @@ static int processcompl(struct async *as, void __user * __user *arg)
 	if (as->userbuffer)
 		if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
 			return -EFAULT;
-	if (put_user(urb->status, &userurb->status))
+	if (put_user(as->status, &userurb->status))
 		return -EFAULT;
 	if (put_user(urb->actual_length, &userurb->actual_length))
 		return -EFAULT;
 	if (put_user(urb->error_count, &userurb->error_count))
 		return -EFAULT;
 
-	if (usb_pipeisoc(urb->pipe)) {
+	if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
 		for (i = 0; i < urb->number_of_packets; i++) {
 			if (put_user(urb->iso_frame_desc[i].actual_length,
 				     &userurb->iso_frame_desc[i].actual_length))
@@ -1233,14 +1248,14 @@ static int processcompl_compat(struct async *as, void __user * __user *arg)
 	if (as->userbuffer)
 		if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
 			return -EFAULT;
-	if (put_user(urb->status, &userurb->status))
+	if (put_user(as->status, &userurb->status))
 		return -EFAULT;
 	if (put_user(urb->actual_length, &userurb->actual_length))
 		return -EFAULT;
 	if (put_user(urb->error_count, &userurb->error_count))
 		return -EFAULT;
 
-	if (usb_pipeisoc(urb->pipe)) {
+	if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
 		for (i = 0; i < urb->number_of_packets; i++) {
 			if (put_user(urb->iso_frame_desc[i].actual_length,
 				     &userurb->iso_frame_desc[i].actual_length))

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

@@ -202,6 +202,11 @@ static int usb_probe_interface(struct device *dev)
 	intf = to_usb_interface(dev);
 	udev = interface_to_usbdev(intf);
 
+ 	if (udev->authorized == 0) {
+ 		dev_err(&intf->dev, "Device is not authorized for usage\n");
+ 		return -ENODEV;
+ 	}
+
 	id = usb_match_id(intf, driver->id_table);
 	if (!id)
 		id = usb_match_dynamic_id(intf, driver);
@@ -945,11 +950,11 @@ done:
 #ifdef	CONFIG_USB_SUSPEND
 
 /* Internal routine to check whether we may autosuspend a device. */
-static int autosuspend_check(struct usb_device *udev)
+static int autosuspend_check(struct usb_device *udev, int reschedule)
 {
 	int			i;
 	struct usb_interface	*intf;
-	unsigned long		suspend_time;
+	unsigned long		suspend_time, j;
 
 	/* For autosuspend, fail fast if anything is in use or autosuspend
 	 * is disabled.  Also fail if any interfaces require remote wakeup
@@ -991,20 +996,20 @@ static int autosuspend_check(struct usb_device *udev)
 	}
 
 	/* If everything is okay but the device hasn't been idle for long
-	 * enough, queue a delayed autosuspend request.
+	 * enough, queue a delayed autosuspend request.  If the device
+	 * _has_ been idle for long enough and the reschedule flag is set,
+	 * likewise queue a delayed (1 second) autosuspend request.
 	 */
-	if (time_after(suspend_time, jiffies)) {
+	j = jiffies;
+	if (time_before(j, suspend_time))
+		reschedule = 1;
+	else
+		suspend_time = j + HZ;
+	if (reschedule) {
 		if (!timer_pending(&udev->autosuspend.timer)) {
-
-			/* The value of jiffies may change between the
-			 * time_after() comparison above and the subtraction
-			 * below.  That's okay; the system behaves sanely
-			 * when a timer is registered for the present moment
-			 * or for the past.
-			 */
 			queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
-				round_jiffies_relative(suspend_time - jiffies));
-			}
+				round_jiffies_relative(suspend_time - j));
+		}
 		return -EAGAIN;
 	}
 	return 0;
@@ -1012,7 +1017,7 @@ static int autosuspend_check(struct usb_device *udev)
 
 #else
 
-static inline int autosuspend_check(struct usb_device *udev)
+static inline int autosuspend_check(struct usb_device *udev, int reschedule)
 {
 	return 0;
 }
@@ -1069,7 +1074,7 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
 	udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
 
 	if (udev->auto_pm) {
-		status = autosuspend_check(udev);
+		status = autosuspend_check(udev, 0);
 		if (status < 0)
 			goto done;
 	}
@@ -1083,15 +1088,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
 				break;
 		}
 	}
-	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;
+	if (status == 0)
 		status = usb_suspend_device(udev, msg);
-	}
 
 	/* If the suspend failed, resume interfaces that did get suspended */
 	if (status != 0) {
@@ -1102,12 +1100,24 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
 
 		/* Try another autosuspend when the interfaces aren't busy */
 		if (udev->auto_pm)
-			autosuspend_check(udev);
+			autosuspend_check(udev, status == -EBUSY);
 
-	/* If the suspend succeeded, propagate it up the tree */
+	/* If the suspend succeeded then prevent any more URB submissions,
+	 * flush any outstanding URBs, and propagate the suspend up the tree.
+	 */
 	} else {
 		cancel_delayed_work(&udev->autosuspend);
-		if (parent)
+		udev->can_submit = 0;
+		for (i = 0; i < 16; ++i) {
+			usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
+			usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
+		}
+
+		/* If this is just a FREEZE or a PRETHAW, udev might
+		 * not really be suspended.  Only true suspends get
+		 * propagated up the device tree.
+		 */
+		if (parent && udev->state == USB_STATE_SUSPENDED)
 			usb_autosuspend_device(parent);
 	}
 
@@ -1156,6 +1166,7 @@ static int usb_resume_both(struct usb_device *udev)
 		status = -ENODEV;
 		goto done;
 	}
+	udev->can_submit = 1;
 
 	/* Propagate the resume up the tree, if necessary */
 	if (udev->state == USB_STATE_SUSPENDED) {
@@ -1529,9 +1540,21 @@ int usb_external_resume_device(struct usb_device *udev)
 
 static int usb_suspend(struct device *dev, pm_message_t message)
 {
+	struct usb_device	*udev;
+
 	if (!is_usb_device(dev))	/* Ignore PM for interfaces */
 		return 0;
-	return usb_external_suspend_device(to_usb_device(dev), message);
+	udev = to_usb_device(dev);
+
+	/* If udev is already suspended, we can skip this suspend and
+	 * we should also skip the upcoming system resume. */
+	if (udev->state == USB_STATE_SUSPENDED) {
+		udev->skip_sys_resume = 1;
+		return 0;
+	}
+
+	udev->skip_sys_resume = 0;
+	return usb_external_suspend_device(udev, message);
 }
 
 static int usb_resume(struct device *dev)
@@ -1542,13 +1565,14 @@ static int usb_resume(struct device *dev)
 		return 0;
 	udev = to_usb_device(dev);
 
-	/* 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->skip_sys_resume is set then udev was already suspended
+	 * when the system suspend started, so we don't want to resume
+	 * udev during this system wakeup.  However a reset-resume counts
+	 * as a wakeup event, so allow a reset-resume to occur if remote
+	 * wakeup is enabled. */
+	if (udev->skip_sys_resume) {
 		if (!(udev->reset_resume && udev->do_remote_wakeup))
-			return -EPERM;
+			return -EHOSTUNREACH;
 	}
 	return usb_external_resume_device(udev);
 }

+ 0 - 1
drivers/usb/core/endpoint.c

@@ -267,7 +267,6 @@ static void ep_device_release(struct device *dev)
 {
 	struct ep_device *ep_dev = to_ep_device(dev);
 
-	dev_dbg(dev, "%s called for %s\n", __FUNCTION__, dev->bus_id);
 	endpoint_free_minor(ep_dev);
 	kfree(ep_dev);
 }

+ 17 - 9
drivers/usb/core/generic.c

@@ -40,7 +40,7 @@ static int is_activesync(struct usb_interface_descriptor *desc)
 		&& desc->bInterfaceProtocol == 1;
 }
 
-static int choose_configuration(struct usb_device *udev)
+int usb_choose_configuration(struct usb_device *udev)
 {
 	int i;
 	int num_configs;
@@ -161,17 +161,20 @@ static int generic_probe(struct usb_device *udev)
 	/* Choose and set the configuration.  This registers the interfaces
 	 * with the driver core and lets interface drivers bind to them.
 	 */
-	c = choose_configuration(udev);
-	if (c >= 0) {
-		err = usb_set_configuration(udev, c);
-		if (err) {
-			dev_err(&udev->dev, "can't set config #%d, error %d\n",
+	if (udev->authorized == 0)
+		dev_err(&udev->dev, "Device is not authorized for usage\n");
+	else {
+		c = usb_choose_configuration(udev);
+		if (c >= 0) {
+			err = usb_set_configuration(udev, c);
+			if (err) {
+				dev_err(&udev->dev, "can't set config #%d, error %d\n",
 					c, err);
-			/* This need not be fatal.  The user can try to
-			 * set other configurations. */
+				/* This need not be fatal.  The user can try to
+				 * set other configurations. */
+			}
 		}
 	}
-
 	/* USB device state == configured ... usable */
 	usb_notify_add_device(udev);
 
@@ -203,8 +206,13 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg)
 	 */
 	if (!udev->parent)
 		rc = hcd_bus_suspend(udev);
+
+	/* Non-root devices don't need to do anything for FREEZE or PRETHAW */
+	else if (msg.event == PM_EVENT_FREEZE || msg.event == PM_EVENT_PRETHAW)
+		rc = 0;
 	else
 		rc = usb_port_suspend(udev);
+
 	return rc;
 }
 

+ 420 - 298
drivers/usb/core/hcd.c

@@ -356,10 +356,18 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
 	const u8	*bufp = tbuf;
 	int		len = 0;
 	int		patch_wakeup = 0;
-	unsigned long	flags;
-	int		status = 0;
+	int		status;
 	int		n;
 
+	might_sleep();
+
+	spin_lock_irq(&hcd_root_hub_lock);
+	status = usb_hcd_link_urb_to_ep(hcd, urb);
+	spin_unlock_irq(&hcd_root_hub_lock);
+	if (status)
+		return status;
+	urb->hcpriv = hcd;	/* Indicate it's queued */
+
 	cmd = (struct usb_ctrlrequest *) urb->setup_packet;
 	typeReq  = (cmd->bRequestType << 8) | cmd->bRequest;
 	wValue   = le16_to_cpu (cmd->wValue);
@@ -523,13 +531,18 @@ error:
 	}
 
 	/* any errors get returned through the urb completion */
-	local_irq_save (flags);
-	spin_lock (&urb->lock);
-	if (urb->status == -EINPROGRESS)
-		urb->status = status;
-	spin_unlock (&urb->lock);
-	usb_hcd_giveback_urb (hcd, urb);
-	local_irq_restore (flags);
+	spin_lock_irq(&hcd_root_hub_lock);
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+	/* This peculiar use of spinlocks echoes what real HC drivers do.
+	 * Avoiding calls to local_irq_disable/enable makes the code
+	 * RT-friendly.
+	 */
+	spin_unlock(&hcd_root_hub_lock);
+	usb_hcd_giveback_urb(hcd, urb, status);
+	spin_lock(&hcd_root_hub_lock);
+
+	spin_unlock_irq(&hcd_root_hub_lock);
 	return 0;
 }
 
@@ -559,31 +572,23 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
 	if (length > 0) {
 
 		/* try to complete the status urb */
-		local_irq_save (flags);
-		spin_lock(&hcd_root_hub_lock);
+		spin_lock_irqsave(&hcd_root_hub_lock, flags);
 		urb = hcd->status_urb;
 		if (urb) {
-			spin_lock(&urb->lock);
-			if (urb->status == -EINPROGRESS) {
-				hcd->poll_pending = 0;
-				hcd->status_urb = NULL;
-				urb->status = 0;
-				urb->hcpriv = NULL;
-				urb->actual_length = length;
-				memcpy(urb->transfer_buffer, buffer, length);
-			} else		/* urb has been unlinked */
-				length = 0;
-			spin_unlock(&urb->lock);
-		} else
-			length = 0;
-		spin_unlock(&hcd_root_hub_lock);
+			hcd->poll_pending = 0;
+			hcd->status_urb = NULL;
+			urb->actual_length = length;
+			memcpy(urb->transfer_buffer, buffer, length);
 
-		/* local irqs are always blocked in completions */
-		if (length > 0)
-			usb_hcd_giveback_urb (hcd, urb);
-		else
+			usb_hcd_unlink_urb_from_ep(hcd, urb);
+			spin_unlock(&hcd_root_hub_lock);
+			usb_hcd_giveback_urb(hcd, urb, 0);
+			spin_lock(&hcd_root_hub_lock);
+		} else {
+			length = 0;
 			hcd->poll_pending = 1;
-		local_irq_restore (flags);
+		}
+		spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
 	}
 
 	/* The USB 2.0 spec says 256 ms.  This is close enough and won't
@@ -611,33 +616,35 @@ static int rh_queue_status (struct usb_hcd *hcd, struct urb *urb)
 	int		len = 1 + (urb->dev->maxchild / 8);
 
 	spin_lock_irqsave (&hcd_root_hub_lock, flags);
-	if (urb->status != -EINPROGRESS)	/* already unlinked */
-		retval = urb->status;
-	else if (hcd->status_urb || urb->transfer_buffer_length < len) {
+	if (hcd->status_urb || urb->transfer_buffer_length < len) {
 		dev_dbg (hcd->self.controller, "not queuing rh status urb\n");
 		retval = -EINVAL;
-	} else {
-		hcd->status_urb = urb;
-		urb->hcpriv = hcd;	/* indicate it's queued */
+		goto done;
+	}
 
-		if (!hcd->uses_new_polling)
-			mod_timer (&hcd->rh_timer,
-				(jiffies/(HZ/4) + 1) * (HZ/4));
+	retval = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (retval)
+		goto done;
 
-		/* If a status change has already occurred, report it ASAP */
-		else if (hcd->poll_pending)
-			mod_timer (&hcd->rh_timer, jiffies);
-		retval = 0;
-	}
+	hcd->status_urb = urb;
+	urb->hcpriv = hcd;	/* indicate it's queued */
+	if (!hcd->uses_new_polling)
+		mod_timer(&hcd->rh_timer, (jiffies/(HZ/4) + 1) * (HZ/4));
+
+	/* If a status change has already occurred, report it ASAP */
+	else if (hcd->poll_pending)
+		mod_timer(&hcd->rh_timer, jiffies);
+	retval = 0;
+ done:
 	spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
 	return retval;
 }
 
 static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
 {
-	if (usb_pipeint (urb->pipe))
+	if (usb_endpoint_xfer_int(&urb->ep->desc))
 		return rh_queue_status (hcd, urb);
-	if (usb_pipecontrol (urb->pipe))
+	if (usb_endpoint_xfer_control(&urb->ep->desc))
 		return rh_call_control (hcd, urb);
 	return -EINVAL;
 }
@@ -647,32 +654,96 @@ static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
 /* Unlinks of root-hub control URBs are legal, but they don't do anything
  * since these URBs always execute synchronously.
  */
-static int usb_rh_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int usb_rh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	unsigned long	flags;
+	int		rc;
+
+	spin_lock_irqsave(&hcd_root_hub_lock, flags);
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
+		goto done;
 
-	if (usb_pipeendpoint(urb->pipe) == 0) {	/* Control URB */
+	if (usb_endpoint_num(&urb->ep->desc) == 0) {	/* Control URB */
 		;	/* Do nothing */
 
 	} else {				/* Status URB */
 		if (!hcd->uses_new_polling)
 			del_timer (&hcd->rh_timer);
-		local_irq_save (flags);
-		spin_lock (&hcd_root_hub_lock);
 		if (urb == hcd->status_urb) {
 			hcd->status_urb = NULL;
-			urb->hcpriv = NULL;
-		} else
-			urb = NULL;		/* wasn't fully queued */
-		spin_unlock (&hcd_root_hub_lock);
-		if (urb)
-			usb_hcd_giveback_urb (hcd, urb);
-		local_irq_restore (flags);
+			usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+			spin_unlock(&hcd_root_hub_lock);
+			usb_hcd_giveback_urb(hcd, urb, status);
+			spin_lock(&hcd_root_hub_lock);
+		}
 	}
+ done:
+	spin_unlock_irqrestore(&hcd_root_hub_lock, flags);
+	return rc;
+}
 
-	return 0;
+
+
+/*
+ * Show & store the current value of authorized_default
+ */
+static ssize_t usb_host_authorized_default_show(struct device *dev,
+						struct device_attribute *attr,
+						char *buf)
+{
+	struct usb_device *rh_usb_dev = to_usb_device(dev);
+	struct usb_bus *usb_bus = rh_usb_dev->bus;
+	struct usb_hcd *usb_hcd;
+
+	if (usb_bus == NULL)	/* FIXME: not sure if this case is possible */
+		return -ENODEV;
+	usb_hcd = bus_to_hcd(usb_bus);
+	return snprintf(buf, PAGE_SIZE, "%u\n", usb_hcd->authorized_default);
+}
+
+static ssize_t usb_host_authorized_default_store(struct device *dev,
+						 struct device_attribute *attr,
+						 const char *buf, size_t size)
+{
+	ssize_t result;
+	unsigned val;
+	struct usb_device *rh_usb_dev = to_usb_device(dev);
+	struct usb_bus *usb_bus = rh_usb_dev->bus;
+	struct usb_hcd *usb_hcd;
+
+	if (usb_bus == NULL)	/* FIXME: not sure if this case is possible */
+		return -ENODEV;
+	usb_hcd = bus_to_hcd(usb_bus);
+	result = sscanf(buf, "%u\n", &val);
+	if (result == 1) {
+		usb_hcd->authorized_default = val? 1 : 0;
+		result = size;
+	}
+	else
+		result = -EINVAL;
+	return result;
 }
 
+static DEVICE_ATTR(authorized_default, 0644,
+	    usb_host_authorized_default_show,
+	    usb_host_authorized_default_store);
+
+
+/* Group all the USB bus attributes */
+static struct attribute *usb_bus_attrs[] = {
+		&dev_attr_authorized_default.attr,
+		NULL,
+};
+
+static struct attribute_group usb_bus_attr_group = {
+	.name = NULL,	/* we want them in the same directory */
+	.attrs = usb_bus_attrs,
+};
+
+
+
 /*-------------------------------------------------------------------------*/
 
 static struct class *usb_host_class;
@@ -726,27 +797,23 @@ static void usb_bus_init (struct usb_bus *bus)
  */
 static int usb_register_bus(struct usb_bus *bus)
 {
+	int result = -E2BIG;
 	int busnum;
 
 	mutex_lock(&usb_bus_list_lock);
 	busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
-	if (busnum < USB_MAXBUS) {
-		set_bit (busnum, busmap.busmap);
-		bus->busnum = busnum;
-	} else {
+	if (busnum >= USB_MAXBUS) {
 		printk (KERN_ERR "%s: too many buses\n", usbcore_name);
-		mutex_unlock(&usb_bus_list_lock);
-		return -E2BIG;
+		goto error_find_busnum;
 	}
-
+	set_bit (busnum, busmap.busmap);
+	bus->busnum = busnum;
 	bus->class_dev = class_device_create(usb_host_class, NULL, MKDEV(0,0),
-					     bus->controller, "usb_host%d", busnum);
-	if (IS_ERR(bus->class_dev)) {
-		clear_bit(busnum, busmap.busmap);
-		mutex_unlock(&usb_bus_list_lock);
-		return PTR_ERR(bus->class_dev);
-	}
-
+					     bus->controller, "usb_host%d",
+					     busnum);
+	result = PTR_ERR(bus->class_dev);
+	if (IS_ERR(bus->class_dev))
+		goto error_create_class_dev;
 	class_set_devdata(bus->class_dev, bus);
 
 	/* Add it to the local list of buses */
@@ -755,8 +822,15 @@ static int usb_register_bus(struct usb_bus *bus)
 
 	usb_notify_add_bus(bus);
 
-	dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum);
+	dev_info (bus->controller, "new USB bus registered, assigned bus "
+		  "number %d\n", bus->busnum);
 	return 0;
+
+error_create_class_dev:
+	clear_bit(busnum, busmap.busmap);
+error_find_busnum:
+	mutex_unlock(&usb_bus_list_lock);
+	return result;
 }
 
 /**
@@ -908,103 +982,145 @@ EXPORT_SYMBOL (usb_calc_bus_time);
 
 /*-------------------------------------------------------------------------*/
 
-static void urb_unlink(struct usb_hcd *hcd, struct urb *urb)
+/**
+ * usb_hcd_link_urb_to_ep - add an URB to its endpoint queue
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being submitted
+ *
+ * Host controller drivers should call this routine in their enqueue()
+ * method.  The HCD's private spinlock must be held and interrupts must
+ * be disabled.  The actions carried out here are required for URB
+ * submission, as well as for endpoint shutdown and for usb_kill_urb.
+ *
+ * Returns 0 for no error, otherwise a negative error code (in which case
+ * the enqueue() method must fail).  If no error occurs but enqueue() fails
+ * anyway, it must call usb_hcd_unlink_urb_from_ep() before releasing
+ * the private spinlock and returning.
+ */
+int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb)
 {
-	unsigned long		flags;
+	int		rc = 0;
 
-	/* clear all state linking urb to this dev (and hcd) */
-	spin_lock_irqsave(&hcd_urb_list_lock, flags);
-	list_del_init (&urb->urb_list);
-	spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
+	spin_lock(&hcd_urb_list_lock);
 
-	if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
-		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);
+	/* Check that the URB isn't being killed */
+	if (unlikely(urb->reject)) {
+		rc = -EPERM;
+		goto done;
 	}
-}
-
-/* may be called in any context with a valid urb->dev usecount
- * caller surrenders "ownership" of urb
- * expects usb_submit_urb() to have sanity checked and conditioned all
- * inputs in the urb
- */
-int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
-{
-	int			status;
-	struct usb_hcd		*hcd = bus_to_hcd(urb->dev->bus);
-	struct usb_host_endpoint *ep;
-	unsigned long		flags;
 
-	if (!hcd)
-		return -ENODEV;
+	if (unlikely(!urb->ep->enabled)) {
+		rc = -ENOENT;
+		goto done;
+	}
 
-	usbmon_urb_submit(&hcd->self, urb);
+	if (unlikely(!urb->dev->can_submit)) {
+		rc = -EHOSTUNREACH;
+		goto done;
+	}
 
 	/*
-	 * Atomically queue the urb,  first to our records, then to the HCD.
-	 * Access to urb->status is controlled by urb->lock ... changes on
-	 * i/o completion (normal or fault) or unlinking.
+	 * Check the host controller's state and add the URB to the
+	 * endpoint's queue.
 	 */
-
-	// FIXME:  verify that quiescing hc works right (RH cleans up)
-
-	spin_lock_irqsave(&hcd_urb_list_lock, flags);
-	ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
-			[usb_pipeendpoint(urb->pipe)];
-	if (unlikely (!ep))
-		status = -ENOENT;
-	else if (unlikely (urb->reject))
-		status = -EPERM;
-	else switch (hcd->state) {
+	switch (hcd->state) {
 	case HC_STATE_RUNNING:
 	case HC_STATE_RESUMING:
-		list_add_tail (&urb->urb_list, &ep->urb_list);
-		status = 0;
+		urb->unlinked = 0;
+		list_add_tail(&urb->urb_list, &urb->ep->urb_list);
 		break;
 	default:
-		status = -ESHUTDOWN;
-		break;
+		rc = -ESHUTDOWN;
+		goto done;
 	}
-	spin_unlock_irqrestore(&hcd_urb_list_lock, flags);
-	if (status) {
-		INIT_LIST_HEAD (&urb->urb_list);
-		usbmon_urb_submit_error(&hcd->self, urb, status);
-		return status;
+ done:
+	spin_unlock(&hcd_urb_list_lock);
+	return rc;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_link_urb_to_ep);
+
+/**
+ * usb_hcd_check_unlink_urb - check whether an URB may be unlinked
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being checked for unlinkability
+ * @status: error code to store in @urb if the unlink succeeds
+ *
+ * Host controller drivers should call this routine in their dequeue()
+ * method.  The HCD's private spinlock must be held and interrupts must
+ * be disabled.  The actions carried out here are required for making
+ * sure than an unlink is valid.
+ *
+ * Returns 0 for no error, otherwise a negative error code (in which case
+ * the dequeue() method must fail).  The possible error codes are:
+ *
+ *	-EIDRM: @urb was not submitted or has already completed.
+ *		The completion function may not have been called yet.
+ *
+ *	-EBUSY: @urb has already been unlinked.
+ */
+int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
+		int status)
+{
+	struct list_head	*tmp;
+
+	/* insist the urb is still queued */
+	list_for_each(tmp, &urb->ep->urb_list) {
+		if (tmp == &urb->urb_list)
+			break;
 	}
+	if (tmp != &urb->urb_list)
+		return -EIDRM;
 
-	/* increment urb's reference count as part of giving it to the HCD
-	 * (which now controls it).  HCD guarantees that it either returns
-	 * an error or calls giveback(), but not both.
+	/* Any status except -EINPROGRESS means something already started to
+	 * unlink this URB from the hardware.  So there's no more work to do.
 	 */
-	urb = usb_get_urb (urb);
-	atomic_inc (&urb->use_count);
-
-	if (is_root_hub(urb->dev)) {
-		/* NOTE:  requirement on hub callers (usbfs and the hub
-		 * driver, for now) that URBs' urb->transfer_buffer be
-		 * valid and usb_buffer_{sync,unmap}() not be needed, since
-		 * they could clobber root hub response data.
-		 */
-		status = rh_urb_enqueue (hcd, urb);
-		goto done;
+	if (urb->unlinked)
+		return -EBUSY;
+	urb->unlinked = status;
+
+	/* IRQ setup can easily be broken so that USB controllers
+	 * never get completion IRQs ... maybe even the ones we need to
+	 * finish unlinking the initial failed usb_set_address()
+	 * or device descriptor fetch.
+	 */
+	if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
+			!is_root_hub(urb->dev)) {
+		dev_warn(hcd->self.controller, "Unlink after no-IRQ?  "
+			"Controller is probably using the wrong IRQ.\n");
+		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
 	}
 
-	/* lower level hcd code should use *_dma exclusively,
+	return 0;
+}
+EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb);
+
+/**
+ * usb_hcd_unlink_urb_from_ep - remove an URB from its endpoint queue
+ * @hcd: host controller to which @urb was submitted
+ * @urb: URB being unlinked
+ *
+ * Host controller drivers should call this routine before calling
+ * usb_hcd_giveback_urb().  The HCD's private spinlock must be held and
+ * interrupts must be disabled.  The actions carried out here are required
+ * for URB completion.
+ */
+void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb)
+{
+	/* clear all state linking urb to this dev (and hcd) */
+	spin_lock(&hcd_urb_list_lock);
+	list_del_init(&urb->urb_list);
+	spin_unlock(&hcd_urb_list_lock);
+}
+EXPORT_SYMBOL_GPL(usb_hcd_unlink_urb_from_ep);
+
+static void map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+	/* Map the URB's buffers for DMA access.
+	 * Lower level HCD code should use *_dma exclusively,
 	 * unless it uses pio or talks to another transport.
 	 */
-	if (hcd->self.uses_dma) {
-		if (usb_pipecontrol (urb->pipe)
+	if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
+		if (usb_endpoint_xfer_control(&urb->ep->desc)
 			&& !(urb->transfer_flags & URB_NO_SETUP_DMA_MAP))
 			urb->setup_dma = dma_map_single (
 					hcd->self.controller,
@@ -1017,20 +1133,75 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
 					hcd->self.controller,
 					urb->transfer_buffer,
 					urb->transfer_buffer_length,
-					usb_pipein (urb->pipe)
+					usb_urb_dir_in(urb)
 					    ? DMA_FROM_DEVICE
 					    : DMA_TO_DEVICE);
 	}
+}
 
-	status = hcd->driver->urb_enqueue (hcd, ep, urb, mem_flags);
-done:
-	if (unlikely (status)) {
-		urb_unlink(hcd, urb);
-		atomic_dec (&urb->use_count);
-		if (urb->reject)
-			wake_up (&usb_kill_urb_queue);
+static void unmap_urb_for_dma(struct usb_hcd *hcd, struct urb *urb)
+{
+	if (hcd->self.uses_dma && !is_root_hub(urb->dev)) {
+		if (usb_endpoint_xfer_control(&urb->ep->desc)
+			&& !(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_urb_dir_in(urb)
+					    ? DMA_FROM_DEVICE
+					    : DMA_TO_DEVICE);
+	}
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* may be called in any context with a valid urb->dev usecount
+ * caller surrenders "ownership" of urb
+ * expects usb_submit_urb() to have sanity checked and conditioned all
+ * inputs in the urb
+ */
+int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
+{
+	int			status;
+	struct usb_hcd		*hcd = bus_to_hcd(urb->dev->bus);
+
+	/* increment urb's reference count as part of giving it to the HCD
+	 * (which will control it).  HCD guarantees that it either returns
+	 * an error or calls giveback(), but not both.
+	 */
+	usb_get_urb(urb);
+	atomic_inc(&urb->use_count);
+	atomic_inc(&urb->dev->urbnum);
+	usbmon_urb_submit(&hcd->self, urb);
+
+	/* NOTE requirements on root-hub callers (usbfs and the hub
+	 * driver, for now):  URBs' urb->transfer_buffer must be
+	 * valid and usb_buffer_{sync,unmap}() not be needed, since
+	 * they could clobber root hub response data.  Also, control
+	 * URBs must be submitted in process context with interrupts
+	 * enabled.
+	 */
+	map_urb_for_dma(hcd, urb);
+	if (is_root_hub(urb->dev))
+		status = rh_urb_enqueue(hcd, urb);
+	else
+		status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);
+
+	if (unlikely(status)) {
 		usbmon_urb_submit_error(&hcd->self, urb, status);
-		usb_put_urb (urb);
+		unmap_urb_for_dma(hcd, urb);
+		urb->hcpriv = NULL;
+		INIT_LIST_HEAD(&urb->urb_list);
+		atomic_dec(&urb->use_count);
+		atomic_dec(&urb->dev->urbnum);
+		if (urb->reject)
+			wake_up(&usb_kill_urb_queue);
+		usb_put_urb(urb);
 	}
 	return status;
 }
@@ -1042,24 +1213,19 @@ done:
  * soon as practical.  we've already set up the urb's return status,
  * but we can't know if the callback completed already.
  */
-static int
-unlink1 (struct usb_hcd *hcd, struct urb *urb)
+static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	int		value;
 
 	if (is_root_hub(urb->dev))
-		value = usb_rh_urb_dequeue (hcd, urb);
+		value = usb_rh_urb_dequeue(hcd, urb, status);
 	else {
 
 		/* The only reason an HCD might fail this call is if
 		 * it has not yet fully queued the urb to begin with.
 		 * Such failures should be harmless. */
-		value = hcd->driver->urb_dequeue (hcd, urb);
+		value = hcd->driver->urb_dequeue(hcd, urb, status);
 	}
-
-	if (value != 0)
-		dev_dbg (hcd->self.controller, "dequeue %p --> %d\n",
-				urb, value);
 	return value;
 }
 
@@ -1071,88 +1237,17 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb)
  */
 int usb_hcd_unlink_urb (struct urb *urb, int status)
 {
-	struct usb_host_endpoint	*ep;
-	struct usb_hcd			*hcd = NULL;
-	struct device			*sys = NULL;
-	unsigned long			flags;
-	struct list_head		*tmp;
-	int				retval;
-
-	if (!urb)
-		return -EINVAL;
-	if (!urb->dev || !urb->dev->bus)
-		return -ENODEV;
-	ep = (usb_pipein(urb->pipe) ? urb->dev->ep_in : urb->dev->ep_out)
-			[usb_pipeendpoint(urb->pipe)];
-	if (!ep)
-		return -ENODEV;
-
-	/*
-	 * we contend for urb->status with the hcd core,
-	 * which changes it while returning the urb.
-	 *
-	 * Caller guaranteed that the urb pointer hasn't been freed, and
-	 * that it was submitted.  But as a rule it can't know whether or
-	 * not it's already been unlinked ... so we respect the reversed
-	 * lock sequence needed for the usb_hcd_giveback_urb() code paths
-	 * (urb lock, then hcd_urb_list_lock) in case some other CPU is now
-	 * unlinking it.
-	 */
-	spin_lock_irqsave (&urb->lock, flags);
-	spin_lock(&hcd_urb_list_lock);
+	struct usb_hcd		*hcd;
+	int			retval;
 
-	sys = &urb->dev->dev;
 	hcd = bus_to_hcd(urb->dev->bus);
-	if (hcd == NULL) {
-		retval = -ENODEV;
-		goto done;
-	}
+	retval = unlink1(hcd, urb, status);
 
-	/* insist the urb is still queued */
-	list_for_each(tmp, &ep->urb_list) {
-		if (tmp == &urb->urb_list)
-			break;
-	}
-	if (tmp != &urb->urb_list) {
-		retval = -EIDRM;
-		goto done;
-	}
-
-	/* Any status except -EINPROGRESS means something already started to
-	 * unlink this URB from the hardware.  So there's no more work to do.
-	 */
-	if (urb->status != -EINPROGRESS) {
-		retval = -EBUSY;
-		goto done;
-	}
-
-	/* IRQ setup can easily be broken so that USB controllers
-	 * never get completion IRQs ... maybe even the ones we need to
-	 * finish unlinking the initial failed usb_set_address()
-	 * or device descriptor fetch.
-	 */
-	if (!test_bit(HCD_FLAG_SAW_IRQ, &hcd->flags) &&
-			!is_root_hub(urb->dev)) {
-		dev_warn (hcd->self.controller, "Unlink after no-IRQ?  "
-			"Controller is probably using the wrong IRQ.\n");
-		set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
-	}
-
-	urb->status = status;
-
-	spin_unlock(&hcd_urb_list_lock);
-	spin_unlock_irqrestore (&urb->lock, flags);
-
-	retval = unlink1 (hcd, urb);
 	if (retval == 0)
 		retval = -EINPROGRESS;
-	return retval;
-
-done:
-	spin_unlock(&hcd_urb_list_lock);
-	spin_unlock_irqrestore (&urb->lock, flags);
-	if (retval != -EIDRM && sys && sys->driver)
-		dev_dbg (sys, "hcd_unlink_urb %p fail %d\n", urb, retval);
+	else if (retval != -EIDRM && retval != -EBUSY)
+		dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n",
+				urb, retval);
 	return retval;
 }
 
@@ -1162,6 +1257,7 @@ done:
  * usb_hcd_giveback_urb - return URB from HCD to device driver
  * @hcd: host controller returning the URB
  * @urb: urb being returned to the USB device driver.
+ * @status: completion status code for the URB.
  * Context: in_interrupt()
  *
  * This hands the URB from HCD to its USB device driver, using its
@@ -1169,14 +1265,27 @@ done:
  * (and is done using urb->hcpriv).  It also released all HCD locks;
  * the device driver won't cause problems if it frees, modifies,
  * or resubmits this URB.
+ *
+ * If @urb was unlinked, the value of @status will be overridden by
+ * @urb->unlinked.  Erroneous short transfers are detected in case
+ * the HCD hasn't checked for them.
  */
-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 status)
 {
-	urb_unlink(hcd, urb);
-	usbmon_urb_complete (&hcd->self, urb);
+	urb->hcpriv = NULL;
+	if (unlikely(urb->unlinked))
+		status = urb->unlinked;
+	else if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
+			urb->actual_length < urb->transfer_buffer_length &&
+			!status))
+		status = -EREMOTEIO;
+
+	unmap_urb_for_dma(hcd, urb);
+	usbmon_urb_complete(&hcd->self, urb, status);
 	usb_unanchor_urb(urb);
 
 	/* pass ownership to the completion handler */
+	urb->status = status;
 	urb->complete (urb);
 	atomic_dec (&urb->use_count);
 	if (unlikely (urb->reject))
@@ -1187,78 +1296,61 @@ EXPORT_SYMBOL (usb_hcd_giveback_urb);
 
 /*-------------------------------------------------------------------------*/
 
-/* disables the endpoint: cancels any pending urbs, then synchronizes with
- * the hcd to make sure all endpoint state is gone from hardware, and then
- * waits until the endpoint's queue is completely drained. use for
- * set_configuration, set_interface, driver removal, physical disconnect.
- *
- * example:  a qh stored in ep->hcpriv, holding state related to endpoint
- * type, maxpacket size, toggle, halt status, and scheduling.
+/* Cancel all URBs pending on this endpoint and wait for the endpoint's
+ * queue to drain completely.  The caller must first insure that no more
+ * URBs can be submitted for this endpoint.
  */
-void usb_hcd_endpoint_disable (struct usb_device *udev,
+void usb_hcd_flush_endpoint(struct usb_device *udev,
 		struct usb_host_endpoint *ep)
 {
 	struct usb_hcd		*hcd;
 	struct urb		*urb;
 
+	if (!ep)
+		return;
+	might_sleep();
 	hcd = bus_to_hcd(udev->bus);
-	local_irq_disable ();
 
-	/* ep is already gone from udev->ep_{in,out}[]; no more submits */
+	/* No more submits can occur */
 rescan:
-	spin_lock(&hcd_urb_list_lock);
+	spin_lock_irq(&hcd_urb_list_lock);
 	list_for_each_entry (urb, &ep->urb_list, urb_list) {
-		int	tmp;
+		int	is_in;
 
-		/* the urb may already have been unlinked */
-		if (urb->status != -EINPROGRESS)
+		if (urb->unlinked)
 			continue;
 		usb_get_urb (urb);
+		is_in = usb_urb_dir_in(urb);
 		spin_unlock(&hcd_urb_list_lock);
 
-		spin_lock (&urb->lock);
-		tmp = urb->status;
-		if (tmp == -EINPROGRESS)
-			urb->status = -ESHUTDOWN;
-		spin_unlock (&urb->lock);
-
-		/* kick hcd unless it's already returning this */
-		if (tmp == -EINPROGRESS) {
-			tmp = urb->pipe;
-			unlink1 (hcd, urb);
-			dev_dbg (hcd->self.controller,
-				"shutdown urb %p pipe %08x ep%d%s%s\n",
-				urb, tmp, usb_pipeendpoint (tmp),
-				(tmp & USB_DIR_IN) ? "in" : "out",
-				({ char *s; \
-				 switch (usb_pipetype (tmp)) { \
-				 case PIPE_CONTROL:	s = ""; break; \
-				 case PIPE_BULK:	s = "-bulk"; break; \
-				 case PIPE_INTERRUPT:	s = "-intr"; break; \
-				 default: 		s = "-iso"; break; \
-				}; s;}));
-		}
+		/* kick hcd */
+		unlink1(hcd, urb, -ESHUTDOWN);
+		dev_dbg (hcd->self.controller,
+			"shutdown urb %p ep%d%s%s\n",
+			urb, usb_endpoint_num(&ep->desc),
+			is_in ? "in" : "out",
+			({	char *s;
+
+				 switch (usb_endpoint_type(&ep->desc)) {
+				 case USB_ENDPOINT_XFER_CONTROL:
+					s = ""; break;
+				 case USB_ENDPOINT_XFER_BULK:
+					s = "-bulk"; break;
+				 case USB_ENDPOINT_XFER_INT:
+					s = "-intr"; break;
+				 default:
+			 		s = "-iso"; break;
+				};
+				s;
+			}));
 		usb_put_urb (urb);
 
 		/* list contents may have changed */
 		goto rescan;
 	}
-	spin_unlock(&hcd_urb_list_lock);
-	local_irq_enable ();
-
-	/* synchronize with the hardware, so old configuration state
-	 * clears out immediately (and will be freed).
-	 */
-	might_sleep ();
-	if (hcd->driver->endpoint_disable)
-		hcd->driver->endpoint_disable (hcd, ep);
+	spin_unlock_irq(&hcd_urb_list_lock);
 
-	/* Wait until the endpoint queue is completely empty.  Most HCDs
-	 * will have done this already in their endpoint_disable method,
-	 * but some might not.  And there could be root-hub control URBs
-	 * still pending since they aren't affected by the HCDs'
-	 * endpoint_disable methods.
-	 */
+	/* Wait until the endpoint queue is completely empty */
 	while (!list_empty (&ep->urb_list)) {
 		spin_lock_irq(&hcd_urb_list_lock);
 
@@ -1278,6 +1370,25 @@ rescan:
 	}
 }
 
+/* Disables the endpoint: synchronizes with the hcd to make sure all
+ * endpoint state is gone from hardware.  usb_hcd_flush_endpoint() must
+ * have been called previously.  Use for set_configuration, set_interface,
+ * driver removal, physical disconnect.
+ *
+ * example:  a qh stored in ep->hcpriv, holding state related to endpoint
+ * type, maxpacket size, toggle, halt status, and scheduling.
+ */
+void usb_hcd_disable_endpoint(struct usb_device *udev,
+		struct usb_host_endpoint *ep)
+{
+	struct usb_hcd		*hcd;
+
+	might_sleep();
+	hcd = bus_to_hcd(udev->bus);
+	if (hcd->driver->endpoint_disable)
+		hcd->driver->endpoint_disable(hcd, ep);
+}
+
 /*-------------------------------------------------------------------------*/
 
 /* called in any context */
@@ -1525,7 +1636,6 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
 	hcd->driver = driver;
 	hcd->product_desc = (driver->product_desc) ? driver->product_desc :
 			"USB Host Controller";
-
 	return hcd;
 }
 EXPORT_SYMBOL (usb_create_hcd);
@@ -1570,6 +1680,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
 
 	dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
 
+	hcd->authorized_default = hcd->wireless? 0 : 1;
 	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 
 	/* HC is in reset state, but accessible.  Now do the one-time init,
@@ -1646,10 +1757,20 @@ int usb_add_hcd(struct usb_hcd *hcd,
 	if ((retval = register_root_hub(hcd)) != 0)
 		goto err_register_root_hub;
 
+	retval = sysfs_create_group(&rhdev->dev.kobj, &usb_bus_attr_group);
+	if (retval < 0) {
+		printk(KERN_ERR "Cannot register USB bus sysfs attributes: %d\n",
+		       retval);
+		goto error_create_attr_group;
+	}
 	if (hcd->uses_new_polling && hcd->poll_rh)
 		usb_hcd_poll_rh_status(hcd);
 	return retval;
 
+error_create_attr_group:
+	mutex_lock(&usb_bus_list_lock);
+	usb_disconnect(&hcd->self.root_hub);
+	mutex_unlock(&usb_bus_list_lock);
 err_register_root_hub:
 	hcd->driver->stop(hcd);
 err_hcd_driver_start:
@@ -1691,6 +1812,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
 	cancel_work_sync(&hcd->wakeup_work);
 #endif
 
+	sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group);
 	mutex_lock(&usb_bus_list_lock);
 	usb_disconnect(&hcd->self.root_hub);
 	mutex_unlock(&usb_bus_list_lock);

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

@@ -19,6 +19,8 @@
 
 #ifdef __KERNEL__
 
+#include <linux/rwsem.h>
+
 /* This file contains declarations of usbcore internals that are mostly
  * used or exposed by Host Controller Drivers.
  */
@@ -51,6 +53,12 @@
  *
  * Since "struct usb_bus" is so thin, you can't share much code in it.
  * This framework is a layer over that, and should be more sharable.
+ *
+ * @authorized_default: Specifies if new devices are authorized to
+ *                      connect by default or they require explicit
+ *                      user space authorization; this bit is settable
+ *                      through /sys/class/usb_host/X/authorized_default.
+ *                      For the rest is RO, so we don't lock to r/w it.
  */
 
 /*-------------------------------------------------------------------------*/
@@ -90,6 +98,7 @@ struct usb_hcd {
 	unsigned		poll_rh:1;	/* poll for rh status? */
 	unsigned		poll_pending:1;	/* status has changed? */
 	unsigned		wireless:1;	/* Wireless USB HCD */
+	unsigned		authorized_default:1;
 
 	int			irq;		/* irq allocated */
 	void __iomem		*regs;		/* device memory/io */
@@ -182,11 +191,10 @@ struct hc_driver {
 	int	(*get_frame_number) (struct usb_hcd *hcd);
 
 	/* manage i/o requests, device state */
-	int	(*urb_enqueue) (struct usb_hcd *hcd,
-					struct usb_host_endpoint *ep,
-					struct urb *urb,
-					gfp_t mem_flags);
-	int	(*urb_dequeue) (struct usb_hcd *hcd, struct urb *urb);
+	int	(*urb_enqueue)(struct usb_hcd *hcd,
+				struct urb *urb, gfp_t mem_flags);
+	int	(*urb_dequeue)(struct usb_hcd *hcd,
+				struct urb *urb, int status);
 
 	/* hw synch, freeing endpoint resources that urb_dequeue can't */
 	void 	(*endpoint_disable)(struct usb_hcd *hcd,
@@ -204,10 +212,18 @@ struct hc_driver {
 		/* Needed only if port-change IRQs are level-triggered */
 };
 
+extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
+extern int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
+		int status);
+extern void usb_hcd_unlink_urb_from_ep(struct usb_hcd *hcd, struct urb *urb);
+
 extern int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags);
 extern int usb_hcd_unlink_urb (struct urb *urb, int status);
-extern void usb_hcd_giveback_urb (struct usb_hcd *hcd, struct urb *urb);
-extern void usb_hcd_endpoint_disable (struct usb_device *udev,
+extern void usb_hcd_giveback_urb(struct usb_hcd *hcd, struct urb *urb,
+		int status);
+extern void usb_hcd_flush_endpoint(struct usb_device *udev,
+		struct usb_host_endpoint *ep);
+extern void usb_hcd_disable_endpoint(struct usb_device *udev,
 		struct usb_host_endpoint *ep);
 extern int usb_hcd_get_frame_number (struct usb_device *udev);
 
@@ -402,7 +418,7 @@ static inline void usbfs_cleanup(void) { }
 struct usb_mon_operations {
 	void (*urb_submit)(struct usb_bus *bus, struct urb *urb);
 	void (*urb_submit_error)(struct usb_bus *bus, struct urb *urb, int err);
-	void (*urb_complete)(struct usb_bus *bus, struct urb *urb);
+	void (*urb_complete)(struct usb_bus *bus, struct urb *urb, int status);
 	/* void (*urb_unlink)(struct usb_bus *bus, struct urb *urb); */
 };
 
@@ -421,10 +437,11 @@ static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
 		(*mon_ops->urb_submit_error)(bus, urb, error);
 }
 
-static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb)
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
+		int status)
 {
 	if (bus->monitored)
-		(*mon_ops->urb_complete)(bus, urb);
+		(*mon_ops->urb_complete)(bus, urb, status);
 }
 
 int usb_mon_register(struct usb_mon_operations *ops);
@@ -435,7 +452,8 @@ void usb_mon_deregister(void);
 static inline void usbmon_urb_submit(struct usb_bus *bus, struct urb *urb) {}
 static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
     int error) {}
-static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
+		int status) {}
 
 #endif /* CONFIG_USB_MON */
 
@@ -454,5 +472,9 @@ static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
 		: (in_interrupt () ? "in_interrupt" : "can sleep"))
 
 
-#endif /* __KERNEL__ */
+/* This rwsem is for use only by the hub driver and ehci-hcd.
+ * Nobody else should touch it.
+ */
+extern struct rw_semaphore ehci_cf_port_reset_rwsem;
 
+#endif /* __KERNEL__ */

+ 204 - 72
drivers/usb/core/hub.c

@@ -125,6 +125,12 @@ MODULE_PARM_DESC(use_both_schemes,
 		"try the other device initialization scheme if the "
 		"first one fails");
 
+/* Mutual exclusion for EHCI CF initialization.  This interferes with
+ * port reset on some companion controllers.
+ */
+DECLARE_RWSEM(ehci_cf_port_reset_rwsem);
+EXPORT_SYMBOL_GPL(ehci_cf_port_reset_rwsem);
+
 
 static inline char *portspeed(int portstatus)
 {
@@ -347,11 +353,11 @@ void usb_kick_khubd(struct usb_device *hdev)
 static void hub_irq(struct urb *urb)
 {
 	struct usb_hub *hub = urb->context;
-	int status;
+	int status = urb->status;
 	int i;
 	unsigned long bits;
 
-	switch (urb->status) {
+	switch (status) {
 	case -ENOENT:		/* synchronous unlink */
 	case -ECONNRESET:	/* async unlink */
 	case -ESHUTDOWN:	/* hardware going away */
@@ -359,10 +365,10 @@ static void hub_irq(struct urb *urb)
 
 	default:		/* presumably an error */
 		/* Cause a hub reset after 10 consecutive errors */
-		dev_dbg (hub->intfdev, "transfer --> %d\n", urb->status);
+		dev_dbg (hub->intfdev, "transfer --> %d\n", status);
 		if ((++hub->nerrors < 10) || hub->error)
 			goto resubmit;
-		hub->error = urb->status;
+		hub->error = status;
 		/* FALL THROUGH */
 
 	/* let khubd handle things */
@@ -1220,54 +1226,14 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
 #endif
 
 /**
- * usb_new_device - perform initial device setup (usbcore-internal)
+ * usb_configure_device_otg - FIXME (usbcore-internal)
  * @udev: newly addressed device (in ADDRESS state)
  *
- * This is called with devices which have been enumerated, but not yet
- * configured.  The device descriptor is available, but not descriptors
- * for any device configuration.  The caller must have locked either
- * the parent hub (if udev is a normal device) or else the
- * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
- * udev has already been installed, but udev is not yet visible through
- * sysfs or other filesystem code.
- *
- * It will return if the device is configured properly or not.  Zero if
- * the interface was registered with the driver core; else a negative
- * errno value.
- *
- * This call is synchronous, and may not be used in an interrupt context.
- *
- * Only the hub driver or root-hub registrar should ever call this.
+ * Do configuration for On-The-Go devices
  */
-int usb_new_device(struct usb_device *udev)
+static int usb_configure_device_otg(struct usb_device *udev)
 {
-	int err;
-
-	/* Determine quirks */
-	usb_detect_quirks(udev);
-
-	err = usb_get_configuration(udev);
-	if (err < 0) {
-		dev_err(&udev->dev, "can't read configurations, error %d\n",
-			err);
-		goto fail;
-	}
-
-	/* read the standard strings and cache them if present */
-	udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
-	udev->manufacturer = usb_cache_string(udev,
-			udev->descriptor.iManufacturer);
-	udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
-
-	/* Tell the world! */
-	dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
-			"SerialNumber=%d\n",
-			udev->descriptor.iManufacturer,
-			udev->descriptor.iProduct,
-			udev->descriptor.iSerialNumber);
-	show_string(udev, "Product", udev->product);
-	show_string(udev, "Manufacturer", udev->manufacturer);
-	show_string(udev, "SerialNumber", udev->serial);
+	int err = 0;
 
 #ifdef	CONFIG_USB_OTG
 	/*
@@ -1329,8 +1295,82 @@ int usb_new_device(struct usb_device *udev)
 		err = -ENOTSUPP;
 		goto fail;
 	}
+fail:
 #endif
+	return err;
+}
+
+
+/**
+ * usb_configure_device - Detect and probe device intfs/otg (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is only called by usb_new_device() and usb_authorize_device()
+ * and FIXME -- all comments that apply to them apply here wrt to
+ * environment.
+ *
+ * If the device is WUSB and not authorized, we don't attempt to read
+ * the string descriptors, as they will be errored out by the device
+ * until it has been authorized.
+ */
+static int usb_configure_device(struct usb_device *udev)
+{
+	int err;
 
+	if (udev->config == NULL) {
+		err = usb_get_configuration(udev);
+		if (err < 0) {
+			dev_err(&udev->dev, "can't read configurations, error %d\n",
+				err);
+			goto fail;
+		}
+	}
+	if (udev->wusb == 1 && udev->authorized == 0) {
+		udev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+		udev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+		udev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+	}
+	else {
+		/* read the standard strings and cache them if present */
+		udev->product = usb_cache_string(udev, udev->descriptor.iProduct);
+		udev->manufacturer = usb_cache_string(udev,
+						      udev->descriptor.iManufacturer);
+		udev->serial = usb_cache_string(udev, udev->descriptor.iSerialNumber);
+	}
+	err = usb_configure_device_otg(udev);
+fail:
+	return err;
+}
+
+
+/**
+ * usb_new_device - perform initial device setup (usbcore-internal)
+ * @udev: newly addressed device (in ADDRESS state)
+ *
+ * This is called with devices which have been enumerated, but not yet
+ * configured.  The device descriptor is available, but not descriptors
+ * for any device configuration.  The caller must have locked either
+ * the parent hub (if udev is a normal device) or else the
+ * usb_bus_list_lock (if udev is a root hub).  The parent's pointer to
+ * udev has already been installed, but udev is not yet visible through
+ * sysfs or other filesystem code.
+ *
+ * It will return if the device is configured properly or not.  Zero if
+ * the interface was registered with the driver core; else a negative
+ * errno value.
+ *
+ * This call is synchronous, and may not be used in an interrupt context.
+ *
+ * Only the hub driver or root-hub registrar should ever call this.
+ */
+int usb_new_device(struct usb_device *udev)
+{
+	int err;
+
+	usb_detect_quirks(udev);		/* Determine quirks */
+	err = usb_configure_device(udev);	/* detect & probe dev/intfs */
+	if (err < 0)
+		goto fail;
 	/* export the usbdev device-node for libusb */
 	udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
 			(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
@@ -1346,19 +1386,106 @@ int usb_new_device(struct usb_device *udev)
 	err = device_add(&udev->dev);
 	if (err) {
 		dev_err(&udev->dev, "can't device_add, error %d\n", err);
-		if (udev->parent)
-			usb_autosuspend_device(udev->parent);
 		goto fail;
 	}
 
-exit:
+	/* Tell the world! */
+	dev_dbg(&udev->dev, "new device strings: Mfr=%d, Product=%d, "
+		"SerialNumber=%d\n",
+		udev->descriptor.iManufacturer,
+		udev->descriptor.iProduct,
+		udev->descriptor.iSerialNumber);
+	show_string(udev, "Product", udev->product);
+	show_string(udev, "Manufacturer", udev->manufacturer);
+	show_string(udev, "SerialNumber", udev->serial);
 	return err;
 
 fail:
 	usb_set_device_state(udev, USB_STATE_NOTATTACHED);
-	goto exit;
+	return err;
 }
 
+
+/**
+ * Similar to usb_disconnect()
+ *
+ * We share a lock (that we have) with device_del(), so we need to
+ * defer its call.
+ */
+int usb_deauthorize_device(struct usb_device *usb_dev)
+{
+	unsigned cnt;
+	usb_lock_device(usb_dev);
+	if (usb_dev->authorized == 0)
+		goto out_unauthorized;
+	usb_dev->authorized = 0;
+	usb_set_configuration(usb_dev, -1);
+	usb_dev->product = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+	usb_dev->manufacturer = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+	usb_dev->serial = kstrdup("n/a (unauthorized)", GFP_KERNEL);
+	kfree(usb_dev->config);
+	usb_dev->config = NULL;
+	for (cnt = 0; cnt < usb_dev->descriptor.bNumConfigurations; cnt++)
+		kfree(usb_dev->rawdescriptors[cnt]);
+	usb_dev->descriptor.bNumConfigurations = 0;
+	kfree(usb_dev->rawdescriptors);
+out_unauthorized:
+	usb_unlock_device(usb_dev);
+	return 0;
+}
+
+
+int usb_authorize_device(struct usb_device *usb_dev)
+{
+	int result = 0, c;
+	usb_lock_device(usb_dev);
+	if (usb_dev->authorized == 1)
+		goto out_authorized;
+	kfree(usb_dev->product);
+	usb_dev->product = NULL;
+	kfree(usb_dev->manufacturer);
+	usb_dev->manufacturer = NULL;
+	kfree(usb_dev->serial);
+	usb_dev->serial = NULL;
+	result = usb_autoresume_device(usb_dev);
+	if (result < 0) {
+		dev_err(&usb_dev->dev,
+			"can't autoresume for authorization: %d\n", result);
+		goto error_autoresume;
+	}
+	result = usb_get_device_descriptor(usb_dev, sizeof(usb_dev->descriptor));
+	if (result < 0) {
+		dev_err(&usb_dev->dev, "can't re-read device descriptor for "
+			"authorization: %d\n", result);
+		goto error_device_descriptor;
+	}
+	usb_dev->authorized = 1;
+	result = usb_configure_device(usb_dev);
+	if (result < 0)
+		goto error_configure;
+	/* Choose and set the configuration.  This registers the interfaces
+	 * with the driver core and lets interface drivers bind to them.
+	 */
+	c = usb_choose_configuration(usb_dev);
+	if (c >= 0) {
+		result = usb_set_configuration(usb_dev, c);
+		if (result) {
+			dev_err(&usb_dev->dev,
+				"can't set config #%d, error %d\n", c, result);
+			/* This need not be fatal.  The user can try to
+			 * set other configurations. */
+		}
+	}
+	dev_info(&usb_dev->dev, "authorized to connect\n");
+error_configure:
+error_device_descriptor:
+error_autoresume:
+out_authorized:
+	usb_unlock_device(usb_dev);	// complements locktree
+	return result;
+}
+
+
 static int hub_port_status(struct usb_hub *hub, int port1,
 			       u16 *status, u16 *change)
 {
@@ -1460,6 +1587,11 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 {
 	int i, status;
 
+	/* Block EHCI CF initialization during the port reset.
+	 * Some companion controllers don't like it when they mix.
+	 */
+	down_read(&ehci_cf_port_reset_rwsem);
+
 	/* Reset the port */
 	for (i = 0; i < PORT_RESET_TRIES; i++) {
 		status = set_port_feature(hub->hdev,
@@ -1481,6 +1613,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 		case 0:
 			/* TRSTRCY = 10 ms; plus some extra */
 			msleep(10 + 40);
+		  	udev->devnum = 0;	/* Device now at address 0 */
 			/* FALL THROUGH */
 		case -ENOTCONN:
 		case -ENODEV:
@@ -1490,7 +1623,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 			usb_set_device_state(udev, status
 					? USB_STATE_NOTATTACHED
 					: USB_STATE_DEFAULT);
-			return status;
+			goto done;
 		}
 
 		dev_dbg (hub->intfdev,
@@ -1503,6 +1636,8 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 		"Cannot enable port %i.  Maybe the USB cable is bad?\n",
 		port1);
 
+ done:
+	up_read(&ehci_cf_port_reset_rwsem);
 	return status;
 }
 
@@ -1833,14 +1968,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
 		struct usb_device	*udev;
 
 		udev = hdev->children [port1-1];
-		if (udev && msg.event == PM_EVENT_SUSPEND &&
-#ifdef	CONFIG_USB_SUSPEND
-				udev->state != USB_STATE_SUSPENDED
-#else
-				udev->dev.power.power_state.event
-					== PM_EVENT_ON
-#endif
-				) {
+		if (udev && udev->can_submit) {
 			if (!hdev->auto_pm)
 				dev_dbg(&intf->dev, "port %d nyet suspended\n",
 						port1);
@@ -1999,26 +2127,27 @@ static void ep0_reinit(struct usb_device *udev)
 {
 	usb_disable_endpoint(udev, 0 + USB_DIR_IN);
 	usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
-	udev->ep_in[0] = udev->ep_out[0] = &udev->ep0;
+	usb_enable_endpoint(udev, &udev->ep0);
 }
 
 #define usb_sndaddr0pipe()	(PIPE_CONTROL << 30)
 #define usb_rcvaddr0pipe()	((PIPE_CONTROL << 30) | USB_DIR_IN)
 
-static int hub_set_address(struct usb_device *udev)
+static int hub_set_address(struct usb_device *udev, int devnum)
 {
 	int retval;
 
-	if (udev->devnum == 0)
+	if (devnum <= 1)
 		return -EINVAL;
 	if (udev->state == USB_STATE_ADDRESS)
 		return 0;
 	if (udev->state != USB_STATE_DEFAULT)
 		return -EINVAL;
 	retval = usb_control_msg(udev, usb_sndaddr0pipe(),
-		USB_REQ_SET_ADDRESS, 0, udev->devnum, 0,
+		USB_REQ_SET_ADDRESS, 0, devnum, 0,
 		NULL, 0, USB_CTRL_SET_TIMEOUT);
 	if (retval == 0) {
+		udev->devnum = devnum;	/* Device now using proper address */
 		usb_set_device_state(udev, USB_STATE_ADDRESS);
 		ep0_reinit(udev);
 	}
@@ -2045,6 +2174,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 	unsigned		delay = HUB_SHORT_RESET_TIME;
 	enum usb_device_speed	oldspeed = udev->speed;
 	char 			*speed, *type;
+	int			devnum = udev->devnum;
 
 	/* root hub ports have a slightly longer reset period
 	 * (from USB 2.0 spec, section 7.1.7.5)
@@ -2074,7 +2204,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 		goto fail;
 	}
 	oldspeed = udev->speed;
-  
+
 	/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
 	 * it's fixed size except for full speed devices.
 	 * For Wireless USB devices, ep0 max packet is always 512 (tho
@@ -2115,7 +2245,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 	dev_info (&udev->dev,
 		  "%s %s speed %sUSB device using %s and address %d\n",
 		  (udev->config) ? "reset" : "new", speed, type,
-		  udev->bus->controller->driver->name, udev->devnum);
+		  udev->bus->controller->driver->name, devnum);
 
 	/* Set up TT records, if needed  */
 	if (hdev->tt) {
@@ -2202,7 +2332,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 		}
 
 		for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
-			retval = hub_set_address(udev);
+			retval = hub_set_address(udev, devnum);
 			if (retval >= 0)
 				break;
 			msleep(200);
@@ -2210,7 +2340,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 		if (retval < 0) {
 			dev_err(&udev->dev,
 				"device not accepting address %d, error %d\n",
-				udev->devnum, retval);
+				devnum, retval);
 			goto fail;
 		}
  
@@ -2263,8 +2393,10 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 	retval = 0;
 
 fail:
-	if (retval)
+	if (retval) {
 		hub_port_disable(hub, port1, 0);
+		udev->devnum = devnum;	/* for disconnect processing */
+	}
 	mutex_unlock(&usb_address0_mutex);
 	return retval;
 }
@@ -2699,9 +2831,9 @@ static void hub_events(void)
 				clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
 				if (hubstatus & HUB_STATUS_LOCAL_POWER)
 					/* FIXME: Is this always true? */
-					hub->limited_power = 0;
-				else
 					hub->limited_power = 1;
+				else
+					hub->limited_power = 0;
 			}
 			if (hubchange & HUB_CHANGE_OVERCURRENT) {
 				dev_dbg (hub_dev, "overcurrent change\n");

+ 29 - 21
drivers/usb/core/message.c

@@ -59,8 +59,8 @@ static int usb_start_wait_urb(struct urb *urb, int timeout, int *actual_length)
 		dev_dbg(&urb->dev->dev,
 			"%s timed out on ep%d%s len=%d/%d\n",
 			current->comm,
-			usb_pipeendpoint(urb->pipe),
-			usb_pipein(urb->pipe) ? "in" : "out",
+			usb_endpoint_num(&urb->ep->desc),
+			usb_urb_dir_in(urb) ? "in" : "out",
 			urb->actual_length,
 			urb->transfer_buffer_length);
 	} else
@@ -250,7 +250,8 @@ static void sg_clean (struct usb_sg_request *io)
 		io->urbs = NULL;
 	}
 	if (io->dev->dev.dma_mask != NULL)
-		usb_buffer_unmap_sg (io->dev, io->pipe, io->sg, io->nents);
+		usb_buffer_unmap_sg (io->dev, usb_pipein(io->pipe),
+				io->sg, io->nents);
 	io->dev = NULL;
 }
 
@@ -278,8 +279,8 @@ static void sg_complete (struct urb *urb)
 		dev_err (io->dev->bus->controller,
 			"dev %s ep%d%s scatterlist error %d/%d\n",
 			io->dev->devpath,
-			usb_pipeendpoint (urb->pipe),
-			usb_pipein (urb->pipe) ? "in" : "out",
+			usb_endpoint_num(&urb->ep->desc),
+			usb_urb_dir_in(urb) ? "in" : "out",
 			status, io->status);
 		// BUG ();
 	}
@@ -379,7 +380,8 @@ int usb_sg_init (
 	 */
 	dma = (dev->dev.dma_mask != NULL);
 	if (dma)
-		io->entries = usb_buffer_map_sg (dev, pipe, sg, nents);
+		io->entries = usb_buffer_map_sg(dev, usb_pipein(pipe),
+				sg, nents);
 	else
 		io->entries = nents;
 
@@ -1013,8 +1015,11 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr)
 		ep = dev->ep_in[epnum];
 		dev->ep_in[epnum] = NULL;
 	}
-	if (ep && dev->bus)
-		usb_hcd_endpoint_disable(dev, ep);
+	if (ep) {
+		ep->enabled = 0;
+		usb_hcd_flush_endpoint(dev, ep);
+		usb_hcd_disable_endpoint(dev, ep);
+	}
 }
 
 /**
@@ -1096,23 +1101,21 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
  * Resets the endpoint toggle, and sets dev->ep_{in,out} pointers.
  * For control endpoints, both the input and output sides are handled.
  */
-static void
-usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
+void usb_enable_endpoint(struct usb_device *dev, struct usb_host_endpoint *ep)
 {
-	unsigned int epaddr = ep->desc.bEndpointAddress;
-	unsigned int epnum = epaddr & USB_ENDPOINT_NUMBER_MASK;
-	int is_control;
+	int epnum = usb_endpoint_num(&ep->desc);
+	int is_out = usb_endpoint_dir_out(&ep->desc);
+	int is_control = usb_endpoint_xfer_control(&ep->desc);
 
-	is_control = ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-			== USB_ENDPOINT_XFER_CONTROL);
-	if (usb_endpoint_out(epaddr) || is_control) {
+	if (is_out || is_control) {
 		usb_settoggle(dev, epnum, 1, 0);
 		dev->ep_out[epnum] = ep;
 	}
-	if (!usb_endpoint_out(epaddr) || is_control) {
+	if (!is_out || is_control) {
 		usb_settoggle(dev, epnum, 0, 0);
 		dev->ep_in[epnum] = ep;
 	}
+	ep->enabled = 1;
 }
 
 /*
@@ -1171,6 +1174,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
 	struct usb_host_interface *alt;
 	int ret;
 	int manual = 0;
+	int changed;
 
 	if (dev->state == USB_STATE_SUSPENDED)
 		return -EHOSTUNREACH;
@@ -1210,7 +1214,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
 	 */
 
 	/* prevent submissions using previous endpoint settings */
-	if (device_is_registered(&iface->dev))
+	changed = (iface->cur_altsetting != alt);
+	if (changed && device_is_registered(&iface->dev))
 		usb_remove_sysfs_intf_files(iface);
 	usb_disable_interface(dev, iface);
 
@@ -1247,7 +1252,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
 	 * (Likewise, EP0 never "halts" on well designed devices.)
 	 */
 	usb_enable_interface(dev, iface);
-	if (device_is_registered(&iface->dev))
+	if (changed && device_is_registered(&iface->dev))
 		usb_create_sysfs_intf_files(iface);
 
 	return 0;
@@ -1328,7 +1333,7 @@ int usb_reset_configuration(struct usb_device *dev)
 	return 0;
 }
 
-void usb_release_interface(struct device *dev)
+static void usb_release_interface(struct device *dev)
 {
 	struct usb_interface *intf = to_usb_interface(dev);
 	struct usb_interface_cache *intfc =
@@ -1481,6 +1486,9 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
  * channels are available independently; and choosing between open
  * standard device protocols (like CDC) or proprietary ones.
  *
+ * Note that a non-authorized device (dev->authorized == 0) will only
+ * be put in unconfigured mode.
+ *
  * Note that USB has an additional level of device configurability,
  * associated with interfaces.  That configurability is accessed using
  * usb_set_interface().
@@ -1502,7 +1510,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
 	struct usb_interface **new_interfaces = NULL;
 	int n, nintf;
 
-	if (configuration == -1)
+	if (dev->authorized == 0 || configuration == -1)
 		configuration = 0;
 	else {
 		for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {

+ 1 - 80
drivers/usb/core/quirks.c

@@ -32,52 +32,6 @@ static const struct usb_device_id usb_quirk_list[] = {
 	{ USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME },
 	/* HP 5300/5370C scanner */
 	{ USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
-	/* Hewlett-Packard PhotoSmart 720 / PhotoSmart 935 (storage) */
-	{ USB_DEVICE(0x03f0, 0x4002), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-	/* SGS Thomson Microelectronics 4in1 card reader */
-	{ USB_DEVICE(0x0483, 0x0321), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-	/* Acer Peripherals Inc. (now BenQ Corp.) Prisa 640BU */
-	{ USB_DEVICE(0x04a5, 0x207e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Benq S2W 3300U */
-	{ USB_DEVICE(0x04a5, 0x20b0), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Canon, Inc. CanoScan N1240U/LiDE30 */
-	{ USB_DEVICE(0x04a9, 0x220e), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Canon, Inc. CanoScan N650U/N656U */
-	{ USB_DEVICE(0x04a9, 0x2206), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Canon, Inc. CanoScan 1220U */
-	{ USB_DEVICE(0x04a9, 0x2207), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Canon, Inc. CanoScan N670U/N676U/LiDE 20 */
-	{ USB_DEVICE(0x04a9, 0x220d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* old Cannon scanner */
-	{ USB_DEVICE(0x04a9, 0x2220), .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 660 */
-	{ USB_DEVICE(0x04b8, 0x0114), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Epson Perfection 1260 Photo */
-	{ USB_DEVICE(0x04b8, 0x011d), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Seiko Epson Corp - Perfection 1670 */
-	{ USB_DEVICE(0x04b8, 0x011f), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* EPSON Perfection 2480 */
-	{ USB_DEVICE(0x04b8, 0x0121), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Seiko Epson Corp.*/
-	{ USB_DEVICE(0x04b8, 0x0122), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Samsung ML-2010 printer */
-	{ USB_DEVICE(0x04e8, 0x326c), .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) */
-	{ USB_DEVICE(0x05cc, 0x2267), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Ultima Electronics Corp.*/
-	{ USB_DEVICE(0x05d8, 0x4005), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-	/* Genesys USB-to-IDE */
-	{ USB_DEVICE(0x0503, 0x0702), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-	/* USB Graphical LCD - EEH Datalink GmbH */
-	{ USB_DEVICE(0x060c, 0x04eb), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
 
 	/* INTEL VALUE SSD */
 	{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
@@ -85,44 +39,15 @@ static const struct usb_device_id usb_quirk_list[] = {
 	/* M-Systems Flash Disk Pioneers */
 	{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
 
-	/* Agfa Snapscan1212u */
-	{ USB_DEVICE(0x06bd, 0x2061), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-	/* Seagate RSS LLC */
-	{ USB_DEVICE(0x0bc2, 0x3000), .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 },
 
-	/* Alcor multi-card reader */
-	{ USB_DEVICE(0x058f, 0x6366), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-	/* Canon EOS 5D in PC Connection mode */
-	{ USB_DEVICE(0x04a9, 0x3101), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
-	/* 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 },
-
-	/* Apple iPhone */
-	{ USB_DEVICE(0x05ac, 0x1290), .driver_info = USB_QUIRK_NO_AUTOSUSPEND },
-
 	/* SKYMEDI USB_DRIVE */
 	{ USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
 
 	{ }  /* terminating entry must be last */
 };
 
-static void usb_autosuspend_quirk(struct usb_device *udev)
-{
-#ifdef	CONFIG_USB_SUSPEND
-	/* disable autosuspend, but allow the user to re-enable it via sysfs */
-	udev->autosuspend_disabled = 1;
-#endif
-}
-
 static const struct usb_device_id *find_id(struct usb_device *udev)
 {
 	const struct usb_device_id *id = usb_quirk_list;
@@ -149,13 +74,9 @@ void usb_detect_quirks(struct usb_device *udev)
 		dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
 				udev->quirks);
 
-	/* do any special quirk handling here if needed */
-	if (udev->quirks & USB_QUIRK_NO_AUTOSUSPEND)
-		usb_autosuspend_quirk(udev);
-
 	/* By default, disable autosuspend for all non-hubs */
 #ifdef	CONFIG_USB_SUSPEND
 	if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
-		udev->autosuspend_delay = -1;
+		udev->autosuspend_disabled = 1;
 #endif
 }

+ 50 - 0
drivers/usb/core/sysfs.c

@@ -169,6 +169,16 @@ show_quirks(struct device *dev, struct device_attribute *attr, char *buf)
 }
 static DEVICE_ATTR(quirks, S_IRUGO, show_quirks, NULL);
 
+static ssize_t
+show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct usb_device *udev;
+
+	udev = to_usb_device(dev);
+	return sprintf(buf, "%d\n", atomic_read(&udev->urbnum));
+}
+static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
+
 
 #if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND)
 static const char power_group[] = "power";
@@ -413,6 +423,44 @@ usb_descriptor_attr(bDeviceProtocol, "%02x\n")
 usb_descriptor_attr(bNumConfigurations, "%d\n")
 usb_descriptor_attr(bMaxPacketSize0, "%d\n")
 
+
+
+/* show if the device is authorized (1) or not (0) */
+static ssize_t usb_dev_authorized_show(struct device *dev,
+				       struct device_attribute *attr,
+				       char *buf)
+{
+	struct usb_device *usb_dev = to_usb_device(dev);
+	return snprintf(buf, PAGE_SIZE, "%u\n", usb_dev->authorized);
+}
+
+
+/*
+ * Authorize a device to be used in the system
+ *
+ * Writing a 0 deauthorizes the device, writing a 1 authorizes it.
+ */
+static ssize_t usb_dev_authorized_store(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t size)
+{
+	ssize_t result;
+	struct usb_device *usb_dev = to_usb_device(dev);
+	unsigned val;
+	result = sscanf(buf, "%u\n", &val);
+	if (result != 1)
+		result = -EINVAL;
+	else if (val == 0)
+		result = usb_deauthorize_device(usb_dev);
+	else
+		result = usb_authorize_device(usb_dev);
+	return result < 0? result : size;
+}
+
+static DEVICE_ATTR(authorized, 0644,
+	    usb_dev_authorized_show, usb_dev_authorized_store);
+
+
 static struct attribute *dev_attrs[] = {
 	/* current configuration's attributes */
 	&dev_attr_configuration.attr,
@@ -420,6 +468,7 @@ static struct attribute *dev_attrs[] = {
 	&dev_attr_bConfigurationValue.attr,
 	&dev_attr_bmAttributes.attr,
 	&dev_attr_bMaxPower.attr,
+	&dev_attr_urbnum.attr,
 	/* device attributes */
 	&dev_attr_idVendor.attr,
 	&dev_attr_idProduct.attr,
@@ -435,6 +484,7 @@ static struct attribute *dev_attrs[] = {
 	&dev_attr_version.attr,
 	&dev_attr_maxchild.attr,
 	&dev_attr_quirks.attr,
+	&dev_attr_authorized.attr,
 	NULL,
 };
 static struct attribute_group dev_attr_grp = {

+ 61 - 45
drivers/usb/core/urb.c

@@ -3,6 +3,7 @@
 #include <linux/bitops.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/log2.h>
 #include <linux/usb.h>
 #include <linux/wait.h>
 #include "hcd.h"
@@ -38,7 +39,6 @@ void usb_init_urb(struct urb *urb)
 	if (urb) {
 		memset(urb, 0, sizeof(*urb));
 		kref_init(&urb->kref);
-		spin_lock_init(&urb->lock);
 		INIT_LIST_HEAD(&urb->anchor_list);
 	}
 }
@@ -277,44 +277,58 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
  */
 int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 {
-	int			pipe, temp, max;
-	struct usb_device	*dev;
-	int			is_out;
+	int				xfertype, max;
+	struct usb_device		*dev;
+	struct usb_host_endpoint	*ep;
+	int				is_out;
 
 	if (!urb || urb->hcpriv || !urb->complete)
 		return -EINVAL;
-	if (!(dev = urb->dev) ||
-	    (dev->state < USB_STATE_DEFAULT) ||
-	    (!dev->bus) || (dev->devnum <= 0))
+	if (!(dev = urb->dev) || dev->state < USB_STATE_DEFAULT)
 		return -ENODEV;
-	if (dev->bus->controller->power.power_state.event != PM_EVENT_ON
-			|| dev->state == USB_STATE_SUSPENDED)
-		return -EHOSTUNREACH;
 
+	/* For now, get the endpoint from the pipe.  Eventually drivers
+	 * will be required to set urb->ep directly and we will eliminate
+	 * urb->pipe.
+	 */
+	ep = (usb_pipein(urb->pipe) ? dev->ep_in : dev->ep_out)
+			[usb_pipeendpoint(urb->pipe)];
+	if (!ep)
+		return -ENOENT;
+
+	urb->ep = ep;
 	urb->status = -EINPROGRESS;
 	urb->actual_length = 0;
 
 	/* Lots of sanity checks, so HCDs can rely on clean data
 	 * and don't need to duplicate tests
 	 */
-	pipe = urb->pipe;
-	temp = usb_pipetype(pipe);
-	is_out = usb_pipeout(pipe);
+	xfertype = usb_endpoint_type(&ep->desc);
+	if (xfertype == USB_ENDPOINT_XFER_CONTROL) {
+		struct usb_ctrlrequest *setup =
+				(struct usb_ctrlrequest *) urb->setup_packet;
+
+		if (!setup)
+			return -ENOEXEC;
+		is_out = !(setup->bRequestType & USB_DIR_IN) ||
+				!setup->wLength;
+	} else {
+		is_out = usb_endpoint_dir_out(&ep->desc);
+	}
 
-	if (!usb_pipecontrol(pipe) && dev->state < USB_STATE_CONFIGURED)
-		return -ENODEV;
+	/* Cache the direction for later use */
+	urb->transfer_flags = (urb->transfer_flags & ~URB_DIR_MASK) |
+			(is_out ? URB_DIR_OUT : URB_DIR_IN);
 
-	/* FIXME there should be a sharable lock protecting us against
-	 * config/altsetting changes and disconnects, kicking in here.
-	 * (here == before maxpacket, and eventually endpoint type,
-	 * checks get made.)
-	 */
+	if (xfertype != USB_ENDPOINT_XFER_CONTROL &&
+			dev->state < USB_STATE_CONFIGURED)
+		return -ENODEV;
 
-	max = usb_maxpacket(dev, pipe, is_out);
+	max = le16_to_cpu(ep->desc.wMaxPacketSize);
 	if (max <= 0) {
 		dev_dbg(&dev->dev,
 			"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
-			usb_pipeendpoint(pipe), is_out ? "out" : "in",
+			usb_endpoint_num(&ep->desc), is_out ? "out" : "in",
 			__FUNCTION__, max);
 		return -EMSGSIZE;
 	}
@@ -323,7 +337,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 	 * but drivers only control those sizes for ISO.
 	 * while we're checking, initialize return status.
 	 */
-	if (temp == PIPE_ISOCHRONOUS) {
+	if (xfertype == USB_ENDPOINT_XFER_ISOC) {
 		int	n, len;
 
 		/* "high bandwidth" mode, 1-3 packets/uframe? */
@@ -358,20 +372,20 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 
 	/* enforce simple/standard policy */
 	allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |
-			URB_NO_INTERRUPT);
-	switch (temp) {
-	case PIPE_BULK:
+			URB_NO_INTERRUPT | URB_DIR_MASK);
+	switch (xfertype) {
+	case USB_ENDPOINT_XFER_BULK:
 		if (is_out)
 			allowed |= URB_ZERO_PACKET;
 		/* FALLTHROUGH */
-	case PIPE_CONTROL:
+	case USB_ENDPOINT_XFER_CONTROL:
 		allowed |= URB_NO_FSBR;	/* only affects UHCI */
 		/* FALLTHROUGH */
 	default:			/* all non-iso endpoints */
 		if (!is_out)
 			allowed |= URB_SHORT_NOT_OK;
 		break;
-	case PIPE_ISOCHRONOUS:
+	case USB_ENDPOINT_XFER_ISOC:
 		allowed |= URB_ISO_ASAP;
 		break;
 	}
@@ -393,9 +407,9 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 	 * supports different values... this uses EHCI/UHCI defaults (and
 	 * EHCI can use smaller non-default values).
 	 */
-	switch (temp) {
-	case PIPE_ISOCHRONOUS:
-	case PIPE_INTERRUPT:
+	switch (xfertype) {
+	case USB_ENDPOINT_XFER_ISOC:
+	case USB_ENDPOINT_XFER_INT:
 		/* too small? */
 		if (urb->interval <= 0)
 			return -EINVAL;
@@ -405,29 +419,27 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 			// NOTE usb handles 2^15
 			if (urb->interval > (1024 * 8))
 				urb->interval = 1024 * 8;
-			temp = 1024 * 8;
+			max = 1024 * 8;
 			break;
 		case USB_SPEED_FULL:	/* units are frames/msec */
 		case USB_SPEED_LOW:
-			if (temp == PIPE_INTERRUPT) {
+			if (xfertype == USB_ENDPOINT_XFER_INT) {
 				if (urb->interval > 255)
 					return -EINVAL;
 				// NOTE ohci only handles up to 32
-				temp = 128;
+				max = 128;
 			} else {
 				if (urb->interval > 1024)
 					urb->interval = 1024;
 				// NOTE usb and ohci handle up to 2^15
-				temp = 1024;
+				max = 1024;
 			}
 			break;
 		default:
 			return -EINVAL;
 		}
-		/* power of two? */
-		while (temp > urb->interval)
-			temp >>= 1;
-		urb->interval = temp;
+		/* Round down to a power of 2, no more than max */
+		urb->interval = min(max, 1 << ilog2(urb->interval));
 	}
 
 	return usb_hcd_submit_urb(urb, mem_flags);
@@ -496,8 +508,10 @@ int usb_unlink_urb(struct urb *urb)
 {
 	if (!urb)
 		return -EINVAL;
-	if (!(urb->dev && urb->dev->bus))
+	if (!urb->dev)
 		return -ENODEV;
+	if (!urb->ep)
+		return -EIDRM;
 	return usb_hcd_unlink_urb(urb, -ECONNRESET);
 }
 
@@ -523,19 +537,21 @@ int usb_unlink_urb(struct urb *urb)
  */
 void usb_kill_urb(struct urb *urb)
 {
+	static DEFINE_MUTEX(reject_mutex);
+
 	might_sleep();
-	if (!(urb && urb->dev && urb->dev->bus))
+	if (!(urb && urb->dev && urb->ep))
 		return;
-	spin_lock_irq(&urb->lock);
+	mutex_lock(&reject_mutex);
 	++urb->reject;
-	spin_unlock_irq(&urb->lock);
+	mutex_unlock(&reject_mutex);
 
 	usb_hcd_unlink_urb(urb, -ENOENT);
 	wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
 
-	spin_lock_irq(&urb->lock);
+	mutex_lock(&reject_mutex);
 	--urb->reject;
-	spin_unlock_irq(&urb->lock);
+	mutex_unlock(&reject_mutex);
 }
 
 /**

+ 30 - 11
drivers/usb/core/usb.c

@@ -223,6 +223,15 @@ static void ksuspend_usb_cleanup(void)
 
 #endif	/* CONFIG_PM */
 
+
+/* Returns 1 if @usb_bus is WUSB, 0 otherwise */
+static unsigned usb_bus_is_wusb(struct usb_bus *bus)
+{
+	struct usb_hcd *hcd = container_of(bus, struct usb_hcd, self);
+	return hcd->wireless;
+}
+
+
 /**
  * usb_alloc_dev - usb device constructor (usbcore-internal)
  * @parent: hub to which device is connected; null to allocate a root hub
@@ -239,6 +248,8 @@ struct usb_device *
 usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
 {
 	struct usb_device *dev;
+	struct usb_hcd *usb_hcd = container_of(bus, struct usb_hcd, self);
+	unsigned root_hub = 0;
 
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev)
@@ -255,12 +266,14 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
 	dev->dev.dma_mask = bus->controller->dma_mask;
 	set_dev_node(&dev->dev, dev_to_node(bus->controller));
 	dev->state = USB_STATE_ATTACHED;
+	atomic_set(&dev->urbnum, 0);
 
 	INIT_LIST_HEAD(&dev->ep0.urb_list);
 	dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
 	dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
 	/* ep0 maxpacket comes later, from device descriptor */
-	dev->ep_in[0] = dev->ep_out[0] = &dev->ep0;
+	usb_enable_endpoint(dev, &dev->ep0);
+	dev->can_submit = 1;
 
 	/* Save readable and stable topology id, distinguishing devices
 	 * by location for diagnostics, tools, driver model, etc.  The
@@ -275,6 +288,7 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
 
 		dev->dev.parent = bus->controller;
 		sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
+		root_hub = 1;
 	} else {
 		/* match any labeling on the hubs; it's one-based */
 		if (parent->devpath[0] == '0')
@@ -301,6 +315,12 @@ usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
 	INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
 	dev->autosuspend_delay = usb_autosuspend_delay * HZ;
 #endif
+	if (root_hub)	/* Root hub always ok [and always wired] */
+		dev->authorized = 1;
+	else {
+		dev->authorized = usb_hcd->authorized_default;
+		dev->wusb = usb_bus_is_wusb(bus)? 1 : 0;
+	}
 	return dev;
 }
 
@@ -748,7 +768,7 @@ void usb_buffer_unmap(struct urb *urb)
 /**
  * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
  * @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
  * @sg: the scatterlist to map
  * @nents: the number of entries in the scatterlist
  *
@@ -771,14 +791,13 @@ void usb_buffer_unmap(struct urb *urb)
  *
  * Reverse the effect of this call with usb_buffer_unmap_sg().
  */
-int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
+int usb_buffer_map_sg(const struct usb_device *dev, int is_in,
 		      struct scatterlist *sg, int nents)
 {
 	struct usb_bus		*bus;
 	struct device		*controller;
 
 	if (!dev
-			|| usb_pipecontrol(pipe)
 			|| !(bus = dev->bus)
 			|| !(controller = bus->controller)
 			|| !controller->dma_mask)
@@ -786,7 +805,7 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
 
 	// FIXME generic api broken like pci, can't report errors
 	return dma_map_sg(controller, sg, nents,
-			usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+			is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /* XXX DISABLED, no users currently.  If you wish to re-enable this
@@ -799,14 +818,14 @@ int usb_buffer_map_sg(const struct usb_device *dev, unsigned pipe,
 /**
  * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s)
  * @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
  * @sg: the scatterlist to synchronize
  * @n_hw_ents: the positive return value from usb_buffer_map_sg
  *
  * Use this when you are re-using a scatterlist's data buffers for
  * another USB request.
  */
-void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_dmasync_sg(const struct usb_device *dev, int is_in,
 			   struct scatterlist *sg, int n_hw_ents)
 {
 	struct usb_bus		*bus;
@@ -819,20 +838,20 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
 		return;
 
 	dma_sync_sg(controller, sg, n_hw_ents,
-			usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+			is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 #endif
 
 /**
  * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
  * @dev: device to which the scatterlist will be mapped
- * @pipe: endpoint defining the mapping direction
+ * @is_in: mapping transfer direction
  * @sg: the scatterlist to unmap
  * @n_hw_ents: the positive return value from usb_buffer_map_sg
  *
  * Reverses the effect of usb_buffer_map_sg().
  */
-void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
+void usb_buffer_unmap_sg(const struct usb_device *dev, int is_in,
 			 struct scatterlist *sg, int n_hw_ents)
 {
 	struct usb_bus		*bus;
@@ -845,7 +864,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
 		return;
 
 	dma_unmap_sg(controller, sg, n_hw_ents,
-			usb_pipein(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
+			is_in ? DMA_FROM_DEVICE : DMA_TO_DEVICE);
 }
 
 /* format to disable USB on kernel command line is: nousb */

+ 5 - 0
drivers/usb/core/usb.h

@@ -8,17 +8,22 @@ extern int usb_create_ep_files(struct device *parent, struct usb_host_endpoint *
 				struct usb_device *udev);
 extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
 
+extern void usb_enable_endpoint(struct usb_device *dev,
+		struct usb_host_endpoint *ep);
 extern void usb_disable_endpoint (struct usb_device *dev, unsigned int epaddr);
 extern void usb_disable_interface (struct usb_device *dev,
 		struct usb_interface *intf);
 extern void usb_release_interface_cache(struct kref *ref);
 extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
+extern int usb_deauthorize_device (struct usb_device *);
+extern int usb_authorize_device (struct usb_device *);
 extern void usb_detect_quirks(struct usb_device *udev);
 
 extern int usb_get_device_descriptor(struct usb_device *dev,
 		unsigned int size);
 extern char *usb_cache_string(struct usb_device *udev, int index);
 extern int usb_set_configuration(struct usb_device *dev, int configuration);
+extern int usb_choose_configuration(struct usb_device *udev);
 
 extern void usb_kick_khubd(struct usb_device *dev);
 extern int usb_match_device(struct usb_device *dev,

+ 25 - 1
drivers/usb/gadget/Kconfig

@@ -67,6 +67,17 @@ config USB_GADGET_DEBUG_FILES
 	   driver on a new board.   Enable these files by choosing "Y"
 	   here.  If in doubt, or to conserve kernel memory, say "N".
 
+config USB_GADGET_DEBUG_FS
+	boolean "Debugging information files in debugfs"
+	depends on USB_GADGET && DEBUG_FS
+	help
+	   Some of the drivers in the "gadget" framework can expose
+	   debugging information in files under /sys/kernel/debug/.
+	   The information in these files may help when you're
+	   troubleshooting or bringing up a driver on a new board.
+	   Enable these files by choosing "Y" here.  If in doubt, or
+	   to conserve kernel memory, say "N".
+
 config	USB_GADGET_SELECTED
 	boolean
 
@@ -103,6 +114,20 @@ config USB_AMD5536UDC
 	default USB_GADGET
 	select USB_GADGET_SELECTED
 
+config USB_GADGET_ATMEL_USBA
+	boolean "Atmel USBA"
+	select USB_GADGET_DUALSPEED
+	depends on AVR32
+	help
+	  USBA is the integrated high-speed USB Device controller on
+	  the AT32AP700x processors from Atmel.
+
+config USB_ATMEL_USBA
+	tristate
+	depends on USB_GADGET_ATMEL_USBA
+	default USB_GADGET
+	select USB_GADGET_SELECTED
+
 config USB_GADGET_FSL_USB2
 	boolean "Freescale Highspeed USB DR Peripheral Controller"
 	depends on MPC834x || PPC_MPC831x
@@ -228,7 +253,6 @@ config USB_LH7A40X
 	default USB_GADGET
 	select USB_GADGET_SELECTED
 
-
 config USB_GADGET_OMAP
 	boolean "OMAP USB Device Controller"
 	depends on ARCH_OMAP

+ 1 - 0
drivers/usb/gadget/Makefile

@@ -14,6 +14,7 @@ obj-$(CONFIG_USB_OMAP)		+= omap_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_ATMEL_USBA)	+= atmel_usba_udc.o
 obj-$(CONFIG_USB_FSL_USB2)	+= fsl_usb2_udc.o
 obj-$(CONFIG_USB_M66592)	+= m66592-udc.o
 

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

@@ -69,7 +69,7 @@
 
 /* gadget stack */
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 /* udc specific */
 #include "amd5536udc.h"
@@ -3244,7 +3244,6 @@ static int udc_pci_probe(
 		retval = -ENOMEM;
 		goto finished;
 	}
-	memset(dev, 0, sizeof(struct udc));
 
 	/* pci setup */
 	if (pci_enable_device(pdev) < 0) {
@@ -3286,14 +3285,12 @@ static int udc_pci_probe(
 
 	pci_set_drvdata(pdev, dev);
 
-	/* chip revision */
-	dev->chiprev = 0;
+	/* chip revision for Hs AMD5536 */
+	dev->chiprev = pdev->revision;
 
 	pci_set_master(pdev);
 	pci_set_mwi(pdev);
 
-	/* chip rev for Hs AMD5536 */
-	pci_read_config_byte(pdev, PCI_REVISION_ID, (u8 *) &dev->chiprev);
 	/* init dma pools */
 	if (use_dma) {
 		retval = init_dma_pools(dev);

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

@@ -38,7 +38,7 @@
 #include <linux/proc_fs.h>
 #include <linux/clk.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/hardware.h>

+ 2077 - 0
drivers/usb/gadget/atmel_usba_udc.c

@@ -0,0 +1,2077 @@
+/*
+ * Driver for the Atmel USBA high speed USB device controller
+ *
+ * Copyright (C) 2005-2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/delay.h>
+
+#include <asm/gpio.h>
+#include <asm/arch/board.h>
+
+#include "atmel_usba_udc.h"
+
+
+static struct usba_udc the_udc;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+
+static int queue_dbg_open(struct inode *inode, struct file *file)
+{
+	struct usba_ep *ep = inode->i_private;
+	struct usba_request *req, *req_copy;
+	struct list_head *queue_data;
+
+	queue_data = kmalloc(sizeof(*queue_data), GFP_KERNEL);
+	if (!queue_data)
+		return -ENOMEM;
+	INIT_LIST_HEAD(queue_data);
+
+	spin_lock_irq(&ep->udc->lock);
+	list_for_each_entry(req, &ep->queue, queue) {
+		req_copy = kmalloc(sizeof(*req_copy), GFP_ATOMIC);
+		if (!req_copy)
+			goto fail;
+		memcpy(req_copy, req, sizeof(*req_copy));
+		list_add_tail(&req_copy->queue, queue_data);
+	}
+	spin_unlock_irq(&ep->udc->lock);
+
+	file->private_data = queue_data;
+	return 0;
+
+fail:
+	spin_unlock_irq(&ep->udc->lock);
+	list_for_each_entry_safe(req, req_copy, queue_data, queue) {
+		list_del(&req->queue);
+		kfree(req);
+	}
+	kfree(queue_data);
+	return -ENOMEM;
+}
+
+/*
+ * bbbbbbbb llllllll IZS sssss nnnn FDL\n\0
+ *
+ * b: buffer address
+ * l: buffer length
+ * I/i: interrupt/no interrupt
+ * Z/z: zero/no zero
+ * S/s: short ok/short not ok
+ * s: status
+ * n: nr_packets
+ * F/f: submitted/not submitted to FIFO
+ * D/d: using/not using DMA
+ * L/l: last transaction/not last transaction
+ */
+static ssize_t queue_dbg_read(struct file *file, char __user *buf,
+		size_t nbytes, loff_t *ppos)
+{
+	struct list_head *queue = file->private_data;
+	struct usba_request *req, *tmp_req;
+	size_t len, remaining, actual = 0;
+	char tmpbuf[38];
+
+	if (!access_ok(VERIFY_WRITE, buf, nbytes))
+		return -EFAULT;
+
+	mutex_lock(&file->f_dentry->d_inode->i_mutex);
+	list_for_each_entry_safe(req, tmp_req, queue, queue) {
+		len = snprintf(tmpbuf, sizeof(tmpbuf),
+				"%8p %08x %c%c%c %5d %c%c%c\n",
+				req->req.buf, req->req.length,
+				req->req.no_interrupt ? 'i' : 'I',
+				req->req.zero ? 'Z' : 'z',
+				req->req.short_not_ok ? 's' : 'S',
+				req->req.status,
+				req->submitted ? 'F' : 'f',
+				req->using_dma ? 'D' : 'd',
+				req->last_transaction ? 'L' : 'l');
+		len = min(len, sizeof(tmpbuf));
+		if (len > nbytes)
+			break;
+
+		list_del(&req->queue);
+		kfree(req);
+
+		remaining = __copy_to_user(buf, tmpbuf, len);
+		actual += len - remaining;
+		if (remaining)
+			break;
+
+		nbytes -= len;
+		buf += len;
+	}
+	mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+
+	return actual;
+}
+
+static int queue_dbg_release(struct inode *inode, struct file *file)
+{
+	struct list_head *queue_data = file->private_data;
+	struct usba_request *req, *tmp_req;
+
+	list_for_each_entry_safe(req, tmp_req, queue_data, queue) {
+		list_del(&req->queue);
+		kfree(req);
+	}
+	kfree(queue_data);
+	return 0;
+}
+
+static int regs_dbg_open(struct inode *inode, struct file *file)
+{
+	struct usba_udc *udc;
+	unsigned int i;
+	u32 *data;
+	int ret = -ENOMEM;
+
+	mutex_lock(&inode->i_mutex);
+	udc = inode->i_private;
+	data = kmalloc(inode->i_size, GFP_KERNEL);
+	if (!data)
+		goto out;
+
+	spin_lock_irq(&udc->lock);
+	for (i = 0; i < inode->i_size / 4; i++)
+		data[i] = __raw_readl(udc->regs + i * 4);
+	spin_unlock_irq(&udc->lock);
+
+	file->private_data = data;
+	ret = 0;
+
+out:
+	mutex_unlock(&inode->i_mutex);
+
+	return ret;
+}
+
+static ssize_t regs_dbg_read(struct file *file, char __user *buf,
+		size_t nbytes, loff_t *ppos)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	int ret;
+
+	mutex_lock(&inode->i_mutex);
+	ret = simple_read_from_buffer(buf, nbytes, ppos,
+			file->private_data,
+			file->f_dentry->d_inode->i_size);
+	mutex_unlock(&inode->i_mutex);
+
+	return ret;
+}
+
+static int regs_dbg_release(struct inode *inode, struct file *file)
+{
+	kfree(file->private_data);
+	return 0;
+}
+
+const struct file_operations queue_dbg_fops = {
+	.owner		= THIS_MODULE,
+	.open		= queue_dbg_open,
+	.llseek		= no_llseek,
+	.read		= queue_dbg_read,
+	.release	= queue_dbg_release,
+};
+
+const struct file_operations regs_dbg_fops = {
+	.owner		= THIS_MODULE,
+	.open		= regs_dbg_open,
+	.llseek		= generic_file_llseek,
+	.read		= regs_dbg_read,
+	.release	= regs_dbg_release,
+};
+
+static void usba_ep_init_debugfs(struct usba_udc *udc,
+		struct usba_ep *ep)
+{
+	struct dentry *ep_root;
+
+	ep_root = debugfs_create_dir(ep->ep.name, udc->debugfs_root);
+	if (!ep_root)
+		goto err_root;
+	ep->debugfs_dir = ep_root;
+
+	ep->debugfs_queue = debugfs_create_file("queue", 0400, ep_root,
+						ep, &queue_dbg_fops);
+	if (!ep->debugfs_queue)
+		goto err_queue;
+
+	if (ep->can_dma) {
+		ep->debugfs_dma_status
+			= debugfs_create_u32("dma_status", 0400, ep_root,
+					&ep->last_dma_status);
+		if (!ep->debugfs_dma_status)
+			goto err_dma_status;
+	}
+	if (ep_is_control(ep)) {
+		ep->debugfs_state
+			= debugfs_create_u32("state", 0400, ep_root,
+					&ep->state);
+		if (!ep->debugfs_state)
+			goto err_state;
+	}
+
+	return;
+
+err_state:
+	if (ep->can_dma)
+		debugfs_remove(ep->debugfs_dma_status);
+err_dma_status:
+	debugfs_remove(ep->debugfs_queue);
+err_queue:
+	debugfs_remove(ep_root);
+err_root:
+	dev_err(&ep->udc->pdev->dev,
+		"failed to create debugfs directory for %s\n", ep->ep.name);
+}
+
+static void usba_ep_cleanup_debugfs(struct usba_ep *ep)
+{
+	debugfs_remove(ep->debugfs_queue);
+	debugfs_remove(ep->debugfs_dma_status);
+	debugfs_remove(ep->debugfs_state);
+	debugfs_remove(ep->debugfs_dir);
+	ep->debugfs_dma_status = NULL;
+	ep->debugfs_dir = NULL;
+}
+
+static void usba_init_debugfs(struct usba_udc *udc)
+{
+	struct dentry *root, *regs;
+	struct resource *regs_resource;
+
+	root = debugfs_create_dir(udc->gadget.name, NULL);
+	if (IS_ERR(root) || !root)
+		goto err_root;
+	udc->debugfs_root = root;
+
+	regs = debugfs_create_file("regs", 0400, root, udc, &regs_dbg_fops);
+	if (!regs)
+		goto err_regs;
+
+	regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM,
+				CTRL_IOMEM_ID);
+	regs->d_inode->i_size = regs_resource->end - regs_resource->start + 1;
+	udc->debugfs_regs = regs;
+
+	usba_ep_init_debugfs(udc, to_usba_ep(udc->gadget.ep0));
+
+	return;
+
+err_regs:
+	debugfs_remove(root);
+err_root:
+	udc->debugfs_root = NULL;
+	dev_err(&udc->pdev->dev, "debugfs is not available\n");
+}
+
+static void usba_cleanup_debugfs(struct usba_udc *udc)
+{
+	usba_ep_cleanup_debugfs(to_usba_ep(udc->gadget.ep0));
+	debugfs_remove(udc->debugfs_regs);
+	debugfs_remove(udc->debugfs_root);
+	udc->debugfs_regs = NULL;
+	udc->debugfs_root = NULL;
+}
+#else
+static inline void usba_ep_init_debugfs(struct usba_udc *udc,
+					 struct usba_ep *ep)
+{
+
+}
+
+static inline void usba_ep_cleanup_debugfs(struct usba_ep *ep)
+{
+
+}
+
+static inline void usba_init_debugfs(struct usba_udc *udc)
+{
+
+}
+
+static inline void usba_cleanup_debugfs(struct usba_udc *udc)
+{
+
+}
+#endif
+
+static int vbus_is_present(struct usba_udc *udc)
+{
+	if (udc->vbus_pin != -1)
+		return gpio_get_value(udc->vbus_pin);
+
+	/* No Vbus detection: Assume always present */
+	return 1;
+}
+
+static void copy_to_fifo(void __iomem *fifo, const void *buf, int len)
+{
+	unsigned long tmp;
+
+	DBG(DBG_FIFO, "copy to FIFO (len %d):\n", len);
+	for (; len > 0; len -= 4, buf += 4, fifo += 4) {
+		tmp = *(unsigned long *)buf;
+		if (len >= 4) {
+			DBG(DBG_FIFO, "  -> %08lx\n", tmp);
+			__raw_writel(tmp, fifo);
+		} else {
+			do {
+				DBG(DBG_FIFO, "  -> %02lx\n", tmp >> 24);
+				__raw_writeb(tmp >> 24, fifo);
+				fifo++;
+				tmp <<= 8;
+			} while (--len);
+			break;
+		}
+	}
+}
+
+static void copy_from_fifo(void *buf, void __iomem *fifo, int len)
+{
+	union {
+		unsigned long *w;
+		unsigned char *b;
+	} p;
+	unsigned long tmp;
+
+	DBG(DBG_FIFO, "copy from FIFO (len %d):\n", len);
+	for (p.w = buf; len > 0; len -= 4, p.w++, fifo += 4) {
+		if (len >= 4) {
+			tmp = __raw_readl(fifo);
+			*p.w = tmp;
+			DBG(DBG_FIFO, "  -> %08lx\n", tmp);
+		} else {
+			do {
+				tmp = __raw_readb(fifo);
+				*p.b = tmp;
+				DBG(DBG_FIFO, " -> %02lx\n", tmp);
+				fifo++, p.b++;
+			} while (--len);
+		}
+	}
+}
+
+static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
+{
+	unsigned int transaction_len;
+
+	transaction_len = req->req.length - req->req.actual;
+	req->last_transaction = 1;
+	if (transaction_len > ep->ep.maxpacket) {
+		transaction_len = ep->ep.maxpacket;
+		req->last_transaction = 0;
+	} else if (transaction_len == ep->ep.maxpacket && req->req.zero)
+		req->last_transaction = 0;
+
+	DBG(DBG_QUEUE, "%s: submit_transaction, req %p (length %d)%s\n",
+		ep->ep.name, req, transaction_len,
+		req->last_transaction ? ", done" : "");
+
+	copy_to_fifo(ep->fifo, req->req.buf + req->req.actual, transaction_len);
+	usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+	req->req.actual += transaction_len;
+}
+
+static void submit_request(struct usba_ep *ep, struct usba_request *req)
+{
+	DBG(DBG_QUEUE, "%s: submit_request: req %p (length %d)\n",
+		ep->ep.name, req, req->req.length);
+
+	req->req.actual = 0;
+	req->submitted = 1;
+
+	if (req->using_dma) {
+		if (req->req.length == 0) {
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+			return;
+		}
+
+		if (req->req.zero)
+			usba_ep_writel(ep, CTL_ENB, USBA_SHORT_PACKET);
+		else
+			usba_ep_writel(ep, CTL_DIS, USBA_SHORT_PACKET);
+
+		usba_dma_writel(ep, ADDRESS, req->req.dma);
+		usba_dma_writel(ep, CONTROL, req->ctrl);
+	} else {
+		next_fifo_transaction(ep, req);
+		if (req->last_transaction) {
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+		} else {
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+		}
+	}
+}
+
+static void submit_next_request(struct usba_ep *ep)
+{
+	struct usba_request *req;
+
+	if (list_empty(&ep->queue)) {
+		usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY | USBA_RX_BK_RDY);
+		return;
+	}
+
+	req = list_entry(ep->queue.next, struct usba_request, queue);
+	if (!req->submitted)
+		submit_request(ep, req);
+}
+
+static void send_status(struct usba_udc *udc, struct usba_ep *ep)
+{
+	ep->state = STATUS_STAGE_IN;
+	usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+	usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+}
+
+static void receive_data(struct usba_ep *ep)
+{
+	struct usba_udc *udc = ep->udc;
+	struct usba_request *req;
+	unsigned long status;
+	unsigned int bytecount, nr_busy;
+	int is_complete = 0;
+
+	status = usba_ep_readl(ep, STA);
+	nr_busy = USBA_BFEXT(BUSY_BANKS, status);
+
+	DBG(DBG_QUEUE, "receive data: nr_busy=%u\n", nr_busy);
+
+	while (nr_busy > 0) {
+		if (list_empty(&ep->queue)) {
+			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+			break;
+		}
+		req = list_entry(ep->queue.next,
+				 struct usba_request, queue);
+
+		bytecount = USBA_BFEXT(BYTE_COUNT, status);
+
+		if (status & (1 << 31))
+			is_complete = 1;
+		if (req->req.actual + bytecount >= req->req.length) {
+			is_complete = 1;
+			bytecount = req->req.length - req->req.actual;
+		}
+
+		copy_from_fifo(req->req.buf + req->req.actual,
+				ep->fifo, bytecount);
+		req->req.actual += bytecount;
+
+		usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+
+		if (is_complete) {
+			DBG(DBG_QUEUE, "%s: request done\n", ep->ep.name);
+			req->req.status = 0;
+			list_del_init(&req->queue);
+			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+			spin_unlock(&udc->lock);
+			req->req.complete(&ep->ep, &req->req);
+			spin_lock(&udc->lock);
+		}
+
+		status = usba_ep_readl(ep, STA);
+		nr_busy = USBA_BFEXT(BUSY_BANKS, status);
+
+		if (is_complete && ep_is_control(ep)) {
+			send_status(udc, ep);
+			break;
+		}
+	}
+}
+
+static void
+request_complete(struct usba_ep *ep, struct usba_request *req, int status)
+{
+	struct usba_udc *udc = ep->udc;
+
+	WARN_ON(!list_empty(&req->queue));
+
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = status;
+
+	if (req->mapped) {
+		dma_unmap_single(
+			&udc->pdev->dev, req->req.dma, req->req.length,
+			ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		req->req.dma = DMA_ADDR_INVALID;
+		req->mapped = 0;
+	}
+
+	DBG(DBG_GADGET | DBG_REQ,
+		"%s: req %p complete: status %d, actual %u\n",
+		ep->ep.name, req, req->req.status, req->req.actual);
+
+	spin_unlock(&udc->lock);
+	req->req.complete(&ep->ep, &req->req);
+	spin_lock(&udc->lock);
+}
+
+static void
+request_complete_list(struct usba_ep *ep, struct list_head *list, int status)
+{
+	struct usba_request *req, *tmp_req;
+
+	list_for_each_entry_safe(req, tmp_req, list, queue) {
+		list_del_init(&req->queue);
+		request_complete(ep, req, status);
+	}
+}
+
+static int
+usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+	unsigned long flags, ept_cfg, maxpacket;
+	unsigned int nr_trans;
+
+	DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc);
+
+	maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
+
+	if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index)
+			|| ep->index == 0
+			|| desc->bDescriptorType != USB_DT_ENDPOINT
+			|| maxpacket == 0
+			|| maxpacket > ep->fifo_size) {
+		DBG(DBG_ERR, "ep_enable: Invalid argument");
+		return -EINVAL;
+	}
+
+	ep->is_isoc = 0;
+	ep->is_in = 0;
+
+	if (maxpacket <= 8)
+		ept_cfg = USBA_BF(EPT_SIZE, USBA_EPT_SIZE_8);
+	else
+		/* LSB is bit 1, not 0 */
+		ept_cfg = USBA_BF(EPT_SIZE, fls(maxpacket - 1) - 3);
+
+	DBG(DBG_HW, "%s: EPT_SIZE = %lu (maxpacket = %lu)\n",
+			ep->ep.name, ept_cfg, maxpacket);
+
+	if ((desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+		ep->is_in = 1;
+		ept_cfg |= USBA_EPT_DIR_IN;
+	}
+
+	switch (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL);
+		ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE);
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		if (!ep->can_isoc) {
+			DBG(DBG_ERR, "ep_enable: %s is not isoc capable\n",
+					ep->ep.name);
+			return -EINVAL;
+		}
+
+		/*
+		 * Bits 11:12 specify number of _additional_
+		 * transactions per microframe.
+		 */
+		nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1;
+		if (nr_trans > 3)
+			return -EINVAL;
+
+		ep->is_isoc = 1;
+		ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_ISO);
+
+		/*
+		 * Do triple-buffering on high-bandwidth iso endpoints.
+		 */
+		if (nr_trans > 1 && ep->nr_banks == 3)
+			ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_TRIPLE);
+		else
+			ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+		ept_cfg |= USBA_BF(NB_TRANS, nr_trans);
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK);
+		ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		ept_cfg |= USBA_BF(EPT_TYPE, USBA_EPT_TYPE_INT);
+		ept_cfg |= USBA_BF(BK_NUMBER, USBA_BK_NUMBER_DOUBLE);
+		break;
+	}
+
+	spin_lock_irqsave(&ep->udc->lock, flags);
+
+	if (ep->desc) {
+		spin_unlock_irqrestore(&ep->udc->lock, flags);
+		DBG(DBG_ERR, "ep%d already enabled\n", ep->index);
+		return -EBUSY;
+	}
+
+	ep->desc = desc;
+	ep->ep.maxpacket = maxpacket;
+
+	usba_ep_writel(ep, CFG, ept_cfg);
+	usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+
+	if (ep->can_dma) {
+		u32 ctrl;
+
+		usba_writel(udc, INT_ENB,
+				(usba_readl(udc, INT_ENB)
+					| USBA_BF(EPT_INT, 1 << ep->index)
+					| USBA_BF(DMA_INT, 1 << ep->index)));
+		ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA;
+		usba_ep_writel(ep, CTL_ENB, ctrl);
+	} else {
+		usba_writel(udc, INT_ENB,
+				(usba_readl(udc, INT_ENB)
+					| USBA_BF(EPT_INT, 1 << ep->index)));
+	}
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index,
+			(unsigned long)usba_ep_readl(ep, CFG));
+	DBG(DBG_HW, "INT_ENB after init: %#08lx\n",
+			(unsigned long)usba_readl(udc, INT_ENB));
+
+	return 0;
+}
+
+static int usba_ep_disable(struct usb_ep *_ep)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+	LIST_HEAD(req_list);
+	unsigned long flags;
+
+	DBG(DBG_GADGET, "ep_disable: %s\n", ep->ep.name);
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	if (!ep->desc) {
+		spin_unlock_irqrestore(&udc->lock, flags);
+		DBG(DBG_ERR, "ep_disable: %s not enabled\n", ep->ep.name);
+		return -EINVAL;
+	}
+	ep->desc = NULL;
+
+	list_splice_init(&ep->queue, &req_list);
+	if (ep->can_dma) {
+		usba_dma_writel(ep, CONTROL, 0);
+		usba_dma_writel(ep, ADDRESS, 0);
+		usba_dma_readl(ep, STATUS);
+	}
+	usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE);
+	usba_writel(udc, INT_ENB,
+			usba_readl(udc, INT_ENB)
+			& ~USBA_BF(EPT_INT, 1 << ep->index));
+
+	request_complete_list(ep, &req_list, -ESHUTDOWN);
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+static struct usb_request *
+usba_ep_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct usba_request *req;
+
+	DBG(DBG_GADGET, "ep_alloc_request: %p, 0x%x\n", _ep, gfp_flags);
+
+	req = kzalloc(sizeof(*req), gfp_flags);
+	if (!req)
+		return NULL;
+
+	INIT_LIST_HEAD(&req->queue);
+	req->req.dma = DMA_ADDR_INVALID;
+
+	return &req->req;
+}
+
+static void
+usba_ep_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct usba_request *req = to_usba_req(_req);
+
+	DBG(DBG_GADGET, "ep_free_request: %p, %p\n", _ep, _req);
+
+	kfree(req);
+}
+
+static int queue_dma(struct usba_udc *udc, struct usba_ep *ep,
+		struct usba_request *req, gfp_t gfp_flags)
+{
+	unsigned long flags;
+	int ret;
+
+	DBG(DBG_DMA, "%s: req l/%u d/%08x %c%c%c\n",
+		ep->ep.name, req->req.length, req->req.dma,
+		req->req.zero ? 'Z' : 'z',
+		req->req.short_not_ok ? 'S' : 's',
+		req->req.no_interrupt ? 'I' : 'i');
+
+	if (req->req.length > 0x10000) {
+		/* Lengths from 0 to 65536 (inclusive) are supported */
+		DBG(DBG_ERR, "invalid request length %u\n", req->req.length);
+		return -EINVAL;
+	}
+
+	req->using_dma = 1;
+
+	if (req->req.dma == DMA_ADDR_INVALID) {
+		req->req.dma = dma_map_single(
+			&udc->pdev->dev, req->req.buf, req->req.length,
+			ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		req->mapped = 1;
+	} else {
+		dma_sync_single_for_device(
+			&udc->pdev->dev, req->req.dma, req->req.length,
+			ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		req->mapped = 0;
+	}
+
+	req->ctrl = USBA_BF(DMA_BUF_LEN, req->req.length)
+			| USBA_DMA_CH_EN | USBA_DMA_END_BUF_IE
+			| USBA_DMA_END_TR_EN | USBA_DMA_END_TR_IE;
+
+	if (ep->is_in)
+		req->ctrl |= USBA_DMA_END_BUF_EN;
+
+	/*
+	 * Add this request to the queue and submit for DMA if
+	 * possible. Check if we're still alive first -- we may have
+	 * received a reset since last time we checked.
+	 */
+	ret = -ESHUTDOWN;
+	spin_lock_irqsave(&udc->lock, flags);
+	if (ep->desc) {
+		if (list_empty(&ep->queue))
+			submit_request(ep, req);
+
+		list_add_tail(&req->queue, &ep->queue);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return ret;
+}
+
+static int
+usba_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct usba_request *req = to_usba_req(_req);
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+	unsigned long flags;
+	int ret;
+
+	DBG(DBG_GADGET | DBG_QUEUE | DBG_REQ, "%s: queue req %p, len %u\n",
+			ep->ep.name, req, _req->length);
+
+	if (!udc->driver || udc->gadget.speed == USB_SPEED_UNKNOWN || !ep->desc)
+		return -ESHUTDOWN;
+
+	req->submitted = 0;
+	req->using_dma = 0;
+	req->last_transaction = 0;
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	if (ep->can_dma)
+		return queue_dma(udc, ep, req, gfp_flags);
+
+	/* May have received a reset since last time we checked */
+	ret = -ESHUTDOWN;
+	spin_lock_irqsave(&udc->lock, flags);
+	if (ep->desc) {
+		list_add_tail(&req->queue, &ep->queue);
+
+		if (ep->is_in || (ep_is_control(ep)
+				&& (ep->state == DATA_STAGE_IN
+					|| ep->state == STATUS_STAGE_IN)))
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_PK_RDY);
+		else
+			usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return ret;
+}
+
+static void
+usba_update_req(struct usba_ep *ep, struct usba_request *req, u32 status)
+{
+	req->req.actual = req->req.length - USBA_BFEXT(DMA_BUF_LEN, status);
+}
+
+static int stop_dma(struct usba_ep *ep, u32 *pstatus)
+{
+	unsigned int timeout;
+	u32 status;
+
+	/*
+	 * Stop the DMA controller. When writing both CH_EN
+	 * and LINK to 0, the other bits are not affected.
+	 */
+	usba_dma_writel(ep, CONTROL, 0);
+
+	/* Wait for the FIFO to empty */
+	for (timeout = 40; timeout; --timeout) {
+		status = usba_dma_readl(ep, STATUS);
+		if (!(status & USBA_DMA_CH_EN))
+			break;
+		udelay(1);
+	}
+
+	if (pstatus)
+		*pstatus = status;
+
+	if (timeout == 0) {
+		dev_err(&ep->udc->pdev->dev,
+			"%s: timed out waiting for DMA FIFO to empty\n",
+			ep->ep.name);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+static int usba_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+	struct usba_request *req = to_usba_req(_req);
+	unsigned long flags;
+	u32 status;
+
+	DBG(DBG_GADGET | DBG_QUEUE, "ep_dequeue: %s, req %p\n",
+			ep->ep.name, req);
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	if (req->using_dma) {
+		/*
+		 * If this request is currently being transferred,
+		 * stop the DMA controller and reset the FIFO.
+		 */
+		if (ep->queue.next == &req->queue) {
+			status = usba_dma_readl(ep, STATUS);
+			if (status & USBA_DMA_CH_EN)
+				stop_dma(ep, &status);
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+			ep->last_dma_status = status;
+#endif
+
+			usba_writel(udc, EPT_RST, 1 << ep->index);
+
+			usba_update_req(ep, req, status);
+		}
+	}
+
+	/*
+	 * Errors should stop the queue from advancing until the
+	 * completion function returns.
+	 */
+	list_del_init(&req->queue);
+
+	request_complete(ep, req, -ECONNRESET);
+
+	/* Process the next request if any */
+	submit_next_request(ep);
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+static int usba_ep_set_halt(struct usb_ep *_ep, int value)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+	unsigned long flags;
+	int ret = 0;
+
+	DBG(DBG_GADGET, "endpoint %s: %s HALT\n", ep->ep.name,
+			value ? "set" : "clear");
+
+	if (!ep->desc) {
+		DBG(DBG_ERR, "Attempted to halt uninitialized ep %s\n",
+				ep->ep.name);
+		return -ENODEV;
+	}
+	if (ep->is_isoc) {
+		DBG(DBG_ERR, "Attempted to halt isochronous ep %s\n",
+				ep->ep.name);
+		return -ENOTTY;
+	}
+
+	spin_lock_irqsave(&udc->lock, flags);
+
+	/*
+	 * We can't halt IN endpoints while there are still data to be
+	 * transferred
+	 */
+	if (!list_empty(&ep->queue)
+			|| ((value && ep->is_in && (usba_ep_readl(ep, STA)
+					& USBA_BF(BUSY_BANKS, -1L))))) {
+		ret = -EAGAIN;
+	} else {
+		if (value)
+			usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
+		else
+			usba_ep_writel(ep, CLR_STA,
+					USBA_FORCE_STALL | USBA_TOGGLE_CLR);
+		usba_ep_readl(ep, STA);
+	}
+
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return ret;
+}
+
+static int usba_ep_fifo_status(struct usb_ep *_ep)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+
+	return USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
+}
+
+static void usba_ep_fifo_flush(struct usb_ep *_ep)
+{
+	struct usba_ep *ep = to_usba_ep(_ep);
+	struct usba_udc *udc = ep->udc;
+
+	usba_writel(udc, EPT_RST, 1 << ep->index);
+}
+
+static const struct usb_ep_ops usba_ep_ops = {
+	.enable		= usba_ep_enable,
+	.disable	= usba_ep_disable,
+	.alloc_request	= usba_ep_alloc_request,
+	.free_request	= usba_ep_free_request,
+	.queue		= usba_ep_queue,
+	.dequeue	= usba_ep_dequeue,
+	.set_halt	= usba_ep_set_halt,
+	.fifo_status	= usba_ep_fifo_status,
+	.fifo_flush	= usba_ep_fifo_flush,
+};
+
+static int usba_udc_get_frame(struct usb_gadget *gadget)
+{
+	struct usba_udc *udc = to_usba_udc(gadget);
+
+	return USBA_BFEXT(FRAME_NUMBER, usba_readl(udc, FNUM));
+}
+
+static int usba_udc_wakeup(struct usb_gadget *gadget)
+{
+	struct usba_udc *udc = to_usba_udc(gadget);
+	unsigned long flags;
+	u32 ctrl;
+	int ret = -EINVAL;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (udc->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) {
+		ctrl = usba_readl(udc, CTRL);
+		usba_writel(udc, CTRL, ctrl | USBA_REMOTE_WAKE_UP);
+		ret = 0;
+	}
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return ret;
+}
+
+static int
+usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
+{
+	struct usba_udc *udc = to_usba_udc(gadget);
+	unsigned long flags;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (is_selfpowered)
+		udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
+	else
+		udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+}
+
+static const struct usb_gadget_ops usba_udc_ops = {
+	.get_frame		= usba_udc_get_frame,
+	.wakeup			= usba_udc_wakeup,
+	.set_selfpowered	= usba_udc_set_selfpowered,
+};
+
+#define EP(nam, idx, maxpkt, maxbk, dma, isoc)			\
+{								\
+	.ep	= {						\
+		.ops		= &usba_ep_ops,			\
+		.name		= nam,				\
+		.maxpacket	= maxpkt,			\
+	},							\
+	.udc		= &the_udc,				\
+	.queue		= LIST_HEAD_INIT(usba_ep[idx].queue),	\
+	.fifo_size	= maxpkt,				\
+	.nr_banks	= maxbk,				\
+	.index		= idx,					\
+	.can_dma	= dma,					\
+	.can_isoc	= isoc,					\
+}
+
+static struct usba_ep usba_ep[] = {
+	EP("ep0", 0, 64, 1, 0, 0),
+	EP("ep1in-bulk", 1, 512, 2, 1, 1),
+	EP("ep2out-bulk", 2, 512, 2, 1, 1),
+	EP("ep3in-int", 3, 64, 3, 1, 0),
+	EP("ep4out-int", 4, 64, 3, 1, 0),
+	EP("ep5in-iso", 5, 1024, 3, 1, 1),
+	EP("ep6out-iso", 6, 1024, 3, 1, 1),
+};
+#undef EP
+
+static struct usb_endpoint_descriptor usba_ep0_desc = {
+	.bLength = USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bEndpointAddress = 0,
+	.bmAttributes = USB_ENDPOINT_XFER_CONTROL,
+	.wMaxPacketSize = __constant_cpu_to_le16(64),
+	/* FIXME: I have no idea what to put here */
+	.bInterval = 1,
+};
+
+static void nop_release(struct device *dev)
+{
+
+}
+
+static struct usba_udc the_udc = {
+	.gadget	= {
+		.ops		= &usba_udc_ops,
+		.ep0		= &usba_ep[0].ep,
+		.ep_list	= LIST_HEAD_INIT(the_udc.gadget.ep_list),
+		.is_dualspeed	= 1,
+		.name		= "atmel_usba_udc",
+		.dev	= {
+			.bus_id		= "gadget",
+			.release	= nop_release,
+		},
+	},
+
+	.lock	= SPIN_LOCK_UNLOCKED,
+};
+
+/*
+ * Called with interrupts disabled and udc->lock held.
+ */
+static void reset_all_endpoints(struct usba_udc *udc)
+{
+	struct usba_ep *ep;
+	struct usba_request *req, *tmp_req;
+
+	usba_writel(udc, EPT_RST, ~0UL);
+
+	ep = to_usba_ep(udc->gadget.ep0);
+	list_for_each_entry_safe(req, tmp_req, &ep->queue, queue) {
+		list_del_init(&req->queue);
+		request_complete(ep, req, -ECONNRESET);
+	}
+
+	list_for_each_entry(ep, &udc->gadget.ep_list, ep.ep_list) {
+		if (ep->desc) {
+			spin_unlock(&udc->lock);
+			usba_ep_disable(&ep->ep);
+			spin_lock(&udc->lock);
+		}
+	}
+}
+
+static struct usba_ep *get_ep_by_addr(struct usba_udc *udc, u16 wIndex)
+{
+	struct usba_ep *ep;
+
+	if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
+		return to_usba_ep(udc->gadget.ep0);
+
+	list_for_each_entry (ep, &udc->gadget.ep_list, ep.ep_list) {
+		u8 bEndpointAddress;
+
+		if (!ep->desc)
+			continue;
+		bEndpointAddress = ep->desc->bEndpointAddress;
+		if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
+			continue;
+		if ((bEndpointAddress & USB_ENDPOINT_NUMBER_MASK)
+				== (wIndex & USB_ENDPOINT_NUMBER_MASK))
+			return ep;
+	}
+
+	return NULL;
+}
+
+/* Called with interrupts disabled and udc->lock held */
+static inline void set_protocol_stall(struct usba_udc *udc, struct usba_ep *ep)
+{
+	usba_ep_writel(ep, SET_STA, USBA_FORCE_STALL);
+	ep->state = WAIT_FOR_SETUP;
+}
+
+static inline int is_stalled(struct usba_udc *udc, struct usba_ep *ep)
+{
+	if (usba_ep_readl(ep, STA) & USBA_FORCE_STALL)
+		return 1;
+	return 0;
+}
+
+static inline void set_address(struct usba_udc *udc, unsigned int addr)
+{
+	u32 regval;
+
+	DBG(DBG_BUS, "setting address %u...\n", addr);
+	regval = usba_readl(udc, CTRL);
+	regval = USBA_BFINS(DEV_ADDR, addr, regval);
+	usba_writel(udc, CTRL, regval);
+}
+
+static int do_test_mode(struct usba_udc *udc)
+{
+	static const char test_packet_buffer[] = {
+		/* JKJKJKJK * 9 */
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		/* JJKKJJKK * 8 */
+		0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+		/* JJKKJJKK * 8 */
+		0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
+		/* JJJJJJJKKKKKKK * 8 */
+		0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+		0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+		/* JJJJJJJK * 8 */
+		0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD,
+		/* {JKKKKKKK * 10}, JK */
+		0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0x7E
+	};
+	struct usba_ep *ep;
+	struct device *dev = &udc->pdev->dev;
+	int test_mode;
+
+	test_mode = udc->test_mode;
+
+	/* Start from a clean slate */
+	reset_all_endpoints(udc);
+
+	switch (test_mode) {
+	case 0x0100:
+		/* Test_J */
+		usba_writel(udc, TST, USBA_TST_J_MODE);
+		dev_info(dev, "Entering Test_J mode...\n");
+		break;
+	case 0x0200:
+		/* Test_K */
+		usba_writel(udc, TST, USBA_TST_K_MODE);
+		dev_info(dev, "Entering Test_K mode...\n");
+		break;
+	case 0x0300:
+		/*
+		 * Test_SE0_NAK: Force high-speed mode and set up ep0
+		 * for Bulk IN transfers
+		 */
+		ep = &usba_ep[0];
+		usba_writel(udc, TST,
+				USBA_BF(SPEED_CFG, USBA_SPEED_CFG_FORCE_HIGH));
+		usba_ep_writel(ep, CFG,
+				USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)
+				| USBA_EPT_DIR_IN
+				| USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK)
+				| USBA_BF(BK_NUMBER, 1));
+		if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) {
+			set_protocol_stall(udc, ep);
+			dev_err(dev, "Test_SE0_NAK: ep0 not mapped\n");
+		} else {
+			usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+			dev_info(dev, "Entering Test_SE0_NAK mode...\n");
+		}
+		break;
+	case 0x0400:
+		/* Test_Packet */
+		ep = &usba_ep[0];
+		usba_ep_writel(ep, CFG,
+				USBA_BF(EPT_SIZE, USBA_EPT_SIZE_64)
+				| USBA_EPT_DIR_IN
+				| USBA_BF(EPT_TYPE, USBA_EPT_TYPE_BULK)
+				| USBA_BF(BK_NUMBER, 1));
+		if (!(usba_ep_readl(ep, CFG) & USBA_EPT_MAPPED)) {
+			set_protocol_stall(udc, ep);
+			dev_err(dev, "Test_Packet: ep0 not mapped\n");
+		} else {
+			usba_ep_writel(ep, CTL_ENB, USBA_EPT_ENABLE);
+			usba_writel(udc, TST, USBA_TST_PKT_MODE);
+			copy_to_fifo(ep->fifo, test_packet_buffer,
+					sizeof(test_packet_buffer));
+			usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+			dev_info(dev, "Entering Test_Packet mode...\n");
+		}
+		break;
+	default:
+		dev_err(dev, "Invalid test mode: 0x%04x\n", test_mode);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+/* Avoid overly long expressions */
+static inline bool feature_is_dev_remote_wakeup(struct usb_ctrlrequest *crq)
+{
+	if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_REMOTE_WAKEUP))
+		return true;
+	return false;
+}
+
+static inline bool feature_is_dev_test_mode(struct usb_ctrlrequest *crq)
+{
+	if (crq->wValue == __constant_cpu_to_le16(USB_DEVICE_TEST_MODE))
+		return true;
+	return false;
+}
+
+static inline bool feature_is_ep_halt(struct usb_ctrlrequest *crq)
+{
+	if (crq->wValue == __constant_cpu_to_le16(USB_ENDPOINT_HALT))
+		return true;
+	return false;
+}
+
+static int handle_ep0_setup(struct usba_udc *udc, struct usba_ep *ep,
+		struct usb_ctrlrequest *crq)
+{
+	int retval = 0;;
+
+	switch (crq->bRequest) {
+	case USB_REQ_GET_STATUS: {
+		u16 status;
+
+		if (crq->bRequestType == (USB_DIR_IN | USB_RECIP_DEVICE)) {
+			status = cpu_to_le16(udc->devstatus);
+		} else if (crq->bRequestType
+				== (USB_DIR_IN | USB_RECIP_INTERFACE)) {
+			status = __constant_cpu_to_le16(0);
+		} else if (crq->bRequestType
+				== (USB_DIR_IN | USB_RECIP_ENDPOINT)) {
+			struct usba_ep *target;
+
+			target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+			if (!target)
+				goto stall;
+
+			status = 0;
+			if (is_stalled(udc, target))
+				status |= __constant_cpu_to_le16(1);
+		} else
+			goto delegate;
+
+		/* Write directly to the FIFO. No queueing is done. */
+		if (crq->wLength != __constant_cpu_to_le16(sizeof(status)))
+			goto stall;
+		ep->state = DATA_STAGE_IN;
+		__raw_writew(status, ep->fifo);
+		usba_ep_writel(ep, SET_STA, USBA_TX_PK_RDY);
+		break;
+	}
+
+	case USB_REQ_CLEAR_FEATURE: {
+		if (crq->bRequestType == USB_RECIP_DEVICE) {
+			if (feature_is_dev_remote_wakeup(crq))
+				udc->devstatus
+					&= ~(1 << USB_DEVICE_REMOTE_WAKEUP);
+			else
+				/* Can't CLEAR_FEATURE TEST_MODE */
+				goto stall;
+		} else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
+			struct usba_ep *target;
+
+			if (crq->wLength != __constant_cpu_to_le16(0)
+					|| !feature_is_ep_halt(crq))
+				goto stall;
+			target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+			if (!target)
+				goto stall;
+
+			usba_ep_writel(target, CLR_STA, USBA_FORCE_STALL);
+			if (target->index != 0)
+				usba_ep_writel(target, CLR_STA,
+						USBA_TOGGLE_CLR);
+		} else {
+			goto delegate;
+		}
+
+		send_status(udc, ep);
+		break;
+	}
+
+	case USB_REQ_SET_FEATURE: {
+		if (crq->bRequestType == USB_RECIP_DEVICE) {
+			if (feature_is_dev_test_mode(crq)) {
+				send_status(udc, ep);
+				ep->state = STATUS_STAGE_TEST;
+				udc->test_mode = le16_to_cpu(crq->wIndex);
+				return 0;
+			} else if (feature_is_dev_remote_wakeup(crq)) {
+				udc->devstatus |= 1 << USB_DEVICE_REMOTE_WAKEUP;
+			} else {
+				goto stall;
+			}
+		} else if (crq->bRequestType == USB_RECIP_ENDPOINT) {
+			struct usba_ep *target;
+
+			if (crq->wLength != __constant_cpu_to_le16(0)
+					|| !feature_is_ep_halt(crq))
+				goto stall;
+
+			target = get_ep_by_addr(udc, le16_to_cpu(crq->wIndex));
+			if (!target)
+				goto stall;
+
+			usba_ep_writel(target, SET_STA, USBA_FORCE_STALL);
+		} else
+			goto delegate;
+
+		send_status(udc, ep);
+		break;
+	}
+
+	case USB_REQ_SET_ADDRESS:
+		if (crq->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE))
+			goto delegate;
+
+		set_address(udc, le16_to_cpu(crq->wValue));
+		send_status(udc, ep);
+		ep->state = STATUS_STAGE_ADDR;
+		break;
+
+	default:
+delegate:
+		spin_unlock(&udc->lock);
+		retval = udc->driver->setup(&udc->gadget, crq);
+		spin_lock(&udc->lock);
+	}
+
+	return retval;
+
+stall:
+	printk(KERN_ERR
+		"udc: %s: Invalid setup request: %02x.%02x v%04x i%04x l%d, "
+		"halting endpoint...\n",
+		ep->ep.name, crq->bRequestType, crq->bRequest,
+		le16_to_cpu(crq->wValue), le16_to_cpu(crq->wIndex),
+		le16_to_cpu(crq->wLength));
+	set_protocol_stall(udc, ep);
+	return -1;
+}
+
+static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+	struct usba_request *req;
+	u32 epstatus;
+	u32 epctrl;
+
+restart:
+	epstatus = usba_ep_readl(ep, STA);
+	epctrl = usba_ep_readl(ep, CTL);
+
+	DBG(DBG_INT, "%s [%d]: s/%08x c/%08x\n",
+			ep->ep.name, ep->state, epstatus, epctrl);
+
+	req = NULL;
+	if (!list_empty(&ep->queue))
+		req = list_entry(ep->queue.next,
+				 struct usba_request, queue);
+
+	if ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
+		if (req->submitted)
+			next_fifo_transaction(ep, req);
+		else
+			submit_request(ep, req);
+
+		if (req->last_transaction) {
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+			usba_ep_writel(ep, CTL_ENB, USBA_TX_COMPLETE);
+		}
+		goto restart;
+	}
+	if ((epstatus & epctrl) & USBA_TX_COMPLETE) {
+		usba_ep_writel(ep, CLR_STA, USBA_TX_COMPLETE);
+
+		switch (ep->state) {
+		case DATA_STAGE_IN:
+			usba_ep_writel(ep, CTL_ENB, USBA_RX_BK_RDY);
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			ep->state = STATUS_STAGE_OUT;
+			break;
+		case STATUS_STAGE_ADDR:
+			/* Activate our new address */
+			usba_writel(udc, CTRL, (usba_readl(udc, CTRL)
+						| USBA_FADDR_EN));
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			ep->state = WAIT_FOR_SETUP;
+			break;
+		case STATUS_STAGE_IN:
+			if (req) {
+				list_del_init(&req->queue);
+				request_complete(ep, req, 0);
+				submit_next_request(ep);
+			}
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			ep->state = WAIT_FOR_SETUP;
+			break;
+		case STATUS_STAGE_TEST:
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_COMPLETE);
+			ep->state = WAIT_FOR_SETUP;
+			if (do_test_mode(udc))
+				set_protocol_stall(udc, ep);
+			break;
+		default:
+			printk(KERN_ERR
+				"udc: %s: TXCOMP: Invalid endpoint state %d, "
+				"halting endpoint...\n",
+				ep->ep.name, ep->state);
+			set_protocol_stall(udc, ep);
+			break;
+		}
+
+		goto restart;
+	}
+	if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
+		switch (ep->state) {
+		case STATUS_STAGE_OUT:
+			usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+
+			if (req) {
+				list_del_init(&req->queue);
+				request_complete(ep, req, 0);
+			}
+			ep->state = WAIT_FOR_SETUP;
+			break;
+
+		case DATA_STAGE_OUT:
+			receive_data(ep);
+			break;
+
+		default:
+			usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+			usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+			printk(KERN_ERR
+				"udc: %s: RXRDY: Invalid endpoint state %d, "
+				"halting endpoint...\n",
+				ep->ep.name, ep->state);
+			set_protocol_stall(udc, ep);
+			break;
+		}
+
+		goto restart;
+	}
+	if (epstatus & USBA_RX_SETUP) {
+		union {
+			struct usb_ctrlrequest crq;
+			unsigned long data[2];
+		} crq;
+		unsigned int pkt_len;
+		int ret;
+
+		if (ep->state != WAIT_FOR_SETUP) {
+			/*
+			 * Didn't expect a SETUP packet at this
+			 * point. Clean up any pending requests (which
+			 * may be successful).
+			 */
+			int status = -EPROTO;
+
+			/*
+			 * RXRDY and TXCOMP are dropped when SETUP
+			 * packets arrive.  Just pretend we received
+			 * the status packet.
+			 */
+			if (ep->state == STATUS_STAGE_OUT
+					|| ep->state == STATUS_STAGE_IN) {
+				usba_ep_writel(ep, CTL_DIS, USBA_RX_BK_RDY);
+				status = 0;
+			}
+
+			if (req) {
+				list_del_init(&req->queue);
+				request_complete(ep, req, status);
+			}
+		}
+
+		pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
+		DBG(DBG_HW, "Packet length: %u\n", pkt_len);
+		if (pkt_len != sizeof(crq)) {
+			printk(KERN_WARNING "udc: Invalid packet length %u "
+				"(expected %lu)\n", pkt_len, sizeof(crq));
+			set_protocol_stall(udc, ep);
+			return;
+		}
+
+		DBG(DBG_FIFO, "Copying ctrl request from 0x%p:\n", ep->fifo);
+		copy_from_fifo(crq.data, ep->fifo, sizeof(crq));
+
+		/* Free up one bank in the FIFO so that we can
+		 * generate or receive a reply right away. */
+		usba_ep_writel(ep, CLR_STA, USBA_RX_SETUP);
+
+		/* printk(KERN_DEBUG "setup: %d: %02x.%02x\n",
+			ep->state, crq.crq.bRequestType,
+			crq.crq.bRequest); */
+
+		if (crq.crq.bRequestType & USB_DIR_IN) {
+			/*
+			 * The USB 2.0 spec states that "if wLength is
+			 * zero, there is no data transfer phase."
+			 * However, testusb #14 seems to actually
+			 * expect a data phase even if wLength = 0...
+			 */
+			ep->state = DATA_STAGE_IN;
+		} else {
+			if (crq.crq.wLength != __constant_cpu_to_le16(0))
+				ep->state = DATA_STAGE_OUT;
+			else
+				ep->state = STATUS_STAGE_IN;
+		}
+
+		ret = -1;
+		if (ep->index == 0)
+			ret = handle_ep0_setup(udc, ep, &crq.crq);
+		else {
+			spin_unlock(&udc->lock);
+			ret = udc->driver->setup(&udc->gadget, &crq.crq);
+			spin_lock(&udc->lock);
+		}
+
+		DBG(DBG_BUS, "req %02x.%02x, length %d, state %d, ret %d\n",
+			crq.crq.bRequestType, crq.crq.bRequest,
+			le16_to_cpu(crq.crq.wLength), ep->state, ret);
+
+		if (ret < 0) {
+			/* Let the host know that we failed */
+			set_protocol_stall(udc, ep);
+		}
+	}
+}
+
+static void usba_ep_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+	struct usba_request *req;
+	u32 epstatus;
+	u32 epctrl;
+
+	epstatus = usba_ep_readl(ep, STA);
+	epctrl = usba_ep_readl(ep, CTL);
+
+	DBG(DBG_INT, "%s: interrupt, status: 0x%08x\n", ep->ep.name, epstatus);
+
+	while ((epctrl & USBA_TX_PK_RDY) && !(epstatus & USBA_TX_PK_RDY)) {
+		DBG(DBG_BUS, "%s: TX PK ready\n", ep->ep.name);
+
+		if (list_empty(&ep->queue)) {
+			dev_warn(&udc->pdev->dev, "ep_irq: queue empty\n");
+			usba_ep_writel(ep, CTL_DIS, USBA_TX_PK_RDY);
+			return;
+		}
+
+		req = list_entry(ep->queue.next, struct usba_request, queue);
+
+		if (req->using_dma) {
+			/* Send a zero-length packet */
+			usba_ep_writel(ep, SET_STA,
+					USBA_TX_PK_RDY);
+			usba_ep_writel(ep, CTL_DIS,
+					USBA_TX_PK_RDY);
+			list_del_init(&req->queue);
+			submit_next_request(ep);
+			request_complete(ep, req, 0);
+		} else {
+			if (req->submitted)
+				next_fifo_transaction(ep, req);
+			else
+				submit_request(ep, req);
+
+			if (req->last_transaction) {
+				list_del_init(&req->queue);
+				submit_next_request(ep);
+				request_complete(ep, req, 0);
+			}
+		}
+
+		epstatus = usba_ep_readl(ep, STA);
+		epctrl = usba_ep_readl(ep, CTL);
+	}
+	if ((epstatus & epctrl) & USBA_RX_BK_RDY) {
+		DBG(DBG_BUS, "%s: RX data ready\n", ep->ep.name);
+		receive_data(ep);
+		usba_ep_writel(ep, CLR_STA, USBA_RX_BK_RDY);
+	}
+}
+
+static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep)
+{
+	struct usba_request *req;
+	u32 status, control, pending;
+
+	status = usba_dma_readl(ep, STATUS);
+	control = usba_dma_readl(ep, CONTROL);
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+	ep->last_dma_status = status;
+#endif
+	pending = status & control;
+	DBG(DBG_INT | DBG_DMA, "dma irq, s/%#08x, c/%#08x\n", status, control);
+
+	if (status & USBA_DMA_CH_EN) {
+		dev_err(&udc->pdev->dev,
+			"DMA_CH_EN is set after transfer is finished!\n");
+		dev_err(&udc->pdev->dev,
+			"status=%#08x, pending=%#08x, control=%#08x\n",
+			status, pending, control);
+
+		/*
+		 * try to pretend nothing happened. We might have to
+		 * do something here...
+		 */
+	}
+
+	if (list_empty(&ep->queue))
+		/* Might happen if a reset comes along at the right moment */
+		return;
+
+	if (pending & (USBA_DMA_END_TR_ST | USBA_DMA_END_BUF_ST)) {
+		req = list_entry(ep->queue.next, struct usba_request, queue);
+		usba_update_req(ep, req, status);
+
+		list_del_init(&req->queue);
+		submit_next_request(ep);
+		request_complete(ep, req, 0);
+	}
+}
+
+static irqreturn_t usba_udc_irq(int irq, void *devid)
+{
+	struct usba_udc *udc = devid;
+	u32 status;
+	u32 dma_status;
+	u32 ep_status;
+
+	spin_lock(&udc->lock);
+
+	status = usba_readl(udc, INT_STA);
+	DBG(DBG_INT, "irq, status=%#08x\n", status);
+
+	if (status & USBA_DET_SUSPEND) {
+		usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
+		DBG(DBG_BUS, "Suspend detected\n");
+		if (udc->gadget.speed != USB_SPEED_UNKNOWN
+				&& udc->driver && udc->driver->suspend) {
+			spin_unlock(&udc->lock);
+			udc->driver->suspend(&udc->gadget);
+			spin_lock(&udc->lock);
+		}
+	}
+
+	if (status & USBA_WAKE_UP) {
+		usba_writel(udc, INT_CLR, USBA_WAKE_UP);
+		DBG(DBG_BUS, "Wake Up CPU detected\n");
+	}
+
+	if (status & USBA_END_OF_RESUME) {
+		usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
+		DBG(DBG_BUS, "Resume detected\n");
+		if (udc->gadget.speed != USB_SPEED_UNKNOWN
+				&& udc->driver && udc->driver->resume) {
+			spin_unlock(&udc->lock);
+			udc->driver->resume(&udc->gadget);
+			spin_lock(&udc->lock);
+		}
+	}
+
+	dma_status = USBA_BFEXT(DMA_INT, status);
+	if (dma_status) {
+		int i;
+
+		for (i = 1; i < USBA_NR_ENDPOINTS; i++)
+			if (dma_status & (1 << i))
+				usba_dma_irq(udc, &usba_ep[i]);
+	}
+
+	ep_status = USBA_BFEXT(EPT_INT, status);
+	if (ep_status) {
+		int i;
+
+		for (i = 0; i < USBA_NR_ENDPOINTS; i++)
+			if (ep_status & (1 << i)) {
+				if (ep_is_control(&usba_ep[i]))
+					usba_control_irq(udc, &usba_ep[i]);
+				else
+					usba_ep_irq(udc, &usba_ep[i]);
+			}
+	}
+
+	if (status & USBA_END_OF_RESET) {
+		struct usba_ep *ep0;
+
+		usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
+		reset_all_endpoints(udc);
+
+		if (status & USBA_HIGH_SPEED) {
+			DBG(DBG_BUS, "High-speed bus reset detected\n");
+			udc->gadget.speed = USB_SPEED_HIGH;
+		} else {
+			DBG(DBG_BUS, "Full-speed bus reset detected\n");
+			udc->gadget.speed = USB_SPEED_FULL;
+		}
+
+		ep0 = &usba_ep[0];
+		ep0->desc = &usba_ep0_desc;
+		ep0->state = WAIT_FOR_SETUP;
+		usba_ep_writel(ep0, CFG,
+				(USBA_BF(EPT_SIZE, EP0_EPT_SIZE)
+				| USBA_BF(EPT_TYPE, USBA_EPT_TYPE_CONTROL)
+				| USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
+		usba_ep_writel(ep0, CTL_ENB,
+				USBA_EPT_ENABLE | USBA_RX_SETUP);
+		usba_writel(udc, INT_ENB,
+				(usba_readl(udc, INT_ENB)
+				| USBA_BF(EPT_INT, 1)
+				| USBA_DET_SUSPEND
+				| USBA_END_OF_RESUME));
+
+		if (!(usba_ep_readl(ep0, CFG) & USBA_EPT_MAPPED))
+			dev_warn(&udc->pdev->dev,
+				 "WARNING: EP0 configuration is invalid!\n");
+	}
+
+	spin_unlock(&udc->lock);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t usba_vbus_irq(int irq, void *devid)
+{
+	struct usba_udc *udc = devid;
+	int vbus;
+
+	/* debounce */
+	udelay(10);
+
+	spin_lock(&udc->lock);
+
+	/* May happen if Vbus pin toggles during probe() */
+	if (!udc->driver)
+		goto out;
+
+	vbus = gpio_get_value(udc->vbus_pin);
+	if (vbus != udc->vbus_prev) {
+		if (vbus) {
+			usba_writel(udc, CTRL, USBA_EN_USBA);
+			usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+		} else {
+			udc->gadget.speed = USB_SPEED_UNKNOWN;
+			reset_all_endpoints(udc);
+			usba_writel(udc, CTRL, 0);
+			spin_unlock(&udc->lock);
+			udc->driver->disconnect(&udc->gadget);
+			spin_lock(&udc->lock);
+		}
+		udc->vbus_prev = vbus;
+	}
+
+out:
+	spin_unlock(&udc->lock);
+
+	return IRQ_HANDLED;
+}
+
+int usb_gadget_register_driver(struct usb_gadget_driver *driver)
+{
+	struct usba_udc *udc = &the_udc;
+	unsigned long flags;
+	int ret;
+
+	if (!udc->pdev)
+		return -ENODEV;
+
+	spin_lock_irqsave(&udc->lock, flags);
+	if (udc->driver) {
+		spin_unlock_irqrestore(&udc->lock, flags);
+		return -EBUSY;
+	}
+
+	udc->devstatus = 1 << USB_DEVICE_SELF_POWERED;
+	udc->driver = driver;
+	udc->gadget.dev.driver = &driver->driver;
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	clk_enable(udc->pclk);
+	clk_enable(udc->hclk);
+
+	ret = driver->bind(&udc->gadget);
+	if (ret) {
+		DBG(DBG_ERR, "Could not bind to driver %s: error %d\n",
+			driver->driver.name, ret);
+		goto err_driver_bind;
+	}
+
+	DBG(DBG_GADGET, "registered driver `%s'\n", driver->driver.name);
+
+	udc->vbus_prev = 0;
+	if (udc->vbus_pin != -1)
+		enable_irq(gpio_to_irq(udc->vbus_pin));
+
+	/* If Vbus is present, enable the controller and wait for reset */
+	spin_lock_irqsave(&udc->lock, flags);
+	if (vbus_is_present(udc) && udc->vbus_prev == 0) {
+		usba_writel(udc, CTRL, USBA_EN_USBA);
+		usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+	}
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	return 0;
+
+err_driver_bind:
+	udc->driver = NULL;
+	udc->gadget.dev.driver = NULL;
+	return ret;
+}
+EXPORT_SYMBOL(usb_gadget_register_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct usba_udc *udc = &the_udc;
+	unsigned long flags;
+
+	if (!udc->pdev)
+		return -ENODEV;
+	if (driver != udc->driver)
+		return -EINVAL;
+
+	if (udc->vbus_pin != -1)
+		disable_irq(gpio_to_irq(udc->vbus_pin));
+
+	spin_lock_irqsave(&udc->lock, flags);
+	udc->gadget.speed = USB_SPEED_UNKNOWN;
+	reset_all_endpoints(udc);
+	spin_unlock_irqrestore(&udc->lock, flags);
+
+	/* This will also disable the DP pullup */
+	usba_writel(udc, CTRL, 0);
+
+	driver->unbind(&udc->gadget);
+	udc->gadget.dev.driver = NULL;
+	udc->driver = NULL;
+
+	clk_disable(udc->hclk);
+	clk_disable(udc->pclk);
+
+	DBG(DBG_GADGET, "unregistered driver `%s'\n", driver->driver.name);
+
+	return 0;
+}
+EXPORT_SYMBOL(usb_gadget_unregister_driver);
+
+static int __init usba_udc_probe(struct platform_device *pdev)
+{
+	struct usba_platform_data *pdata = pdev->dev.platform_data;
+	struct resource *regs, *fifo;
+	struct clk *pclk, *hclk;
+	struct usba_udc *udc = &the_udc;
+	int irq, ret, i;
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, CTRL_IOMEM_ID);
+	fifo = platform_get_resource(pdev, IORESOURCE_MEM, FIFO_IOMEM_ID);
+	if (!regs || !fifo)
+		return -ENXIO;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	pclk = clk_get(&pdev->dev, "pclk");
+	if (IS_ERR(pclk))
+		return PTR_ERR(pclk);
+	hclk = clk_get(&pdev->dev, "hclk");
+	if (IS_ERR(hclk)) {
+		ret = PTR_ERR(hclk);
+		goto err_get_hclk;
+	}
+
+	udc->pdev = pdev;
+	udc->pclk = pclk;
+	udc->hclk = hclk;
+	udc->vbus_pin = -1;
+
+	ret = -ENOMEM;
+	udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+	if (!udc->regs) {
+		dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n");
+		goto err_map_regs;
+	}
+	dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n",
+		 (unsigned long)regs->start, udc->regs);
+	udc->fifo = ioremap(fifo->start, fifo->end - fifo->start + 1);
+	if (!udc->fifo) {
+		dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n");
+		goto err_map_fifo;
+	}
+	dev_info(&pdev->dev, "FIFO at 0x%08lx mapped at %p\n",
+		 (unsigned long)fifo->start, udc->fifo);
+
+	device_initialize(&udc->gadget.dev);
+	udc->gadget.dev.parent = &pdev->dev;
+	udc->gadget.dev.dma_mask = pdev->dev.dma_mask;
+
+	platform_set_drvdata(pdev, udc);
+
+	/* Make sure we start from a clean slate */
+	clk_enable(pclk);
+	usba_writel(udc, CTRL, 0);
+	clk_disable(pclk);
+
+	INIT_LIST_HEAD(&usba_ep[0].ep.ep_list);
+	usba_ep[0].ep_regs = udc->regs + USBA_EPT_BASE(0);
+	usba_ep[0].dma_regs = udc->regs + USBA_DMA_BASE(0);
+	usba_ep[0].fifo = udc->fifo + USBA_FIFO_BASE(0);
+	for (i = 1; i < ARRAY_SIZE(usba_ep); i++) {
+		struct usba_ep *ep = &usba_ep[i];
+
+		ep->ep_regs = udc->regs + USBA_EPT_BASE(i);
+		ep->dma_regs = udc->regs + USBA_DMA_BASE(i);
+		ep->fifo = udc->fifo + USBA_FIFO_BASE(i);
+
+		list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+	}
+
+	ret = request_irq(irq, usba_udc_irq, 0, "atmel_usba_udc", udc);
+	if (ret) {
+		dev_err(&pdev->dev, "Cannot request irq %d (error %d)\n",
+			irq, ret);
+		goto err_request_irq;
+	}
+	udc->irq = irq;
+
+	ret = device_add(&udc->gadget.dev);
+	if (ret) {
+		dev_dbg(&pdev->dev, "Could not add gadget: %d\n", ret);
+		goto err_device_add;
+	}
+
+	if (pdata && pdata->vbus_pin != GPIO_PIN_NONE) {
+		if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
+			udc->vbus_pin = pdata->vbus_pin;
+
+			ret = request_irq(gpio_to_irq(udc->vbus_pin),
+					usba_vbus_irq, 0,
+					"atmel_usba_udc", udc);
+			if (ret) {
+				gpio_free(udc->vbus_pin);
+				udc->vbus_pin = -1;
+				dev_warn(&udc->pdev->dev,
+					 "failed to request vbus irq; "
+					 "assuming always on\n");
+			} else {
+				disable_irq(gpio_to_irq(udc->vbus_pin));
+			}
+		}
+	}
+
+	usba_init_debugfs(udc);
+	for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
+		usba_ep_init_debugfs(udc, &usba_ep[i]);
+
+	return 0;
+
+err_device_add:
+	free_irq(irq, udc);
+err_request_irq:
+	iounmap(udc->fifo);
+err_map_fifo:
+	iounmap(udc->regs);
+err_map_regs:
+	clk_put(hclk);
+err_get_hclk:
+	clk_put(pclk);
+
+	platform_set_drvdata(pdev, NULL);
+
+	return ret;
+}
+
+static int __exit usba_udc_remove(struct platform_device *pdev)
+{
+	struct usba_udc *udc;
+	int i;
+
+	udc = platform_get_drvdata(pdev);
+
+	for (i = 1; i < ARRAY_SIZE(usba_ep); i++)
+		usba_ep_cleanup_debugfs(&usba_ep[i]);
+	usba_cleanup_debugfs(udc);
+
+	if (udc->vbus_pin != -1)
+		gpio_free(udc->vbus_pin);
+
+	free_irq(udc->irq, udc);
+	iounmap(udc->fifo);
+	iounmap(udc->regs);
+	clk_put(udc->hclk);
+	clk_put(udc->pclk);
+
+	device_unregister(&udc->gadget.dev);
+
+	return 0;
+}
+
+static struct platform_driver udc_driver = {
+	.remove		= __exit_p(usba_udc_remove),
+	.driver		= {
+		.name		= "atmel_usba_udc",
+	},
+};
+
+static int __init udc_init(void)
+{
+	return platform_driver_probe(&udc_driver, usba_udc_probe);
+}
+module_init(udc_init);
+
+static void __exit udc_exit(void)
+{
+	platform_driver_unregister(&udc_driver);
+}
+module_exit(udc_exit);
+
+MODULE_DESCRIPTION("Atmel USBA UDC driver");
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_LICENSE("GPL");

+ 352 - 0
drivers/usb/gadget/atmel_usba_udc.h

@@ -0,0 +1,352 @@
+/*
+ * Driver for the Atmel USBA high speed USB device controller
+ *
+ * Copyright (C) 2005-2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __LINUX_USB_GADGET_USBA_UDC_H__
+#define __LINUX_USB_GADGET_USBA_UDC_H__
+
+/* USB register offsets */
+#define USBA_CTRL				0x0000
+#define USBA_FNUM				0x0004
+#define USBA_INT_ENB				0x0010
+#define USBA_INT_STA				0x0014
+#define USBA_INT_CLR				0x0018
+#define USBA_EPT_RST				0x001c
+#define USBA_TST				0x00e0
+
+/* USB endpoint register offsets */
+#define USBA_EPT_CFG				0x0000
+#define USBA_EPT_CTL_ENB			0x0004
+#define USBA_EPT_CTL_DIS			0x0008
+#define USBA_EPT_CTL				0x000c
+#define USBA_EPT_SET_STA			0x0014
+#define USBA_EPT_CLR_STA			0x0018
+#define USBA_EPT_STA				0x001c
+
+/* USB DMA register offsets */
+#define USBA_DMA_NXT_DSC			0x0000
+#define USBA_DMA_ADDRESS			0x0004
+#define USBA_DMA_CONTROL			0x0008
+#define USBA_DMA_STATUS				0x000c
+
+/* Bitfields in CTRL */
+#define USBA_DEV_ADDR_OFFSET			0
+#define USBA_DEV_ADDR_SIZE			7
+#define USBA_FADDR_EN				(1 <<  7)
+#define USBA_EN_USBA				(1 <<  8)
+#define USBA_DETACH				(1 <<  9)
+#define USBA_REMOTE_WAKE_UP			(1 << 10)
+
+/* Bitfields in FNUM */
+#define USBA_MICRO_FRAME_NUM_OFFSET		0
+#define USBA_MICRO_FRAME_NUM_SIZE		3
+#define USBA_FRAME_NUMBER_OFFSET		3
+#define USBA_FRAME_NUMBER_SIZE			11
+#define USBA_FRAME_NUM_ERROR			(1 << 31)
+
+/* Bitfields in INT_ENB/INT_STA/INT_CLR */
+#define USBA_HIGH_SPEED				(1 <<  0)
+#define USBA_DET_SUSPEND			(1 <<  1)
+#define USBA_MICRO_SOF				(1 <<  2)
+#define USBA_SOF				(1 <<  3)
+#define USBA_END_OF_RESET			(1 <<  4)
+#define USBA_WAKE_UP				(1 <<  5)
+#define USBA_END_OF_RESUME			(1 <<  6)
+#define USBA_UPSTREAM_RESUME			(1 <<  7)
+#define USBA_EPT_INT_OFFSET			8
+#define USBA_EPT_INT_SIZE			16
+#define USBA_DMA_INT_OFFSET			24
+#define USBA_DMA_INT_SIZE			8
+
+/* Bitfields in EPT_RST */
+#define USBA_RST_OFFSET				0
+#define USBA_RST_SIZE				16
+
+/* Bitfields in USBA_TST */
+#define USBA_SPEED_CFG_OFFSET			0
+#define USBA_SPEED_CFG_SIZE			2
+#define USBA_TST_J_MODE				(1 <<  2)
+#define USBA_TST_K_MODE				(1 <<  3)
+#define USBA_TST_PKT_MODE			(1 <<  4)
+#define USBA_OPMODE2				(1 <<  5)
+
+/* Bitfields in EPT_CFG */
+#define USBA_EPT_SIZE_OFFSET			0
+#define USBA_EPT_SIZE_SIZE			3
+#define USBA_EPT_DIR_IN				(1 <<  3)
+#define USBA_EPT_TYPE_OFFSET			4
+#define USBA_EPT_TYPE_SIZE			2
+#define USBA_BK_NUMBER_OFFSET			6
+#define USBA_BK_NUMBER_SIZE			2
+#define USBA_NB_TRANS_OFFSET			8
+#define USBA_NB_TRANS_SIZE			2
+#define USBA_EPT_MAPPED				(1 << 31)
+
+/* Bitfields in EPT_CTL/EPT_CTL_ENB/EPT_CTL_DIS */
+#define USBA_EPT_ENABLE				(1 <<  0)
+#define USBA_AUTO_VALID				(1 <<  1)
+#define USBA_INTDIS_DMA				(1 <<  3)
+#define USBA_NYET_DIS				(1 <<  4)
+#define USBA_DATAX_RX				(1 <<  6)
+#define USBA_MDATA_RX				(1 <<  7)
+/* Bits 8-15 and 31 enable interrupts for respective bits in EPT_STA */
+#define USBA_BUSY_BANK_IE			(1 << 18)
+
+/* Bitfields in EPT_SET_STA/EPT_CLR_STA/EPT_STA */
+#define USBA_FORCE_STALL			(1 <<  5)
+#define USBA_TOGGLE_CLR				(1 <<  6)
+#define USBA_TOGGLE_SEQ_OFFSET			6
+#define USBA_TOGGLE_SEQ_SIZE			2
+#define USBA_ERR_OVFLW				(1 <<  8)
+#define USBA_RX_BK_RDY				(1 <<  9)
+#define USBA_KILL_BANK				(1 <<  9)
+#define USBA_TX_COMPLETE			(1 << 10)
+#define USBA_TX_PK_RDY				(1 << 11)
+#define USBA_ISO_ERR_TRANS			(1 << 11)
+#define USBA_RX_SETUP				(1 << 12)
+#define USBA_ISO_ERR_FLOW			(1 << 12)
+#define USBA_STALL_SENT				(1 << 13)
+#define USBA_ISO_ERR_CRC			(1 << 13)
+#define USBA_ISO_ERR_NBTRANS			(1 << 13)
+#define USBA_NAK_IN				(1 << 14)
+#define USBA_ISO_ERR_FLUSH			(1 << 14)
+#define USBA_NAK_OUT				(1 << 15)
+#define USBA_CURRENT_BANK_OFFSET		16
+#define USBA_CURRENT_BANK_SIZE			2
+#define USBA_BUSY_BANKS_OFFSET			18
+#define USBA_BUSY_BANKS_SIZE			2
+#define USBA_BYTE_COUNT_OFFSET			20
+#define USBA_BYTE_COUNT_SIZE			11
+#define USBA_SHORT_PACKET			(1 << 31)
+
+/* Bitfields in DMA_CONTROL */
+#define USBA_DMA_CH_EN				(1 <<  0)
+#define USBA_DMA_LINK				(1 <<  1)
+#define USBA_DMA_END_TR_EN			(1 <<  2)
+#define USBA_DMA_END_BUF_EN			(1 <<  3)
+#define USBA_DMA_END_TR_IE			(1 <<  4)
+#define USBA_DMA_END_BUF_IE			(1 <<  5)
+#define USBA_DMA_DESC_LOAD_IE			(1 <<  6)
+#define USBA_DMA_BURST_LOCK			(1 <<  7)
+#define USBA_DMA_BUF_LEN_OFFSET			16
+#define USBA_DMA_BUF_LEN_SIZE			16
+
+/* Bitfields in DMA_STATUS */
+#define USBA_DMA_CH_ACTIVE			(1 <<  1)
+#define USBA_DMA_END_TR_ST			(1 <<  4)
+#define USBA_DMA_END_BUF_ST			(1 <<  5)
+#define USBA_DMA_DESC_LOAD_ST			(1 <<  6)
+
+/* Constants for SPEED_CFG */
+#define USBA_SPEED_CFG_NORMAL			0
+#define USBA_SPEED_CFG_FORCE_HIGH		2
+#define USBA_SPEED_CFG_FORCE_FULL		3
+
+/* Constants for EPT_SIZE */
+#define USBA_EPT_SIZE_8				0
+#define USBA_EPT_SIZE_16			1
+#define USBA_EPT_SIZE_32			2
+#define USBA_EPT_SIZE_64			3
+#define USBA_EPT_SIZE_128			4
+#define USBA_EPT_SIZE_256			5
+#define USBA_EPT_SIZE_512			6
+#define USBA_EPT_SIZE_1024			7
+
+/* Constants for EPT_TYPE */
+#define USBA_EPT_TYPE_CONTROL			0
+#define USBA_EPT_TYPE_ISO			1
+#define USBA_EPT_TYPE_BULK			2
+#define USBA_EPT_TYPE_INT			3
+
+/* Constants for BK_NUMBER */
+#define USBA_BK_NUMBER_ZERO			0
+#define USBA_BK_NUMBER_ONE			1
+#define USBA_BK_NUMBER_DOUBLE			2
+#define USBA_BK_NUMBER_TRIPLE			3
+
+/* Bit manipulation macros */
+#define USBA_BF(name, value)					\
+	(((value) & ((1 << USBA_##name##_SIZE) - 1))		\
+	 << USBA_##name##_OFFSET)
+#define USBA_BFEXT(name, value)					\
+	(((value) >> USBA_##name##_OFFSET)			\
+	 & ((1 << USBA_##name##_SIZE) - 1))
+#define USBA_BFINS(name, value, old)				\
+	(((old) & ~(((1 << USBA_##name##_SIZE) - 1)		\
+		    << USBA_##name##_OFFSET))			\
+	 | USBA_BF(name, value))
+
+/* Register access macros */
+#define usba_readl(udc, reg)					\
+	__raw_readl((udc)->regs + USBA_##reg)
+#define usba_writel(udc, reg, value)				\
+	__raw_writel((value), (udc)->regs + USBA_##reg)
+#define usba_ep_readl(ep, reg)					\
+	__raw_readl((ep)->ep_regs + USBA_EPT_##reg)
+#define usba_ep_writel(ep, reg, value)				\
+	__raw_writel((value), (ep)->ep_regs + USBA_EPT_##reg)
+#define usba_dma_readl(ep, reg)					\
+	__raw_readl((ep)->dma_regs + USBA_DMA_##reg)
+#define usba_dma_writel(ep, reg, value)				\
+	__raw_writel((value), (ep)->dma_regs + USBA_DMA_##reg)
+
+/* Calculate base address for a given endpoint or DMA controller */
+#define USBA_EPT_BASE(x)	(0x100 + (x) * 0x20)
+#define USBA_DMA_BASE(x)	(0x300 + (x) * 0x10)
+#define USBA_FIFO_BASE(x)	((x) << 16)
+
+/* Synth parameters */
+#define USBA_NR_ENDPOINTS	7
+
+#define EP0_FIFO_SIZE		64
+#define EP0_EPT_SIZE		USBA_EPT_SIZE_64
+#define EP0_NR_BANKS		1
+
+/*
+ * REVISIT: Try to eliminate this value. Can we rely on req->mapped to
+ * provide this information?
+ */
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+#define FIFO_IOMEM_ID	0
+#define CTRL_IOMEM_ID	1
+
+#ifdef DEBUG
+#define DBG_ERR		0x0001	/* report all error returns */
+#define DBG_HW		0x0002	/* debug hardware initialization */
+#define DBG_GADGET	0x0004	/* calls to/from gadget driver */
+#define DBG_INT		0x0008	/* interrupts */
+#define DBG_BUS		0x0010	/* report changes in bus state */
+#define DBG_QUEUE	0x0020  /* debug request queue processing */
+#define DBG_FIFO	0x0040  /* debug FIFO contents */
+#define DBG_DMA		0x0080  /* debug DMA handling */
+#define DBG_REQ		0x0100	/* print out queued request length */
+#define DBG_ALL		0xffff
+#define DBG_NONE	0x0000
+
+#define DEBUG_LEVEL	(DBG_ERR)
+#define DBG(level, fmt, ...)					\
+	do {							\
+		if ((level) & DEBUG_LEVEL)			\
+			printk(KERN_DEBUG "udc: " fmt, ## __VA_ARGS__);	\
+	} while (0)
+#else
+#define DBG(level, fmt...)
+#endif
+
+enum usba_ctrl_state {
+	WAIT_FOR_SETUP,
+	DATA_STAGE_IN,
+	DATA_STAGE_OUT,
+	STATUS_STAGE_IN,
+	STATUS_STAGE_OUT,
+	STATUS_STAGE_ADDR,
+	STATUS_STAGE_TEST,
+};
+/*
+  EP_STATE_IDLE,
+  EP_STATE_SETUP,
+  EP_STATE_IN_DATA,
+  EP_STATE_OUT_DATA,
+  EP_STATE_SET_ADDR_STATUS,
+  EP_STATE_RX_STATUS,
+  EP_STATE_TX_STATUS,
+  EP_STATE_HALT,
+*/
+
+struct usba_dma_desc {
+	dma_addr_t next;
+	dma_addr_t addr;
+	u32 ctrl;
+};
+
+struct usba_ep {
+	int					state;
+	void __iomem				*ep_regs;
+	void __iomem				*dma_regs;
+	void __iomem				*fifo;
+	struct usb_ep				ep;
+	struct usba_udc				*udc;
+
+	struct list_head			queue;
+	const struct usb_endpoint_descriptor	*desc;
+
+	u16					fifo_size;
+	u8					nr_banks;
+	u8					index;
+	unsigned int				can_dma:1;
+	unsigned int				can_isoc:1;
+	unsigned int				is_isoc:1;
+	unsigned int				is_in:1;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+	u32					last_dma_status;
+	struct dentry				*debugfs_dir;
+	struct dentry				*debugfs_queue;
+	struct dentry				*debugfs_dma_status;
+	struct dentry				*debugfs_state;
+#endif
+};
+
+struct usba_request {
+	struct usb_request			req;
+	struct list_head			queue;
+
+	u32					ctrl;
+
+	unsigned int				submitted:1;
+	unsigned int				last_transaction:1;
+	unsigned int				using_dma:1;
+	unsigned int				mapped:1;
+};
+
+struct usba_udc {
+	/* Protect hw registers from concurrent modifications */
+	spinlock_t lock;
+
+	void __iomem *regs;
+	void __iomem *fifo;
+
+	struct usb_gadget gadget;
+	struct usb_gadget_driver *driver;
+	struct platform_device *pdev;
+	int irq;
+	int vbus_pin;
+	struct clk *pclk;
+	struct clk *hclk;
+
+	u16 devstatus;
+
+	u16 test_mode;
+	int vbus_prev;
+
+#ifdef CONFIG_USB_GADGET_DEBUG_FS
+	struct dentry *debugfs_root;
+	struct dentry *debugfs_regs;
+#endif
+};
+
+static inline struct usba_ep *to_usba_ep(struct usb_ep *ep)
+{
+	return container_of(ep, struct usba_ep, ep);
+}
+
+static inline struct usba_request *to_usba_req(struct usb_request *req)
+{
+	return container_of(req, struct usba_request, req);
+}
+
+static inline struct usba_udc *to_usba_udc(struct usb_gadget *gadget)
+{
+	return container_of(gadget, struct usba_udc, gadget);
+}
+
+#define ep_is_control(ep)	((ep)->index == 0)
+#define ep_is_idle(ep)		((ep)->state == EP_STATE_IDLE)
+
+#endif /* __LINUX_USB_GADGET_USBA_UDC_H */

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

@@ -25,7 +25,7 @@
 #include <linux/device.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 
 /**

+ 46 - 47
drivers/usb/gadget/dummy_hcd.c

@@ -46,7 +46,7 @@
 #include <linux/interrupt.h>
 #include <linux/platform_device.h>
 #include <linux/usb.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
@@ -962,13 +962,13 @@ static struct platform_driver dummy_udc_driver = {
 
 static int dummy_urb_enqueue (
 	struct usb_hcd			*hcd,
-	struct usb_host_endpoint	*ep,
 	struct urb			*urb,
 	gfp_t				mem_flags
 ) {
 	struct dummy	*dum;
 	struct urbp	*urbp;
 	unsigned long	flags;
+	int		rc;
 
 	if (!urb->transfer_buffer && urb->transfer_buffer_length)
 		return -EINVAL;
@@ -980,6 +980,11 @@ static int dummy_urb_enqueue (
 
 	dum = hcd_to_dummy (hcd);
 	spin_lock_irqsave (&dum->lock, flags);
+	rc = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (rc) {
+		kfree(urbp);
+		goto done;
+	}
 
 	if (!dum->udev) {
 		dum->udev = urb->dev;
@@ -996,36 +1001,35 @@ static int dummy_urb_enqueue (
 	if (!timer_pending (&dum->timer))
 		mod_timer (&dum->timer, jiffies + 1);
 
-	spin_unlock_irqrestore (&dum->lock, flags);
-	return 0;
+ done:
+	spin_unlock_irqrestore(&dum->lock, flags);
+	return rc;
 }
 
-static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	struct dummy	*dum;
 	unsigned long	flags;
+	int		rc;
 
 	/* giveback happens automatically in timer callback,
 	 * so make sure the callback happens */
 	dum = hcd_to_dummy (hcd);
 	spin_lock_irqsave (&dum->lock, flags);
-	if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list))
+
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (!rc && dum->rh_state != DUMMY_RH_RUNNING &&
+			!list_empty(&dum->urbp_list))
 		mod_timer (&dum->timer, jiffies);
-	spin_unlock_irqrestore (&dum->lock, flags);
-	return 0;
-}
 
-static void maybe_set_status (struct urb *urb, int status)
-{
-	spin_lock (&urb->lock);
-	if (urb->status == -EINPROGRESS)
-		urb->status = status;
-	spin_unlock (&urb->lock);
+	spin_unlock_irqrestore (&dum->lock, flags);
+	return rc;
 }
 
 /* transfer up to a frame's worth; caller must own lock */
 static int
-transfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit)
+transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit,
+		int *status)
 {
 	struct dummy_request	*req;
 
@@ -1088,24 +1092,20 @@ top:
 		 *
 		 * partially filling a buffer optionally blocks queue advances
 		 * (so completion handlers can clean up the queue) but we don't
-		 * need to emulate such data-in-flight.  so we only show part
-		 * of the URB_SHORT_NOT_OK effect: completion status.
+		 * need to emulate such data-in-flight.
 		 */
 		if (is_short) {
 			if (host_len == dev_len) {
 				req->req.status = 0;
-				maybe_set_status (urb, 0);
+				*status = 0;
 			} else if (to_host) {
 				req->req.status = 0;
 				if (dev_len > host_len)
-					maybe_set_status (urb, -EOVERFLOW);
+					*status = -EOVERFLOW;
 				else
-					maybe_set_status (urb,
-						(urb->transfer_flags
-							& URB_SHORT_NOT_OK)
-						? -EREMOTEIO : 0);
+					*status = 0;
 			} else if (!to_host) {
-				maybe_set_status (urb, 0);
+				*status = 0;
 				if (host_len > dev_len)
 					req->req.status = -EOVERFLOW;
 				else
@@ -1119,9 +1119,8 @@ top:
 				req->req.status = 0;
 			if (urb->transfer_buffer_length == urb->actual_length
 					&& !(urb->transfer_flags
-						& URB_ZERO_PACKET)) {
-				maybe_set_status (urb, 0);
-			}
+						& URB_ZERO_PACKET))
+				*status = 0;
 		}
 
 		/* device side completion --> continuable */
@@ -1137,7 +1136,7 @@ top:
 		}
 
 		/* host side completion --> terminate */
-		if (urb->status != -EINPROGRESS)
+		if (*status != -EINPROGRESS)
 			break;
 
 		/* rescan to continue with any other queued i/o */
@@ -1248,12 +1247,12 @@ restart:
 		u8			address;
 		struct dummy_ep		*ep = NULL;
 		int			type;
+		int			status = -EINPROGRESS;
 
 		urb = urbp->urb;
-		if (urb->status != -EINPROGRESS) {
-			/* likely it was just unlinked */
+		if (urb->unlinked)
 			goto return_urb;
-		} else if (dum->rh_state != DUMMY_RH_RUNNING)
+		else if (dum->rh_state != DUMMY_RH_RUNNING)
 			continue;
 		type = usb_pipetype (urb->pipe);
 
@@ -1274,7 +1273,7 @@ restart:
 			dev_dbg (dummy_dev(dum),
 				"no ep configured for urb %p\n",
 				urb);
-			maybe_set_status (urb, -EPROTO);
+			status = -EPROTO;
 			goto return_urb;
 		}
 
@@ -1289,7 +1288,7 @@ restart:
 			/* NOTE: must not be iso! */
 			dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n",
 					ep->ep.name, urb);
-			maybe_set_status (urb, -EPIPE);
+			status = -EPIPE;
 			goto return_urb;
 		}
 		/* FIXME make sure both ends agree on maxpacket */
@@ -1307,7 +1306,7 @@ restart:
 			w_value = le16_to_cpu(setup.wValue);
 			if (le16_to_cpu(setup.wLength) !=
 					urb->transfer_buffer_length) {
-				maybe_set_status (urb, -EOVERFLOW);
+				status = -EOVERFLOW;
 				goto return_urb;
 			}
 
@@ -1337,7 +1336,7 @@ restart:
 				if (setup.bRequestType != Dev_Request)
 					break;
 				dum->address = w_value;
-				maybe_set_status (urb, 0);
+				status = 0;
 				dev_dbg (udc_dev(dum), "set_address = %d\n",
 						w_value);
 				value = 0;
@@ -1364,7 +1363,7 @@ restart:
 					if (value == 0) {
 						dum->devstatus |=
 							(1 << w_value);
-						maybe_set_status (urb, 0);
+						status = 0;
 					}
 
 				} else if (setup.bRequestType == Ep_Request) {
@@ -1376,7 +1375,7 @@ restart:
 					}
 					ep2->halted = 1;
 					value = 0;
-					maybe_set_status (urb, 0);
+					status = 0;
 				}
 				break;
 			case USB_REQ_CLEAR_FEATURE:
@@ -1386,7 +1385,7 @@ restart:
 						dum->devstatus &= ~(1 <<
 							USB_DEVICE_REMOTE_WAKEUP);
 						value = 0;
-						maybe_set_status (urb, 0);
+						status = 0;
 						break;
 					default:
 						value = -EOPNOTSUPP;
@@ -1401,7 +1400,7 @@ restart:
 					}
 					ep2->halted = 0;
 					value = 0;
-					maybe_set_status (urb, 0);
+					status = 0;
 				}
 				break;
 			case USB_REQ_GET_STATUS:
@@ -1438,7 +1437,7 @@ restart:
 					urb->actual_length = min (2,
 						urb->transfer_buffer_length);
 					value = 0;
-					maybe_set_status (urb, 0);
+					status = 0;
 				}
 				break;
 			}
@@ -1465,7 +1464,7 @@ restart:
 					dev_dbg (udc_dev(dum),
 						"setup --> %d\n",
 						value);
-				maybe_set_status (urb, -EPIPE);
+				status = -EPIPE;
 				urb->actual_length = 0;
 			}
 
@@ -1482,7 +1481,7 @@ restart:
 			 * report random errors, to debug drivers.
 			 */
 			limit = max (limit, periodic_bytes (dum, ep));
-			maybe_set_status (urb, -ENOSYS);
+			status = -ENOSYS;
 			break;
 
 		case PIPE_INTERRUPT:
@@ -1496,23 +1495,23 @@ restart:
 		default:
 		treat_control_like_bulk:
 			ep->last_io = jiffies;
-			total = transfer (dum, urb, ep, limit);
+			total = transfer(dum, urb, ep, limit, &status);
 			break;
 		}
 
 		/* incomplete transfer? */
-		if (urb->status == -EINPROGRESS)
+		if (status == -EINPROGRESS)
 			continue;
 
 return_urb:
-		urb->hcpriv = NULL;
 		list_del (&urbp->urbp_list);
 		kfree (urbp);
 		if (ep)
 			ep->already_seen = ep->setup_stage = 0;
 
+		usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb);
 		spin_unlock (&dum->lock);
-		usb_hcd_giveback_urb (dummy_to_hcd(dum), urb);
+		usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status);
 		spin_lock (&dum->lock);
 
 		goto restart;

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

@@ -28,7 +28,7 @@
 #include <linux/string.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 

+ 67 - 88
drivers/usb/gadget/ether.c

@@ -19,40 +19,18 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
+/* #define VERBOSE_DEBUG */
 
-// #define DEBUG 1
-// #define VERBOSE
-
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
 #include <linux/utsname.h>
 #include <linux/device.h>
-#include <linux/moduleparam.h>
 #include <linux/ctype.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/uaccess.h>
-#include <asm/unaligned.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
-#include <linux/usb_gadget.h>
-
-#include <linux/random.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/ethtool.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
@@ -356,15 +334,15 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR);
 #define qlen(gadget) \
 	(DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1))
 
-/* also defer IRQs on highspeed TX */
-#define TX_DELAY	qmult
-
 static inline int BITRATE(struct usb_gadget *g)
 {
 	return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS;
 }
 
 #else	/* full speed (low speed doesn't do bulk) */
+
+#define qmult		1
+
 #define	DEVSPEED	USB_SPEED_FULL
 
 #define qlen(gadget) DEFAULT_QLEN
@@ -390,7 +368,7 @@ static inline int BITRATE(struct usb_gadget *g)
 	do { } while (0)
 #endif /* DEBUG */
 
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
 #define VDEBUG	DEBUG
 #else
 #define VDEBUG(dev,fmt,args...) \
@@ -830,8 +808,6 @@ static const struct usb_descriptor_header *fs_rndis_function [] = {
 };
 #endif
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-
 /*
  * usb 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at full speed.
@@ -934,18 +910,15 @@ static const struct usb_descriptor_header *hs_rndis_function [] = {
 
 
 /* maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
-
-#else
-
-/* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g,hs,fs) (((void)(g)), (fs))
-
-static inline void __init hs_subset_descriptors(void)
+static inline struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+		struct usb_endpoint_descriptor *fs)
 {
+	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return hs;
+	return fs;
 }
 
-#endif	/* !CONFIG_USB_GADGET_DUALSPEED */
 
 /*-------------------------------------------------------------------------*/
 
@@ -989,22 +962,19 @@ static struct usb_gadget_strings	stringtab = {
  * complications: class descriptors, and an altsetting.
  */
 static int
-config_buf (enum usb_device_speed speed,
-	u8 *buf, u8 type,
-	unsigned index, int is_otg)
+config_buf(struct usb_gadget *g, u8 *buf, u8 type, unsigned index, int is_otg)
 {
 	int					len;
 	const struct usb_config_descriptor	*config;
 	const struct usb_descriptor_header	**function;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	int				hs = (speed == USB_SPEED_HIGH);
+	int					hs = 0;
 
-	if (type == USB_DT_OTHER_SPEED_CONFIG)
-		hs = !hs;
+	if (gadget_is_dualspeed(g)) {
+		hs = (g->speed == USB_SPEED_HIGH);
+		if (type == USB_DT_OTHER_SPEED_CONFIG)
+			hs = !hs;
+	}
 #define which_fn(t)	(hs ? hs_ ## t ## _function : fs_ ## t ## _function)
-#else
-#define	which_fn(t)	(fs_ ## t ## _function)
-#endif
 
 	if (index >= device_desc.bNumConfigurations)
 		return -EINVAL;
@@ -1217,7 +1187,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags)
 		if (number)
 			eth_reset_config (dev);
 		usb_gadget_vbus_draw(dev->gadget,
-				dev->gadget->is_otg ? 8 : 100);
+				gadget_is_otg(dev->gadget) ? 8 : 100);
 	} else {
 		char *speed;
 		unsigned power;
@@ -1399,24 +1369,22 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 			value = min (wLength, (u16) sizeof device_desc);
 			memcpy (req->buf, &device_desc, value);
 			break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 		case USB_DT_DEVICE_QUALIFIER:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 			value = min (wLength, (u16) sizeof dev_qualifier);
 			memcpy (req->buf, &dev_qualifier, value);
 			break;
 
 		case USB_DT_OTHER_SPEED_CONFIG:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 			// FALLTHROUGH
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
 		case USB_DT_CONFIG:
-			value = config_buf (gadget->speed, req->buf,
+			value = config_buf(gadget, req->buf,
 					wValue >> 8,
 					wValue & 0xff,
-					gadget->is_otg);
+					gadget_is_otg(gadget));
 			if (value >= 0)
 				value = min (wLength, (u16) value);
 			break;
@@ -1585,12 +1553,12 @@ done_set_intf:
 				&& rndis_control_intf.bInterfaceNumber
 					== wIndex) {
 			u8 *buf;
+			u32 n;
 
 			/* return the result */
-			buf = rndis_get_next_response (dev->rndis_config,
-						       &value);
+			buf = rndis_get_next_response(dev->rndis_config, &n);
 			if (buf) {
-				memcpy (req->buf, buf, value);
+				memcpy(req->buf, buf, n);
 				req->complete = rndis_response_complete;
 				rndis_free_response(dev->rndis_config, buf);
 			}
@@ -1989,8 +1957,20 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
 	}
 
 	spin_lock_irqsave(&dev->req_lock, flags);
+	/*
+	 * this freelist can be empty if an interrupt triggered disconnect()
+	 * and reconfigured the gadget (shutting down this queue) after the
+	 * network stack decided to xmit but before we got the spinlock.
+	 */
+	if (list_empty(&dev->tx_reqs)) {
+		spin_unlock_irqrestore(&dev->req_lock, flags);
+		return 1;
+	}
+
 	req = container_of (dev->tx_reqs.next, struct usb_request, list);
 	list_del (&req->list);
+
+	/* temporarily stop TX queue when the freelist empties */
 	if (list_empty (&dev->tx_reqs))
 		netif_stop_queue (net);
 	spin_unlock_irqrestore(&dev->req_lock, flags);
@@ -2026,12 +2006,11 @@ static int eth_start_xmit (struct sk_buff *skb, struct net_device *net)
 
 	req->length = length;
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
 	/* throttle highspeed IRQ rate back slightly */
-	req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
-		? ((atomic_read (&dev->tx_qlen) % TX_DELAY) != 0)
-		: 0;
-#endif
+	if (gadget_is_dualspeed(dev->gadget))
+		req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
+			? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
+			: 0;
 
 	retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
 	switch (retval) {
@@ -2188,8 +2167,7 @@ static int eth_stop (struct net_device *net)
 	}
 
 	if (rndis_active(dev)) {
-		rndis_set_param_medium (dev->rndis_config,
-					NDIS_MEDIUM_802_3, 0);
+		rndis_set_param_medium(dev->rndis_config, NDIS_MEDIUM_802_3, 0);
 		(void) rndis_signal_disconnect (dev->rndis_config);
 	}
 
@@ -2443,26 +2421,28 @@ autoconf_fail:
 	if (rndis)
 		device_desc.bNumConfigurations = 2;
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-	if (rndis)
-		dev_qualifier.bNumConfigurations = 2;
-	else if (!cdc)
-		dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
+	if (gadget_is_dualspeed(gadget)) {
+		if (rndis)
+			dev_qualifier.bNumConfigurations = 2;
+		else if (!cdc)
+			dev_qualifier.bDeviceClass = USB_CLASS_VENDOR_SPEC;
 
-	/* assumes ep0 uses the same value for both speeds ... */
-	dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+		/* assumes ep0 uses the same value for both speeds ... */
+		dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
 
-	/* and that all endpoints are dual-speed */
-	hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
-	hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
+		/* and that all endpoints are dual-speed */
+		hs_source_desc.bEndpointAddress =
+				fs_source_desc.bEndpointAddress;
+		hs_sink_desc.bEndpointAddress =
+				fs_sink_desc.bEndpointAddress;
 #if defined(DEV_CONFIG_CDC) || defined(CONFIG_USB_ETH_RNDIS)
-	if (status_ep)
-		hs_status_desc.bEndpointAddress =
-				fs_status_desc.bEndpointAddress;
+		if (status_ep)
+			hs_status_desc.bEndpointAddress =
+					fs_status_desc.bEndpointAddress;
 #endif
-#endif	/* DUALSPEED */
+	}
 
-	if (gadget->is_otg) {
+	if (gadget_is_otg(gadget)) {
 		otg_descriptor.bmAttributes |= USB_OTG_HNP,
 		eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 		eth_config.bMaxPower = 4;
@@ -2598,12 +2578,11 @@ fail0:
 		if (rndis_set_param_dev (dev->rndis_config, dev->net,
 					 &dev->stats, &dev->cdc_filter))
 			goto fail0;
-		if (rndis_set_param_vendor (dev->rndis_config, vendorID,
-					    manufacturer))
+		if (rndis_set_param_vendor(dev->rndis_config, vendorID,
+					manufacturer))
 			goto fail0;
-		if (rndis_set_param_medium (dev->rndis_config,
-					    NDIS_MEDIUM_802_3,
-					    0))
+		if (rndis_set_param_medium(dev->rndis_config,
+					NDIS_MEDIUM_802_3, 0))
 			goto fail0;
 		INFO (dev, "RNDIS ready\n");
 	}

+ 108 - 141
drivers/usb/gadget/file_storage.c

@@ -1,7 +1,7 @@
 /*
  * file_storage.c -- File-backed USB Storage Gadget, for USB development
  *
- * Copyright (C) 2003-2005 Alan Stern
+ * Copyright (C) 2003-2007 Alan Stern
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -217,17 +217,11 @@
  */
 
 
-#undef DEBUG
-#undef VERBOSE
-#undef DUMP_MSGS
-
+/* #define VERBOSE_DEBUG */
+/* #define DUMP_MSGS */
 
-#include <asm/system.h>
-#include <asm/uaccess.h>
 
-#include <linux/bitops.h>
 #include <linux/blkdev.h>
-#include <linux/compiler.h>
 #include <linux/completion.h>
 #include <linux/dcache.h>
 #include <linux/delay.h>
@@ -235,18 +229,10 @@
 #include <linux/fcntl.h>
 #include <linux/file.h>
 #include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
 #include <linux/kref.h>
 #include <linux/kthread.h>
 #include <linux/limits.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/moduleparam.h>
-#include <linux/pagemap.h>
 #include <linux/rwsem.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
@@ -254,7 +240,7 @@
 #include <linux/utsname.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
@@ -263,7 +249,7 @@
 
 #define DRIVER_DESC		"File-backed Storage Gadget"
 #define DRIVER_NAME		"g_file_storage"
-#define DRIVER_VERSION		"28 November 2005"
+#define DRIVER_VERSION		"7 August 2007"
 
 static const char longname[] = DRIVER_DESC;
 static const char shortname[] = DRIVER_NAME;
@@ -289,57 +275,48 @@ MODULE_LICENSE("Dual BSD/GPL");
 
 /*-------------------------------------------------------------------------*/
 
-#define xprintk(f,level,fmt,args...) \
-	dev_printk(level , &(f)->gadget->dev , fmt , ## args)
-#define yprintk(l,level,fmt,args...) \
-	dev_printk(level , &(l)->dev , fmt , ## args)
-
 #ifdef DEBUG
-#define DBG(fsg,fmt,args...) \
-	xprintk(fsg , KERN_DEBUG , fmt , ## args)
 #define LDBG(lun,fmt,args...) \
-	yprintk(lun , KERN_DEBUG , fmt , ## args)
+	dev_dbg(&(lun)->dev , fmt , ## args)
 #define MDBG(fmt,args...) \
 	printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args)
 #else
-#define DBG(fsg,fmt,args...) \
-	do { } while (0)
 #define LDBG(lun,fmt,args...) \
 	do { } while (0)
 #define MDBG(fmt,args...) \
 	do { } while (0)
-#undef VERBOSE
+#undef VERBOSE_DEBUG
 #undef DUMP_MSGS
 #endif /* DEBUG */
 
-#ifdef VERBOSE
-#define VDBG	DBG
+#ifdef VERBOSE_DEBUG
 #define VLDBG	LDBG
 #else
-#define VDBG(fsg,fmt,args...) \
-	do { } while (0)
 #define VLDBG(lun,fmt,args...) \
 	do { } while (0)
-#endif /* VERBOSE */
+#endif /* VERBOSE_DEBUG */
 
-#define ERROR(fsg,fmt,args...) \
-	xprintk(fsg , KERN_ERR , fmt , ## args)
 #define LERROR(lun,fmt,args...) \
-	yprintk(lun , KERN_ERR , fmt , ## args)
-
-#define WARN(fsg,fmt,args...) \
-	xprintk(fsg , KERN_WARNING , fmt , ## args)
+	dev_err(&(lun)->dev , fmt , ## args)
 #define LWARN(lun,fmt,args...) \
-	yprintk(lun , KERN_WARNING , fmt , ## args)
-
-#define INFO(fsg,fmt,args...) \
-	xprintk(fsg , KERN_INFO , fmt , ## args)
+	dev_warn(&(lun)->dev , fmt , ## args)
 #define LINFO(lun,fmt,args...) \
-	yprintk(lun , KERN_INFO , fmt , ## args)
+	dev_info(&(lun)->dev , fmt , ## args)
 
 #define MINFO(fmt,args...) \
 	printk(KERN_INFO DRIVER_NAME ": " fmt , ## args)
 
+#define DBG(d, fmt, args...) \
+	dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+	dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+	dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+	dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+	dev_info(&(d)->gadget->dev , fmt , ## args)
+
 
 /*-------------------------------------------------------------------------*/
 
@@ -350,8 +327,8 @@ MODULE_LICENSE("Dual BSD/GPL");
 static struct {
 	char		*file[MAX_LUNS];
 	int		ro[MAX_LUNS];
-	int		num_filenames;
-	int		num_ros;
+	unsigned int	num_filenames;
+	unsigned int	num_ros;
 	unsigned int	nluns;
 
 	int		removable;
@@ -578,7 +555,7 @@ struct lun {
 
 #define backing_file_is_open(curlun)	((curlun)->filp != NULL)
 
-static inline struct lun *dev_to_lun(struct device *dev)
+static struct lun *dev_to_lun(struct device *dev)
 {
 	return container_of(dev, struct lun, dev);
 }
@@ -711,13 +688,13 @@ struct fsg_dev {
 
 typedef void (*fsg_routine_t)(struct fsg_dev *);
 
-static int inline exception_in_progress(struct fsg_dev *fsg)
+static int exception_in_progress(struct fsg_dev *fsg)
 {
 	return (fsg->state > FSG_STATE_IDLE);
 }
 
 /* Make bulk-out requests be divisible by the maxpacket size */
-static void inline set_bulk_out_req_length(struct fsg_dev *fsg,
+static void set_bulk_out_req_length(struct fsg_dev *fsg,
 		struct fsg_buffhd *bh, unsigned int length)
 {
 	unsigned int	rem;
@@ -743,50 +720,36 @@ static void	close_all_backing_files(struct fsg_dev *fsg);
 static void dump_msg(struct fsg_dev *fsg, const char *label,
 		const u8 *buf, unsigned int length)
 {
-	unsigned int	start, num, i;
-	char		line[52], *p;
-
-	if (length >= 512)
-		return;
-	DBG(fsg, "%s, length %u:\n", label, length);
-
-	start = 0;
-	while (length > 0) {
-		num = min(length, 16u);
-		p = line;
-		for (i = 0; i < num; ++i) {
-			if (i == 8)
-				*p++ = ' ';
-			sprintf(p, " %02x", buf[i]);
-			p += 3;
-		}
-		*p = 0;
-		printk(KERN_DEBUG "%6x: %s\n", start, line);
-		buf += num;
-		start += num;
-		length -= num;
+	if (length < 512) {
+		DBG(fsg, "%s, length %u:\n", label, length);
+		print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET,
+				16, 1, buf, length, 0);
 	}
 }
 
-static void inline dump_cdb(struct fsg_dev *fsg)
+static void dump_cdb(struct fsg_dev *fsg)
 {}
 
 #else
 
-static void inline dump_msg(struct fsg_dev *fsg, const char *label,
+static void dump_msg(struct fsg_dev *fsg, const char *label,
 		const u8 *buf, unsigned int length)
 {}
 
-static void inline dump_cdb(struct fsg_dev *fsg)
-{
-	int	i;
-	char	cmdbuf[3*MAX_COMMAND_SIZE + 1];
+#ifdef VERBOSE_DEBUG
 
-	for (i = 0; i < fsg->cmnd_size; ++i)
-		sprintf(cmdbuf + i*3, " %02x", fsg->cmnd[i]);
-	VDBG(fsg, "SCSI CDB: %s\n", cmdbuf);
+static void dump_cdb(struct fsg_dev *fsg)
+{
+	print_hex_dump(KERN_DEBUG, "SCSI CDB: ", DUMP_PREFIX_NONE,
+			16, 1, fsg->cmnd, fsg->cmnd_size, 0);
 }
 
+#else
+
+static void dump_cdb(struct fsg_dev *fsg)
+{}
+
+#endif /* VERBOSE_DEBUG */
 #endif /* DUMP_MSGS */
 
 
@@ -809,24 +772,24 @@ static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep)
 
 /* Routines for unaligned data access */
 
-static u16 inline get_be16(u8 *buf)
+static u16 get_be16(u8 *buf)
 {
 	return ((u16) buf[0] << 8) | ((u16) buf[1]);
 }
 
-static u32 inline get_be32(u8 *buf)
+static u32 get_be32(u8 *buf)
 {
 	return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) |
 			((u32) buf[2] << 8) | ((u32) buf[3]);
 }
 
-static void inline put_be16(u8 *buf, u16 val)
+static void put_be16(u8 *buf, u16 val)
 {
 	buf[0] = val >> 8;
 	buf[1] = val;
 }
 
-static void inline put_be32(u8 *buf, u32 val)
+static void put_be32(u8 *buf, u32 val)
 {
 	buf[0] = val >> 24;
 	buf[1] = val >> 16;
@@ -950,8 +913,6 @@ static const struct usb_descriptor_header *fs_function[] = {
 #define FS_FUNCTION_PRE_EP_ENTRIES	2
 
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-
 /*
  * USB 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at full speed.
@@ -1014,14 +975,14 @@ static const struct usb_descriptor_header *hs_function[] = {
 #define HS_FUNCTION_PRE_EP_ENTRIES	2
 
 /* Maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,fs,hs)	(((g)->speed==USB_SPEED_HIGH) ? (hs) : (fs))
-
-#else
-
-/* If there's no high speed support, always use the full-speed descriptor. */
-#define ep_desc(g,fs,hs)	fs
-
-#endif	/* !CONFIG_USB_GADGET_DUALSPEED */
+static struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
+		struct usb_endpoint_descriptor *hs)
+{
+	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return hs;
+	return fs;
+}
 
 
 /* The CBI specification limits the serial string to 12 uppercase hexadecimal
@@ -1053,26 +1014,22 @@ static struct usb_gadget_strings	stringtab = {
 static int populate_config_buf(struct usb_gadget *gadget,
 		u8 *buf, u8 type, unsigned index)
 {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 	enum usb_device_speed			speed = gadget->speed;
-#endif
 	int					len;
 	const struct usb_descriptor_header	**function;
 
 	if (index > 0)
 		return -EINVAL;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	if (type == USB_DT_OTHER_SPEED_CONFIG)
+	if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG)
 		speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed;
-	if (speed == USB_SPEED_HIGH)
+	if (gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH)
 		function = hs_function;
 	else
-#endif
 		function = fs_function;
 
 	/* for now, don't advertise srp-only devices */
-	if (!gadget->is_otg)
+	if (!gadget_is_otg(gadget))
 		function++;
 
 	len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function);
@@ -1394,10 +1351,9 @@ static int standard_setup_req(struct fsg_dev *fsg,
 			value = sizeof device_desc;
 			memcpy(req->buf, &device_desc, value);
 			break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 		case USB_DT_DEVICE_QUALIFIER:
 			VDBG(fsg, "get device qualifier\n");
-			if (!fsg->gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(fsg->gadget))
 				break;
 			value = sizeof dev_qualifier;
 			memcpy(req->buf, &dev_qualifier, value);
@@ -1405,15 +1361,12 @@ static int standard_setup_req(struct fsg_dev *fsg,
 
 		case USB_DT_OTHER_SPEED_CONFIG:
 			VDBG(fsg, "get other-speed config descriptor\n");
-			if (!fsg->gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(fsg->gadget))
 				break;
 			goto get_config;
-#endif
 		case USB_DT_CONFIG:
 			VDBG(fsg, "get configuration descriptor\n");
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-		get_config:
-#endif
+get_config:
 			value = populate_config_buf(fsg->gadget,
 					req->buf,
 					w_value >> 8,
@@ -1646,7 +1599,8 @@ static int do_read(struct fsg_dev *fsg)
 		/* Wait for the next buffer to become available */
 		bh = fsg->next_buffhd_to_fill;
 		while (bh->state != BUF_STATE_EMPTY) {
-			if ((rc = sleep_thread(fsg)) != 0)
+			rc = sleep_thread(fsg);
+			if (rc)
 				return rc;
 		}
 
@@ -1885,7 +1839,8 @@ static int do_write(struct fsg_dev *fsg)
 		}
 
 		/* Wait for something to happen */
-		if ((rc = sleep_thread(fsg)) != 0)
+		rc = sleep_thread(fsg);
+		if (rc)
 			return rc;
 	}
 
@@ -2369,7 +2324,8 @@ static int pad_with_zeros(struct fsg_dev *fsg)
 
 		/* Wait for the next buffer to be free */
 		while (bh->state != BUF_STATE_EMPTY) {
-			if ((rc = sleep_thread(fsg)) != 0)
+			rc = sleep_thread(fsg);
+			if (rc)
 				return rc;
 		}
 
@@ -2429,7 +2385,8 @@ static int throw_away_data(struct fsg_dev *fsg)
 		}
 
 		/* Otherwise wait for something to happen */
-		if ((rc = sleep_thread(fsg)) != 0)
+		rc = sleep_thread(fsg);
+		if (rc)
 			return rc;
 	}
 	return 0;
@@ -2551,7 +2508,8 @@ static int send_status(struct fsg_dev *fsg)
 	/* Wait for the next buffer to become available */
 	bh = fsg->next_buffhd_to_fill;
 	while (bh->state != BUF_STATE_EMPTY) {
-		if ((rc = sleep_thread(fsg)) != 0)
+		rc = sleep_thread(fsg);
+		if (rc)
 			return rc;
 	}
 
@@ -2771,9 +2729,10 @@ static int do_scsi_command(struct fsg_dev *fsg)
 	/* Wait for the next buffer to become available for data or status */
 	bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
 	while (bh->state != BUF_STATE_EMPTY) {
-		if ((rc = sleep_thread(fsg)) != 0)
+		rc = sleep_thread(fsg);
+		if (rc)
 			return rc;
-		}
+	}
 	fsg->phase_error = 0;
 	fsg->short_packet_received = 0;
 
@@ -3005,7 +2964,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
 
 	/* Is the CBW meaningful? */
 	if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG ||
-			cbw->Length < 6 || cbw->Length > MAX_COMMAND_SIZE) {
+			cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
 		DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
 				"cmdlen %u\n",
 				cbw->Lun, cbw->Flags, cbw->Length);
@@ -3045,9 +3004,10 @@ static int get_next_command(struct fsg_dev *fsg)
 		/* Wait for the next buffer to become available */
 		bh = fsg->next_buffhd_to_fill;
 		while (bh->state != BUF_STATE_EMPTY) {
-			if ((rc = sleep_thread(fsg)) != 0)
+			rc = sleep_thread(fsg);
+			if (rc)
 				return rc;
-			}
+		}
 
 		/* Queue a request to read a Bulk-only CBW */
 		set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN);
@@ -3061,9 +3021,10 @@ static int get_next_command(struct fsg_dev *fsg)
 
 		/* Wait for the CBW to arrive */
 		while (bh->state != BUF_STATE_FULL) {
-			if ((rc = sleep_thread(fsg)) != 0)
+			rc = sleep_thread(fsg);
+			if (rc)
 				return rc;
-			}
+		}
 		smp_rmb();
 		rc = received_cbw(fsg, bh);
 		bh->state = BUF_STATE_EMPTY;
@@ -3072,9 +3033,10 @@ static int get_next_command(struct fsg_dev *fsg)
 
 		/* Wait for the next command to arrive */
 		while (fsg->cbbuf_cmnd_size == 0) {
-			if ((rc = sleep_thread(fsg)) != 0)
+			rc = sleep_thread(fsg);
+			if (rc)
 				return rc;
-			}
+		}
 
 		/* Is the previous status interrupt request still busy?
 		 * The host is allowed to skip reading the status,
@@ -3595,7 +3557,8 @@ static ssize_t show_ro(struct device *dev, struct device_attribute *attr, char *
 	return sprintf(buf, "%d\n", curlun->ro);
 }
 
-static ssize_t show_file(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_file(struct device *dev, struct device_attribute *attr,
+		char *buf)
 {
 	struct lun	*curlun = dev_to_lun(dev);
 	struct fsg_dev	*fsg = dev_get_drvdata(dev);
@@ -3604,8 +3567,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char
 
 	down_read(&fsg->filesem);
 	if (backing_file_is_open(curlun)) {	// Get the complete pathname
-		p = d_path(curlun->filp->f_path.dentry, curlun->filp->f_path.mnt,
-				buf, PAGE_SIZE - 1);
+		p = d_path(curlun->filp->f_path.dentry,
+				curlun->filp->f_path.mnt, buf, PAGE_SIZE - 1);
 		if (IS_ERR(p))
 			rc = PTR_ERR(p);
 		else {
@@ -3623,7 +3586,8 @@ static ssize_t show_file(struct device *dev, struct device_attribute *attr, char
 }
 
 
-static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_ro(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
 {
 	ssize_t		rc = count;
 	struct lun	*curlun = dev_to_lun(dev);
@@ -3647,7 +3611,8 @@ static ssize_t store_ro(struct device *dev, struct device_attribute *attr, const
 	return rc;
 }
 
-static ssize_t store_file(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t store_file(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
 {
 	struct lun	*curlun = dev_to_lun(dev);
 	struct fsg_dev	*fsg = dev_get_drvdata(dev);
@@ -3859,7 +3824,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
 	/* Find out how many LUNs there should be */
 	i = mod_data.nluns;
 	if (i == 0)
-		i = max(mod_data.num_filenames, 1);
+		i = max(mod_data.num_filenames, 1u);
 	if (i > MAX_LUNS) {
 		ERROR(fsg, "invalid number of LUNs: %d\n", i);
 		rc = -EINVAL;
@@ -3944,21 +3909,23 @@ static int __init fsg_bind(struct usb_gadget *gadget)
 	intf_desc.bInterfaceProtocol = mod_data.transport_type;
 	fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
+	if (gadget_is_dualspeed(gadget)) {
+		hs_function[i + HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
 
-	/* Assume ep0 uses the same maxpacket value for both speeds */
-	dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
+		/* Assume ep0 uses the same maxpacket value for both speeds */
+		dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
 
-	/* Assume that all endpoint addresses are the same for both speeds */
-	hs_bulk_in_desc.bEndpointAddress = fs_bulk_in_desc.bEndpointAddress;
-	hs_bulk_out_desc.bEndpointAddress = fs_bulk_out_desc.bEndpointAddress;
-	hs_intr_in_desc.bEndpointAddress = fs_intr_in_desc.bEndpointAddress;
-#endif
+		/* Assume endpoint addresses are the same for both speeds */
+		hs_bulk_in_desc.bEndpointAddress =
+				fs_bulk_in_desc.bEndpointAddress;
+		hs_bulk_out_desc.bEndpointAddress =
+				fs_bulk_out_desc.bEndpointAddress;
+		hs_intr_in_desc.bEndpointAddress =
+				fs_intr_in_desc.bEndpointAddress;
+	}
 
-	if (gadget->is_otg) {
+	if (gadget_is_otg(gadget))
 		otg_desc.bmAttributes |= USB_OTG_HNP;
-	}
 
 	rc = -ENOMEM;
 

+ 5 - 8
drivers/usb/gadget/fsl_usb2_udc.c

@@ -35,7 +35,7 @@
 #include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.h>
@@ -1090,14 +1090,11 @@ static int fsl_vbus_session(struct usb_gadget *gadget, int is_active)
  */
 static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA)
 {
-#ifdef CONFIG_USB_OTG
 	struct fsl_udc *udc;
 
 	udc = container_of(gadget, struct fsl_udc, gadget);
-
 	if (udc->transceiver)
 		return otg_set_power(udc->transceiver, mA);
-#endif
 	return -ENOTSUPP;
 }
 
@@ -1120,7 +1117,7 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)
 	return 0;
 }
 
-/* defined in usb_gadget.h */
+/* defined in gadget.h */
 static struct usb_gadget_ops fsl_gadget_ops = {
 	.get_frame = fsl_get_frame,
 	.wakeup = fsl_wakeup,
@@ -1321,7 +1318,7 @@ static void setup_received_irq(struct fsl_udc *udc,
 				| USB_TYPE_STANDARD)) {
 			/* Note: The driver has not include OTG support yet.
 			 * This will be set when OTG support is added */
-			if (!udc->gadget.is_otg)
+			if (!gadget_is_otg(udc->gadget))
 				break;
 			else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
 				udc->gadget.b_hnp_enable = 1;
@@ -1330,6 +1327,8 @@ static void setup_received_irq(struct fsl_udc *udc,
 			else if (setup->bRequest ==
 					USB_DEVICE_A_ALT_HNP_SUPPORT)
 				udc->gadget.a_alt_hnp_support = 1;
+			else
+				break;
 			rc = 0;
 		} else
 			break;
@@ -1840,10 +1839,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 	if (!driver || driver != udc_controller->driver || !driver->unbind)
 		return -EINVAL;
 
-#ifdef CONFIG_USB_OTG
 	if (udc_controller->transceiver)
 		(void)otg_set_peripheral(udc_controller->transceiver, 0);
-#endif
 
 	/* stop DR, disable intr */
 	dr_controller_stop(udc_controller);

+ 33 - 49
drivers/usb/gadget/gmidi.c

@@ -18,17 +18,11 @@
  * http://www.usb.org/developers/devclass_docs/midi10.pdf
  */
 
-#define DEBUG 1
-// #define VERBOSE
+/* #define VERBOSE_DEBUG */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
 #include <linux/utsname.h>
 #include <linux/device.h>
-#include <linux/moduleparam.h>
 
 #include <sound/driver.h>
 #include <sound/core.h>
@@ -36,7 +30,7 @@
 #include <sound/rawmidi.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/audio.h>
 #include <linux/usb/midi.h>
 
@@ -139,30 +133,16 @@ struct gmidi_device {
 static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req);
 
 
-#define xprintk(d,level,fmt,args...) \
-	dev_printk(level , &(d)->gadget->dev , fmt , ## args)
-
-#ifdef DEBUG
-#define DBG(dev,fmt,args...) \
-	xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev,fmt,args...) \
-	do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG	DBG
-#else
-#define VDBG(dev,fmt,args...) \
-	do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev,fmt,args...) \
-	xprintk(dev , KERN_ERR , fmt , ## args)
-#define WARN(dev,fmt,args...) \
-	xprintk(dev , KERN_WARNING , fmt , ## args)
-#define INFO(dev,fmt,args...) \
-	xprintk(dev , KERN_INFO , fmt , ## args)
+#define DBG(d, fmt, args...) \
+	dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+	dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+	dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+	dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+	dev_info(&(d)->gadget->dev , fmt , ## args)
 
 
 static unsigned buflen = 256;
@@ -425,7 +405,7 @@ static int config_buf(struct usb_gadget *gadget,
 	return len;
 }
 
-static struct usb_request* alloc_ep_req(struct usb_ep *ep, unsigned length)
+static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
 {
 	struct usb_request	*req;
 
@@ -455,7 +435,7 @@ static const uint8_t gmidi_cin_length[] = {
  * Receives a chunk of MIDI data.
  */
 static void gmidi_read_data(struct usb_ep *ep, int cable,
-				   uint8_t* data, int length)
+				   uint8_t *data, int length)
 {
 	struct gmidi_device *dev = ep->driver_data;
 	/* cable is ignored, because for now we only have one. */
@@ -541,7 +521,7 @@ static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags)
 {
 	int err = 0;
 	struct usb_request *req;
-	struct usb_ep* ep;
+	struct usb_ep *ep;
 	unsigned i;
 
 	err = usb_ep_enable(dev->in_ep, &bulk_in_desc);
@@ -628,7 +608,7 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags)
 
 	if (gadget_is_sa1100(gadget) && dev->config) {
 		/* tx fifo is full, but we can't clear it...*/
-		INFO(dev, "can't change configurations\n");
+		ERROR(dev, "can't change configurations\n");
 		return -ESPIPE;
 	}
 	gmidi_reset_config(dev);
@@ -843,7 +823,7 @@ static void gmidi_disconnect(struct usb_gadget *gadget)
 static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget)
 {
 	struct gmidi_device *dev = get_gadget_data(gadget);
-	struct snd_card* card;
+	struct snd_card *card;
 
 	DBG(dev, "unbind\n");
 
@@ -867,12 +847,12 @@ static int gmidi_snd_free(struct snd_device *device)
 	return 0;
 }
 
-static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0,
+static void gmidi_transmit_packet(struct usb_request *req, uint8_t p0,
 					uint8_t p1, uint8_t p2, uint8_t p3)
 {
 	unsigned length = req->length;
+	u8 *buf = (u8 *)req->buf + length;
 
-	uint8_t* buf = (uint8_t*)req->buf + length;
 	buf[0] = p0;
 	buf[1] = p1;
 	buf[2] = p2;
@@ -883,8 +863,8 @@ static void gmidi_transmit_packet(struct usb_request* req, uint8_t p0,
 /*
  * Converts MIDI commands to USB MIDI packets.
  */
-static void gmidi_transmit_byte(struct usb_request* req,
-				struct gmidi_in_port* port, uint8_t b)
+static void gmidi_transmit_byte(struct usb_request *req,
+				struct gmidi_in_port *port, uint8_t b)
 {
 	uint8_t p0 = port->cable;
 
@@ -981,10 +961,10 @@ static void gmidi_transmit_byte(struct usb_request* req,
 	}
 }
 
-static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req)
+static void gmidi_transmit(struct gmidi_device *dev, struct usb_request *req)
 {
-	struct usb_ep* ep = dev->in_ep;
-	struct gmidi_in_port* port = &dev->in_port;
+	struct usb_ep *ep = dev->in_ep;
+	struct gmidi_in_port *port = &dev->in_port;
 
 	if (!ep) {
 		return;
@@ -1020,14 +1000,14 @@ static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req)
 
 static void gmidi_in_tasklet(unsigned long data)
 {
-	struct gmidi_device* dev = (struct gmidi_device*)data;
+	struct gmidi_device *dev = (struct gmidi_device *)data;
 
 	gmidi_transmit(dev, NULL);
 }
 
 static int gmidi_in_open(struct snd_rawmidi_substream *substream)
 {
-	struct gmidi_device* dev = substream->rmidi->private_data;
+	struct gmidi_device *dev = substream->rmidi->private_data;
 
 	VDBG(dev, "gmidi_in_open\n");
 	dev->in_substream = substream;
@@ -1037,13 +1017,15 @@ static int gmidi_in_open(struct snd_rawmidi_substream *substream)
 
 static int gmidi_in_close(struct snd_rawmidi_substream *substream)
 {
+	struct gmidi_device *dev = substream->rmidi->private_data;
+
 	VDBG(dev, "gmidi_in_close\n");
 	return 0;
 }
 
 static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
 {
-	struct gmidi_device* dev = substream->rmidi->private_data;
+	struct gmidi_device *dev = substream->rmidi->private_data;
 
 	VDBG(dev, "gmidi_in_trigger %d\n", up);
 	dev->in_port.active = up;
@@ -1054,7 +1036,7 @@ static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
 
 static int gmidi_out_open(struct snd_rawmidi_substream *substream)
 {
-	struct gmidi_device* dev = substream->rmidi->private_data;
+	struct gmidi_device *dev = substream->rmidi->private_data;
 
 	VDBG(dev, "gmidi_out_open\n");
 	dev->out_substream = substream;
@@ -1063,13 +1045,15 @@ static int gmidi_out_open(struct snd_rawmidi_substream *substream)
 
 static int gmidi_out_close(struct snd_rawmidi_substream *substream)
 {
+	struct gmidi_device *dev = substream->rmidi->private_data;
+
 	VDBG(dev, "gmidi_out_close\n");
 	return 0;
 }
 
 static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up)
 {
-	struct gmidi_device* dev = substream->rmidi->private_data;
+	struct gmidi_device *dev = substream->rmidi->private_data;
 
 	VDBG(dev, "gmidi_out_trigger %d\n", up);
 	if (up) {

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

@@ -37,7 +37,7 @@
 #include <linux/proc_fs.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>

+ 21 - 25
drivers/usb/gadget/inode.c

@@ -20,8 +20,7 @@
  */
 
 
-// #define	DEBUG			/* data to help fault diagnosis */
-// #define	VERBOSE		/* extra debug messages (success too) */
+/* #define VERBOSE_DEBUG */
 
 #include <linux/init.h>
 #include <linux/module.h>
@@ -38,7 +37,7 @@
 #include <linux/moduleparam.h>
 
 #include <linux/usb/gadgetfs.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 
 /*
@@ -253,7 +252,7 @@ static const char *CHIP;
 	do { } while (0)
 #endif /* DEBUG */
 
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
 #define VDEBUG	DBG
 #else
 #define VDEBUG(dev,fmt,args...) \
@@ -1010,11 +1009,12 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
 			/* assume that was SET_CONFIGURATION */
 			if (dev->current_config) {
 				unsigned power;
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-				if (dev->gadget->speed == USB_SPEED_HIGH)
+
+				if (gadget_is_dualspeed(dev->gadget)
+						&& (dev->gadget->speed
+							== USB_SPEED_HIGH))
 					power = dev->hs_config->bMaxPower;
 				else
-#endif
 					power = dev->config->bMaxPower;
 				usb_gadget_vbus_draw(dev->gadget, 2 * power);
 			}
@@ -1355,24 +1355,21 @@ static int
 config_buf (struct dev_data *dev, u8 type, unsigned index)
 {
 	int		len;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	int		hs;
-#endif
+	int		hs = 0;
 
 	/* only one configuration */
 	if (index > 0)
 		return -EINVAL;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	hs = (dev->gadget->speed == USB_SPEED_HIGH);
-	if (type == USB_DT_OTHER_SPEED_CONFIG)
-		hs = !hs;
+	if (gadget_is_dualspeed(dev->gadget)) {
+		hs = (dev->gadget->speed == USB_SPEED_HIGH);
+		if (type == USB_DT_OTHER_SPEED_CONFIG)
+			hs = !hs;
+	}
 	if (hs) {
 		dev->req->buf = dev->hs_config;
 		len = le16_to_cpu(dev->hs_config->wTotalLength);
-	} else
-#endif
-	{
+	} else {
 		dev->req->buf = dev->config;
 		len = le16_to_cpu(dev->config->wTotalLength);
 	}
@@ -1393,13 +1390,13 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 	spin_lock (&dev->lock);
 	dev->setup_abort = 0;
 	if (dev->state == STATE_DEV_UNCONNECTED) {
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-		if (gadget->speed == USB_SPEED_HIGH && dev->hs_config == NULL) {
+		if (gadget_is_dualspeed(gadget)
+				&& gadget->speed == USB_SPEED_HIGH
+				&& dev->hs_config == NULL) {
 			spin_unlock(&dev->lock);
 			ERROR (dev, "no high speed config??\n");
 			return -EINVAL;
 		}
-#endif	/* CONFIG_USB_GADGET_DUALSPEED */
 
 		dev->state = STATE_DEV_CONNECTED;
 		dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
@@ -1469,13 +1466,12 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 			// user mode expected to disable endpoints
 		} else {
 			u8	config, power;
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-			if (gadget->speed == USB_SPEED_HIGH) {
+
+			if (gadget_is_dualspeed(gadget)
+					&& gadget->speed == USB_SPEED_HIGH) {
 				config = dev->hs_config->bConfigurationValue;
 				power = dev->hs_config->bMaxPower;
-			} else
-#endif
-			{
+			} else {
 				config = dev->config->bConfigurationValue;
 				power = dev->config->bMaxPower;
 			}

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

@@ -50,7 +50,7 @@
 #include <asm/hardware.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 /*
  * Memory map

+ 1 - 1
drivers/usb/gadget/m66592-udc.c

@@ -27,7 +27,7 @@
 #include <linux/platform_device.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "m66592-udc.h"
 

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

@@ -62,7 +62,7 @@
 #include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>

+ 4 - 8
drivers/usb/gadget/omap_udc.c

@@ -38,7 +38,7 @@
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/dma-mapping.h>
 #include <linux/clk.h>
@@ -1241,19 +1241,15 @@ static void pullup_enable(struct omap_udc *udc)
 	udc->gadget.dev.parent->power.power_state = PMSG_ON;
 	udc->gadget.dev.power.power_state = PMSG_ON;
 	UDC_SYSCON1_REG |= UDC_PULLUP_EN;
-#ifndef CONFIG_USB_OTG
-	if (!cpu_is_omap15xx())
+	if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx())
 		OTG_CTRL_REG |= OTG_BSESSVLD;
-#endif
 	UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
 }
 
 static void pullup_disable(struct omap_udc *udc)
 {
-#ifndef CONFIG_USB_OTG
-	if (!cpu_is_omap15xx())
+	if (!gadget_is_otg(udc->gadget) && !cpu_is_omap15xx())
 		OTG_CTRL_REG &= ~OTG_BSESSVLD;
-#endif
 	UDC_IRQ_EN_REG = UDC_DS_CHG_IE;
 	UDC_SYSCON1_REG &= ~UDC_PULLUP_EN;
 }
@@ -1390,7 +1386,7 @@ static void update_otg(struct omap_udc *udc)
 {
 	u16	devstat;
 
-	if (!udc->gadget.is_otg)
+	if (!gadget_is_otg(udc->gadget))
 		return;
 
 	if (OTG_CTRL_REG & OTG_ID)

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

@@ -54,7 +54,7 @@
 #include <asm/hardware.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/mach/udc_pxa2xx.h>
 

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

@@ -42,7 +42,7 @@
 #include <linux/seq_file.h>
 
 #include <linux/usb.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>

+ 80 - 94
drivers/usb/gadget/serial.c

@@ -17,34 +17,15 @@
  *
  */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
 #include <linux/utsname.h>
-#include <linux/wait.h>
-#include <linux/proc_fs.h>
 #include <linux/device.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
-#include <linux/mutex.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
-#include <asm/uaccess.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/cdc.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
@@ -89,30 +70,29 @@
 #define GS_DEFAULT_PARITY		USB_CDC_NO_PARITY
 #define GS_DEFAULT_CHAR_FORMAT		USB_CDC_1_STOP_BITS
 
-/* select highspeed/fullspeed, hiding highspeed if not configured */
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-#define GS_SPEED_SELECT(is_hs,hs,fs) ((is_hs) ? (hs) : (fs))
-#else
-#define GS_SPEED_SELECT(is_hs,hs,fs) (fs)
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+/* maxpacket and other transfer characteristics vary by speed. */
+static inline struct usb_endpoint_descriptor *
+choose_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+		struct usb_endpoint_descriptor *fs)
+{
+	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return hs;
+	return fs;
+}
+
 
 /* debug settings */
-#ifdef GS_DEBUG
+#ifdef DEBUG
 static int debug = 1;
+#else
+#define	debug 0
+#endif
 
 #define gs_debug(format, arg...) \
 	do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
 #define gs_debug_level(level, format, arg...) \
 	do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0)
 
-#else
-
-#define gs_debug(format, arg...) \
-	do { } while(0)
-#define gs_debug_level(level, format, arg...) \
-	do { } while(0)
-
-#endif /* GS_DEBUG */
 
 /* Thanks to NetChip Technologies for donating this product ID.
  *
@@ -147,10 +127,10 @@ struct gs_req_entry {
 
 /* the port structure holds info for each port, one for each minor number */
 struct gs_port {
-	struct gs_dev 		*port_dev;	/* pointer to device struct */
+	struct gs_dev		*port_dev;	/* pointer to device struct */
 	struct tty_struct	*port_tty;	/* pointer to tty struct */
 	spinlock_t		port_lock;
-	int 			port_num;
+	int			port_num;
 	int			port_open_count;
 	int			port_in_use;	/* open/close in progress */
 	wait_queue_head_t	port_write_wait;/* waiting to write */
@@ -188,7 +168,7 @@ static void __exit gs_module_exit(void);
 /* tty driver */
 static int gs_open(struct tty_struct *tty, struct file *file);
 static void gs_close(struct tty_struct *tty, struct file *file);
-static int gs_write(struct tty_struct *tty, 
+static int gs_write(struct tty_struct *tty,
 	const unsigned char *buf, int count);
 static void gs_put_char(struct tty_struct *tty, unsigned char ch);
 static void gs_flush_chars(struct tty_struct *tty);
@@ -222,7 +202,7 @@ static void gs_setup_complete(struct usb_ep *ep, struct usb_request *req);
 static void gs_disconnect(struct usb_gadget *gadget);
 static int gs_set_config(struct gs_dev *dev, unsigned config);
 static void gs_reset_config(struct gs_dev *dev);
-static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
+static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
 		u8 type, unsigned int index, int is_otg);
 
 static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
@@ -415,18 +395,18 @@ static const struct usb_cdc_header_desc gs_header_desc = {
 };
 
 static const struct usb_cdc_call_mgmt_descriptor gs_call_mgmt_descriptor = {
-	.bLength =  		sizeof(gs_call_mgmt_descriptor),
-	.bDescriptorType = 	USB_DT_CS_INTERFACE,
-	.bDescriptorSubType = 	USB_CDC_CALL_MANAGEMENT_TYPE,
-	.bmCapabilities = 	0,
-	.bDataInterface = 	1,	/* index of data interface */
+	.bLength =		sizeof(gs_call_mgmt_descriptor),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_CALL_MANAGEMENT_TYPE,
+	.bmCapabilities =	0,
+	.bDataInterface =	1,	/* index of data interface */
 };
 
 static struct usb_cdc_acm_descriptor gs_acm_descriptor = {
-	.bLength =  		sizeof(gs_acm_descriptor),
-	.bDescriptorType = 	USB_DT_CS_INTERFACE,
-	.bDescriptorSubType = 	USB_CDC_ACM_TYPE,
-	.bmCapabilities = 	0,
+	.bLength =		sizeof(gs_acm_descriptor),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubType =	USB_CDC_ACM_TYPE,
+	.bmCapabilities =	0,
 };
 
 static const struct usb_cdc_union_desc gs_union_desc = {
@@ -436,7 +416,7 @@ static const struct usb_cdc_union_desc gs_union_desc = {
 	.bMasterInterface0 =	0,	/* index of control interface */
 	.bSlaveInterface0 =	1,	/* index of data interface */
 };
- 
+
 static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
@@ -482,7 +462,6 @@ static const struct usb_descriptor_header *gs_acm_fullspeed_function[] = {
 	NULL,
 };
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 static struct usb_endpoint_descriptor gs_highspeed_notify_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
@@ -536,15 +515,13 @@ static const struct usb_descriptor_header *gs_acm_highspeed_function[] = {
 	NULL,
 };
 
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
-
 
 /* Module */
 MODULE_DESCRIPTION(GS_LONG_NAME);
 MODULE_AUTHOR("Al Borchers");
 MODULE_LICENSE("GPL");
 
-#ifdef GS_DEBUG
+#ifdef DEBUG
 module_param(debug, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
 #endif
@@ -915,7 +892,8 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch)
 		return;
 	}
 
-	gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p, %p, %p\n", port->port_num, tty, ch, __builtin_return_address(0), __builtin_return_address(1), __builtin_return_address(2));
+	gs_debug("gs_put_char: (%d,%p) char=0x%x, called from %p\n",
+		port->port_num, tty, ch, __builtin_return_address(0));
 
 	spin_lock_irqsave(&port->port_lock, flags);
 
@@ -1116,7 +1094,11 @@ static int gs_send(struct gs_dev *dev)
 		len = gs_send_packet(dev, req->buf, ep->maxpacket);
 
 		if (len > 0) {
-gs_debug_level(3, "gs_send: len=%d, 0x%2.2x 0x%2.2x 0x%2.2x ...\n", len, *((unsigned char *)req->buf), *((unsigned char *)req->buf+1), *((unsigned char *)req->buf+2));
+			gs_debug_level(3, "gs_send: len=%d, 0x%2.2x "
+					"0x%2.2x 0x%2.2x ...\n", len,
+					*((unsigned char *)req->buf),
+					*((unsigned char *)req->buf+1),
+					*((unsigned char *)req->buf+2));
 			list_del(&req_entry->re_entry);
 			req->length = len;
 			spin_unlock_irqrestore(&dev->dev_lock, flags);
@@ -1269,7 +1251,7 @@ static void gs_read_complete(struct usb_ep *ep, struct usb_request *req)
 
 	switch(req->status) {
 	case 0:
- 		/* normal completion */
+		/* normal completion */
 		gs_recv_packet(dev, req->buf, req->actual);
 requeue:
 		req->length = ep->maxpacket;
@@ -1406,23 +1388,24 @@ static int __init gs_bind(struct usb_gadget *gadget)
 		? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
 	gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	gs_qualifier_desc.bDeviceClass = use_acm
-		? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
-	/* assume ep0 uses the same packet size for both speeds */
-	gs_qualifier_desc.bMaxPacketSize0 = gs_device_desc.bMaxPacketSize0;
-	/* assume endpoints are dual-speed */
-	gs_highspeed_notify_desc.bEndpointAddress =
-		gs_fullspeed_notify_desc.bEndpointAddress;
-	gs_highspeed_in_desc.bEndpointAddress =
-		gs_fullspeed_in_desc.bEndpointAddress;
-	gs_highspeed_out_desc.bEndpointAddress =
-		gs_fullspeed_out_desc.bEndpointAddress;
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
+	if (gadget_is_dualspeed(gadget)) {
+		gs_qualifier_desc.bDeviceClass = use_acm
+			? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
+		/* assume ep0 uses the same packet size for both speeds */
+		gs_qualifier_desc.bMaxPacketSize0 =
+			gs_device_desc.bMaxPacketSize0;
+		/* assume endpoints are dual-speed */
+		gs_highspeed_notify_desc.bEndpointAddress =
+			gs_fullspeed_notify_desc.bEndpointAddress;
+		gs_highspeed_in_desc.bEndpointAddress =
+			gs_fullspeed_in_desc.bEndpointAddress;
+		gs_highspeed_out_desc.bEndpointAddress =
+			gs_fullspeed_out_desc.bEndpointAddress;
+	}
 
 	usb_gadget_set_selfpowered(gadget);
 
-	if (gadget->is_otg) {
+	if (gadget_is_otg(gadget)) {
 		gs_otg_descriptor.bmAttributes |= USB_OTG_HNP,
 		gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 		gs_acm_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@@ -1487,6 +1470,12 @@ static void /* __init_or_exit */ gs_unbind(struct usb_gadget *gadget)
 			dev->dev_ctrl_req = NULL;
 		}
 		gs_free_ports(dev);
+		if (dev->dev_notify_ep)
+			usb_ep_disable(dev->dev_notify_ep);
+		if (dev->dev_in_ep)
+			usb_ep_disable(dev->dev_in_ep);
+		if (dev->dev_out_ep)
+			usb_ep_disable(dev->dev_out_ep);
 		kfree(dev);
 		set_gadget_data(gadget, NULL);
 	}
@@ -1570,9 +1559,8 @@ static int gs_setup_standard(struct usb_gadget *gadget,
 			memcpy(req->buf, &gs_device_desc, ret);
 			break;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 		case USB_DT_DEVICE_QUALIFIER:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 			ret = min(wLength,
 				(u16)sizeof(struct usb_qualifier_descriptor));
@@ -1580,14 +1568,13 @@ static int gs_setup_standard(struct usb_gadget *gadget,
 			break;
 
 		case USB_DT_OTHER_SPEED_CONFIG:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 			/* fall through */
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
 		case USB_DT_CONFIG:
-			ret = gs_build_config_buf(req->buf, gadget->speed,
+			ret = gs_build_config_buf(req->buf, gadget,
 				wValue >> 8, wValue & 0xff,
-				gadget->is_otg);
+				gadget_is_otg(gadget));
 			if (ret >= 0)
 				ret = min(wLength, (u16)ret);
 			break;
@@ -1827,8 +1814,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
 
 		if (EP_NOTIFY_NAME
 		&& strcmp(ep->name, EP_NOTIFY_NAME) == 0) {
-			ep_desc = GS_SPEED_SELECT(
-				gadget->speed == USB_SPEED_HIGH,
+			ep_desc = choose_ep_desc(gadget,
 				&gs_highspeed_notify_desc,
 				&gs_fullspeed_notify_desc);
 			ret = usb_ep_enable(ep,ep_desc);
@@ -1844,9 +1830,8 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
 		}
 
 		else if (strcmp(ep->name, EP_IN_NAME) == 0) {
-			ep_desc = GS_SPEED_SELECT(
-				gadget->speed == USB_SPEED_HIGH,
- 				&gs_highspeed_in_desc,
+			ep_desc = choose_ep_desc(gadget,
+				&gs_highspeed_in_desc,
 				&gs_fullspeed_in_desc);
 			ret = usb_ep_enable(ep,ep_desc);
 			if (ret == 0) {
@@ -1861,8 +1846,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
 		}
 
 		else if (strcmp(ep->name, EP_OUT_NAME) == 0) {
-			ep_desc = GS_SPEED_SELECT(
-				gadget->speed == USB_SPEED_HIGH,
+			ep_desc = choose_ep_desc(gadget,
 				&gs_highspeed_out_desc,
 				&gs_fullspeed_out_desc);
 			ret = usb_ep_enable(ep,ep_desc);
@@ -1981,11 +1965,11 @@ static void gs_reset_config(struct gs_dev *dev)
  * Builds the config descriptors in the given buffer and returns the
  * length, or a negative error number.
  */
-static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
+static int gs_build_config_buf(u8 *buf, struct usb_gadget *g,
 	u8 type, unsigned int index, int is_otg)
 {
 	int len;
-	int high_speed;
+	int high_speed = 0;
 	const struct usb_config_descriptor *config_desc;
 	const struct usb_descriptor_header **function;
 
@@ -1993,20 +1977,22 @@ static int gs_build_config_buf(u8 *buf, enum usb_device_speed speed,
 		return -EINVAL;
 
 	/* other speed switches high and full speed */
-	high_speed = (speed == USB_SPEED_HIGH);
-	if (type == USB_DT_OTHER_SPEED_CONFIG)
-		high_speed = !high_speed;
+	if (gadget_is_dualspeed(g)) {
+		high_speed = (g->speed == USB_SPEED_HIGH);
+		if (type == USB_DT_OTHER_SPEED_CONFIG)
+			high_speed = !high_speed;
+	}
 
 	if (use_acm) {
 		config_desc = &gs_acm_config_desc;
-		function = GS_SPEED_SELECT(high_speed,
-			gs_acm_highspeed_function,
-			gs_acm_fullspeed_function);
+		function = high_speed
+			? gs_acm_highspeed_function
+			: gs_acm_fullspeed_function;
 	} else {
 		config_desc = &gs_bulk_config_desc;
-		function = GS_SPEED_SELECT(high_speed,
-			gs_bulk_highspeed_function,
-			gs_bulk_fullspeed_function);
+		function = high_speed
+			? gs_bulk_highspeed_function
+			: gs_bulk_fullspeed_function;
 	}
 
 	/* for now, don't advertise srp-only devices */

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

@@ -15,7 +15,7 @@
 #include <linux/init.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include <asm/unaligned.h>
 

+ 97 - 142
drivers/usb/gadget/zero.c

@@ -1,38 +1,22 @@
 /*
  * zero.c -- Gadget Zero, for USB development
  *
- * Copyright (C) 2003-2004 David Brownell
+ * Copyright (C) 2003-2007 David Brownell
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions, and the following disclaimer,
- *    without modification.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The names of the above-listed copyright holders may not be used
- *    to endorse or promote products derived from this software without
- *    specific prior written permission.
+ * 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.
  *
- * ALTERNATIVELY, this software may be distributed under the terms of the
- * GNU General Public License ("GPL") as published by the Free Software
- * Foundation, either version 2 of that 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.
  *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
- * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 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
  */
 
 
@@ -57,40 +41,28 @@
  * Many drivers will only have one configuration, letting them be much
  * simpler if they also don't support high speed operation (like this
  * driver does).
+ *
+ * Why is *this* driver using two configurations, rather than setting up
+ * two interfaces with different functions?  To help verify that multiple
+ * configuration infrastucture is working correctly; also, so that it can
+ * work with low capability USB controllers without four bulk endpoints.
  */
 
-#define DEBUG 1
-// #define VERBOSE
+/* #define VERBOSE_DEBUG */
 
-#include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/delay.h>
-#include <linux/ioport.h>
-#include <linux/slab.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/timer.h>
-#include <linux/list.h>
-#include <linux/interrupt.h>
 #include <linux/utsname.h>
 #include <linux/device.h>
-#include <linux/moduleparam.h>
-
-#include <asm/byteorder.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/system.h>
-#include <asm/unaligned.h>
 
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 #include "gadget_chips.h"
 
 
 /*-------------------------------------------------------------------------*/
 
-#define DRIVER_VERSION		"St Patrick's Day 2004"
+#define DRIVER_VERSION		"Lughnasadh, 2007"
 
 static const char shortname [] = "zero";
 static const char longname [] = "Gadget Zero";
@@ -131,30 +103,16 @@ struct zero_dev {
 	struct timer_list	resume;
 };
 
-#define xprintk(d,level,fmt,args...) \
-	dev_printk(level , &(d)->gadget->dev , fmt , ## args)
-
-#ifdef DEBUG
-#define DBG(dev,fmt,args...) \
-	xprintk(dev , KERN_DEBUG , fmt , ## args)
-#else
-#define DBG(dev,fmt,args...) \
-	do { } while (0)
-#endif /* DEBUG */
-
-#ifdef VERBOSE
-#define VDBG	DBG
-#else
-#define VDBG(dev,fmt,args...) \
-	do { } while (0)
-#endif /* VERBOSE */
-
-#define ERROR(dev,fmt,args...) \
-	xprintk(dev , KERN_ERR , fmt , ## args)
-#define WARN(dev,fmt,args...) \
-	xprintk(dev , KERN_WARNING , fmt , ## args)
-#define INFO(dev,fmt,args...) \
-	xprintk(dev , KERN_INFO , fmt , ## args)
+#define DBG(d, fmt, args...) \
+	dev_dbg(&(d)->gadget->dev , fmt , ## args)
+#define VDBG(d, fmt, args...) \
+	dev_vdbg(&(d)->gadget->dev , fmt , ## args)
+#define ERROR(d, fmt, args...) \
+	dev_err(&(d)->gadget->dev , fmt , ## args)
+#define WARN(d, fmt, args...) \
+	dev_warn(&(d)->gadget->dev , fmt , ## args)
+#define INFO(d, fmt, args...) \
+	dev_info(&(d)->gadget->dev , fmt , ## args)
 
 /*-------------------------------------------------------------------------*/
 
@@ -326,8 +284,6 @@ static const struct usb_descriptor_header *fs_loopback_function [] = {
 	NULL,
 };
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-
 /*
  * usb 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at full speed.
@@ -383,17 +339,20 @@ static const struct usb_descriptor_header *hs_loopback_function [] = {
 };
 
 /* maxpacket and other transfer characteristics vary by speed. */
-#define ep_desc(g,hs,fs) (((g)->speed==USB_SPEED_HIGH)?(hs):(fs))
-
-#else
+static inline struct usb_endpoint_descriptor *
+ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *hs,
+		struct usb_endpoint_descriptor *fs)
+{
+	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+		return hs;
+	return fs;
+}
 
-/* if there's no high speed support, maxpacket doesn't change. */
-#define ep_desc(g,hs,fs) fs
+static char manufacturer[50];
 
-#endif	/* !CONFIG_USB_GADGET_DUALSPEED */
+/* default serial number takes at least two packets */
+static char serial[] = "0123456789.0123456789.0123456789";
 
-static char				manufacturer [50];
-static char				serial [40];
 
 /* static strings, in UTF-8 */
 static struct usb_string		strings [] = {
@@ -435,30 +394,29 @@ config_buf (struct usb_gadget *gadget,
 	int				is_source_sink;
 	int				len;
 	const struct usb_descriptor_header **function;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	int				hs = (gadget->speed == USB_SPEED_HIGH);
-#endif
+	int				hs = 0;
 
 	/* two configurations will always be index 0 and index 1 */
 	if (index > 1)
 		return -EINVAL;
 	is_source_sink = loopdefault ? (index == 1) : (index == 0);
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	if (type == USB_DT_OTHER_SPEED_CONFIG)
-		hs = !hs;
+	if (gadget_is_dualspeed(gadget)) {
+		hs = (gadget->speed == USB_SPEED_HIGH);
+		if (type == USB_DT_OTHER_SPEED_CONFIG)
+			hs = !hs;
+	}
 	if (hs)
 		function = is_source_sink
 			? hs_source_sink_function
 			: hs_loopback_function;
 	else
-#endif
 		function = is_source_sink
 			? fs_source_sink_function
 			: fs_loopback_function;
 
 	/* for now, don't advertise srp-only devices */
-	if (!gadget->is_otg)
+	if (!gadget_is_otg(gadget))
 		function++;
 
 	len = usb_gadget_config_buf (is_source_sink
@@ -498,6 +456,19 @@ static void free_ep_req (struct usb_ep *ep, struct usb_request *req)
 
 /*-------------------------------------------------------------------------*/
 
+/*
+ * SOURCE/SINK FUNCTION ... a primary testing vehicle for USB peripherals,
+ * this just sinks bulk packets OUT to the peripheral and sources them IN
+ * to the host, optionally with specific data patterns.
+ *
+ * In terms of control messaging, this supports all the standard requests
+ * plus two that support control-OUT tests.
+ *
+ * Note that because this doesn't queue more than one request at a time,
+ * some other function must be used to test queueing logic.  The network
+ * link (g_ether) is probably the best option for that.
+ */
+
 /* optionally require specific source/sink data patterns  */
 
 static int
@@ -534,12 +505,7 @@ check_read_data (
 	return 0;
 }
 
-static void
-reinit_write_data (
-	struct zero_dev		*dev,
-	struct usb_ep		*ep,
-	struct usb_request	*req
-)
+static void reinit_write_data(struct usb_ep *ep, struct usb_request *req)
 {
 	unsigned	i;
 	u8		*buf = req->buf;
@@ -566,16 +532,16 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
 
 	switch (status) {
 
-	case 0: 			/* normal completion? */
+	case 0:				/* normal completion? */
 		if (ep == dev->out_ep) {
 			check_read_data (dev, ep, req);
 			memset (req->buf, 0x55, req->length);
 		} else
-			reinit_write_data (dev, ep, req);
+			reinit_write_data(ep, req);
 		break;
 
 	/* this endpoint is normally active while we're configured */
-	case -ECONNABORTED: 		/* hardware forced ep reset */
+	case -ECONNABORTED:		/* hardware forced ep reset */
 	case -ECONNRESET:		/* request dequeued */
 	case -ESHUTDOWN:		/* disconnect from host */
 		VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
@@ -607,8 +573,7 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
 	}
 }
 
-static struct usb_request *
-source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
+static struct usb_request *source_sink_start_ep(struct usb_ep *ep)
 {
 	struct usb_request	*req;
 	int			status;
@@ -621,11 +586,11 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
 	req->complete = source_sink_complete;
 
 	if (strcmp (ep->name, EP_IN_NAME) == 0)
-		reinit_write_data (ep->driver_data, ep, req);
+		reinit_write_data(ep, req);
 	else
 		memset (req->buf, 0x55, req->length);
 
-	status = usb_ep_queue (ep, req, gfp_flags);
+	status = usb_ep_queue(ep, req, GFP_ATOMIC);
 	if (status) {
 		struct zero_dev	*dev = ep->driver_data;
 
@@ -637,8 +602,7 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
 	return req;
 }
 
-static int
-set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
+static int set_source_sink_config(struct zero_dev *dev)
 {
 	int			result = 0;
 	struct usb_ep		*ep;
@@ -653,8 +617,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
 			result = usb_ep_enable (ep, d);
 			if (result == 0) {
 				ep->driver_data = dev;
-				if (source_sink_start_ep(ep, gfp_flags)
-						!= NULL) {
+				if (source_sink_start_ep(ep) != NULL) {
 					dev->in_ep = ep;
 					continue;
 				}
@@ -668,8 +631,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
 			result = usb_ep_enable (ep, d);
 			if (result == 0) {
 				ep->driver_data = dev;
-				if (source_sink_start_ep(ep, gfp_flags)
-						!= NULL) {
+				if (source_sink_start_ep(ep) != NULL) {
 					dev->out_ep = ep;
 					continue;
 				}
@@ -701,7 +663,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
 
 	switch (status) {
 
-	case 0: 			/* normal completion? */
+	case 0:				/* normal completion? */
 		if (ep == dev->out_ep) {
 			/* loop this OUT packet back IN to the host */
 			req->zero = (req->actual < req->length);
@@ -735,7 +697,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
 	 * rely on the hardware driver to clean up on disconnect or
 	 * endpoint disable.
 	 */
-	case -ECONNABORTED: 		/* hardware forced ep reset */
+	case -ECONNABORTED:		/* hardware forced ep reset */
 	case -ECONNRESET:		/* request dequeued */
 	case -ESHUTDOWN:		/* disconnect from host */
 		free_ep_req (ep, req);
@@ -743,8 +705,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
 	}
 }
 
-static int
-set_loopback_config (struct zero_dev *dev, gfp_t gfp_flags)
+static int set_loopback_config(struct zero_dev *dev)
 {
 	int			result = 0;
 	struct usb_ep		*ep;
@@ -844,8 +805,7 @@ static void zero_reset_config (struct zero_dev *dev)
  * code can do, perhaps by disallowing more than one configuration or
  * by limiting configuration choices (like the pxa2xx).
  */
-static int
-zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
+static int zero_set_config(struct zero_dev *dev, unsigned number)
 {
 	int			result = 0;
 	struct usb_gadget	*gadget = dev->gadget;
@@ -855,17 +815,17 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
 
 	if (gadget_is_sa1100 (gadget) && dev->config) {
 		/* tx fifo is full, but we can't clear it...*/
-		INFO (dev, "can't change configurations\n");
+		ERROR(dev, "can't change configurations\n");
 		return -ESPIPE;
 	}
 	zero_reset_config (dev);
 
 	switch (number) {
 	case CONFIG_SOURCE_SINK:
-		result = set_source_sink_config (dev, gfp_flags);
+		result = set_source_sink_config(dev);
 		break;
 	case CONFIG_LOOPBACK:
-		result = set_loopback_config (dev, gfp_flags);
+		result = set_loopback_config(dev);
 		break;
 	default:
 		result = -EINVAL;
@@ -885,7 +845,7 @@ zero_set_config (struct zero_dev *dev, unsigned number, gfp_t gfp_flags)
 		case USB_SPEED_LOW:	speed = "low"; break;
 		case USB_SPEED_FULL:	speed = "full"; break;
 		case USB_SPEED_HIGH:	speed = "high"; break;
-		default: 		speed = "?"; break;
+		default:		speed = "?"; break;
 		}
 
 		dev->config = number;
@@ -938,19 +898,17 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 			value = min (w_length, (u16) sizeof device_desc);
 			memcpy (req->buf, &device_desc, value);
 			break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 		case USB_DT_DEVICE_QUALIFIER:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 			value = min (w_length, (u16) sizeof dev_qualifier);
 			memcpy (req->buf, &dev_qualifier, value);
 			break;
 
 		case USB_DT_OTHER_SPEED_CONFIG:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 			// FALLTHROUGH
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
 		case USB_DT_CONFIG:
 			value = config_buf (gadget, req->buf,
 					w_value >> 8,
@@ -984,7 +942,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 		else
 			VDBG (dev, "HNP inactive\n");
 		spin_lock (&dev->lock);
-		value = zero_set_config (dev, w_value, GFP_ATOMIC);
+		value = zero_set_config(dev, w_value);
 		spin_unlock (&dev->lock);
 		break;
 	case USB_REQ_GET_CONFIGURATION:
@@ -1013,7 +971,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 			 * use this "reset the config" shortcut.
 			 */
 			zero_reset_config (dev);
-			zero_set_config (dev, config, GFP_ATOMIC);
+			zero_set_config(dev, config);
 			value = 0;
 		}
 		spin_unlock (&dev->lock);
@@ -1163,7 +1121,7 @@ autoconf_fail:
 	}
 	EP_IN_NAME = ep->name;
 	ep->driver_data = ep;	/* claim */
-	
+
 	ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
 	if (!ep)
 		goto autoconf_fail;
@@ -1207,16 +1165,18 @@ autoconf_fail:
 
 	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	/* assume ep0 uses the same value for both speeds ... */
-	dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
+	if (gadget_is_dualspeed(gadget)) {
+		/* assume ep0 uses the same value for both speeds ... */
+		dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
 
-	/* and that all endpoints are dual-speed */
-	hs_source_desc.bEndpointAddress = fs_source_desc.bEndpointAddress;
-	hs_sink_desc.bEndpointAddress = fs_sink_desc.bEndpointAddress;
-#endif
+		/* and that all endpoints are dual-speed */
+		hs_source_desc.bEndpointAddress =
+				fs_source_desc.bEndpointAddress;
+		hs_sink_desc.bEndpointAddress =
+				fs_sink_desc.bEndpointAddress;
+	}
 
-	if (gadget->is_otg) {
+	if (gadget_is_otg(gadget)) {
 		otg_descriptor.bmAttributes |= USB_OTG_HNP,
 		source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 		loopback_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
@@ -1294,23 +1254,18 @@ static struct usb_gadget_driver zero_driver = {
 	.suspend	= zero_suspend,
 	.resume		= zero_resume,
 
-	.driver 	= {
+	.driver		= {
 		.name		= (char *) shortname,
 		.owner		= THIS_MODULE,
 	},
 };
 
-MODULE_AUTHOR ("David Brownell");
-MODULE_LICENSE ("Dual BSD/GPL");
+MODULE_AUTHOR("David Brownell");
+MODULE_LICENSE("GPL");
 
 
 static int __init init (void)
 {
-	/* a real value would likely come through some id prom
-	 * or module option.  this one takes at least two packets.
-	 */
-	strlcpy (serial, "0123456789.0123456789.0123456789", sizeof serial);
-
 	return usb_gadget_register_driver (&zero_driver);
 }
 module_init (init);

+ 13 - 0
drivers/usb/host/Kconfig

@@ -154,6 +154,19 @@ config USB_OHCI_HCD_PCI
 	  Enables support for PCI-bus plug-in USB controller cards.
 	  If unsure, say Y.
 
+config USB_OHCI_HCD_SSB
+	bool "OHCI support for Broadcom SSB OHCI core"
+	depends on USB_OHCI_HCD && SSB && EXPERIMENTAL
+	default n
+	---help---
+	  Support for the Sonics Silicon Backplane (SSB) attached
+	  Broadcom USB OHCI core.
+
+	  This device is present in some embedded devices with
+	  Broadcom based SSB bus.
+
+	  If unsure, say N.
+
 config USB_OHCI_BIG_ENDIAN_DESC
 	bool
 	depends on USB_OHCI_HCD

+ 2 - 4
drivers/usb/host/ehci-au1xxx.c

@@ -220,10 +220,8 @@ static const struct hc_driver ehci_au1xxx_hc_driver = {
 	 */
 	.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
+	.bus_suspend = ehci_bus_suspend,
+	.bus_resume = ehci_bus_resume,
 };
 
 /*-------------------------------------------------------------------------*/

+ 17 - 5
drivers/usb/host/ehci-hcd.c

@@ -570,10 +570,18 @@ static int ehci_run (struct usb_hcd *hcd)
 	 * are explicitly handed to companion controller(s), so no TT is
 	 * involved with the root hub.  (Except where one is integrated,
 	 * and there's no companion controller unless maybe for USB OTG.)
+	 *
+	 * Turning on the CF flag will transfer ownership of all ports
+	 * from the companions to the EHCI controller.  If any of the
+	 * companions are in the middle of a port reset at the time, it
+	 * could cause trouble.  Write-locking ehci_cf_port_reset_rwsem
+	 * guarantees that no resets are in progress.
 	 */
+	down_write(&ehci_cf_port_reset_rwsem);
 	hcd->state = HC_STATE_RUNNING;
 	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
 	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
+	up_write(&ehci_cf_port_reset_rwsem);
 
 	temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
 	ehci_info (ehci,
@@ -719,7 +727,6 @@ dead:
  */
 static int ehci_urb_enqueue (
 	struct usb_hcd	*hcd,
-	struct usb_host_endpoint *ep,
 	struct urb	*urb,
 	gfp_t		mem_flags
 ) {
@@ -734,12 +741,12 @@ static int ehci_urb_enqueue (
 	default:
 		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
 			return -ENOMEM;
-		return submit_async (ehci, ep, urb, &qtd_list, mem_flags);
+		return submit_async(ehci, urb, &qtd_list, mem_flags);
 
 	case PIPE_INTERRUPT:
 		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
 			return -ENOMEM;
-		return intr_submit (ehci, ep, urb, &qtd_list, mem_flags);
+		return intr_submit(ehci, urb, &qtd_list, mem_flags);
 
 	case PIPE_ISOCHRONOUS:
 		if (urb->dev->speed == USB_SPEED_HIGH)
@@ -777,13 +784,18 @@ static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
  * completions normally happen asynchronously
  */
 
-static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int ehci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	struct ehci_hcd		*ehci = hcd_to_ehci (hcd);
 	struct ehci_qh		*qh;
 	unsigned long		flags;
+	int			rc;
 
 	spin_lock_irqsave (&ehci->lock, flags);
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
+		goto done;
+
 	switch (usb_pipetype (urb->pipe)) {
 	// case PIPE_CONTROL:
 	// case PIPE_BULK:
@@ -838,7 +850,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
 	}
 done:
 	spin_unlock_irqrestore (&ehci->lock, flags);
-	return 0;
+	return rc;
 }
 
 /*-------------------------------------------------------------------------*/

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

@@ -58,8 +58,6 @@ static int ehci_pci_reinit(struct ehci_hcd *ehci, struct pci_dev *pdev)
 	if (!retval)
 		ehci_dbg(ehci, "MWI active\n");
 
-	ehci_port_power(ehci, 0);
-
 	return 0;
 }
 
@@ -156,8 +154,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
 		break;
 	}
 
-	if (ehci_is_TDI(ehci))
-		ehci_reset(ehci);
+	ehci_reset(ehci);
 
 	/* at least the Genesys GL880S needs fixup here */
 	temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);

+ 2 - 4
drivers/usb/host/ehci-ppc-soc.c

@@ -160,10 +160,8 @@ static const struct hc_driver ehci_ppc_soc_hc_driver = {
 	 */
 	.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
+	.bus_suspend = ehci_bus_suspend,
+	.bus_resume = ehci_bus_resume,
 };
 
 static int ehci_hcd_ppc_soc_drv_probe(struct platform_device *pdev)

+ 1 - 1
drivers/usb/host/ehci-ps3.c

@@ -47,7 +47,7 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
 	if (result)
 		return result;
 
-	ehci_port_power(ehci, 0);
+	ehci_reset(ehci);
 
 	return result;
 }

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

@@ -139,63 +139,65 @@ qh_refresh (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
 /*-------------------------------------------------------------------------*/
 
-static void qtd_copy_status (
+static int qtd_copy_status (
 	struct ehci_hcd *ehci,
 	struct urb *urb,
 	size_t length,
 	u32 token
 )
 {
+	int	status = -EINPROGRESS;
+
 	/* count IN/OUT bytes, not SETUP (even short packets) */
 	if (likely (QTD_PID (token) != 2))
 		urb->actual_length += length - QTD_LENGTH (token);
 
 	/* don't modify error codes */
-	if (unlikely (urb->status != -EINPROGRESS))
-		return;
+	if (unlikely(urb->unlinked))
+		return status;
 
 	/* force cleanup after short read; not always an error */
 	if (unlikely (IS_SHORT_READ (token)))
-		urb->status = -EREMOTEIO;
+		status = -EREMOTEIO;
 
 	/* serious "can't proceed" faults reported by the hardware */
 	if (token & QTD_STS_HALT) {
 		if (token & QTD_STS_BABBLE) {
 			/* FIXME "must" disable babbling device's port too */
-			urb->status = -EOVERFLOW;
+			status = -EOVERFLOW;
 		} else if (token & QTD_STS_MMF) {
 			/* fs/ls interrupt xfer missed the complete-split */
-			urb->status = -EPROTO;
+			status = -EPROTO;
 		} else if (token & QTD_STS_DBE) {
-			urb->status = (QTD_PID (token) == 1) /* IN ? */
+			status = (QTD_PID (token) == 1) /* IN ? */
 				? -ENOSR  /* hc couldn't read data */
 				: -ECOMM; /* hc couldn't write data */
 		} else if (token & QTD_STS_XACT) {
 			/* timeout, bad crc, wrong PID, etc; retried */
 			if (QTD_CERR (token))
-				urb->status = -EPIPE;
+				status = -EPIPE;
 			else {
 				ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n",
 					urb->dev->devpath,
 					usb_pipeendpoint (urb->pipe),
 					usb_pipein (urb->pipe) ? "in" : "out");
-				urb->status = -EPROTO;
+				status = -EPROTO;
 			}
 		/* CERR nonzero + no errors + halt --> stall */
 		} else if (QTD_CERR (token))
-			urb->status = -EPIPE;
+			status = -EPIPE;
 		else	/* unknown */
-			urb->status = -EPROTO;
+			status = -EPROTO;
 
 		ehci_vdbg (ehci,
 			"dev%d ep%d%s qtd token %08x --> status %d\n",
 			usb_pipedevice (urb->pipe),
 			usb_pipeendpoint (urb->pipe),
 			usb_pipein (urb->pipe) ? "in" : "out",
-			token, urb->status);
+			token, status);
 
 		/* if async CSPLIT failed, try cleaning out the TT buffer */
-		if (urb->status != -EPIPE
+		if (status != -EPIPE
 				&& urb->dev->tt && !usb_pipeint (urb->pipe)
 				&& ((token & QTD_STS_MMF) != 0
 					|| QTD_CERR(token) == 0)
@@ -212,10 +214,12 @@ static void qtd_copy_status (
 			usb_hub_tt_clear_buffer (urb->dev, urb->pipe);
 		}
 	}
+
+	return status;
 }
 
 static void
-ehci_urb_done (struct ehci_hcd *ehci, struct urb *urb)
+ehci_urb_done(struct ehci_hcd *ehci, struct urb *urb, int status)
 __releases(ehci->lock)
 __acquires(ehci->lock)
 {
@@ -231,25 +235,13 @@ __acquires(ehci->lock)
 		qh_put (qh);
 	}
 
-	spin_lock (&urb->lock);
-	urb->hcpriv = NULL;
-	switch (urb->status) {
-	case -EINPROGRESS:		/* success */
-		urb->status = 0;
-	default:			/* fault */
-		COUNT (ehci->stats.complete);
-		break;
-	case -EREMOTEIO:		/* fault or normal */
-		if (!(urb->transfer_flags & URB_SHORT_NOT_OK))
-			urb->status = 0;
-		COUNT (ehci->stats.complete);
-		break;
-	case -ECONNRESET:		/* canceled */
-	case -ENOENT:
-		COUNT (ehci->stats.unlink);
-		break;
+	if (unlikely(urb->unlinked)) {
+		COUNT(ehci->stats.unlink);
+	} else {
+		if (likely(status == -EINPROGRESS))
+			status = 0;
+		COUNT(ehci->stats.complete);
 	}
-	spin_unlock (&urb->lock);
 
 #ifdef EHCI_URB_TRACE
 	ehci_dbg (ehci,
@@ -257,13 +249,14 @@ __acquires(ehci->lock)
 		__FUNCTION__, urb->dev->devpath, urb,
 		usb_pipeendpoint (urb->pipe),
 		usb_pipein (urb->pipe) ? "in" : "out",
-		urb->status,
+		status,
 		urb->actual_length, urb->transfer_buffer_length);
 #endif
 
 	/* complete() can reenter this HCD */
+	usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
 	spin_unlock (&ehci->lock);
-	usb_hcd_giveback_urb (ehci_to_hcd(ehci), urb);
+	usb_hcd_giveback_urb(ehci_to_hcd(ehci), urb, status);
 	spin_lock (&ehci->lock);
 }
 
@@ -283,6 +276,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
 {
 	struct ehci_qtd		*last = NULL, *end = qh->dummy;
 	struct list_head	*entry, *tmp;
+	int			last_status = -EINPROGRESS;
 	int			stopped;
 	unsigned		count = 0;
 	int			do_status = 0;
@@ -311,6 +305,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
 		struct ehci_qtd	*qtd;
 		struct urb	*urb;
 		u32		token = 0;
+		int		qtd_status;
 
 		qtd = list_entry (entry, struct ehci_qtd, qtd_list);
 		urb = qtd->urb;
@@ -318,11 +313,12 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
 		/* clean up any state from previous QTD ...*/
 		if (last) {
 			if (likely (last->urb != urb)) {
-				ehci_urb_done (ehci, last->urb);
+				ehci_urb_done(ehci, last->urb, last_status);
 				count++;
 			}
 			ehci_qtd_free (ehci, last);
 			last = NULL;
+			last_status = -EINPROGRESS;
 		}
 
 		/* ignore urbs submitted during completions we reported */
@@ -358,13 +354,14 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
 			stopped = 1;
 
 			if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)))
-				urb->status = -ESHUTDOWN;
+				last_status = -ESHUTDOWN;
 
 			/* ignore active urbs unless some previous qtd
 			 * for the urb faulted (including short read) or
 			 * its urb was canceled.  we may patch qh or qtds.
 			 */
-			if (likely (urb->status == -EINPROGRESS))
+			if (likely(last_status == -EINPROGRESS &&
+					!urb->unlinked))
 				continue;
 
 			/* issue status after short control reads */
@@ -392,11 +389,14 @@ halt:
 		}
 
 		/* remove it from the queue */
-		spin_lock (&urb->lock);
-		qtd_copy_status (ehci, urb, qtd->length, token);
-		do_status = (urb->status == -EREMOTEIO)
-				&& usb_pipecontrol (urb->pipe);
-		spin_unlock (&urb->lock);
+		qtd_status = qtd_copy_status(ehci, urb, qtd->length, token);
+		if (unlikely(qtd_status == -EREMOTEIO)) {
+			do_status = (!urb->unlinked &&
+					usb_pipecontrol(urb->pipe));
+			qtd_status = 0;
+		}
+		if (likely(last_status == -EINPROGRESS))
+			last_status = qtd_status;
 
 		if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
 			last = list_entry (qtd->qtd_list.prev,
@@ -409,7 +409,7 @@ halt:
 
 	/* last urb's completion might still need calling */
 	if (likely (last != NULL)) {
-		ehci_urb_done (ehci, last->urb);
+		ehci_urb_done(ehci, last->urb, last_status);
 		count++;
 		ehci_qtd_free (ehci, last);
 	}
@@ -913,7 +913,6 @@ static struct ehci_qh *qh_append_tds (
 static int
 submit_async (
 	struct ehci_hcd		*ehci,
-	struct usb_host_endpoint *ep,
 	struct urb		*urb,
 	struct list_head	*qtd_list,
 	gfp_t			mem_flags
@@ -922,10 +921,10 @@ submit_async (
 	int			epnum;
 	unsigned long		flags;
 	struct ehci_qh		*qh = NULL;
-	int			rc = 0;
+	int			rc;
 
 	qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
-	epnum = ep->desc.bEndpointAddress;
+	epnum = urb->ep->desc.bEndpointAddress;
 
 #ifdef EHCI_URB_TRACE
 	ehci_dbg (ehci,
@@ -933,7 +932,7 @@ submit_async (
 		__FUNCTION__, urb->dev->devpath, urb,
 		epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
 		urb->transfer_buffer_length,
-		qtd, ep->hcpriv);
+		qtd, urb->ep->hcpriv);
 #endif
 
 	spin_lock_irqsave (&ehci->lock, flags);
@@ -942,9 +941,13 @@ submit_async (
 		rc = -ESHUTDOWN;
 		goto done;
 	}
+	rc = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+	if (unlikely(rc))
+		goto done;
 
-	qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+	qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
 	if (unlikely(qh == NULL)) {
+		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
 		rc = -ENOMEM;
 		goto done;
 	}

+ 33 - 14
drivers/usb/host/ehci-sched.c

@@ -797,7 +797,6 @@ done:
 
 static int intr_submit (
 	struct ehci_hcd		*ehci,
-	struct usb_host_endpoint *ep,
 	struct urb		*urb,
 	struct list_head	*qtd_list,
 	gfp_t			mem_flags
@@ -805,23 +804,26 @@ static int intr_submit (
 	unsigned		epnum;
 	unsigned long		flags;
 	struct ehci_qh		*qh;
-	int			status = 0;
+	int			status;
 	struct list_head	empty;
 
 	/* get endpoint and transfer/schedule data */
-	epnum = ep->desc.bEndpointAddress;
+	epnum = urb->ep->desc.bEndpointAddress;
 
 	spin_lock_irqsave (&ehci->lock, flags);
 
 	if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
 			&ehci_to_hcd(ehci)->flags))) {
 		status = -ESHUTDOWN;
-		goto done;
+		goto done_not_linked;
 	}
+	status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+	if (unlikely(status))
+		goto done_not_linked;
 
 	/* get qh and force any scheduling errors */
 	INIT_LIST_HEAD (&empty);
-	qh = qh_append_tds (ehci, urb, &empty, epnum, &ep->hcpriv);
+	qh = qh_append_tds(ehci, urb, &empty, epnum, &urb->ep->hcpriv);
 	if (qh == NULL) {
 		status = -ENOMEM;
 		goto done;
@@ -832,13 +834,16 @@ static int intr_submit (
 	}
 
 	/* then queue the urb's tds to the qh */
-	qh = qh_append_tds (ehci, urb, qtd_list, epnum, &ep->hcpriv);
+	qh = qh_append_tds(ehci, urb, qtd_list, epnum, &urb->ep->hcpriv);
 	BUG_ON (qh == NULL);
 
 	/* ... update usbfs periodic stats */
 	ehci_to_hcd(ehci)->self.bandwidth_int_reqs++;
 
 done:
+	if (unlikely(status))
+		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
 	spin_unlock_irqrestore (&ehci->lock, flags);
 	if (status)
 		qtd_list_free (ehci, urb, qtd_list);
@@ -1622,7 +1627,7 @@ itd_complete (
 
 	/* give urb back to the driver ... can be out-of-order */
 	dev = urb->dev;
-	ehci_urb_done (ehci, urb);
+	ehci_urb_done(ehci, urb, 0);
 	urb = NULL;
 
 	/* defer stopping schedule; completion can submit */
@@ -1686,12 +1691,19 @@ static int itd_submit (struct ehci_hcd *ehci, struct urb *urb,
 	/* schedule ... need to lock */
 	spin_lock_irqsave (&ehci->lock, flags);
 	if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
-			       &ehci_to_hcd(ehci)->flags)))
+			       &ehci_to_hcd(ehci)->flags))) {
 		status = -ESHUTDOWN;
-	else
-		status = iso_stream_schedule (ehci, urb, stream);
+		goto done_not_linked;
+	}
+	status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+	if (unlikely(status))
+		goto done_not_linked;
+	status = iso_stream_schedule(ehci, urb, stream);
 	if (likely (status == 0))
 		itd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+	else
+		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
 	spin_unlock_irqrestore (&ehci->lock, flags);
 
 done:
@@ -1988,7 +2000,7 @@ sitd_complete (
 
 	/* give urb back to the driver */
 	dev = urb->dev;
-	ehci_urb_done (ehci, urb);
+	ehci_urb_done(ehci, urb, 0);
 	urb = NULL;
 
 	/* defer stopping schedule; completion can submit */
@@ -2049,12 +2061,19 @@ static int sitd_submit (struct ehci_hcd *ehci, struct urb *urb,
 	/* schedule ... need to lock */
 	spin_lock_irqsave (&ehci->lock, flags);
 	if (unlikely(!test_bit(HCD_FLAG_HW_ACCESSIBLE,
-			       &ehci_to_hcd(ehci)->flags)))
+			       &ehci_to_hcd(ehci)->flags))) {
 		status = -ESHUTDOWN;
-	else
-		status = iso_stream_schedule (ehci, urb, stream);
+		goto done_not_linked;
+	}
+	status = usb_hcd_link_urb_to_ep(ehci_to_hcd(ehci), urb);
+	if (unlikely(status))
+		goto done_not_linked;
+	status = iso_stream_schedule(ehci, urb, stream);
 	if (status == 0)
 		sitd_link_urb (ehci, urb, ehci->periodic_size << 3, stream);
+	else
+		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
+done_not_linked:
 	spin_unlock_irqrestore (&ehci->lock, flags);
 
 done:

+ 27 - 34
drivers/usb/host/isp116x-hcd.c

@@ -277,12 +277,11 @@ static void preproc_atl_queue(struct isp116x *isp116x)
   processed urbs.
 */
 static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
-			   struct urb *urb)
+			   struct urb *urb, int status)
 __releases(isp116x->lock) __acquires(isp116x->lock)
 {
 	unsigned i;
 
-	urb->hcpriv = NULL;
 	ep->error_count = 0;
 
 	if (usb_pipecontrol(urb->pipe))
@@ -290,8 +289,9 @@ __releases(isp116x->lock) __acquires(isp116x->lock)
 
 	urb_dbg(urb, "Finish");
 
+	usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb);
 	spin_unlock(&isp116x->lock);
-	usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb);
+	usb_hcd_giveback_urb(isp116x_to_hcd(isp116x), urb, status);
 	spin_lock(&isp116x->lock);
 
 	/* take idle endpoints out of the schedule */
@@ -445,12 +445,7 @@ static void postproc_atl_queue(struct isp116x *isp116x)
 			if (PTD_GET_ACTIVE(ptd)
 			    || (cc != TD_CC_NOERROR && cc < 0x0E))
 				break;
-			if ((urb->transfer_flags & URB_SHORT_NOT_OK) &&
-					urb->actual_length <
-						urb->transfer_buffer_length)
-				status = -EREMOTEIO;
-			else
-				status = 0;
+			status = 0;
 			ep->nextpid = 0;
 			break;
 		default:
@@ -458,14 +453,8 @@ static void postproc_atl_queue(struct isp116x *isp116x)
 		}
 
  done:
-		if (status != -EINPROGRESS) {
-			spin_lock(&urb->lock);
-			if (urb->status == -EINPROGRESS)
-				urb->status = status;
-			spin_unlock(&urb->lock);
-		}
-		if (urb->status != -EINPROGRESS)
-			finish_request(isp116x, ep, urb);
+		if (status != -EINPROGRESS || urb->unlinked)
+			finish_request(isp116x, ep, urb, status);
 	}
 }
 
@@ -673,7 +662,7 @@ static int balance(struct isp116x *isp116x, u16 period, u16 load)
 /*-----------------------------------------------------------------*/
 
 static int isp116x_urb_enqueue(struct usb_hcd *hcd,
-			       struct usb_host_endpoint *hep, struct urb *urb,
+			       struct urb *urb,
 			       gfp_t mem_flags)
 {
 	struct isp116x *isp116x = hcd_to_isp116x(hcd);
@@ -682,6 +671,7 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
 	int is_out = !usb_pipein(pipe);
 	int type = usb_pipetype(pipe);
 	int epnum = usb_pipeendpoint(pipe);
+	struct usb_host_endpoint *hep = urb->ep;
 	struct isp116x_ep *ep = NULL;
 	unsigned long flags;
 	int i;
@@ -705,7 +695,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
 	if (!HC_IS_RUNNING(hcd->state)) {
 		kfree(ep);
 		ret = -ENODEV;
-		goto fail;
+		goto fail_not_linked;
+	}
+	ret = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (ret) {
+		kfree(ep);
+		goto fail_not_linked;
 	}
 
 	if (hep->hcpriv)
@@ -808,16 +803,13 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
 		}
 	}
 
-	/* in case of unlink-during-submit */
-	if (urb->status != -EINPROGRESS) {
-		finish_request(isp116x, ep, urb);
-		ret = 0;
-		goto fail;
-	}
 	urb->hcpriv = hep;
 	start_atl_transfers(isp116x);
 
       fail:
+	if (ret)
+		usb_hcd_unlink_urb_from_ep(hcd, urb);
+      fail_not_linked:
 	spin_unlock_irqrestore(&isp116x->lock, flags);
 	return ret;
 }
@@ -825,20 +817,21 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
 /*
    Dequeue URBs.
 */
-static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+		int status)
 {
 	struct isp116x *isp116x = hcd_to_isp116x(hcd);
 	struct usb_host_endpoint *hep;
 	struct isp116x_ep *ep, *ep_act;
 	unsigned long flags;
+	int rc;
 
 	spin_lock_irqsave(&isp116x->lock, flags);
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
+		goto done;
+
 	hep = urb->hcpriv;
-	/* URB already unlinked (or never linked)? */
-	if (!hep) {
-		spin_unlock_irqrestore(&isp116x->lock, flags);
-		return 0;
-	}
 	ep = hep->hcpriv;
 	WARN_ON(hep != ep->hep);
 
@@ -855,10 +848,10 @@ static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
 			}
 
 	if (urb)
-		finish_request(isp116x, ep, urb);
-
+		finish_request(isp116x, ep, urb, status);
+ done:
 	spin_unlock_irqrestore(&isp116x->lock, flags);
-	return 0;
+	return rc;
 }
 
 static void isp116x_endpoint_disable(struct usb_hcd *hcd,

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

@@ -24,7 +24,7 @@
  * small: 0) header + data packets 1) just header
  */
 static void __maybe_unused
-urb_print (struct urb * urb, char * str, int small)
+urb_print(struct urb * urb, char * str, int small, int status)
 {
 	unsigned int pipe= urb->pipe;
 
@@ -34,7 +34,7 @@ urb_print (struct urb * urb, char * str, int small)
 	}
 
 #ifndef	OHCI_VERBOSE_DEBUG
-	if (urb->status != 0)
+	if (status != 0)
 #endif
 	dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d",
 		    str,
@@ -46,7 +46,7 @@ urb_print (struct urb * urb, char * str, int small)
 		    urb->transfer_flags,
 		    urb->actual_length,
 		    urb->transfer_buffer_length,
-		    urb->status);
+		    status);
 
 #ifdef	OHCI_VERBOSE_DEBUG
 	if (!small) {
@@ -66,7 +66,7 @@ urb_print (struct urb * urb, char * str, int small)
 						urb->transfer_buffer_length: urb->actual_length;
 			for (i = 0; i < 16 && i < len; i++)
 				printk (" %02x", ((__u8 *) urb->transfer_buffer) [i]);
-			printk ("%s stat:%d\n", i < len? "...": "", urb->status);
+			printk ("%s stat:%d\n", i < len? "...": "", status);
 		}
 	}
 #endif

+ 180 - 54
drivers/usb/host/ohci-hcd.c

@@ -81,7 +81,6 @@ static void ohci_dump (struct ohci_hcd *ohci, int verbose);
 static int ohci_init (struct ohci_hcd *ohci);
 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-dbg.c"
@@ -118,7 +117,6 @@ MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake");
  */
 static int ohci_urb_enqueue (
 	struct usb_hcd	*hcd,
-	struct usb_host_endpoint *ep,
 	struct urb	*urb,
 	gfp_t		mem_flags
 ) {
@@ -131,11 +129,11 @@ static int ohci_urb_enqueue (
 	int		retval = 0;
 
 #ifdef OHCI_VERBOSE_DEBUG
-	urb_print (urb, "SUB", usb_pipein (pipe));
+	urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS);
 #endif
 
 	/* every endpoint has a ed, locate and maybe (re)initialize it */
-	if (! (ed = ed_get (ohci, ep, urb->dev, pipe, urb->interval)))
+	if (! (ed = ed_get (ohci, urb->ep, urb->dev, pipe, urb->interval)))
 		return -ENOMEM;
 
 	/* for the private part of the URB we need the number of TDs (size) */
@@ -200,22 +198,17 @@ static int ohci_urb_enqueue (
 		retval = -ENODEV;
 		goto fail;
 	}
-
-	/* in case of unlink-during-submit */
-	spin_lock (&urb->lock);
-	if (urb->status != -EINPROGRESS) {
-		spin_unlock (&urb->lock);
-		urb->hcpriv = urb_priv;
-		finish_urb (ohci, urb);
-		retval = 0;
+	retval = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (retval)
 		goto fail;
-	}
 
 	/* schedule the ed if needed */
 	if (ed->state == ED_IDLE) {
 		retval = ed_schedule (ohci, ed);
-		if (retval < 0)
-			goto fail0;
+		if (retval < 0) {
+			usb_hcd_unlink_urb_from_ep(hcd, urb);
+			goto fail;
+		}
 		if (ed->type == PIPE_ISOCHRONOUS) {
 			u16	frame = ohci_frame_no(ohci);
 
@@ -239,8 +232,6 @@ static int ohci_urb_enqueue (
 	urb->hcpriv = urb_priv;
 	td_submit_urb (ohci, urb);
 
-fail0:
-	spin_unlock (&urb->lock);
 fail:
 	if (retval)
 		urb_free_priv (ohci, urb_priv);
@@ -249,22 +240,26 @@ fail:
 }
 
 /*
- * decouple the URB from the HC queues (TDs, urb_priv); it's
- * already marked using urb->status.  reporting is always done
+ * decouple the URB from the HC queues (TDs, urb_priv).
+ * reporting is always done
  * asynchronously, and we might be dealing with an urb that's
  * partially transferred, or an ED with other urbs being unlinked.
  */
-static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
+static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 	unsigned long		flags;
+	int			rc;
 
 #ifdef OHCI_VERBOSE_DEBUG
-	urb_print (urb, "UNLINK", 1);
+	urb_print(urb, "UNLINK", 1, status);
 #endif
 
 	spin_lock_irqsave (&ohci->lock, flags);
-	if (HC_IS_RUNNING(hcd->state)) {
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc) {
+		;	/* Do nothing */
+	} else if (HC_IS_RUNNING(hcd->state)) {
 		urb_priv_t  *urb_priv;
 
 		/* Unless an IRQ completed the unlink while it was being
@@ -282,10 +277,10 @@ static int ohci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
 		 * any more ... just clean up every urb's memory.
 		 */
 		if (urb->hcpriv)
-			finish_urb (ohci, urb);
+			finish_urb(ohci, urb, status);
 	}
 	spin_unlock_irqrestore (&ohci->lock, flags);
-	return 0;
+	return rc;
 }
 
 /*-------------------------------------------------------------------------*/
@@ -314,6 +309,8 @@ rescan:
 	if (!HC_IS_RUNNING (hcd->state)) {
 sanitize:
 		ed->state = ED_IDLE;
+		if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
+			ohci->eds_scheduled--;
 		finish_unlinks (ohci, 0);
 	}
 
@@ -321,7 +318,12 @@ sanitize:
 	case ED_UNLINK:		/* wait for hw to finish? */
 		/* major IRQ delivery trouble loses INTR_SF too... */
 		if (limit-- == 0) {
-			ohci_warn (ohci, "IRQ INTR_SF lossage\n");
+			ohci_warn(ohci, "ED unlink timeout\n");
+			if (quirk_zfmicro(ohci)) {
+				ohci_warn(ohci, "Attempting ZF TD recovery\n");
+				ohci->ed_to_check = ed;
+				ohci->zf_delay = 2;
+			}
 			goto sanitize;
 		}
 		spin_unlock_irqrestore (&ohci->lock, flags);
@@ -379,6 +381,93 @@ ohci_shutdown (struct usb_hcd *hcd)
 	(void) ohci_readl (ohci, &ohci->regs->control);
 }
 
+static int check_ed(struct ohci_hcd *ohci, struct ed *ed)
+{
+	return (hc32_to_cpu(ohci, ed->hwINFO) & ED_IN) != 0
+		&& (hc32_to_cpu(ohci, ed->hwHeadP) & TD_MASK)
+			== (hc32_to_cpu(ohci, ed->hwTailP) & TD_MASK)
+		&& !list_empty(&ed->td_list);
+}
+
+/* ZF Micro watchdog timer callback. The ZF Micro chipset sometimes completes
+ * an interrupt TD but neglects to add it to the donelist.  On systems with
+ * this chipset, we need to periodically check the state of the queues to look
+ * for such "lost" TDs.
+ */
+static void unlink_watchdog_func(unsigned long _ohci)
+{
+	long		flags;
+	unsigned	max;
+	unsigned	seen_count = 0;
+	unsigned	i;
+	struct ed	**seen = NULL;
+	struct ohci_hcd	*ohci = (struct ohci_hcd *) _ohci;
+
+	spin_lock_irqsave(&ohci->lock, flags);
+	max = ohci->eds_scheduled;
+	if (!max)
+		goto done;
+
+	if (ohci->ed_to_check)
+		goto out;
+
+	seen = kcalloc(max, sizeof *seen, GFP_ATOMIC);
+	if (!seen)
+		goto out;
+
+	for (i = 0; i < NUM_INTS; i++) {
+		struct ed	*ed = ohci->periodic[i];
+
+		while (ed) {
+			unsigned	temp;
+
+			/* scan this branch of the periodic schedule tree */
+			for (temp = 0; temp < seen_count; temp++) {
+				if (seen[temp] == ed) {
+					/* we've checked it and what's after */
+					ed = NULL;
+					break;
+				}
+			}
+			if (!ed)
+				break;
+			seen[seen_count++] = ed;
+			if (!check_ed(ohci, ed)) {
+				ed = ed->ed_next;
+				continue;
+			}
+
+			/* HC's TD list is empty, but HCD sees at least one
+			 * TD that's not been sent through the donelist.
+			 */
+			ohci->ed_to_check = ed;
+			ohci->zf_delay = 2;
+
+			/* The HC may wait until the next frame to report the
+			 * TD as done through the donelist and INTR_WDH.  (We
+			 * just *assume* it's not a multi-TD interrupt URB;
+			 * those could defer the IRQ more than one frame, using
+			 * DI...)  Check again after the next INTR_SF.
+			 */
+			ohci_writel(ohci, OHCI_INTR_SF,
+					&ohci->regs->intrstatus);
+			ohci_writel(ohci, OHCI_INTR_SF,
+					&ohci->regs->intrenable);
+
+			/* flush those writes */
+			(void) ohci_readl(ohci, &ohci->regs->control);
+
+			goto out;
+		}
+	}
+out:
+	kfree(seen);
+	if (ohci->eds_scheduled)
+		mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ));
+done:
+	spin_unlock_irqrestore(&ohci->lock, flags);
+}
+
 /*-------------------------------------------------------------------------*
  * HC functions
  *-------------------------------------------------------------------------*/
@@ -616,6 +705,15 @@ retry:
 	mdelay ((temp >> 23) & 0x1fe);
 	hcd->state = HC_STATE_RUNNING;
 
+	if (quirk_zfmicro(ohci)) {
+		/* Create timer to watch for bad queue state on ZF Micro */
+		setup_timer(&ohci->unlink_watchdog, unlink_watchdog_func,
+				(unsigned long) ohci);
+
+		ohci->eds_scheduled = 0;
+		ohci->ed_to_check = NULL;
+	}
+
 	ohci_dump (ohci, 1);
 
 	return 0;
@@ -629,10 +727,11 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
 {
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 	struct ohci_regs __iomem *regs = ohci->regs;
- 	int			ints; 
+	int			ints;
 
 	/* we can eliminate a (slow) ohci_readl()
-	   if _only_ WDH caused this irq */
+	 * if _only_ WDH caused this irq
+	 */
 	if ((ohci->hcca->done_head != 0)
 			&& ! (hc32_to_cpup (ohci, &ohci->hcca->done_head)
 				& 0x01)) {
@@ -651,7 +750,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
 
 	if (ints & OHCI_INTR_UE) {
 		// e.g. due to PCI Master/Target Abort
-		if (ohci->flags & OHCI_QUIRK_NEC) {
+		if (quirk_nec(ohci)) {
 			/* Workaround for a silicon bug in some NEC chips used
 			 * in Apple's PowerBooks. Adapted from Darwin code.
 			 */
@@ -713,6 +812,31 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
 			ohci_writel (ohci, OHCI_INTR_WDH, &regs->intrenable);
 	}
 
+	if (quirk_zfmicro(ohci) && (ints & OHCI_INTR_SF)) {
+		spin_lock(&ohci->lock);
+		if (ohci->ed_to_check) {
+			struct ed *ed = ohci->ed_to_check;
+
+			if (check_ed(ohci, ed)) {
+				/* HC thinks the TD list is empty; HCD knows
+				 * at least one TD is outstanding
+				 */
+				if (--ohci->zf_delay == 0) {
+					struct td *td = list_entry(
+						ed->td_list.next,
+						struct td, td_list);
+					ohci_warn(ohci,
+						  "Reclaiming orphan TD %p\n",
+						  td);
+					takeback_td(ohci, td);
+					ohci->ed_to_check = NULL;
+				}
+			} else
+				ohci->ed_to_check = NULL;
+		}
+		spin_unlock(&ohci->lock);
+	}
+
 	/* could track INTR_SO to reduce available PCI/... bandwidth */
 
 	/* handle any pending URB/ED unlinks, leaving INTR_SF enabled
@@ -721,7 +845,9 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
 	spin_lock (&ohci->lock);
 	if (ohci->ed_rm_list)
 		finish_unlinks (ohci, ohci_frame_no(ohci));
-	if ((ints & OHCI_INTR_SF) != 0 && !ohci->ed_rm_list
+	if ((ints & OHCI_INTR_SF) != 0
+			&& !ohci->ed_rm_list
+			&& !ohci->ed_to_check
 			&& HC_IS_RUNNING(hcd->state))
 		ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);
 	spin_unlock (&ohci->lock);
@@ -751,6 +877,9 @@ static void ohci_stop (struct usb_hcd *hcd)
 	free_irq(hcd->irq, hcd);
 	hcd->irq = -1;
 
+	if (quirk_zfmicro(ohci))
+		del_timer(&ohci->unlink_watchdog);
+
 	remove_debug_files (ohci);
 	ohci_mem_cleanup (ohci);
 	if (ohci->hcca) {
@@ -798,9 +927,8 @@ static int ohci_restart (struct ohci_hcd *ohci)
 					ed, ed->state);
 		}
 
-		spin_lock (&urb->lock);
-		urb->status = -ESHUTDOWN;
-		spin_unlock (&urb->lock);
+		if (!urb->unlinked)
+			urb->unlinked = -ESHUTDOWN;
 	}
 	finish_unlinks (ohci, 0);
 	spin_unlock_irq(&ohci->lock);
@@ -828,27 +956,6 @@ static int ohci_restart (struct ohci_hcd *ohci)
 
 /*-------------------------------------------------------------------------*/
 
-/* 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);
-}
-
-/*-------------------------------------------------------------------------*/
-
 #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
 
 MODULE_AUTHOR (DRIVER_AUTHOR);
@@ -926,11 +1033,17 @@ MODULE_LICENSE ("GPL");
 #define PS3_SYSTEM_BUS_DRIVER	ps3_ohci_driver
 #endif
 
+#ifdef CONFIG_USB_OHCI_HCD_SSB
+#include "ohci-ssb.c"
+#define SSB_OHCI_DRIVER		ssb_ohci_driver
+#endif
+
 #if	!defined(PCI_DRIVER) &&		\
 	!defined(PLATFORM_DRIVER) &&	\
 	!defined(OF_PLATFORM_DRIVER) &&	\
 	!defined(SA1111_DRIVER) &&	\
-	!defined(PS3_SYSTEM_BUS_DRIVER)
+	!defined(PS3_SYSTEM_BUS_DRIVER) && \
+	!defined(SSB_OHCI_DRIVER)
 #error "missing bus glue for ohci-hcd"
 #endif
 
@@ -975,10 +1088,20 @@ static int __init ohci_hcd_mod_init(void)
 		goto error_pci;
 #endif
 
+#ifdef SSB_OHCI_DRIVER
+	retval = ssb_driver_register(&SSB_OHCI_DRIVER);
+	if (retval)
+		goto error_ssb;
+#endif
+
 	return retval;
 
 	/* Error path */
+#ifdef SSB_OHCI_DRIVER
+ error_ssb:
+#endif
 #ifdef PCI_DRIVER
+	pci_unregister_driver(&PCI_DRIVER);
  error_pci:
 #endif
 #ifdef SA1111_DRIVER
@@ -1003,6 +1126,9 @@ module_init(ohci_hcd_mod_init);
 
 static void __exit ohci_hcd_mod_exit(void)
 {
+#ifdef SSB_OHCI_DRIVER
+	ssb_driver_unregister(&SSB_OHCI_DRIVER);
+#endif
 #ifdef PCI_DRIVER
 	pci_unregister_driver(&PCI_DRIVER);
 #endif

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

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

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

@@ -84,7 +84,7 @@ static int ohci_quirk_zfmicro(struct usb_hcd *hcd)
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 
 	ohci->flags |= OHCI_QUIRK_ZFMICRO;
-	ohci_dbg (ohci, "enabled Compaq ZFMicro chipset quirk\n");
+	ohci_dbg(ohci, "enabled Compaq ZFMicro chipset quirks\n");
 
 	return 0;
 }
@@ -113,11 +113,31 @@ static int ohci_quirk_toshiba_scc(struct usb_hcd *hcd)
 
 /* Check for NEC chip and apply quirk for allegedly lost interrupts.
  */
+
+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 %s, %d\n",
+			 "ohci_init", status);
+		return;
+	}
+
+	status = ohci_restart(ohci);
+	if (status != 0)
+		ohci_err(ohci, "Restarting NEC controller failed in %s, %d\n",
+			 "ohci_restart", status);
+}
+
 static int ohci_quirk_nec(struct usb_hcd *hcd)
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 
 	ohci->flags |= OHCI_QUIRK_NEC;
+	INIT_WORK(&ohci->nec_work, ohci_quirk_nec_worker);
 	ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n");
 
 	return 0;

+ 4 - 1
drivers/usb/host/ohci-ppc-of.c

@@ -134,8 +134,11 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
 	}
 
 	ohci = hcd_to_ohci(hcd);
-	if (is_bigendian)
+	if (is_bigendian) {
 		ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+		if (of_device_is_compatible(dn, "mpc5200-ohci"))
+			ohci->flags |= OHCI_QUIRK_FRAME_NO;
+	}
 
 	ohci_hcd_init(ohci);
 

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

@@ -73,6 +73,11 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
 
 	ohci = hcd_to_ohci(hcd);
 	ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
+
+#ifdef CONFIG_PPC_MPC52xx
+	/* MPC52xx doesn't need frame_no shift */
+	ohci->flags |= OHCI_QUIRK_FRAME_NO;
+#endif
 	ohci_hcd_init(ohci);
 
 	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);

+ 92 - 95
drivers/usb/host/ohci-q.c

@@ -36,29 +36,15 @@ static void urb_free_priv (struct ohci_hcd *hc, urb_priv_t *urb_priv)
  * PRECONDITION:  ohci lock held, irqs blocked.
  */
 static void
-finish_urb (struct ohci_hcd *ohci, struct urb *urb)
+finish_urb(struct ohci_hcd *ohci, struct urb *urb, int status)
 __releases(ohci->lock)
 __acquires(ohci->lock)
 {
 	// ASSERT (urb->hcpriv != 0);
 
 	urb_free_priv (ohci, urb->hcpriv);
-	urb->hcpriv = NULL;
-
-	spin_lock (&urb->lock);
-	if (likely (urb->status == -EINPROGRESS))
-		urb->status = 0;
-	/* report short control reads right even though the data TD always
-	 * has TD_R set.  (much simpler, but creates the 1-td limit.)
-	 */
-	if (unlikely (urb->transfer_flags & URB_SHORT_NOT_OK)
-			&& unlikely (usb_pipecontrol (urb->pipe))
-			&& urb->actual_length < urb->transfer_buffer_length
-			&& usb_pipein (urb->pipe)
-			&& urb->status == 0) {
-		urb->status = -EREMOTEIO;
-	}
-	spin_unlock (&urb->lock);
+	if (likely(status == -EINPROGRESS))
+		status = 0;
 
 	switch (usb_pipetype (urb->pipe)) {
 	case PIPE_ISOCHRONOUS:
@@ -70,12 +56,13 @@ __acquires(ohci->lock)
 	}
 
 #ifdef OHCI_VERBOSE_DEBUG
-	urb_print (urb, "RET", usb_pipeout (urb->pipe));
+	urb_print(urb, "RET", usb_pipeout (urb->pipe), status);
 #endif
 
 	/* urb->complete() can reenter this HCD */
+	usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb);
 	spin_unlock (&ohci->lock);
-	usb_hcd_giveback_urb (ohci_to_hcd(ohci), urb);
+	usb_hcd_giveback_urb(ohci_to_hcd(ohci), urb, status);
 	spin_lock (&ohci->lock);
 
 	/* stop periodic dma if it's not needed */
@@ -179,6 +166,10 @@ static int ed_schedule (struct ohci_hcd *ohci, struct ed *ed)
 	ed->ed_prev = NULL;
 	ed->ed_next = NULL;
 	ed->hwNextED = 0;
+	if (quirk_zfmicro(ohci)
+			&& (ed->type == PIPE_INTERRUPT)
+			&& !(ohci->eds_scheduled++))
+		mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ));
 	wmb ();
 
 	/* we care about rm_list when setting CLE/BLE in case the HC was at
@@ -708,19 +699,18 @@ static void td_submit_urb (
  * Done List handling functions
  *-------------------------------------------------------------------------*/
 
-/* calculate transfer length/status and update the urb
- * PRECONDITION:  irqsafe (only for urb->status locking)
- */
-static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
+/* calculate transfer length/status and update the urb */
+static int td_done(struct ohci_hcd *ohci, struct urb *urb, struct td *td)
 {
 	u32	tdINFO = hc32_to_cpup (ohci, &td->hwINFO);
 	int	cc = 0;
+	int	status = -EINPROGRESS;
 
 	list_del (&td->td_list);
 
 	/* ISO ... drivers see per-TD length/status */
 	if (tdINFO & TD_ISO) {
-		u16	tdPSW = ohci_hwPSW (ohci, td, 0);
+		u16	tdPSW = ohci_hwPSW(ohci, td, 0);
 		int	dlen = 0;
 
 		/* NOTE:  assumes FC in tdINFO == 0, and that
@@ -729,7 +719,7 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
 
 		cc = (tdPSW >> 12) & 0xF;
 		if (tdINFO & TD_CC)	/* hc didn't touch? */
-			return;
+			return status;
 
 		if (usb_pipeout (urb->pipe))
 			dlen = urb->iso_frame_desc [td->index].length;
@@ -762,12 +752,8 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
 		if (cc == TD_DATAUNDERRUN
 				&& !(urb->transfer_flags & URB_SHORT_NOT_OK))
 			cc = TD_CC_NOERROR;
-		if (cc != TD_CC_NOERROR && cc < 0x0E) {
-			spin_lock (&urb->lock);
-			if (urb->status == -EINPROGRESS)
-				urb->status = cc_to_error [cc];
-			spin_unlock (&urb->lock);
-		}
+		if (cc != TD_CC_NOERROR && cc < 0x0E)
+			status = cc_to_error[cc];
 
 		/* count all non-empty packets except control SETUP packet */
 		if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) {
@@ -786,14 +772,15 @@ static void td_done (struct ohci_hcd *ohci, struct urb *urb, struct td *td)
 				urb->actual_length,
 				urb->transfer_buffer_length);
 	}
+	return status;
 }
 
 /*-------------------------------------------------------------------------*/
 
-static inline struct td *
-ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
+static void ed_halted(struct ohci_hcd *ohci, struct td *td, int cc)
 {
 	struct urb		*urb = td->urb;
+	urb_priv_t		*urb_priv = urb->hcpriv;
 	struct ed		*ed = td->ed;
 	struct list_head	*tmp = td->td_list.next;
 	__hc32			toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C);
@@ -805,13 +792,12 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
 	wmb ();
 	ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H);
 
-	/* put any later tds from this urb onto the donelist, after 'td',
-	 * order won't matter here: no errors, and nothing was transferred.
-	 * also patch the ed so it looks as if those tds completed normally.
+	/* Get rid of all later tds from this urb.  We don't have
+	 * to be careful: no errors and nothing was transferred.
+	 * Also patch the ed so it looks as if those tds completed normally.
 	 */
 	while (tmp != &ed->td_list) {
 		struct td	*next;
-		__hc32		info;
 
 		next = list_entry (tmp, struct td, td_list);
 		tmp = next->td_list.next;
@@ -826,14 +812,9 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
 		 * then we need to leave the control STATUS packet queued
 		 * and clear ED_SKIP.
 		 */
-		info = next->hwINFO;
-		info |= cpu_to_hc32 (ohci, TD_DONE);
-		info &= ~cpu_to_hc32 (ohci, TD_CC);
-		next->hwINFO = info;
-
-		next->next_dl_td = rev;
-		rev = next;
 
+		list_del(&next->td_list);
+		urb_priv->td_cnt++;
 		ed->hwHeadP = next->hwNextTD | toggle;
 	}
 
@@ -859,8 +840,6 @@ ed_halted (struct ohci_hcd *ohci, struct td *td, int cc, struct td *rev)
 			hc32_to_cpu (ohci, td->hwINFO),
 			cc, cc_to_error [cc]);
 	}
-
-	return rev;
 }
 
 /* replies to the request have to be on a FIFO basis so
@@ -897,7 +876,7 @@ static struct td *dl_reverse_done_list (struct ohci_hcd *ohci)
 		 */
 		if (cc != TD_CC_NOERROR
 				&& (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H)))
-			td_rev = ed_halted (ohci, td, cc, td_rev);
+			ed_halted(ohci, td, cc);
 
 		td->next_dl_td = td_rev;
 		td_rev = td;
@@ -940,8 +919,12 @@ skip_ed:
 								TD_MASK;
 
 				/* INTR_WDH may need to clean up first */
-				if (td->td_dma != head)
-					goto skip_ed;
+				if (td->td_dma != head) {
+					if (ed == ohci->ed_to_check)
+						ohci->ed_to_check = NULL;
+					else
+						goto skip_ed;
+				}
 			}
 		}
 
@@ -974,7 +957,7 @@ rescan_this:
 			urb = td->urb;
 			urb_priv = td->urb->hcpriv;
 
-			if (urb->status == -EINPROGRESS) {
+			if (!urb->unlinked) {
 				prev = &td->hwNextTD;
 				continue;
 			}
@@ -990,7 +973,7 @@ rescan_this:
 			/* if URB is done, clean up */
 			if (urb_priv->td_cnt == urb_priv->length) {
 				modified = completed = 1;
-				finish_urb (ohci, urb);
+				finish_urb(ohci, urb, 0);
 			}
 		}
 		if (completed && !list_empty (&ed->td_list))
@@ -998,6 +981,8 @@ rescan_this:
 
 		/* ED's now officially unlinked, hc doesn't see */
 		ed->state = ED_IDLE;
+		if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
+			ohci->eds_scheduled--;
 		ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
 		ed->hwNextED = 0;
 		wmb ();
@@ -1021,7 +1006,7 @@ rescan_this:
 
 		if (ohci->ed_controltail) {
 			command |= OHCI_CLF;
-			if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+			if (quirk_zfmicro(ohci))
 				mdelay(1);
 			if (!(ohci->hc_control & OHCI_CTRL_CLE)) {
 				control |= OHCI_CTRL_CLE;
@@ -1031,7 +1016,7 @@ rescan_this:
 		}
 		if (ohci->ed_bulktail) {
 			command |= OHCI_BLF;
-			if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+			if (quirk_zfmicro(ohci))
 				mdelay(1);
 			if (!(ohci->hc_control & OHCI_CTRL_BLE)) {
 				control |= OHCI_CTRL_BLE;
@@ -1043,13 +1028,13 @@ rescan_this:
 		/* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */
 		if (control) {
 			ohci->hc_control |= control;
-			if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+			if (quirk_zfmicro(ohci))
 				mdelay(1);
 			ohci_writel (ohci, ohci->hc_control,
 					&ohci->regs->control);
 		}
 		if (command) {
-			if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+			if (quirk_zfmicro(ohci))
 				mdelay(1);
 			ohci_writel (ohci, command, &ohci->regs->cmdstatus);
 		}
@@ -1060,12 +1045,61 @@ rescan_this:
 
 /*-------------------------------------------------------------------------*/
 
+/*
+ * Used to take back a TD from the host controller. This would normally be
+ * called from within dl_done_list, however it may be called directly if the
+ * HC no longer sees the TD and it has not appeared on the donelist (after
+ * two frames).  This bug has been observed on ZF Micro systems.
+ */
+static void takeback_td(struct ohci_hcd *ohci, struct td *td)
+{
+	struct urb	*urb = td->urb;
+	urb_priv_t	*urb_priv = urb->hcpriv;
+	struct ed	*ed = td->ed;
+	int		status;
+
+	/* update URB's length and status from TD */
+	status = td_done(ohci, urb, td);
+	urb_priv->td_cnt++;
+
+	/* If all this urb's TDs are done, call complete() */
+	if (urb_priv->td_cnt == urb_priv->length)
+		finish_urb(ohci, urb, status);
+
+	/* clean schedule:  unlink EDs that are no longer busy */
+	if (list_empty(&ed->td_list)) {
+		if (ed->state == ED_OPER)
+			start_ed_unlink(ohci, ed);
+
+	/* ... reenabling halted EDs only after fault cleanup */
+	} else if ((ed->hwINFO & cpu_to_hc32(ohci, ED_SKIP | ED_DEQUEUE))
+			== cpu_to_hc32(ohci, ED_SKIP)) {
+		td = list_entry(ed->td_list.next, struct td, td_list);
+		if (!(td->hwINFO & cpu_to_hc32(ohci, TD_DONE))) {
+			ed->hwINFO &= ~cpu_to_hc32(ohci, ED_SKIP);
+			/* ... hc may need waking-up */
+			switch (ed->type) {
+			case PIPE_CONTROL:
+				ohci_writel(ohci, OHCI_CLF,
+						&ohci->regs->cmdstatus);
+				break;
+			case PIPE_BULK:
+				ohci_writel(ohci, OHCI_BLF,
+						&ohci->regs->cmdstatus);
+				break;
+			}
+		}
+	}
+}
+
 /*
  * Process normal completions (error or success) and clean the schedules.
  *
  * This is the main path for handing urbs back to drivers.  The only other
- * path is finish_unlinks(), which unlinks URBs using ed_rm_list, instead of
- * scanning the (re-reversed) donelist as this does.
+ * normal path is finish_unlinks(), which unlinks URBs using ed_rm_list,
+ * instead of scanning the (re-reversed) donelist as this does.  There's
+ * an abnormal path too, handling a quirk in some Compaq silicon:  URBs
+ * with TDs that appear to be orphaned are directly reclaimed.
  */
 static void
 dl_done_list (struct ohci_hcd *ohci)
@@ -1074,44 +1108,7 @@ dl_done_list (struct ohci_hcd *ohci)
 
 	while (td) {
 		struct td	*td_next = td->next_dl_td;
-		struct urb	*urb = td->urb;
-		urb_priv_t	*urb_priv = urb->hcpriv;
-		struct ed	*ed = td->ed;
-
-		/* update URB's length and status from TD */
-		td_done (ohci, urb, td);
-		urb_priv->td_cnt++;
-
-		/* If all this urb's TDs are done, call complete() */
-		if (urb_priv->td_cnt == urb_priv->length)
-			finish_urb (ohci, urb);
-
-		/* clean schedule:  unlink EDs that are no longer busy */
-		if (list_empty (&ed->td_list)) {
-			if (ed->state == ED_OPER)
-				start_ed_unlink (ohci, ed);
-
-		/* ... reenabling halted EDs only after fault cleanup */
-		} else if ((ed->hwINFO & cpu_to_hc32 (ohci,
-						ED_SKIP | ED_DEQUEUE))
-					== cpu_to_hc32 (ohci, ED_SKIP)) {
-			td = list_entry (ed->td_list.next, struct td, td_list);
-			if (!(td->hwINFO & cpu_to_hc32 (ohci, TD_DONE))) {
-				ed->hwINFO &= ~cpu_to_hc32 (ohci, ED_SKIP);
-				/* ... hc may need waking-up */
-				switch (ed->type) {
-				case PIPE_CONTROL:
-					ohci_writel (ohci, OHCI_CLF,
-						&ohci->regs->cmdstatus);
-					break;
-				case PIPE_BULK:
-					ohci_writel (ohci, OHCI_BLF,
-						&ohci->regs->cmdstatus);
-					break;
-				}
-			}
-		}
-
+		takeback_td(ohci, td);
 		td = td_next;
 	}
 }

+ 247 - 0
drivers/usb/host/ohci-ssb.c

@@ -0,0 +1,247 @@
+/*
+ * Sonics Silicon Backplane
+ * Broadcom USB-core OHCI driver
+ *
+ * Copyright 2007 Michael Buesch <mb@bu3sch.de>
+ *
+ * Derived from the OHCI-PCI driver
+ * Copyright 1999 Roman Weissgaerber
+ * Copyright 2000-2002 David Brownell
+ * Copyright 1999 Linus Torvalds
+ * Copyright 1999 Gregory P. Smith
+ *
+ * Derived from the USBcore related parts of Broadcom-SB
+ * Copyright 2005 Broadcom Corporation
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+#include <linux/ssb/ssb.h>
+
+
+#define SSB_OHCI_TMSLOW_HOSTMODE	(1 << 29)
+
+struct ssb_ohci_device {
+	struct ohci_hcd ohci; /* _must_ be at the beginning. */
+
+	u32 enable_flags;
+};
+
+static inline
+struct ssb_ohci_device *hcd_to_ssb_ohci(struct usb_hcd *hcd)
+{
+	return (struct ssb_ohci_device *)(hcd->hcd_priv);
+}
+
+
+static int ssb_ohci_reset(struct usb_hcd *hcd)
+{
+	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+	struct ohci_hcd *ohci = &ohcidev->ohci;
+	int err;
+
+	ohci_hcd_init(ohci);
+	err = ohci_init(ohci);
+
+	return err;
+}
+
+static int ssb_ohci_start(struct usb_hcd *hcd)
+{
+	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+	struct ohci_hcd *ohci = &ohcidev->ohci;
+	int err;
+
+	err = ohci_run(ohci);
+	if (err < 0) {
+		ohci_err(ohci, "can't start\n");
+		ohci_stop(hcd);
+	}
+
+	return err;
+}
+
+#ifdef CONFIG_PM
+static int ssb_ohci_hcd_suspend(struct usb_hcd *hcd, pm_message_t message)
+{
+	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+	struct ohci_hcd *ohci = &ohcidev->ohci;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ohci->lock, flags);
+
+	ohci_writel(ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
+	ohci_readl(ohci, &ohci->regs->intrdisable); /* commit write */
+
+	/* make sure snapshot being resumed re-enumerates everything */
+	if (message.event == PM_EVENT_PRETHAW)
+		ohci_usb_reset(ohci);
+
+	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+	spin_unlock_irqrestore(&ohci->lock, flags);
+	return 0;
+}
+
+static int ssb_ohci_hcd_resume(struct usb_hcd *hcd)
+{
+	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+	usb_hcd_resume_root_hub(hcd);
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+static const struct hc_driver ssb_ohci_hc_driver = {
+	.description		= "ssb-usb-ohci",
+	.product_desc		= "SSB OHCI Controller",
+	.hcd_priv_size		= sizeof(struct ssb_ohci_device),
+
+	.irq			= ohci_irq,
+	.flags			= HCD_MEMORY | HCD_USB11,
+
+	.reset			= ssb_ohci_reset,
+	.start			= ssb_ohci_start,
+	.stop			= ohci_stop,
+	.shutdown		= ohci_shutdown,
+
+#ifdef CONFIG_PM
+	.suspend		= ssb_ohci_hcd_suspend,
+	.resume			= ssb_ohci_hcd_resume,
+#endif
+
+	.urb_enqueue		= ohci_urb_enqueue,
+	.urb_dequeue		= ohci_urb_dequeue,
+	.endpoint_disable	= ohci_endpoint_disable,
+
+	.get_frame_number	= ohci_get_frame,
+
+	.hub_status_data	= ohci_hub_status_data,
+	.hub_control		= ohci_hub_control,
+	.hub_irq_enable		= ohci_rhsc_enable,
+	.bus_suspend		= ohci_bus_suspend,
+	.bus_resume		= ohci_bus_resume,
+
+	.start_port_reset	= ohci_start_port_reset,
+};
+
+static void ssb_ohci_detach(struct ssb_device *dev)
+{
+	struct usb_hcd *hcd = ssb_get_drvdata(dev);
+
+	usb_remove_hcd(hcd);
+	iounmap(hcd->regs);
+	usb_put_hcd(hcd);
+	ssb_device_disable(dev, 0);
+}
+
+static int ssb_ohci_attach(struct ssb_device *dev)
+{
+	struct ssb_ohci_device *ohcidev;
+	struct usb_hcd *hcd;
+	int err = -ENOMEM;
+	u32 tmp, flags = 0;
+
+	if (dev->id.coreid == SSB_DEV_USB11_HOSTDEV)
+		flags |= SSB_OHCI_TMSLOW_HOSTMODE;
+
+	ssb_device_enable(dev, flags);
+
+	hcd = usb_create_hcd(&ssb_ohci_hc_driver, dev->dev,
+			dev->dev->bus_id);
+	if (!hcd)
+		goto err_dev_disable;
+	ohcidev = hcd_to_ssb_ohci(hcd);
+	ohcidev->enable_flags = flags;
+
+	tmp = ssb_read32(dev, SSB_ADMATCH0);
+	hcd->rsrc_start = ssb_admatch_base(tmp);
+	hcd->rsrc_len = ssb_admatch_size(tmp);
+	hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs)
+		goto err_put_hcd;
+	err = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
+	if (err)
+		goto err_iounmap;
+
+	ssb_set_drvdata(dev, hcd);
+
+	return err;
+
+err_iounmap:
+	iounmap(hcd->regs);
+err_put_hcd:
+	usb_put_hcd(hcd);
+err_dev_disable:
+	ssb_device_disable(dev, flags);
+	return err;
+}
+
+static int ssb_ohci_probe(struct ssb_device *dev,
+		const struct ssb_device_id *id)
+{
+	int err;
+	u16 chipid_top;
+
+	/* USBcores are only connected on embedded devices. */
+	chipid_top = (dev->bus->chip_id & 0xFF00);
+	if (chipid_top != 0x4700 && chipid_top != 0x5300)
+		return -ENODEV;
+
+	/* TODO: Probably need checks here; is the core connected? */
+
+	if (usb_disabled())
+		return -ENODEV;
+
+	/* We currently always attach SSB_DEV_USB11_HOSTDEV
+	 * as HOST OHCI. If we want to attach it as Client device,
+	 * we must branch here and call into the (yet to
+	 * be written) Client mode driver. Same for remove(). */
+
+	err = ssb_ohci_attach(dev);
+
+	return err;
+}
+
+static void ssb_ohci_remove(struct ssb_device *dev)
+{
+	ssb_ohci_detach(dev);
+}
+
+#ifdef CONFIG_PM
+
+static int ssb_ohci_suspend(struct ssb_device *dev, pm_message_t state)
+{
+	ssb_device_disable(dev, 0);
+
+	return 0;
+}
+
+static int ssb_ohci_resume(struct ssb_device *dev)
+{
+	struct usb_hcd *hcd = ssb_get_drvdata(dev);
+	struct ssb_ohci_device *ohcidev = hcd_to_ssb_ohci(hcd);
+
+	ssb_device_enable(dev, ohcidev->enable_flags);
+
+	return 0;
+}
+
+#else /* !CONFIG_PM */
+#define ssb_ohci_suspend	NULL
+#define ssb_ohci_resume	NULL
+#endif /* CONFIG_PM */
+
+static const struct ssb_device_id ssb_ohci_table[] = {
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
+	SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
+	SSB_DEVTABLE_END
+};
+MODULE_DEVICE_TABLE(ssb, ssb_ohci_table);
+
+static struct ssb_driver ssb_ohci_driver = {
+	.name		= KBUILD_MODNAME,
+	.id_table	= ssb_ohci_table,
+	.probe		= ssb_ohci_probe,
+	.remove		= ssb_ohci_remove,
+	.suspend	= ssb_ohci_suspend,
+	.resume		= ssb_ohci_resume,
+};

+ 32 - 7
drivers/usb/host/ohci.h

@@ -398,11 +398,38 @@ struct ohci_hcd {
 #define	OHCI_QUIRK_BE_MMIO	0x10			/* BE registers */
 #define	OHCI_QUIRK_ZFMICRO	0x20			/* Compaq ZFMicro chipset*/
 #define	OHCI_QUIRK_NEC		0x40			/* lost interrupts */
+#define	OHCI_QUIRK_FRAME_NO	0x80			/* no big endian frame_no shift */
 	// there are also chip quirks/bugs in init logic
 
 	struct work_struct	nec_work;	/* Worker for NEC quirk */
+
+	/* Needed for ZF Micro quirk */
+	struct timer_list	unlink_watchdog;
+	unsigned		eds_scheduled;
+	struct ed		*ed_to_check;
+	unsigned		zf_delay;
 };
 
+#ifdef CONFIG_PCI
+static inline int quirk_nec(struct ohci_hcd *ohci)
+{
+	return ohci->flags & OHCI_QUIRK_NEC;
+}
+static inline int quirk_zfmicro(struct ohci_hcd *ohci)
+{
+	return ohci->flags & OHCI_QUIRK_ZFMICRO;
+}
+#else
+static inline int quirk_nec(struct ohci_hcd *ohci)
+{
+	return 0;
+}
+static inline int quirk_zfmicro(struct ohci_hcd *ohci)
+{
+	return 0;
+}
+#endif
+
 /* convert between an hcd pointer and the corresponding ohci_hcd */
 static inline struct ohci_hcd *hcd_to_ohci (struct usb_hcd *hcd)
 {
@@ -607,15 +634,12 @@ static inline u32 hc32_to_cpup (const struct ohci_hcd *ohci, const __hc32 *x)
 /* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
  * hardware handles 16 bit reads.  That creates a different confusion on
  * some big-endian SOC implementations.  Same thing happens with PSW access.
- *
- * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over
- * to arch/powerpc
  */
 
-#ifdef CONFIG_STB03xxx
-#define OHCI_BE_FRAME_NO_SHIFT	16
+#ifdef CONFIG_PPC_MPC52xx
+#define big_endian_frame_no_quirk(ohci)	(ohci->flags & OHCI_QUIRK_FRAME_NO)
 #else
-#define OHCI_BE_FRAME_NO_SHIFT	0
+#define big_endian_frame_no_quirk(ohci)	0
 #endif
 
 static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
@@ -623,7 +647,8 @@ static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
 	u32 tmp;
 	if (big_endian_desc(ohci)) {
 		tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
-		tmp >>= OHCI_BE_FRAME_NO_SHIFT;
+		if (!big_endian_frame_no_quirk(ohci))
+			tmp >>= 16;
 	} else
 		tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no);
 

+ 86 - 86
drivers/usb/host/r8a66597-hcd.c

@@ -782,10 +782,12 @@ static void force_dequeue(struct r8a66597 *r8a66597, u16 pipenum, u16 address)
 		kfree(td);
 
 		if (urb) {
-			urb->status = -ENODEV;
-			urb->hcpriv = NULL;
+			usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597),
+					urb);
+
 			spin_unlock(&r8a66597->lock);
-			usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb);
+			usb_hcd_giveback_urb(r8a66597_to_hcd(r8a66597), urb,
+					-ENODEV);
 			spin_lock(&r8a66597->lock);
 		}
 		break;
@@ -832,7 +834,7 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,
 	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.maxpacket = le16_to_cpu(ep->wMaxPacketSize);
 	info.type = get_r8a66597_type(ep->bmAttributes
 				      & USB_ENDPOINT_XFERTYPE_MASK);
 	info.bufnum = get_bufnum(info.pipenum);
@@ -923,7 +925,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597,
 	r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
 
 	for (i = 0; i < 4; i++) {
-		r8a66597_write(r8a66597, p[i], setup_addr);
+		r8a66597_write(r8a66597, cpu_to_le16(p[i]), setup_addr);
 		setup_addr += 2;
 	}
 	r8a66597_write(r8a66597, SUREQ, DCPCTR);
@@ -1032,6 +1034,15 @@ static void prepare_status_packet(struct r8a66597 *r8a66597,
 	pipe_start(r8a66597, td->pipe);
 }
 
+static int is_set_address(unsigned char *setup_packet)
+{
+	if (((setup_packet[0] & USB_TYPE_MASK) == USB_TYPE_STANDARD) &&
+			setup_packet[1] == USB_REQ_SET_ADDRESS)
+		return 1;
+	else
+		return 0;
+}
+
 /* this function must be called with interrupt disabled */
 static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
 {
@@ -1039,7 +1050,7 @@ static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
 
 	switch (td->type) {
 	case USB_PID_SETUP:
-		if (td->urb->setup_packet[1] == USB_REQ_SET_ADDRESS) {
+		if (is_set_address(td->urb->setup_packet)) {
 			td->set_address = 1;
 			td->urb->setup_packet[2] = alloc_usb_address(r8a66597,
 								     td->urb);
@@ -1106,8 +1117,9 @@ static void set_td_timer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
 }
 
 /* this function must be called with interrupt disabled */
-static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
-		 u16 pipenum, struct urb *urb)
+static void finish_request(struct r8a66597 *r8a66597, struct r8a66597_td *td,
+		u16 pipenum, struct urb *urb, int status)
+__releases(r8a66597->lock) __acquires(r8a66597->lock)
 {
 	int restart = 0;
 	struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
@@ -1115,7 +1127,7 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
 	r8a66597->timeout_map &= ~(1 << pipenum);
 
 	if (likely(td)) {
-		if (td->set_address && urb->status != 0)
+		if (td->set_address && (status != 0 || urb->unlinked))
 			r8a66597->address_map &= ~(1 << urb->setup_packet[2]);
 
 		pipe_toggle_save(r8a66597, td->pipe, urb);
@@ -1130,9 +1142,9 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *td,
 		if (usb_pipeisoc(urb->pipe))
 			urb->start_frame = r8a66597_get_frame(hcd);
 
-		urb->hcpriv = NULL;
+		usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597), urb);
 		spin_unlock(&r8a66597->lock);
-		usb_hcd_giveback_urb(hcd, urb);
+		usb_hcd_giveback_urb(hcd, urb, status);
 		spin_lock(&r8a66597->lock);
 	}
 
@@ -1146,14 +1158,6 @@ static void done(struct r8a66597 *r8a66597, struct r8a66597_td *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;
@@ -1162,6 +1166,7 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
 	struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
 	struct urb *urb;
 	int finish = 0;
+	int status = 0;
 
 	if (unlikely(!td))
 		return;
@@ -1170,17 +1175,15 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
 	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);
+		finish_request(r8a66597, td, pipenum, td->urb, -EPIPE);
 		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);
@@ -1189,29 +1192,31 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
 		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);
+	bufsize = min(urb_len, (int) td->maxpacket);
+	if (rcv_len <= bufsize) {
+		size = rcv_len;
+	} else {
+		size = bufsize;
+		status = -EOVERFLOW;
+		finish = 1;
+	}
 
 	/* update parameters */
 	urb->actual_length += size;
 	if (rcv_len == 0)
 		td->zero_packet = 1;
-	if ((size % td->maxpacket) > 0) {
+	if (rcv_len < bufsize) {
 		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;
+		urb->iso_frame_desc[td->iso_cnt].status = status;
 		td->iso_cnt++;
+		finish = 0;
 	}
 
 	/* check transfer finish */
-	if (check_transfer_finish(td, urb)) {
+	if (finish || check_transfer_finish(td, urb)) {
 		pipe_stop(r8a66597, td->pipe);
 		pipe_irq_disable(r8a66597, pipenum);
 		finish = 1;
@@ -1226,11 +1231,8 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
 					   buf, size);
 	}
 
-	if (finish && pipenum != 0) {
-		if (td->urb->status == -EINPROGRESS)
-			td->urb->status = 0;
-		finish_request(r8a66597, td, pipenum, urb);
-	}
+	if (finish && pipenum != 0)
+		finish_request(r8a66597, td, pipenum, urb, status);
 }
 
 static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
@@ -1248,11 +1250,10 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
 	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);
+		finish_request(r8a66597, td, pipenum, urb, -EPIPE);
 		return;
 	}
 
@@ -1297,7 +1298,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
 }
 
 
-static void check_next_phase(struct r8a66597 *r8a66597)
+static void check_next_phase(struct r8a66597 *r8a66597, int status)
 {
 	struct r8a66597_td *td = r8a66597_get_td(r8a66597, 0);
 	struct urb *urb;
@@ -1310,49 +1311,41 @@ static void check_next_phase(struct r8a66597 *r8a66597)
 	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) {
+		if (urb->transfer_buffer_length == urb->actual_length)
 			td->type = USB_PID_ACK;
-			urb->status = 0;
-		} else if (usb_pipeout(urb->pipe))
+		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);
+	if (finish || status != 0 || urb->unlinked)
+		finish_request(r8a66597, td, 0, urb, status);
 	else
 		start_transfer(r8a66597, td);
 }
 
-static void set_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
+static int get_urb_error(struct r8a66597 *r8a66597, u16 pipenum)
 {
 	struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
 
-	if (td && td->urb) {
+	if (td) {
 		u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID;
 
 		if (pid == PID_NAK)
-			td->urb->status = -ECONNRESET;
+			return -ECONNRESET;
 		else
-			td->urb->status = -EPIPE;
+			return -EPIPE;
 	}
+	return 0;
 }
 
 static void irq_pipe_ready(struct r8a66597 *r8a66597)
@@ -1371,7 +1364,7 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597)
 			packet_read(r8a66597, 0);
 		else
 			pipe_irq_disable(r8a66597, 0);
-		check_next_phase(r8a66597);
+		check_next_phase(r8a66597, 0);
 	}
 
 	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1405,7 +1398,7 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597)
 		td = r8a66597_get_td(r8a66597, 0);
 		if (td && td->type != USB_PID_OUT)
 			disable_irq_empty(r8a66597, 0);
-		check_next_phase(r8a66597);
+		check_next_phase(r8a66597, 0);
 	}
 
 	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1420,9 +1413,8 @@ static void irq_pipe_empty(struct r8a66597 *r8a66597)
 			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);
+				finish_request(r8a66597, td, pipenum, td->urb,
+						0);
 			}
 		}
 	}
@@ -1433,15 +1425,16 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
 	u16 check;
 	u16 pipenum;
 	u16 mask;
+	int status;
 
 	mask = r8a66597_read(r8a66597, NRDYSTS)
 	       & r8a66597_read(r8a66597, NRDYENB);
 	r8a66597_write(r8a66597, ~mask, NRDYSTS);
 	if (mask & NRDY0) {
 		cfifo_change(r8a66597, 0);
-		set_urb_error(r8a66597, 0);
+		status = get_urb_error(r8a66597, 0);
 		pipe_irq_disable(r8a66597, 0);
-		check_next_phase(r8a66597);
+		check_next_phase(r8a66597, status);
 	}
 
 	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1452,10 +1445,10 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
 			if (unlikely(!td))
 				continue;
 
-			set_urb_error(r8a66597, pipenum);
+			status = get_urb_error(r8a66597, pipenum);
 			pipe_irq_disable(r8a66597, pipenum);
 			pipe_stop(r8a66597, td->pipe);
-			finish_request(r8a66597, td, pipenum, td->urb);
+			finish_request(r8a66597, td, pipenum, td->urb, status);
 		}
 	}
 }
@@ -1475,6 +1468,7 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
 	u16 intsts0, intsts1, intsts2;
 	u16 intenb0, intenb1, intenb2;
 	u16 mask0, mask1, mask2;
+	int status;
 
 	spin_lock(&r8a66597->lock);
 
@@ -1518,12 +1512,12 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
 		}
 		if (mask1 & SIGN) {
 			r8a66597_write(r8a66597, ~SIGN, INTSTS1);
-			set_urb_error(r8a66597, 0);
-			check_next_phase(r8a66597);
+			status = get_urb_error(r8a66597, 0);
+			check_next_phase(r8a66597, status);
 		}
 		if (mask1 & SACK) {
 			r8a66597_write(r8a66597, ~SACK, INTSTS1);
-			check_next_phase(r8a66597);
+			check_next_phase(r8a66597, 0);
 		}
 	}
 	if (mask0) {
@@ -1722,21 +1716,25 @@ static struct r8a66597_td *r8a66597_make_td(struct r8a66597 *r8a66597,
 }
 
 static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
-				struct usb_host_endpoint *hep,
 				struct urb *urb,
 				gfp_t mem_flags)
 {
+	struct usb_host_endpoint *hep = urb->ep;
 	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
 	struct r8a66597_td *td = NULL;
-	int ret = 0, request = 0;
+	int ret, request = 0;
 	unsigned long flags;
 
 	spin_lock_irqsave(&r8a66597->lock, flags);
 	if (!get_urb_to_r8a66597_dev(r8a66597, urb)) {
 		ret = -ENODEV;
-		goto error;
+		goto error_not_linked;
 	}
 
+	ret = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (ret)
+		goto error_not_linked;
+
 	if (!hep->hcpriv) {
 		hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe),
 				GFP_ATOMIC);
@@ -1761,15 +1759,7 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
 	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);
@@ -1781,26 +1771,36 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
 		set_td_timer(r8a66597, td);
 
 error:
+	if (ret)
+		usb_hcd_unlink_urb_from_ep(hcd, urb);
+error_not_linked:
 	spin_unlock_irqrestore(&r8a66597->lock, flags);
 	return ret;
 }
 
-static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int r8a66597_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+		int status)
 {
 	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
 	struct r8a66597_td *td;
 	unsigned long flags;
+	int rc;
 
 	spin_lock_irqsave(&r8a66597->lock, flags);
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
+		goto done;
+
 	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);
+		finish_request(r8a66597, td, td->pipenum, urb, status);
 	}
+ done:
 	spin_unlock_irqrestore(&r8a66597->lock, flags);
-	return 0;
+	return rc;
 }
 
 static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
@@ -1830,7 +1830,7 @@ static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
 	td = r8a66597_get_td(r8a66597, pipenum);
 	if (td)
 		urb = td->urb;
-	done(r8a66597, td, pipenum, urb);
+	finish_request(r8a66597, td, pipenum, urb, -ESHUTDOWN);
 	kfree(hep->hcpriv);
 	hep->hcpriv = NULL;
 	spin_unlock_irqrestore(&r8a66597->lock, flags);
@@ -2027,7 +2027,7 @@ static int r8a66597_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 	case GetPortStatus:
 		if (wIndex > R8A66597_MAX_ROOT_HUB)
 			goto error;
-		*(u32 *)buf = rh->port;
+		*(u32 *)buf = cpu_to_le32(rh->port);
 		break;
 	case SetPortFeature:
 		if (wIndex > R8A66597_MAX_ROOT_HUB)
@@ -2126,8 +2126,8 @@ static int __init_or_module r8a66597_remove(struct platform_device *pdev)
 	struct usb_hcd		*hcd = r8a66597_to_hcd(r8a66597);
 
 	del_timer_sync(&r8a66597->rh_timer);
-	iounmap((void *)r8a66597->reg);
 	usb_remove_hcd(hcd);
+	iounmap((void *)r8a66597->reg);
 	usb_put_hcd(hcd);
 	return 0;
 }

+ 27 - 47
drivers/usb/host/sl811-hcd.c

@@ -435,14 +435,9 @@ static void finish_request(
 	if (usb_pipecontrol(urb->pipe))
 		ep->nextpid = USB_PID_SETUP;
 
-	spin_lock(&urb->lock);
-	if (urb->status == -EINPROGRESS)
-		urb->status = status;
-	urb->hcpriv = NULL;
-	spin_unlock(&urb->lock);
-
+	usb_hcd_unlink_urb_from_ep(sl811_to_hcd(sl811), urb);
 	spin_unlock(&sl811->lock);
-	usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb);
+	usb_hcd_giveback_urb(sl811_to_hcd(sl811), urb, status);
 	spin_lock(&sl811->lock);
 
 	/* leave active endpoints in the schedule */
@@ -538,35 +533,21 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank)
 						bank + SL11H_XFERCNTREG);
 			if (len > ep->length) {
 				len = ep->length;
-				urb->status = -EOVERFLOW;
+				urbstat = -EOVERFLOW;
 			}
 			urb->actual_length += len;
 			sl811_read_buf(sl811, SL811HS_PACKET_BUF(bank == 0),
 					buf, len);
 			usb_dotoggle(udev, ep->epnum, 0);
-			if (urb->actual_length == urb->transfer_buffer_length)
-				urbstat = 0;
-			else if (len < ep->maxpacket) {
-				if (urb->transfer_flags & URB_SHORT_NOT_OK)
-					urbstat = -EREMOTEIO;
+			if (urbstat == -EINPROGRESS &&
+					(len < ep->maxpacket ||
+						urb->actual_length ==
+						urb->transfer_buffer_length)) {
+				if (usb_pipecontrol(urb->pipe))
+					ep->nextpid = USB_PID_ACK;
 				else
 					urbstat = 0;
 			}
-			if (usb_pipecontrol(urb->pipe)
-					&& (urbstat == -EREMOTEIO
-						|| urbstat == 0)) {
-
-				/* NOTE if the status stage STALLs (why?),
-				 * this reports the wrong urb status.
-				 */
-				spin_lock(&urb->lock);
-				if (urb->status == -EINPROGRESS)
-					urb->status = urbstat;
-				spin_unlock(&urb->lock);
-
-				urb = NULL;
-				ep->nextpid = USB_PID_ACK;
-			}
 			break;
 		case USB_PID_SETUP:
 			// PACKET("...ACK/setup_%02x qh%p\n", bank, ep);
@@ -605,7 +586,7 @@ done(struct sl811 *sl811, struct sl811h_ep *ep, u8 bank)
 				bank, status, ep, urbstat);
 	}
 
-	if (urb && (urbstat != -EINPROGRESS || urb->status != -EINPROGRESS))
+	if (urbstat != -EINPROGRESS || urb->unlinked)
 		finish_request(sl811, ep, urb, urbstat);
 }
 
@@ -807,7 +788,6 @@ static int balance(struct sl811 *sl811, u16 period, u16 load)
 
 static int sl811h_urb_enqueue(
 	struct usb_hcd		*hcd,
-	struct usb_host_endpoint *hep,
 	struct urb		*urb,
 	gfp_t			mem_flags
 ) {
@@ -820,7 +800,8 @@ static int sl811h_urb_enqueue(
 	struct sl811h_ep	*ep = NULL;
 	unsigned long		flags;
 	int			i;
-	int			retval = 0;
+	int			retval;
+	struct usb_host_endpoint	*hep = urb->ep;
 
 #ifdef	DISABLE_ISO
 	if (type == PIPE_ISOCHRONOUS)
@@ -838,7 +819,12 @@ static int sl811h_urb_enqueue(
 			|| !HC_IS_RUNNING(hcd->state)) {
 		retval = -ENODEV;
 		kfree(ep);
-		goto fail;
+		goto fail_not_linked;
+	}
+	retval = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (retval) {
+		kfree(ep);
+		goto fail_not_linked;
 	}
 
 	if (hep->hcpriv) {
@@ -951,37 +937,31 @@ static int sl811h_urb_enqueue(
 		sofirq_on(sl811);
 	}
 
-	/* in case of unlink-during-submit */
-	spin_lock(&urb->lock);
-	if (urb->status != -EINPROGRESS) {
-		spin_unlock(&urb->lock);
-		finish_request(sl811, ep, urb, 0);
-		retval = 0;
-		goto fail;
-	}
 	urb->hcpriv = hep;
-	spin_unlock(&urb->lock);
-
 	start_transfer(sl811);
 	sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
 fail:
+	if (retval)
+		usb_hcd_unlink_urb_from_ep(hcd, urb);
+fail_not_linked:
 	spin_unlock_irqrestore(&sl811->lock, flags);
 	return retval;
 }
 
-static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	struct sl811		*sl811 = hcd_to_sl811(hcd);
 	struct usb_host_endpoint *hep;
 	unsigned long		flags;
 	struct sl811h_ep	*ep;
-	int			retval = 0;
+	int			retval;
 
 	spin_lock_irqsave(&sl811->lock, flags);
-	hep = urb->hcpriv;
-	if (!hep)
+	retval = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (retval)
 		goto fail;
 
+	hep = urb->hcpriv;
 	ep = hep->hcpriv;
 	if (ep) {
 		/* finish right away if this urb can't be active ...
@@ -1029,8 +1009,8 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
 			VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
 				(sl811->active_a == ep) ? "A" : "B");
 	} else
-fail:
 		retval = -EINVAL;
+ fail:
 	spin_unlock_irqrestore(&sl811->lock, flags);
 	return retval;
 }

+ 215 - 155
drivers/usb/host/u132-hcd.c

@@ -51,7 +51,6 @@
 #include <linux/usb.h>
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
-#include <linux/pci_ids.h>
 #include <linux/mutex.h>
 #include <asm/io.h>
 #include <asm/irq.h>
@@ -184,7 +183,7 @@ struct u132_ring {
 struct u132 {
         struct kref kref;
         struct list_head u132_list;
-        struct semaphore sw_lock;
+        struct mutex sw_lock;
         struct semaphore scheduler_lock;
         struct u132_platform_data *board;
         struct platform_device *platform_dev;
@@ -493,20 +492,20 @@ static void u132_hcd_monitor_work(struct work_struct *work)
                 return;
         } else {
                 int retval;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 retval = read_roothub_info(u132);
                 if (retval) {
                         struct usb_hcd *hcd = u132_to_hcd(u132);
                         u132_disable(u132);
                         u132->going = 1;
-                        up(&u132->sw_lock);
+                        mutex_unlock(&u132->sw_lock);
                         usb_hc_died(hcd);
                         ftdi_elan_gone_away(u132->platform_dev);
                         u132_monitor_put_kref(u132);
                         return;
                 } else {
                         u132_monitor_requeue_work(u132, 500);
-                        up(&u132->sw_lock);
+                        mutex_unlock(&u132->sw_lock);
                         return;
                 }
         }
@@ -519,9 +518,8 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
         unsigned long irqs;
         struct usb_hcd *hcd = u132_to_hcd(u132);
         urb->error_count = 0;
-        urb->status = status;
-        urb->hcpriv = NULL;
         spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
         endp->queue_next += 1;
         if (ENDP_QUEUE_SIZE > --endp->queue_size) {
                 endp->active = 0;
@@ -543,7 +541,7 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
         u132_ring_queue_work(u132, ring, 0);
         up(&u132->scheduler_lock);
         u132_endp_put_kref(u132, endp);
-        usb_hcd_giveback_urb(hcd, urb);
+	usb_hcd_giveback_urb(hcd, urb, status);
         return;
 }
 
@@ -559,9 +557,8 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
         unsigned long irqs;
         struct usb_hcd *hcd = u132_to_hcd(u132);
         urb->error_count = 0;
-        urb->status = status;
-        urb->hcpriv = NULL;
         spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
         endp->queue_next += 1;
         if (ENDP_QUEUE_SIZE > --endp->queue_size) {
                 endp->active = 0;
@@ -576,7 +573,7 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
                 endp->active = 0;
                 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                 kfree(urbq);
-        } usb_hcd_giveback_urb(hcd, urb);
+	} usb_hcd_giveback_urb(hcd, urb, status);
         return;
 }
 
@@ -646,12 +643,12 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer + urb->actual_length;
                 u8 *b = buf;
@@ -717,10 +714,10 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -745,12 +742,12 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 urb->actual_length += len;
                 endp->toggle_bits = toggle_bits;
@@ -769,10 +766,10 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -798,12 +795,12 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer + urb->actual_length;
                 u8 *b = buf;
@@ -872,10 +869,10 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -899,20 +896,20 @@ static void u132_hcd_configure_empty_sent(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -937,12 +934,12 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer;
                 u8 *b = buf;
@@ -981,10 +978,10 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1008,20 +1005,20 @@ static void u132_hcd_configure_empty_recv(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1046,12 +1043,12 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 if (usb_pipein(urb->pipe)) {
                         int retval;
                         struct u132_ring *ring = endp->ring;
@@ -1078,10 +1075,10 @@ static void u132_hcd_configure_setup_sent(void *data, struct urb *urb, u8 *buf,
                         return;
                 }
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1107,22 +1104,22 @@ static void u132_hcd_enumeration_empty_recv(void *data, struct urb *urb,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 u132->addr[0].address = 0;
                 endp->usb_addr = udev->usb_addr;
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1146,12 +1143,12 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 int retval;
                 struct u132_ring *ring = endp->ring;
                 up(&u132->scheduler_lock);
@@ -1163,10 +1160,10 @@ static void u132_hcd_enumeration_address_sent(void *data, struct urb *urb,
                         u132_hcd_giveback_urb(u132, endp, urb, retval);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1190,20 +1187,20 @@ static void u132_hcd_initial_empty_sent(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1228,12 +1225,12 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 int retval;
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer;
@@ -1252,10 +1249,10 @@ static void u132_hcd_initial_input_recv(void *data, struct urb *urb, u8 *buf,
                         u132_hcd_giveback_urb(u132, endp, urb, retval);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1280,12 +1277,12 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 int retval;
                 struct u132_ring *ring = endp->ring;
                 up(&u132->scheduler_lock);
@@ -1297,10 +1294,10 @@ static void u132_hcd_initial_setup_sent(void *data, struct urb *urb, u8 *buf,
                         u132_hcd_giveback_urb(u132, endp, urb, retval);
                 return;
         } else {
-                dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p statu"
-                        "s=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "CALLBACK called urb=%p "
+				"unlinked=%d\n", urb, urb->unlinked);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
         }
 }
@@ -1805,10 +1802,10 @@ static void u132_hcd_stop(struct usb_hcd *hcd)
                 dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
                         "ed\n", hcd);
         } else {
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 msleep(100);
                 u132_power(u132, 0);
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
         }
 }
 
@@ -1830,7 +1827,7 @@ static int u132_hcd_start(struct usb_hcd *hcd)
                         (pdev->dev.platform_data))->vendor;
                 u16 device = ((struct u132_platform_data *)
                         (pdev->dev.platform_data))->device;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 msleep(10);
                 if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
                         u132->flags = OHCI_QUIRK_AMD756;
@@ -1845,7 +1842,7 @@ static int u132_hcd_start(struct usb_hcd *hcd)
                         u132->going = 1;
                 }
                 msleep(100);
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
                 return retval;
         } else {
                 dev_err(&u132->platform_dev->dev, "platform_device missing\n");
@@ -1865,32 +1862,44 @@ static int u132_hcd_reset(struct usb_hcd *hcd)
                 return -ESHUTDOWN;
         } else {
                 int retval;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 retval = u132_init(u132);
                 if (retval) {
                         u132_disable(u132);
                         u132->going = 1;
                 }
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
                 return retval;
         }
 }
 
 static int create_endpoint_and_queue_int(struct u132 *u132,
-        struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
+	struct u132_udev *udev, struct urb *urb,
         struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
         gfp_t mem_flags)
 {
         struct u132_ring *ring;
         unsigned long irqs;
-        u8 endp_number = ++u132->num_endpoints;
-        struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
-                kmalloc(sizeof(struct u132_endp), mem_flags);
+	int rc;
+	u8 endp_number;
+	struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
         if (!endp) {
                 return -ENOMEM;
         }
+
+	spin_lock_init(&endp->queue_lock.slock);
+	spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+	rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+	if (rc) {
+		spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+		kfree(endp);
+		return rc;
+	}
+
+	endp_number = ++u132->num_endpoints;
+	urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
         INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
-        spin_lock_init(&endp->queue_lock.slock);
         INIT_LIST_HEAD(&endp->urb_more);
         ring = endp->ring = &u132->ring[0];
         if (ring->curr_endp) {
@@ -1906,7 +1915,7 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
         endp->delayed = 0;
         endp->endp_number = endp_number;
         endp->u132 = u132;
-        endp->hep = hep;
+	endp->hep = urb->ep;
         endp->pipetype = usb_pipetype(urb->pipe);
         u132_endp_init_kref(u132, endp);
         if (usb_pipein(urb->pipe)) {
@@ -1925,7 +1934,6 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
                 u132_udev_get_kref(u132, udev);
         }
         urb->hcpriv = u132;
-        spin_lock_irqsave(&endp->queue_lock.slock, irqs);
         endp->delayed = 1;
         endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
         endp->udev_number = address;
@@ -1940,8 +1948,8 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
         return 0;
 }
 
-static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
-        struct usb_host_endpoint *hep, struct urb *urb,
+static int queue_int_on_old_endpoint(struct u132 *u132,
+	struct u132_udev *udev, struct urb *urb,
         struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
         u8 usb_endp, u8 address)
 {
@@ -1965,21 +1973,33 @@ static int queue_int_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
 }
 
 static int create_endpoint_and_queue_bulk(struct u132 *u132,
-        struct u132_udev *udev, struct usb_host_endpoint *hep, struct urb *urb,
+	struct u132_udev *udev, struct urb *urb,
         struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
         gfp_t mem_flags)
 {
         int ring_number;
         struct u132_ring *ring;
         unsigned long irqs;
-        u8 endp_number = ++u132->num_endpoints;
-        struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
-                kmalloc(sizeof(struct u132_endp), mem_flags);
+	int rc;
+	u8 endp_number;
+	struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
         if (!endp) {
                 return -ENOMEM;
         }
+
+	spin_lock_init(&endp->queue_lock.slock);
+	spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+	rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+	if (rc) {
+		spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+		kfree(endp);
+		return rc;
+	}
+
+	endp_number = ++u132->num_endpoints;
+	urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
         INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
-        spin_lock_init(&endp->queue_lock.slock);
         INIT_LIST_HEAD(&endp->urb_more);
         endp->dequeueing = 0;
         endp->edset_flush = 0;
@@ -1987,7 +2007,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
         endp->delayed = 0;
         endp->endp_number = endp_number;
         endp->u132 = u132;
-        endp->hep = hep;
+	endp->hep = urb->ep;
         endp->pipetype = usb_pipetype(urb->pipe);
         u132_endp_init_kref(u132, endp);
         if (usb_pipein(urb->pipe)) {
@@ -2016,7 +2036,6 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
         }
         ring->length += 1;
         urb->hcpriv = u132;
-        spin_lock_irqsave(&endp->queue_lock.slock, irqs);
         endp->udev_number = address;
         endp->usb_addr = usb_addr;
         endp->usb_endp = usb_endp;
@@ -2030,7 +2049,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
 }
 
 static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
-         struct usb_host_endpoint *hep, struct urb *urb,
+	struct urb *urb,
         struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
         u8 usb_endp, u8 address)
 {
@@ -2052,19 +2071,32 @@ static int queue_bulk_on_old_endpoint(struct u132 *u132, struct u132_udev *udev,
 }
 
 static int create_endpoint_and_queue_control(struct u132 *u132,
-        struct usb_host_endpoint *hep, struct urb *urb,
+	struct urb *urb,
         struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp,
         gfp_t mem_flags)
 {
         struct u132_ring *ring;
-        u8 endp_number = ++u132->num_endpoints;
-        struct u132_endp *endp = hep->hcpriv = u132->endp[endp_number - 1] =
-                kmalloc(sizeof(struct u132_endp), mem_flags);
+	unsigned long irqs;
+	int rc;
+	u8 endp_number;
+	struct u132_endp *endp = kmalloc(sizeof(struct u132_endp), mem_flags);
+
         if (!endp) {
                 return -ENOMEM;
         }
+
+	spin_lock_init(&endp->queue_lock.slock);
+	spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+	rc = usb_hcd_link_urb_to_ep(u132_to_hcd(u132), urb);
+	if (rc) {
+		spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+		kfree(endp);
+		return rc;
+	}
+
+	endp_number = ++u132->num_endpoints;
+	urb->ep->hcpriv = u132->endp[endp_number - 1] = endp;
         INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
-        spin_lock_init(&endp->queue_lock.slock);
         INIT_LIST_HEAD(&endp->urb_more);
         ring = endp->ring = &u132->ring[0];
         if (ring->curr_endp) {
@@ -2080,11 +2112,10 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
         endp->delayed = 0;
         endp->endp_number = endp_number;
         endp->u132 = u132;
-        endp->hep = hep;
+	endp->hep = urb->ep;
         u132_endp_init_kref(u132, endp);
         u132_endp_get_kref(u132, endp);
         if (usb_addr == 0) {
-                unsigned long irqs;
                 u8 address = u132->addr[usb_addr].address;
                 struct u132_udev *udev = &u132->udev[address];
                 endp->udev_number = address;
@@ -2098,7 +2129,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
                 udev->endp_number_in[usb_endp] = endp_number;
                 udev->endp_number_out[usb_endp] = endp_number;
                 urb->hcpriv = u132;
-                spin_lock_irqsave(&endp->queue_lock.slock, irqs);
                 endp->queue_size = 1;
                 endp->queue_last = 0;
                 endp->queue_next = 0;
@@ -2107,7 +2137,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
                 u132_endp_queue_work(u132, endp, 0);
                 return 0;
         } else {                /*(usb_addr > 0) */
-                unsigned long irqs;
                 u8 address = u132->addr[usb_addr].address;
                 struct u132_udev *udev = &u132->udev[address];
                 endp->udev_number = address;
@@ -2121,7 +2150,6 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
                 udev->endp_number_in[usb_endp] = endp_number;
                 udev->endp_number_out[usb_endp] = endp_number;
                 urb->hcpriv = u132;
-                spin_lock_irqsave(&endp->queue_lock.slock, irqs);
                 endp->queue_size = 1;
                 endp->queue_last = 0;
                 endp->queue_next = 0;
@@ -2133,7 +2161,7 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
 }
 
 static int queue_control_on_old_endpoint(struct u132 *u132,
-        struct usb_host_endpoint *hep, struct urb *urb,
+	struct urb *urb,
         struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
         u8 usb_endp)
 {
@@ -2233,8 +2261,8 @@ static int queue_control_on_old_endpoint(struct u132 *u132,
         }
 }
 
-static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
-        struct urb *urb, gfp_t mem_flags)
+static int u132_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+		gfp_t mem_flags)
 {
         struct u132 *u132 = hcd_to_u132(hcd);
         if (irqs_disabled()) {
@@ -2249,8 +2277,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                         , u132->going);
                 return -ENODEV;
         } else if (u132->going > 0) {
-                dev_err(&u132->platform_dev->dev, "device is being removed urb="
-                        "%p status=%d\n", urb, urb->status);
+		dev_err(&u132->platform_dev->dev, "device is being removed "
+				"urb=%p\n", urb);
                 return -ESHUTDOWN;
         } else {
                 u8 usb_addr = usb_pipedevice(urb->pipe);
@@ -2259,16 +2287,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                 if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
                         u8 address = u132->addr[usb_addr].address;
                         struct u132_udev *udev = &u132->udev[address];
-                        struct u132_endp *endp = hep->hcpriv;
+                        struct u132_endp *endp = urb->ep->hcpriv;
                         urb->actual_length = 0;
                         if (endp) {
                                 unsigned long irqs;
                                 int retval;
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                         irqs);
-                                retval = queue_int_on_old_endpoint(u132, udev,
-                                        hep, urb, usb_dev, endp, usb_addr,
-                                        usb_endp, address);
+				retval = usb_hcd_link_urb_to_ep(hcd, urb);
+				if (retval == 0) {
+					retval = queue_int_on_old_endpoint(
+							u132, udev, urb,
+							usb_dev, endp,
+							usb_addr, usb_endp,
+							address);
+					if (retval)
+						usb_hcd_unlink_urb_from_ep(
+								hcd, urb);
+				}
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
                                         irqs);
                                 if (retval) {
@@ -2283,8 +2319,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                                 return -EINVAL;
                         } else {        /*(endp == NULL) */
                                 return create_endpoint_and_queue_int(u132, udev,
-                                         hep, urb, usb_dev, usb_addr, usb_endp,
-                                        address, mem_flags);
+						urb, usb_dev, usb_addr,
+						usb_endp, address, mem_flags);
                         }
                 } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
                         dev_err(&u132->platform_dev->dev, "the hardware does no"
@@ -2293,16 +2329,24 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                 } else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
                         u8 address = u132->addr[usb_addr].address;
                         struct u132_udev *udev = &u132->udev[address];
-                        struct u132_endp *endp = hep->hcpriv;
+                        struct u132_endp *endp = urb->ep->hcpriv;
                         urb->actual_length = 0;
                         if (endp) {
                                 unsigned long irqs;
                                 int retval;
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                         irqs);
-                                retval = queue_bulk_on_old_endpoint(u132, udev,
-                                        hep, urb, usb_dev, endp, usb_addr,
-                                        usb_endp, address);
+				retval = usb_hcd_link_urb_to_ep(hcd, urb);
+				if (retval == 0) {
+					retval = queue_bulk_on_old_endpoint(
+							u132, udev, urb,
+							usb_dev, endp,
+							usb_addr, usb_endp,
+							address);
+					if (retval)
+						usb_hcd_unlink_urb_from_ep(
+								hcd, urb);
+				}
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
                                         irqs);
                                 if (retval) {
@@ -2315,10 +2359,10 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                                 return -EINVAL;
                         } else
                                 return create_endpoint_and_queue_bulk(u132,
-                                        udev, hep, urb, usb_dev, usb_addr,
+					udev, urb, usb_dev, usb_addr,
                                         usb_endp, address, mem_flags);
                 } else {
-                        struct u132_endp *endp = hep->hcpriv;
+                        struct u132_endp *endp = urb->ep->hcpriv;
                         u16 urb_size = 8;
                         u8 *b = urb->setup_packet;
                         int i = 0;
@@ -2341,9 +2385,16 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                                 int retval;
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                         irqs);
-                                retval = queue_control_on_old_endpoint(u132,
-                                        hep, urb, usb_dev, endp, usb_addr,
-                                        usb_endp);
+				retval = usb_hcd_link_urb_to_ep(hcd, urb);
+				if (retval == 0) {
+					retval = queue_control_on_old_endpoint(
+							u132, urb, usb_dev,
+							endp, usb_addr,
+							usb_endp);
+					if (retval)
+						usb_hcd_unlink_urb_from_ep(
+								hcd, urb);
+				}
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
                                         irqs);
                                 if (retval) {
@@ -2356,7 +2407,7 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                                 return -EINVAL;
                         } else
                                 return create_endpoint_and_queue_control(u132,
-                                        hep, urb, usb_dev, usb_addr, usb_endp,
+					urb, usb_dev, usb_addr, usb_endp,
                                         mem_flags);
                 }
         }
@@ -2375,8 +2426,7 @@ static int dequeue_from_overflow_chain(struct u132 *u132,
                         list_del(scan);
                         endp->queue_size -= 1;
                         urb->error_count = 0;
-                        urb->hcpriv = NULL;
-                        usb_hcd_giveback_urb(hcd, urb);
+			usb_hcd_giveback_urb(hcd, urb, 0);
                         return 0;
                 } else
                         continue;
@@ -2391,10 +2441,17 @@ static int dequeue_from_overflow_chain(struct u132 *u132,
 }
 
 static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
-        struct urb *urb)
+		struct urb *urb, int status)
 {
         unsigned long irqs;
+	int rc;
+
         spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+	rc = usb_hcd_check_unlink_urb(u132_to_hcd(u132), urb, status);
+	if (rc) {
+		spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
+		return rc;
+	}
         if (endp->queue_size == 0) {
                 dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]"
                         "=%p ring[%d] %c%c usb_endp=%d usb_addr=%d\n", urb,
@@ -2410,11 +2467,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
                         endp->edset_flush = 1;
                         u132_endp_queue_work(u132, endp, 0);
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
-                        urb->hcpriv = NULL;
                         return 0;
                 } else {
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
-                        u132_hcd_abandon_urb(u132, endp, urb, urb->status);
+			u132_hcd_abandon_urb(u132, endp, urb, status);
                         return 0;
                 }
         } else {
@@ -2439,6 +2495,8 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
                 }
                 if (urb_slot) {
                         struct usb_hcd *hcd = u132_to_hcd(u132);
+
+			usb_hcd_unlink_urb_from_ep(hcd, urb);
                         endp->queue_size -= 1;
                         if (list_empty(&endp->urb_more)) {
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
@@ -2453,8 +2511,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
                                         irqs);
                                 kfree(urbq);
                         } urb->error_count = 0;
-                        urb->hcpriv = NULL;
-                        usb_hcd_giveback_urb(hcd, urb);
+			usb_hcd_giveback_urb(hcd, urb, status);
                         return 0;
                 } else if (list_empty(&endp->urb_more)) {
                         dev_err(&u132->platform_dev->dev, "urb=%p not found in "
@@ -2468,7 +2525,10 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                         return -EINVAL;
                 } else {
-                        int retval = dequeue_from_overflow_chain(u132, endp,
+			int retval;
+
+			usb_hcd_unlink_urb_from_ep(u132_to_hcd(u132), urb);
+			retval = dequeue_from_overflow_chain(u132, endp,
                                 urb);
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                         return retval;
@@ -2476,7 +2536,7 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
         }
 }
 
-static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
         struct u132 *u132 = hcd_to_u132(hcd);
         if (u132->going > 2) {
@@ -2491,11 +2551,11 @@ static int u132_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
                 if (usb_pipein(urb->pipe)) {
                         u8 endp_number = udev->endp_number_in[usb_endp];
                         struct u132_endp *endp = u132->endp[endp_number - 1];
-                        return u132_endp_urb_dequeue(u132, endp, urb);
+                        return u132_endp_urb_dequeue(u132, endp, urb, status);
                 } else {
                         u8 endp_number = udev->endp_number_out[usb_endp];
                         struct u132_endp *endp = u132->endp[endp_number - 1];
-                        return u132_endp_urb_dequeue(u132, endp, urb);
+                        return u132_endp_urb_dequeue(u132, endp, urb, status);
                 }
         }
 }
@@ -2805,7 +2865,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                 return -ESHUTDOWN;
         } else {
                 int retval = 0;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 switch (typeReq) {
                 case ClearHubFeature:
                         switch (wValue) {
@@ -2868,7 +2928,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                       stall:retval = -EPIPE;
                         break;
                 }
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
                 return retval;
         }
 }
@@ -3004,7 +3064,7 @@ static int __devexit u132_remove(struct platform_device *pdev)
                         dev_err(&u132->platform_dev->dev, "removing device u132"
 				".%d\n", u132->sequence_num);
                         msleep(100);
-                        down(&u132->sw_lock);
+                        mutex_lock(&u132->sw_lock);
                         u132_monitor_cancel_work(u132);
                         while (rings-- > 0) {
                                 struct u132_ring *ring = &u132->ring[rings];
@@ -3017,7 +3077,7 @@ static int __devexit u132_remove(struct platform_device *pdev)
                         u132->going += 1;
                         printk(KERN_INFO "removing device u132.%d\n",
                                 u132->sequence_num);
-                        up(&u132->sw_lock);
+                        mutex_unlock(&u132->sw_lock);
                         usb_remove_hcd(hcd);
                         u132_u132_put_kref(u132);
                         return 0;
@@ -3037,7 +3097,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
         u132->platform_dev = pdev;
         u132->power = 0;
         u132->reset = 0;
-        init_MUTEX(&u132->sw_lock);
+        mutex_init(&u132->sw_lock);
         init_MUTEX(&u132->scheduler_lock);
         while (rings-- > 0) {
                 struct u132_ring *ring = &u132->ring[rings];
@@ -3047,7 +3107,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
                 ring->curr_endp = NULL;
                 INIT_DELAYED_WORK(&ring->scheduler,
 				  u132_hcd_ring_work_scheduler);
-        } down(&u132->sw_lock);
+        } mutex_lock(&u132->sw_lock);
         INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work);
         while (ports-- > 0) {
                 struct u132_port *port = &u132->port[ports];
@@ -3077,7 +3137,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
         while (endps-- > 0) {
                 u132->endp[endps] = NULL;
         }
-        up(&u132->sw_lock);
+        mutex_unlock(&u132->sw_lock);
         return;
 }
 

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

@@ -120,8 +120,8 @@ static int uhci_show_urbp(struct urb_priv *urbp, char *buf, int len, int space)
 	out += sprintf(out, "%s%s", ptype, (urbp->fsbr ? " FSBR" : ""));
 	out += sprintf(out, " Actlen=%d", urbp->urb->actual_length);
 
-	if (urbp->urb->status != -EINPROGRESS)
-		out += sprintf(out, " Status=%d", urbp->urb->status);
+	if (urbp->urb->unlinked)
+		out += sprintf(out, " Unlinked=%d", urbp->urb->unlinked);
 	out += sprintf(out, "\n");
 
 	i = nactive = ninactive = 0;

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

@@ -146,7 +146,6 @@ struct uhci_qh {
 	short phase;			/* Between 0 and period-1 */
 	short load;			/* Periodic time requirement, in us */
 	unsigned int iso_frame;		/* Frame # for iso_packet_desc */
-	int iso_status;			/* Status for Isochronous URBs */
 
 	int state;			/* QH_STATE_xxx; see above */
 	int type;			/* Queue type (control, bulk, etc) */
@@ -457,21 +456,6 @@ struct urb_priv {
 };
 
 
-/*
- * Locking in uhci.c
- *
- * Almost everything relating to the hardware schedule and processing
- * of URBs is protected by uhci->lock.  urb->status is protected by
- * urb->lock; that's the one exception.
- *
- * To prevent deadlocks, never lock uhci->lock while holding urb->lock.
- * The safe order of locking is:
- *
- * #1 uhci->lock
- * #2 urb->lock
- */
-
-
 /* Some special IDs */
 
 #define PCI_VENDOR_ID_GENESYS		0x17a0

+ 26 - 44
drivers/usb/host/uhci-q.c

@@ -757,7 +757,6 @@ static void uhci_free_urb_priv(struct uhci_hcd *uhci,
 		uhci_free_td(uhci, td);
 	}
 
-	urbp->urb->hcpriv = NULL;
 	kmem_cache_free(uhci_up_cachep, urbp);
 }
 
@@ -1324,7 +1323,6 @@ static int uhci_submit_isochronous(struct uhci_hcd *uhci, struct urb *urb,
 	if (list_empty(&qh->queue)) {
 		qh->iso_packet_desc = &urb->iso_frame_desc[0];
 		qh->iso_frame = urb->start_frame;
-		qh->iso_status = 0;
 	}
 
 	qh->skel = SKEL_ISO;
@@ -1361,22 +1359,18 @@ static int uhci_result_isochronous(struct uhci_hcd *uhci, struct urb *urb)
 			qh->iso_packet_desc->actual_length = actlength;
 			qh->iso_packet_desc->status = status;
 		}
-
-		if (status) {
+		if (status)
 			urb->error_count++;
-			qh->iso_status = status;
-		}
 
 		uhci_remove_td_from_urbp(td);
 		uhci_free_td(uhci, td);
 		qh->iso_frame += qh->period;
 		++qh->iso_packet_desc;
 	}
-	return qh->iso_status;
+	return 0;
 }
 
 static int uhci_urb_enqueue(struct usb_hcd *hcd,
-		struct usb_host_endpoint *hep,
 		struct urb *urb, gfp_t mem_flags)
 {
 	int ret;
@@ -1387,19 +1381,19 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
 
 	spin_lock_irqsave(&uhci->lock, flags);
 
-	ret = urb->status;
-	if (ret != -EINPROGRESS)		/* URB already unlinked! */
-		goto done;
+	ret = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (ret)
+		goto done_not_linked;
 
 	ret = -ENOMEM;
 	urbp = uhci_alloc_urb_priv(uhci, urb);
 	if (!urbp)
 		goto done;
 
-	if (hep->hcpriv)
-		qh = (struct uhci_qh *) hep->hcpriv;
+	if (urb->ep->hcpriv)
+		qh = urb->ep->hcpriv;
 	else {
-		qh = uhci_alloc_qh(uhci, urb->dev, hep);
+		qh = uhci_alloc_qh(uhci, urb->dev, urb->ep);
 		if (!qh)
 			goto err_no_qh;
 	}
@@ -1440,27 +1434,29 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
 err_submit_failed:
 	if (qh->state == QH_STATE_IDLE)
 		uhci_make_qh_idle(uhci, qh);	/* Reclaim unused QH */
-
 err_no_qh:
 	uhci_free_urb_priv(uhci, urbp);
-
 done:
+	if (ret)
+		usb_hcd_unlink_urb_from_ep(hcd, urb);
+done_not_linked:
 	spin_unlock_irqrestore(&uhci->lock, flags);
 	return ret;
 }
 
-static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
+static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 	unsigned long flags;
-	struct urb_priv *urbp;
 	struct uhci_qh *qh;
+	int rc;
 
 	spin_lock_irqsave(&uhci->lock, flags);
-	urbp = urb->hcpriv;
-	if (!urbp)			/* URB was never linked! */
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
 		goto done;
-	qh = urbp->qh;
+
+	qh = ((struct urb_priv *) urb->hcpriv)->qh;
 
 	/* Remove Isochronous TDs from the frame list ASAP */
 	if (qh->type == USB_ENDPOINT_XFER_ISOC) {
@@ -1477,14 +1473,14 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
 
 done:
 	spin_unlock_irqrestore(&uhci->lock, flags);
-	return 0;
+	return rc;
 }
 
 /*
  * Finish unlinking an URB and give it back
  */
 static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh,
-		struct urb *urb)
+		struct urb *urb, int status)
 __releases(uhci->lock)
 __acquires(uhci->lock)
 {
@@ -1497,13 +1493,6 @@ __acquires(uhci->lock)
 		 * unlinked first.  Regardless, don't confuse people with a
 		 * negative length. */
 		urb->actual_length = max(urb->actual_length, 0);
-
-		/* Report erroneous short transfers */
-		if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
-				urb->actual_length <
-					urb->transfer_buffer_length &&
-				urb->status == 0))
-			urb->status = -EREMOTEIO;
 	}
 
 	/* When giving back the first URB in an Isochronous queue,
@@ -1516,7 +1505,6 @@ __acquires(uhci->lock)
 
 		qh->iso_packet_desc = &nurb->iso_frame_desc[0];
 		qh->iso_frame = nurb->start_frame;
-		qh->iso_status = 0;
 	}
 
 	/* Take the URB off the QH's queue.  If the queue is now empty,
@@ -1529,9 +1517,10 @@ __acquires(uhci->lock)
 	}
 
 	uhci_free_urb_priv(uhci, urbp);
+	usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb);
 
 	spin_unlock(&uhci->lock);
-	usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
+	usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, status);
 	spin_lock(&uhci->lock);
 
 	/* If the queue is now empty, we can unlink the QH and give up its
@@ -1567,24 +1556,17 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
 		if (status == -EINPROGRESS)
 			break;
 
-		spin_lock(&urb->lock);
-		if (urb->status == -EINPROGRESS)	/* Not dequeued */
-			urb->status = status;
-		else
-			status = ECONNRESET;		/* Not -ECONNRESET */
-		spin_unlock(&urb->lock);
-
 		/* Dequeued but completed URBs can't be given back unless
 		 * the QH is stopped or has finished unlinking. */
-		if (status == ECONNRESET) {
+		if (urb->unlinked) {
 			if (QH_FINISHED_UNLINKING(qh))
 				qh->is_stopped = 1;
 			else if (!qh->is_stopped)
 				return;
 		}
 
-		uhci_giveback_urb(uhci, qh, urb);
-		if (status < 0 && qh->type != USB_ENDPOINT_XFER_ISOC)
+		uhci_giveback_urb(uhci, qh, urb, status);
+		if (status < 0)
 			break;
 	}
 
@@ -1599,7 +1581,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
 restart:
 	list_for_each_entry(urbp, &qh->queue, node) {
 		urb = urbp->urb;
-		if (urb->status != -EINPROGRESS) {
+		if (urb->unlinked) {
 
 			/* Fix up the TD links and save the toggles for
 			 * non-Isochronous queues.  For Isochronous queues,
@@ -1608,7 +1590,7 @@ restart:
 				qh->is_stopped = 0;
 				return;
 			}
-			uhci_giveback_urb(uhci, qh, urb);
+			uhci_giveback_urb(uhci, qh, urb, 0);
 			goto restart;
 		}
 	}

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

@@ -188,7 +188,8 @@ static void adu_interrupt_in_callback(struct urb *urb)
 	spin_lock(&dev->buflock);
 
 	if (status != 0) {
-		if ((status != -ENOENT) && (status != -ECONNRESET)) {
+		if ((status != -ENOENT) && (status != -ECONNRESET) &&
+			(status != -ESHUTDOWN)) {
 			dbg(1," %s : nonzero status received: %d",
 			    __FUNCTION__, status);
 		}

+ 5 - 2
drivers/usb/misc/berry_charge.c

@@ -71,7 +71,7 @@ static int magic_charge(struct usb_device *udev)
 	if (retval != 2) {
 		dev_err(&udev->dev, "First magic command failed: %d.\n",
 			retval);
-		return retval;
+		goto exit;
 	}
 
 	dbg(&udev->dev, "Sending second magic command\n");
@@ -80,7 +80,7 @@ static int magic_charge(struct usb_device *udev)
 	if (retval != 0) {
 		dev_err(&udev->dev, "Second magic command failed: %d.\n",
 			retval);
-		return retval;
+		goto exit;
 	}
 
 	dbg(&udev->dev, "Calling set_configuration\n");
@@ -88,6 +88,8 @@ static int magic_charge(struct usb_device *udev)
 	if (retval)
 		dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
 
+exit:
+	kfree(dummy_buffer);
 	return retval;
 }
 
@@ -112,6 +114,7 @@ static int magic_dual_mode(struct usb_device *udev)
 	if (retval)
 		dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
 
+	kfree(dummy_buffer);
 	return retval;
 }
 

+ 5 - 3
drivers/usb/misc/ftdi-elan.c

@@ -2777,12 +2777,14 @@ static int ftdi_elan_probe(struct usb_interface *interface,
         size_t buffer_size;
         int i;
         int retval = -ENOMEM;
-        struct usb_ftdi *ftdi = kmalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
-        if (ftdi == NULL) {
+        struct usb_ftdi *ftdi;
+
+	ftdi = kzalloc(sizeof(struct usb_ftdi), GFP_KERNEL);
+	if (!ftdi) {
                 printk(KERN_ERR "Out of memory\n");
                 return -ENOMEM;
         }
-        memset(ftdi, 0x00, sizeof(struct usb_ftdi));
+
         mutex_lock(&ftdi_module_lock);
         list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
         ftdi->sequence_num = ++ftdi_instances;

+ 41 - 159
drivers/usb/misc/sisusbvga/sisusb.c

@@ -32,7 +32,7 @@
  * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ * Author:	Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
@@ -962,12 +962,12 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
 			   packet.address = 0x00000194;
 			   packet.data    = addr;
 			   ret = sisusb_send_bridge_packet(sisusb, 10,
-			   					&packet, 0);
+								&packet, 0);
 			   packet.header  = 0x001f;
 			   packet.address = 0x00000190;
 			   packet.data    = (length & ~3);
 			   ret |= sisusb_send_bridge_packet(sisusb, 10,
-			   					&packet, 0);
+								&packet, 0);
 			   if (sisusb->flagb0 != 0x16) {
 				packet.header  = 0x001f;
 				packet.address = 0x00000180;
@@ -1003,23 +1003,17 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
 			if (ret) {
 				msgcount++;
 				if (msgcount < 500)
-					printk(KERN_ERR
-						"sisusbvga[%d]: Wrote %zd of "
-						"%d bytes, error %d\n",
-						sisusb->minor, *bytes_written,
-						length, ret);
+					dev_err(&sisusb->sisusb_dev->dev, "Wrote %zd of %d bytes, error %d\n",
+						*bytes_written, length, ret);
 				else if (msgcount == 500)
-					printk(KERN_ERR
-						"sisusbvga[%d]: Too many errors"
-						", logging stopped\n",
-						sisusb->minor);
+					dev_err(&sisusb->sisusb_dev->dev, "Too many errors, logging stopped\n");
 			}
 			addr += (*bytes_written);
 			length -= (*bytes_written);
 	    }
 
 	    if (ret)
-	    	break;
+		break;
 
 	}
 
@@ -1261,51 +1255,10 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
 				addr += 4;
 				length -= 4;
 			}
-#if 0		/* That does not work, as EP 2 is an OUT EP! */
-		default:
-			CLEARPACKET(&packet);
-			packet.header  = 0x001f;
-			packet.address = 0x000001a0;
-			packet.data    = 0x00000006;
-			ret |= sisusb_send_bridge_packet(sisusb, 10,
-								&packet, 0);
-			packet.header  = 0x001f;
-			packet.address = 0x000001b0;
-			packet.data    = (length & ~3) | 0x40000000;
-			ret |= sisusb_send_bridge_packet(sisusb, 10,
-								&packet, 0);
-			packet.header  = 0x001f;
-			packet.address = 0x000001b4;
-			packet.data    = addr;
-			ret |= sisusb_send_bridge_packet(sisusb, 10,
-								&packet, 0);
-			packet.header  = 0x001f;
-			packet.address = 0x000001a4;
-			packet.data    = 0x00000001;
-			ret |= sisusb_send_bridge_packet(sisusb, 10,
-								&packet, 0);
-			if (userbuffer) {
-				ret |= sisusb_recv_bulk_msg(sisusb,
-							SISUSB_EP_GFX_BULK_IN,
-							(length & ~3),
-							NULL, userbuffer,
-							bytes_read, 0);
-				if (!ret) userbuffer += (*bytes_read);
-			} else {
-				ret |= sisusb_recv_bulk_msg(sisusb,
-							SISUSB_EP_GFX_BULK_IN,
-							(length & ~3),
-							kernbuffer, NULL,
-							bytes_read, 0);
-				if (!ret) kernbuffer += (*bytes_read);
-			}
-			addr += (*bytes_read);
-			length -= (*bytes_read);
-#endif
 	    }
 
 	    if (ret)
-	    	break;
+		break;
 	}
 
 	return ret;
@@ -1401,22 +1354,6 @@ sisusb_readb(struct sisusb_usb_data *sisusb, u32 adr, u8 *data)
 	return(sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, adr, data));
 }
 
-#if 0
-
-int
-sisusb_writew(struct sisusb_usb_data *sisusb, u32 adr, u16 data)
-{
-	return(sisusb_write_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
-}
-
-int
-sisusb_readw(struct sisusb_usb_data *sisusb, u32 adr, u16 *data)
-{
-	return(sisusb_read_memio_word(sisusb, SISUSB_TYPE_MEM, adr, data));
-}
-
-#endif  /*  0  */
-
 int
 sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
 			u32 dest, int length, size_t *bytes_written)
@@ -1446,10 +1383,10 @@ sisusb_testreadwrite(struct sisusb_usb_data *sisusb)
     sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
 
     for(i = 1; i <= 7; i++) {
-        printk(KERN_DEBUG "sisusb: rwtest %d bytes\n", i);
+        dev_dbg(&sisusb->sisusb_dev->dev, "sisusb: rwtest %d bytes\n", i);
 	sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
 	for(j = 0; j < i; j++) {
-	     printk(KERN_DEBUG "sisusb: rwtest read[%d] = %x\n", j, destbuffer[j]);
+	     dev_dbg(&sisusb->sisusb_dev->dev, "rwtest read[%d] = %x\n", j, destbuffer[j]);
 	}
     }
 }
@@ -1533,9 +1470,9 @@ sisusb_clear_vram(struct sisusb_usb_data *sisusb, u32 address, int length)
 #define SETIREGAND(r,i,a)	sisusb_setidxregand(sisusb, r, i, a)
 #define SETIREGANDOR(r,i,a,o)	sisusb_setidxregandor(sisusb, r, i, a, o)
 #define READL(a,d)	sisusb_read_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
-#define WRITEL(a,d) 	sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEL(a,d)	sisusb_write_memio_long(sisusb, SISUSB_TYPE_MEM, a, d)
 #define READB(a,d)	sisusb_read_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
-#define WRITEB(a,d) 	sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
+#define WRITEB(a,d)	sisusb_write_memio_byte(sisusb, SISUSB_TYPE_MEM, a, d)
 
 static int
 sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
@@ -2008,7 +1945,7 @@ sisusb_set_default_mode(struct sisusb_usb_data *sisusb, int touchengines)
 		SETIREG(SISSR, 0x26, 0x00);
 	}
 
-	SETIREG(SISCR, 0x34, 0x44);  	/* we just set std mode #44 */
+	SETIREG(SISCR, 0x34, 0x44);	/* we just set std mode #44 */
 
 	return ret;
 }
@@ -2168,17 +2105,12 @@ sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
 		if (ramtype <= 1) {
 			ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
 			if (iret) {
-				printk(KERN_ERR "sisusbvga[%d]: RAM size "
-					"detection failed, "
-					"assuming 8MB video RAM\n",
-					sisusb->minor);
+				dev_err(&sisusb->sisusb_dev->dev,"RAM size detection failed, assuming 8MB video RAM\n");
 				ret |= SETIREG(SISSR,0x14,0x31);
 				/* TODO */
 			}
 		} else {
-			printk(KERN_ERR "sisusbvga[%d]: DDR RAM device found, "
-					"assuming 8MB video RAM\n",
-					sisusb->minor);
+			dev_err(&sisusb->sisusb_dev->dev, "DDR RAM device found, assuming 8MB video RAM\n");
 			ret |= SETIREG(SISSR,0x14,0x31);
 			/* *** TODO *** */
 		}
@@ -2249,8 +2181,7 @@ sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
 		break;
 	}
 
-	printk(KERN_INFO "sisusbvga[%d]: %dMB %s %s, bus width %d\n",
-			sisusb->minor, (sisusb->vramsize >> 20), ramtypetext1,
+	dev_info(&sisusb->sisusb_dev->dev, "%dMB %s %s, bus width %d\n", (sisusb->vramsize >> 20), ramtypetext1,
 			ramtypetext2[ramtype], bw);
 }
 
@@ -2509,11 +2440,8 @@ sisusb_open(struct inode *inode, struct file *file)
 	struct usb_interface *interface;
 	int subminor = iminor(inode);
 
-	if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
-		printk(KERN_ERR "sisusb[%d]: Failed to find interface\n",
-				subminor);
+	if (!(interface = usb_find_interface(&sisusb_driver, subminor)))
 		return -ENODEV;
-	}
 
 	if (!(sisusb = usb_get_intfdata(interface)))
 		return -ENODEV;
@@ -2534,18 +2462,12 @@ sisusb_open(struct inode *inode, struct file *file)
 		if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
 			if (sisusb_init_gfxdevice(sisusb, 0)) {
 				mutex_unlock(&sisusb->lock);
-				printk(KERN_ERR
-					"sisusbvga[%d]: Failed to initialize "
-					"device\n",
-					sisusb->minor);
+				dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n");
 				return -EIO;
 			}
 		} else {
 			mutex_unlock(&sisusb->lock);
-			printk(KERN_ERR
-				"sisusbvga[%d]: Device not attached to "
-				"USB 2.0 hub\n",
-				sisusb->minor);
+			dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n");
 			return -EIO;
 		}
 	}
@@ -2586,7 +2508,6 @@ static int
 sisusb_release(struct inode *inode, struct file *file)
 {
 	struct sisusb_usb_data *sisusb;
-	int myminor;
 
 	if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
 		return -ENODEV;
@@ -2599,8 +2520,6 @@ sisusb_release(struct inode *inode, struct file *file)
 			sisusb_kill_all_busy(sisusb);
 	}
 
-	myminor = sisusb->minor;
-
 	sisusb->isopen = 0;
 	file->private_data = NULL;
 
@@ -2942,7 +2861,7 @@ static int
 sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
 							unsigned long arg)
 {
-	int 	retval, port, length;
+	int	retval, port, length;
 	u32	address;
 
 	/* All our commands require the device
@@ -3065,12 +2984,12 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
 
 static int
 sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-	     						unsigned long arg)
+							unsigned long arg)
 {
 	struct sisusb_usb_data *sisusb;
 	struct sisusb_info x;
 	struct sisusb_command y;
-	int 	retval = 0;
+	int	retval = 0;
 	u32 __user *argp = (u32 __user *)arg;
 
 	if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
@@ -3095,7 +3014,7 @@ sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 
 		case SISUSB_GET_CONFIG:
 
-			x.sisusb_id   	    = SISUSB_ID;
+			x.sisusb_id	    = SISUSB_ID;
 			x.sisusb_version    = SISUSB_VERSION;
 			x.sisusb_revision   = SISUSB_REVISION;
 			x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
@@ -3164,7 +3083,7 @@ static const struct file_operations usb_sisusb_fops = {
 	.release =	sisusb_release,
 	.read =		sisusb_read,
 	.write =	sisusb_write,
-	.llseek = 	sisusb_lseek,
+	.llseek =	sisusb_lseek,
 #ifdef SISUSB_NEW_CONFIG_COMPAT
 	.compat_ioctl = sisusb_compat_ioctl,
 #endif
@@ -3183,17 +3102,13 @@ static int sisusb_probe(struct usb_interface *intf,
 	struct usb_device *dev = interface_to_usbdev(intf);
 	struct sisusb_usb_data *sisusb;
 	int retval = 0, i;
-	const char *memfail =
-		KERN_ERR
-		"sisusbvga[%d]: Failed to allocate memory for %s buffer\n";
 
-	printk(KERN_INFO "sisusb: USB2VGA dongle found at address %d\n",
+	dev_info(&dev->dev, "USB2VGA dongle found at address %d\n",
 		dev->devnum);
 
 	/* Allocate memory for our private */
 	if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
-		printk(KERN_ERR
-			"sisusb: Failed to allocate memory for private data\n");
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for private data\n");
 		return -ENOMEM;
 	}
 	kref_init(&sisusb->kref);
@@ -3202,8 +3117,7 @@ static int sisusb_probe(struct usb_interface *intf,
 
 	/* Register device */
 	if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
-		printk(KERN_ERR
-			"sisusb: Failed to get a minor for device %d\n",
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to get a minor for device %d\n",
 			dev->devnum);
 		retval = -ENODEV;
 		goto error_1;
@@ -3221,7 +3135,7 @@ static int sisusb_probe(struct usb_interface *intf,
 	sisusb->ibufsize = SISUSB_IBUF_SIZE;
 	if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
 					GFP_KERNEL, &sisusb->transfer_dma_in))) {
-		printk(memfail, "input", sisusb->minor);
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for input buffer");
 		retval = -ENOMEM;
 		goto error_2;
 	}
@@ -3233,7 +3147,7 @@ static int sisusb_probe(struct usb_interface *intf,
 					GFP_KERNEL,
 					&sisusb->transfer_dma_out[i]))) {
 			if (i == 0) {
-				printk(memfail, "output", sisusb->minor);
+				dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n");
 				retval = -ENOMEM;
 				goto error_3;
 			}
@@ -3245,9 +3159,7 @@ static int sisusb_probe(struct usb_interface *intf,
 
 	/* Allocate URBs */
 	if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
-		printk(KERN_ERR
-			"sisusbvga[%d]: Failed to allocate URBs\n",
-			sisusb->minor);
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
 		retval = -ENOMEM;
 		goto error_3;
 	}
@@ -3255,9 +3167,7 @@ static int sisusb_probe(struct usb_interface *intf,
 
 	for (i = 0; i < sisusb->numobufs; i++) {
 		if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
-			printk(KERN_ERR
-				"sisusbvga[%d]: Failed to allocate URBs\n",
-				sisusb->minor);
+			dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate URBs\n");
 			retval = -ENOMEM;
 			goto error_4;
 		}
@@ -3266,15 +3176,12 @@ static int sisusb_probe(struct usb_interface *intf,
 		sisusb->urbstatus[i] = 0;
 	}
 
-	printk(KERN_INFO "sisusbvga[%d]: Allocated %d output buffers\n",
-					sisusb->minor, sisusb->numobufs);
+	dev_info(&sisusb->sisusb_dev->dev, "Allocated %d output buffers\n", sisusb->numobufs);
 
 #ifdef INCL_SISUSB_CON
 	/* Allocate our SiS_Pr */
 	if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
-		printk(KERN_ERR
-			"sisusbvga[%d]: Failed to allocate SiS_Pr\n",
-			sisusb->minor);
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate SiS_Pr\n");
 	}
 #endif
 
@@ -3296,10 +3203,7 @@ static int sisusb_probe(struct usb_interface *intf,
 	ret |= register_ioctl32_conversion(SISUSB_GET_CONFIG,      NULL);
 	ret |= register_ioctl32_conversion(SISUSB_COMMAND,         NULL);
 	if (ret)
-		printk(KERN_ERR
-			"sisusbvga[%d]: Error registering ioctl32 "
-			"translations\n",
-			sisusb->minor);
+		dev_err(&sisusb->sisusb_dev->dev, "Error registering ioctl32 translations\n");
 	else
 		sisusb->ioctl32registered = 1;
 	}
@@ -3315,23 +3219,17 @@ static int sisusb_probe(struct usb_interface *intf,
 			initscreen = 0;
 #endif
 		if (sisusb_init_gfxdevice(sisusb, initscreen))
-			printk(KERN_ERR
-				"sisusbvga[%d]: Failed to early "
-				"initialize device\n",
-				sisusb->minor);
+			dev_err(&sisusb->sisusb_dev->dev, "Failed to early initialize device\n");
 
 	} else
-		printk(KERN_INFO
-			"sisusbvga[%d]: Not attached to USB 2.0 hub, "
-			"deferring init\n",
-			sisusb->minor);
+		dev_info(&sisusb->sisusb_dev->dev, "Not attached to USB 2.0 hub, deferring init\n");
 
 	sisusb->ready = 1;
 
 #ifdef SISUSBENDIANTEST
-	printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
+	dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST ***\n");
 	sisusb_testreadwrite(sisusb);
-	printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
+	dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n");
 #endif
 
 #ifdef INCL_SISUSB_CON
@@ -3354,7 +3252,6 @@ error_1:
 static void sisusb_disconnect(struct usb_interface *intf)
 {
 	struct sisusb_usb_data *sisusb;
-	int minor;
 
 	/* This should *not* happen */
 	if (!(sisusb = usb_get_intfdata(intf)))
@@ -3364,8 +3261,6 @@ static void sisusb_disconnect(struct usb_interface *intf)
 	sisusb_console_exit(sisusb);
 #endif
 
-	minor = sisusb->minor;
-
 	usb_deregister_dev(intf, &usb_sisusb_class);
 
 	mutex_lock(&sisusb->lock);
@@ -3384,10 +3279,7 @@ static void sisusb_disconnect(struct usb_interface *intf)
 		ret |= unregister_ioctl32_conversion(SISUSB_GET_CONFIG);
 		ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
 		if (ret) {
-			printk(KERN_ERR
-				"sisusbvga[%d]: Error unregistering "
-				"ioctl32 translations\n",
-				minor);
+			dev_err(&sisusb->sisusb_dev->dev, "Error unregistering ioctl32 translations\n");
 		}
 	}
 #endif
@@ -3400,7 +3292,7 @@ static void sisusb_disconnect(struct usb_interface *intf)
 	/* decrement our usage count */
 	kref_put(&sisusb->kref, sisusb_delete);
 
-	printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
+	dev_info(&sisusb->sisusb_dev->dev, "Disconnected\n");
 }
 
 static struct usb_device_id sisusb_table [] = {
@@ -3424,22 +3316,12 @@ static struct usb_driver sisusb_driver = {
 
 static int __init usb_sisusb_init(void)
 {
-	int retval;
 
 #ifdef INCL_SISUSB_CON
 	sisusb_init_concode();
 #endif
 
-	if (!(retval = usb_register(&sisusb_driver))) {
-
-		printk(KERN_INFO "sisusb: Driver version %d.%d.%d\n",
-			SISUSB_VERSION, SISUSB_REVISION, SISUSB_PATCHLEVEL);
-		printk(KERN_INFO
-			"sisusb: Copyright (C) 2005 Thomas Winischhofer\n");
-
-	}
-
-	return retval;
+	return usb_register(&sisusb_driver);
 }
 
 static void __exit usb_sisusb_exit(void)

+ 63 - 67
drivers/usb/misc/sisusbvga/sisusb.h

@@ -8,29 +8,29 @@
  *
  * Otherwise, the following license terms apply:
  *
- * * Redistribution and use in source and binary forms, with or without
- * * modification, are permitted provided that the following conditions
- * * are met:
- * * 1) Redistributions of source code must retain the above copyright
- * *    notice, this list of conditions and the following disclaimer.
- * * 2) Redistributions in binary form must reproduce the above copyright
- * *    notice, this list of conditions and the following disclaimer in the
- * *    documentation and/or other materials provided with the distribution.
- * * 3) The name of the author may not be used to endorse or promote products
- * *    derived from this software without specific prior written permission.
- * *
- * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
- * * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1) Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2) Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3) The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
  *
- * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESSED OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Author:	Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
@@ -44,16 +44,14 @@
 #include <linux/mutex.h>
 
 /* For older kernels, support for text consoles is by default
- * off. To ensable text console support, change the following:
+ * off. To enable text console support, change the following:
  */
-#if 0
-#define CONFIG_USB_SISUSBVGA_CON
-#endif
+/* #define CONFIG_USB_SISUSBVGA_CON */
 
 /* Version Information */
 
 #define SISUSB_VERSION		0
-#define SISUSB_REVISION 	0
+#define SISUSB_REVISION		0
 #define SISUSB_PATCHLEVEL	8
 
 /* Include console and mode switching code? */
@@ -74,7 +72,7 @@
 #define SISUSB_IBUF_SIZE  0x01000
 #define SISUSB_OBUF_SIZE  0x10000	/* fixed */
 
-#define NUMOBUFS 8			/* max number of output buffers/output URBs */
+#define NUMOBUFS 8		/* max number of output buffers/output URBs */
 
 /* About endianness:
  *
@@ -93,7 +91,7 @@
  */
 
 #ifdef __BIG_ENDIAN
-#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) 		\
+#define SISUSB_CORRECT_ENDIANNESS_PACKET(p)		\
 	do {						\
 		p->header  = cpu_to_le16(p->header);	\
 		p->address = cpu_to_le32(p->address);	\
@@ -105,7 +103,7 @@
 
 struct sisusb_usb_data;
 
-struct sisusb_urb_context {		/* urb->context for outbound bulk URBs */
+struct sisusb_urb_context {	/* urb->context for outbound bulk URBs */
 	struct sisusb_usb_data *sisusb;
 	int urbindex;
 	int *actual_length;
@@ -116,16 +114,16 @@ struct sisusb_usb_data {
 	struct usb_interface *interface;
 	struct kref kref;
 	wait_queue_head_t wait_q;	/* for syncind and timeouts */
-	struct mutex lock;		/* general race avoidance */
-	unsigned int ifnum;		/* interface number of the USB device */
-	int minor;			/* minor (for logging clarity) */
-	int isopen;			/* !=0 if open */
-	int present;			/* !=0 if device is present on the bus */
-	int ready;			/* !=0 if device is ready for userland */
+	struct mutex lock;	/* general race avoidance */
+	unsigned int ifnum;	/* interface number of the USB device */
+	int minor;		/* minor (for logging clarity) */
+	int isopen;		/* !=0 if open */
+	int present;		/* !=0 if device is present on the bus */
+	int ready;		/* !=0 if device is ready for userland */
 #ifdef SISUSB_OLD_CONFIG_COMPAT
 	int ioctl32registered;
 #endif
-	int numobufs;			/* number of obufs = number of out urbs */
+	int numobufs;		/* number of obufs = number of out urbs */
 	char *obuf[NUMOBUFS], *ibuf;	/* transfer buffers */
 	int obufsize, ibufsize;
 	dma_addr_t transfer_dma_out[NUMOBUFS];
@@ -136,13 +134,13 @@ struct sisusb_usb_data {
 	unsigned char completein;
 	struct sisusb_urb_context urbout_context[NUMOBUFS];
 	unsigned long flagb0;
-	unsigned long vrambase;		/* framebuffer base */
-	unsigned int vramsize;		/* framebuffer size (bytes) */
+	unsigned long vrambase;	/* framebuffer base */
+	unsigned int vramsize;	/* framebuffer size (bytes) */
 	unsigned long mmiobase;
 	unsigned int mmiosize;
 	unsigned long ioportbase;
-	unsigned char devinit;		/* device initialized? */
-	unsigned char gfxinit;		/* graphics core initialized? */
+	unsigned char devinit;	/* device initialized? */
+	unsigned char gfxinit;	/* graphics core initialized? */
 	unsigned short chipid, chipvendor;
 	unsigned short chiprevision;
 #ifdef INCL_SISUSB_CON
@@ -152,7 +150,7 @@ struct sisusb_usb_data {
 	int haveconsole, con_first, con_last;
 	int havethisconsole[MAX_NR_CONSOLES];
 	int textmodedestroyed;
-	unsigned int sisusb_num_columns; /* real number, not vt's idea */
+	unsigned int sisusb_num_columns;	/* real number, not vt's idea */
 	int cur_start_addr, con_rolled_over;
 	int sisusb_cursor_loc, bad_cursor_pos;
 	int sisusb_cursor_size_from;
@@ -197,7 +195,7 @@ struct sisusb_packet {
 	unsigned short header;
 	u32 address;
 	u32 data;
-} __attribute__((__packed__));
+} __attribute__ ((__packed__));
 
 #define CLEARPACKET(packet) memset(packet, 0, 10)
 
@@ -265,36 +263,36 @@ struct sisusb_packet {
 
 /* Structure argument for SISUSB_GET_INFO ioctl  */
 struct sisusb_info {
-	__u32	sisusb_id;		/* for identifying sisusb */
-#define SISUSB_ID  0x53495355		/* Identify myself with 'SISU' */
-	__u8	sisusb_version;
-	__u8	sisusb_revision;
-	__u8	sisusb_patchlevel;
-	__u8	sisusb_gfxinit;		/* graphics core initialized? */
+	__u32 sisusb_id;	/* for identifying sisusb */
+#define SISUSB_ID  0x53495355	/* Identify myself with 'SISU' */
+	__u8 sisusb_version;
+	__u8 sisusb_revision;
+	__u8 sisusb_patchlevel;
+	__u8 sisusb_gfxinit;	/* graphics core initialized? */
 
-	__u32	sisusb_vrambase;
-	__u32	sisusb_mmiobase;
-	__u32	sisusb_iobase;
-	__u32	sisusb_pcibase;
+	__u32 sisusb_vrambase;
+	__u32 sisusb_mmiobase;
+	__u32 sisusb_iobase;
+	__u32 sisusb_pcibase;
 
-	__u32	sisusb_vramsize;	/* framebuffer size in bytes */
+	__u32 sisusb_vramsize;	/* framebuffer size in bytes */
 
-	__u32	sisusb_minor;
+	__u32 sisusb_minor;
 
-	__u32   sisusb_fbdevactive;	/* != 0 if framebuffer device active */
+	__u32 sisusb_fbdevactive;	/* != 0 if framebuffer device active */
 
-	__u32   sisusb_conactive;	/* != 0 if console driver active */
+	__u32 sisusb_conactive;	/* != 0 if console driver active */
 
-	__u8	sisusb_reserved[28];	/* for future use */
+	__u8 sisusb_reserved[28];	/* for future use */
 };
 
 struct sisusb_command {
-	__u8   operation;	/* see below */
-	__u8   data0;		/* operation dependent */
-	__u8   data1;		/* operation dependent */
-	__u8   data2;		/* operation dependent */
-	__u32  data3;		/* operation dependent */
-	__u32  data4;		/* for future use */
+	__u8 operation;		/* see below */
+	__u8 data0;		/* operation dependent */
+	__u8 data1;		/* operation dependent */
+	__u8 data2;		/* operation dependent */
+	__u32 data3;		/* operation dependent */
+	__u32 data4;		/* for future use */
 };
 
 #define SUCMD_GET	0x01	/* for all: data0 = index, data3 = port */
@@ -306,7 +304,7 @@ struct sisusb_command {
 
 #define SUCMD_CLRSCR	0x07	/* data0:1:2 = length, data3 = address */
 
-#define SUCMD_HANDLETEXTMODE 0x08 /* Reset/destroy text mode */
+#define SUCMD_HANDLETEXTMODE 0x08	/* Reset/destroy text mode */
 
 #define SUCMD_SETMODE	0x09	/* Set a display mode (data3 = SiS mode) */
 #define SUCMD_SETVESAMODE 0x0a	/* Set a display mode (data3 = VESA mode) */
@@ -315,6 +313,4 @@ struct sisusb_command {
 #define SISUSB_GET_CONFIG_SIZE	_IOR(0xF3,0x3E,__u32)
 #define SISUSB_GET_CONFIG	_IOR(0xF3,0x3F,struct sisusb_info)
 
-
 #endif /* SISUSB_H */
-

+ 5 - 55
drivers/usb/misc/sisusbvga/sisusb_con.c

@@ -52,6 +52,7 @@
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/fs.h>
+#include <linux/usb.h>
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/string.h>
@@ -373,14 +374,6 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x)
 		return;
 
 	/* sisusb->lock is down */
-
-	/* Don't need to put the character into buffer ourselves,
-	 * because the vt does this BEFORE calling us.
-	 */
-#if 0
-	sisusbcon_writew(ch, SISUSB_VADDR(x, y));
-#endif
-
 	if (sisusb_is_inactive(c, sisusb)) {
 		mutex_unlock(&sisusb->lock);
 		return;
@@ -490,10 +483,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx,
 	struct sisusb_usb_data *sisusb;
 	ssize_t written;
 	int cols, length;
-#if 0
-	u16 *src, *dest;
-	int i;
-#endif
 
 	if (width <= 0 || height <= 0)
 		return;
@@ -505,41 +494,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx,
 
 	cols = sisusb->sisusb_num_columns;
 
-	/* Don't need to move data outselves, because
-	 * vt does this BEFORE calling us.
-	 * This is only used by vt's insert/deletechar.
-	 */
-#if 0
-	if (sx == 0 && dx == 0 && width >= c->vc_cols && width <= cols) {
-
-		sisusbcon_memmovew(SISUSB_VADDR(0, dy), SISUSB_VADDR(0, sy),
-					height * width * 2);
-
-	} else if (dy < sy || (dy == sy && dx < sx)) {
-
-		src  = SISUSB_VADDR(sx, sy);
-		dest = SISUSB_VADDR(dx, dy);
-
-		for (i = height; i > 0; i--) {
-			sisusbcon_memmovew(dest, src, width * 2);
-			src  += cols;
-			dest += cols;
-		}
-
-	} else {
-
-		src  = SISUSB_VADDR(sx, sy + height - 1);
-		dest = SISUSB_VADDR(dx, dy + height - 1);
-
-		for (i = height; i > 0; i--) {
-			sisusbcon_memmovew(dest, src, width * 2);
-			src  -= cols;
-			dest -= cols;
-		}
-
-	}
-#endif
-
 	if (sisusb_is_inactive(c, sisusb)) {
 		mutex_unlock(&sisusb->lock);
 		return;
@@ -584,7 +538,7 @@ sisusbcon_switch(struct vc_data *c)
 	 */
 	if (c->vc_origin == (unsigned long)c->vc_screenbuf) {
 		mutex_unlock(&sisusb->lock);
-		printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n");
+		dev_dbg(&sisusb->sisusb_dev->dev, "ASSERT ORIGIN != SCREENBUF!\n");
 		return 0;
 	}
 
@@ -1475,7 +1429,7 @@ static const struct consw sisusb_dummy_con = {
 int
 sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
 {
-	int i, ret, minor = sisusb->minor;
+	int i, ret;
 
 	mutex_lock(&sisusb->lock);
 
@@ -1508,9 +1462,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
 	/* Set up text mode (and upload  default font) */
 	if (sisusb_reset_text_mode(sisusb, 1)) {
 		mutex_unlock(&sisusb->lock);
-		printk(KERN_ERR
-			"sisusbvga[%d]: Failed to set up text mode\n",
-			minor);
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to set up text mode\n");
 		return 1;
 	}
 
@@ -1531,9 +1483,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
 	/* Allocate screen buffer */
 	if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
 		mutex_unlock(&sisusb->lock);
-		printk(KERN_ERR
-			"sisusbvga[%d]: Failed to allocate screen buffer\n",
-			minor);
+		dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate screen buffer\n");
 		return 1;
 	}
 

+ 134 - 220
drivers/usb/misc/sisusbvga/sisusb_init.c

@@ -32,7 +32,7 @@
  * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ * Author:	Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
@@ -55,109 +55,18 @@
 /*         POINTER INITIALIZATION            */
 /*********************************************/
 
-static void
-SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
+static void SiSUSB_InitPtr(struct SiS_Private *SiS_Pr)
 {
-	SiS_Pr->SiS_ModeResInfo   = SiSUSB_ModeResInfo;
-	SiS_Pr->SiS_StandTable    = SiSUSB_StandTable;
-
-	SiS_Pr->SiS_SModeIDTable  = SiSUSB_SModeIDTable;
-	SiS_Pr->SiS_EModeIDTable  = SiSUSB_EModeIDTable;
-	SiS_Pr->SiS_RefIndex      = SiSUSB_RefIndex;
-	SiS_Pr->SiS_CRT1Table     = SiSUSB_CRT1Table;
-
-	SiS_Pr->SiS_VCLKData      = SiSUSB_VCLKData;
-}
-
-/*********************************************/
-/*            HELPER: Get ModeID             */
-/*********************************************/
+	SiS_Pr->SiS_ModeResInfo = SiSUSB_ModeResInfo;
+	SiS_Pr->SiS_StandTable = SiSUSB_StandTable;
 
-#if 0
-unsigned short
-SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
-{
-	unsigned short ModeIndex = 0;
-
-	switch (HDisplay)
-	{
-		case 320:
-			if (VDisplay == 200)
-				ModeIndex = ModeIndex_320x200[Depth];
-			else if (VDisplay == 240)
-				ModeIndex = ModeIndex_320x240[Depth];
-			break;
-		case 400:
-			if (VDisplay == 300)
-				ModeIndex = ModeIndex_400x300[Depth];
-			break;
-		case 512:
-			if (VDisplay == 384)
-				ModeIndex = ModeIndex_512x384[Depth];
-			break;
-		case 640:
-			if (VDisplay == 480)
-				ModeIndex = ModeIndex_640x480[Depth];
-			else if (VDisplay == 400)
-				ModeIndex = ModeIndex_640x400[Depth];
-			break;
-		case 720:
-			if (VDisplay == 480)
-				ModeIndex = ModeIndex_720x480[Depth];
-			else if (VDisplay == 576)
-				ModeIndex = ModeIndex_720x576[Depth];
-			break;
-		case 768:
-			if (VDisplay == 576)
-				ModeIndex = ModeIndex_768x576[Depth];
-			break;
-		case 800:
-			if (VDisplay == 600)
-				ModeIndex = ModeIndex_800x600[Depth];
-			else if (VDisplay == 480)
-				ModeIndex = ModeIndex_800x480[Depth];
-			break;
-		case 848:
-			if (VDisplay == 480)
-				ModeIndex = ModeIndex_848x480[Depth];
-			break;
-		case 856:
-			if (VDisplay == 480)
-				ModeIndex = ModeIndex_856x480[Depth];
-			break;
-		case 960:
-			if (VDisplay == 540)
-				ModeIndex = ModeIndex_960x540[Depth];
-			else if (VDisplay == 600)
-				ModeIndex = ModeIndex_960x600[Depth];
-			break;
-		case 1024:
-			if (VDisplay == 576)
-				ModeIndex = ModeIndex_1024x576[Depth];
-			else if (VDisplay == 768)
-				ModeIndex = ModeIndex_1024x768[Depth];
-			break;
-		case 1152:
-			if (VDisplay == 864)
-				ModeIndex = ModeIndex_1152x864[Depth];
-			break;
-		case 1280:
-			switch (VDisplay) {
-				case 720:
-					ModeIndex = ModeIndex_1280x720[Depth];
-					break;
-				case 768:
-					ModeIndex = ModeIndex_1280x768[Depth];
-					break;
-				case 1024:
-					ModeIndex = ModeIndex_1280x1024[Depth];
-					break;
-			}
-	}
+	SiS_Pr->SiS_SModeIDTable = SiSUSB_SModeIDTable;
+	SiS_Pr->SiS_EModeIDTable = SiSUSB_EModeIDTable;
+	SiS_Pr->SiS_RefIndex = SiSUSB_RefIndex;
+	SiS_Pr->SiS_CRT1Table = SiSUSB_CRT1Table;
 
-	return ModeIndex;
+	SiS_Pr->SiS_VCLKData = SiSUSB_VCLKData;
 }
-#endif  /*  0  */
 
 /*********************************************/
 /*          HELPER: SetReg, GetReg           */
@@ -165,21 +74,20 @@ SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
 
 static void
 SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port,
-			unsigned short index, unsigned short data)
+	   unsigned short index, unsigned short data)
 {
 	sisusb_setidxreg(SiS_Pr->sisusb, port, index, data);
 }
 
 static void
 SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port,
-						unsigned short data)
+	       unsigned short data)
 {
 	sisusb_setreg(SiS_Pr->sisusb, port, data);
 }
 
 static unsigned char
-SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port,
-						unsigned short index)
+SiS_GetReg(struct SiS_Private *SiS_Pr, unsigned long port, unsigned short index)
 {
 	u8 data;
 
@@ -200,22 +108,22 @@ SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port)
 
 static void
 SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port,
-			unsigned short index, unsigned short DataAND,
-						unsigned short DataOR)
+		unsigned short index, unsigned short DataAND,
+		unsigned short DataOR)
 {
 	sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR);
 }
 
 static void
 SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port,
-			unsigned short index, unsigned short DataAND)
+	      unsigned short index, unsigned short DataAND)
 {
 	sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND);
 }
 
 static void
-SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port,
-			unsigned short index, unsigned short DataOR)
+SiS_SetRegOR(struct SiS_Private *SiS_Pr, unsigned long port,
+	     unsigned short index, unsigned short DataOR)
 {
 	sisusb_setidxregor(SiS_Pr->sisusb, port, index, DataOR);
 }
@@ -224,8 +132,7 @@ SiS_SetRegOR(struct SiS_Private *SiS_Pr,unsigned long port,
 /*      HELPER: DisplayOn, DisplayOff        */
 /*********************************************/
 
-static void
-SiS_DisplayOn(struct SiS_Private *SiS_Pr)
+static void SiS_DisplayOn(struct SiS_Private *SiS_Pr)
 {
 	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, 0xDF);
 }
@@ -234,8 +141,7 @@ SiS_DisplayOn(struct SiS_Private *SiS_Pr)
 /*        HELPER: Init Port Addresses        */
 /*********************************************/
 
-static void
-SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
+static void SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
 {
 	SiS_Pr->SiS_P3c4 = BaseAddr + 0x14;
 	SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
@@ -258,8 +164,7 @@ SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
 /*             HELPER: GetSysFlags           */
 /*********************************************/
 
-static void
-SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
+static void SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
 {
 	SiS_Pr->SiS_MyCR63 = 0x63;
 }
@@ -268,8 +173,7 @@ SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
 /*         HELPER: Init PCI & Engines        */
 /*********************************************/
 
-static void
-SiSInitPCIetc(struct SiS_Private *SiS_Pr)
+static void SiSInitPCIetc(struct SiS_Private *SiS_Pr)
 {
 	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1);
 	/*  - Enable 2D (0x40)
@@ -285,8 +189,7 @@ SiSInitPCIetc(struct SiS_Private *SiS_Pr)
 /*        HELPER: SET SEGMENT REGISTERS      */
 /*********************************************/
 
-static void
-SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
 {
 	unsigned short temp;
 
@@ -299,8 +202,7 @@ SiS_SetSegRegLower(struct SiS_Private *SiS_Pr, unsigned short value)
 	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
 }
 
-static void
-SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
 {
 	unsigned short temp;
 
@@ -313,15 +215,13 @@ SiS_SetSegRegUpper(struct SiS_Private *SiS_Pr, unsigned short value)
 	SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3cd, temp);
 }
 
-static void
-SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
+static void SiS_SetSegmentReg(struct SiS_Private *SiS_Pr, unsigned short value)
 {
 	SiS_SetSegRegLower(SiS_Pr, value);
 	SiS_SetSegRegUpper(SiS_Pr, value);
 }
 
-static void
-SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentReg(struct SiS_Private *SiS_Pr)
 {
 	SiS_SetSegmentReg(SiS_Pr, 0);
 }
@@ -337,14 +237,12 @@ SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value)
 	SiS_SetSegmentReg(SiS_Pr, value);
 }
 
-static void
-SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentRegOver(struct SiS_Private *SiS_Pr)
 {
 	SiS_SetSegmentRegOver(SiS_Pr, 0);
 }
 
-static void
-SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
+static void SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
 {
 	SiS_ResetSegmentReg(SiS_Pr);
 	SiS_ResetSegmentRegOver(SiS_Pr);
@@ -356,7 +254,7 @@ SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
 
 static int
 SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
-						unsigned short *ModeIdIndex)
+		 unsigned short *ModeIdIndex)
 {
 	if ((*ModeNo) <= 0x13) {
 
@@ -367,12 +265,14 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
 
 	} else {
 
-		for(*ModeIdIndex = 0; ;(*ModeIdIndex)++) {
+		for (*ModeIdIndex = 0;; (*ModeIdIndex)++) {
 
-			if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == (*ModeNo))
+			if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
+			    (*ModeNo))
 				break;
 
-			if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)
+			if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
+			    0xFF)
 				return 0;
 		}
 
@@ -385,8 +285,7 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
 /*            HELPER: ENABLE CRT1            */
 /*********************************************/
 
-static void
-SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
+static void SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
 {
 	/* Enable CRT1 gating */
 	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf);
@@ -398,9 +297,9 @@ SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
 
 static unsigned short
 SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-		unsigned short ModeIdIndex)
+		  unsigned short ModeIdIndex)
 {
-	static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8};
+	static const unsigned short ColorDepth[6] = { 1, 2, 4, 4, 6, 8 };
 	unsigned short modeflag;
 	short index;
 
@@ -411,7 +310,8 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 	}
 
 	index = (modeflag & ModeTypeMask) - ModeEGA;
-	if (index < 0) index = 0;
+	if (index < 0)
+		index = 0;
 	return ColorDepth[index];
 }
 
@@ -421,7 +321,7 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static unsigned short
 SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-		unsigned short ModeIdIndex, unsigned short rrti)
+	      unsigned short ModeIdIndex, unsigned short rrti)
 {
 	unsigned short xres, temp, colordepth, infoflag;
 
@@ -458,8 +358,8 @@ SiS_SetSeqRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
 	SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20;
 	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata);
 
-	for(i = 2; i <= 4; i++) {
-		SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i-1];
+	for (i = 2; i <= 4; i++) {
+		SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[i - 1];
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, SRdata);
 	}
 }
@@ -488,7 +388,7 @@ SiS_SetCRTCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
 
 	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
 
-	for(i = 0; i <= 0x18; i++) {
+	for (i = 0; i <= 0x18; i++) {
 		CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata);
 	}
@@ -504,7 +404,7 @@ SiS_SetATTRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
 	unsigned char ARdata;
 	unsigned short i;
 
-	for(i = 0; i <= 0x13; i++) {
+	for (i = 0; i <= 0x13; i++) {
 		ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
 		SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
 		SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i);
@@ -529,7 +429,7 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
 	unsigned char GRdata;
 	unsigned short i;
 
-	for(i = 0; i <= 0x08; i++) {
+	for (i = 0; i <= 0x08; i++) {
 		GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i];
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata);
 	}
@@ -544,12 +444,11 @@ SiS_SetGRCRegs(struct SiS_Private *SiS_Pr, unsigned short StandTableIndex)
 /*          CLEAR EXTENDED REGISTERS         */
 /*********************************************/
 
-static void
-SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
+static void SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
 {
 	int i;
 
-	for(i = 0x0A; i <= 0x0E; i++) {
+	for (i = 0x0A; i <= 0x0E; i++) {
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00);
 	}
 
@@ -562,15 +461,16 @@ SiS_ClearExt1Regs(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
 
 static unsigned short
 SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-					unsigned short ModeIdIndex)
+	       unsigned short ModeIdIndex)
 {
 	unsigned short rrti, i, index, temp;
 
 	if (ModeNo <= 0x13)
 		return 0xFFFF;
 
-	index = SiS_GetReg(SiS_Pr,SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
-	if (index > 0) index--;
+	index = SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x33) & 0x0F;
+	if (index > 0)
+		index--;
 
 	rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
 	ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID;
@@ -580,13 +480,14 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 		if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo)
 			break;
 
-		temp = SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
+		temp =
+		    SiS_Pr->SiS_RefIndex[rrti + i].Ext_InfoFlag & ModeTypeMask;
 		if (temp < SiS_Pr->SiS_ModeType)
 			break;
 
 		i++;
 		index--;
-	} while(index != 0xFFFF);
+	} while (index != 0xFFFF);
 
 	i--;
 
@@ -597,8 +498,7 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 /*                  SYNC                     */
 /*********************************************/
 
-static void
-SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
+static void SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
 {
 	unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8;
 	sync &= 0xC0;
@@ -612,39 +512,40 @@ SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
 
 static void
 SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-			unsigned short ModeIdIndex, unsigned short rrti)
+		unsigned short ModeIdIndex, unsigned short rrti)
 {
-	unsigned char  index;
+	unsigned char index;
 	unsigned short temp, i, j, modeflag;
 
-	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4,0x11,0x7f);
+	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, 0x11, 0x7f);
 
 	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
 	index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC;
 
-	for(i = 0,j = 0; i <= 7; i++, j++) {
+	for (i = 0, j = 0; i <= 7; i++, j++) {
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
-				SiS_Pr->SiS_CRT1Table[index].CR[i]);
+			   SiS_Pr->SiS_CRT1Table[index].CR[i]);
 	}
-	for(j = 0x10; i <= 10; i++, j++) {
+	for (j = 0x10; i <= 10; i++, j++) {
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
-				SiS_Pr->SiS_CRT1Table[index].CR[i]);
+			   SiS_Pr->SiS_CRT1Table[index].CR[i]);
 	}
-	for(j = 0x15; i <= 12; i++, j++) {
+	for (j = 0x15; i <= 12; i++, j++) {
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, j,
-				SiS_Pr->SiS_CRT1Table[index].CR[i]);
+			   SiS_Pr->SiS_CRT1Table[index].CR[i]);
 	}
-	for(j = 0x0A; i <= 15; i++, j++) {
+	for (j = 0x0A; i <= 15; i++, j++) {
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, j,
-				SiS_Pr->SiS_CRT1Table[index].CR[i]);
+			   SiS_Pr->SiS_CRT1Table[index].CR[i]);
 	}
 
 	temp = SiS_Pr->SiS_CRT1Table[index].CR[16] & 0xE0;
-	SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4, 0x0E, temp);
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0E, temp);
 
 	temp = ((SiS_Pr->SiS_CRT1Table[index].CR[16]) & 0x01) << 5;
-	if (modeflag & DoubleScanMode)  temp |= 0x80;
+	if (modeflag & DoubleScanMode)
+		temp |= 0x80;
 	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp);
 
 	if (SiS_Pr->SiS_ModeType > ModeVGA)
@@ -659,10 +560,10 @@ SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static void
 SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-			unsigned short ModeIdIndex, unsigned short rrti)
+		  unsigned short ModeIdIndex, unsigned short rrti)
 {
 	unsigned short du = SiS_GetOffset(SiS_Pr, ModeNo, ModeIdIndex, rrti);
-	unsigned short infoflag =  SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
+	unsigned short infoflag = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag;
 	unsigned short temp;
 
 	temp = (du >> 8) & 0x0f;
@@ -670,11 +571,13 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF));
 
-	if (infoflag & InterlaceMode) du >>= 1;
+	if (infoflag & InterlaceMode)
+		du >>= 1;
 
 	du <<= 5;
 	temp = (du >> 8) & 0xff;
-	if (du & 0xff) temp++;
+	if (du & 0xff)
+		temp++;
 	temp++;
 	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, temp);
 }
@@ -685,17 +588,17 @@ SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static void
 SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-						unsigned short rrti)
+		unsigned short rrti)
 {
 	unsigned short index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK;
 	unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B;
 	unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C;
 
-	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4,0x31,0xCF);
+	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3c4, 0x31, 0xCF);
 
-	SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2B,clka);
-	SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2C,clkb);
-	SiS_SetReg(SiS_Pr,SiS_Pr->SiS_P3c4,0x2D,0x01);
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2B, clka);
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2C, clkb);
+	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x2D, 0x01);
 }
 
 /*********************************************/
@@ -704,7 +607,7 @@ SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static void
 SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-							unsigned short mi)
+		    unsigned short mi)
 {
 	unsigned short modeflag = SiS_Pr->SiS_EModeIDTable[mi].Ext_ModeFlag;
 
@@ -729,7 +632,7 @@ SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static void
 SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-							unsigned short rrti)
+		 unsigned short rrti)
 {
 	unsigned short data = 0, VCLK = 0, index = 0;
 
@@ -738,7 +641,8 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 		VCLK = SiS_Pr->SiS_VCLKData[index].CLOCK;
 	}
 
-	if (VCLK >= 166) data |= 0x0c;
+	if (VCLK >= 166)
+		data |= 0x0c;
 	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data);
 
 	if (VCLK >= 166)
@@ -758,7 +662,7 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static void
 SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-			unsigned short ModeIdIndex, unsigned short rrti)
+		    unsigned short ModeIdIndex, unsigned short rrti)
 {
 	unsigned short data, infoflag = 0, modeflag;
 
@@ -778,17 +682,22 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 			data |= 0x02;
 			data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2);
 		}
-		if (infoflag & InterlaceMode) data |= 0x20;
+		if (infoflag & InterlaceMode)
+			data |= 0x20;
 	}
 	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data);
 
 	data = 0;
 	if (infoflag & InterlaceMode) {
 		/* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */
-		unsigned short hrs = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
-			((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2)) - 3;
-		unsigned short hto = (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
-			((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8)) + 5;
+		unsigned short hrs =
+		    (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x04) |
+		     ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0xc0) << 2))
+		    - 3;
+		unsigned short hto =
+		    (SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x00) |
+		     ((SiS_GetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x0b) & 0x03) << 8))
+		    + 5;
 		data = hrs - (hto >> 1) + 3;
 	}
 	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF));
@@ -829,20 +738,26 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 static void
 SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
-		unsigned short shiftflag, unsigned short dl, unsigned short ah,
-		unsigned short al, unsigned short dh)
+	     unsigned short shiftflag, unsigned short dl, unsigned short ah,
+	     unsigned short al, unsigned short dh)
 {
 	unsigned short d1, d2, d3;
 
 	switch (dl) {
-		case  0:
-			d1 = dh; d2 = ah; d3 = al;
-			break;
-		case  1:
-			d1 = ah; d2 = al; d3 = dh;
-			break;
-		default:
-			d1 = al; d2 = dh; d3 = ah;
+	case 0:
+		d1 = dh;
+		d2 = ah;
+		d3 = al;
+		break;
+	case 1:
+		d1 = ah;
+		d2 = al;
+		d3 = dh;
+		break;
+	default:
+		d1 = al;
+		d2 = dh;
+		d3 = ah;
 	}
 	SiS_SetRegByte(SiS_Pr, DACData, (d1 << shiftflag));
 	SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag));
@@ -850,7 +765,8 @@ SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
 }
 
 static void
-SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi)
+SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
+	    unsigned short mi)
 {
 	unsigned short data, data2, time, i, j, k, m, n, o;
 	unsigned short si, di, bx, sf;
@@ -884,41 +800,45 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi
 
 	SiS_SetRegByte(SiS_Pr, DACAddr, 0x00);
 
-	for(i = 0; i < j; i++) {
+	for (i = 0; i < j; i++) {
 		data = table[i];
-		for(k = 0; k < 3; k++) {
+		for (k = 0; k < 3; k++) {
 			data2 = 0;
-			if (data & 0x01) data2 += 0x2A;
-			if (data & 0x02) data2 += 0x15;
+			if (data & 0x01)
+				data2 += 0x2A;
+			if (data & 0x02)
+				data2 += 0x15;
 			SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf));
 			data >>= 2;
 		}
 	}
 
 	if (time == 256) {
-		for(i = 16; i < 32; i++) {
+		for (i = 16; i < 32; i++) {
 			data = table[i] << sf;
-			for(k = 0; k < 3; k++)
+			for (k = 0; k < 3; k++)
 				SiS_SetRegByte(SiS_Pr, DACData, data);
 		}
 		si = 32;
-		for(m = 0; m < 9; m++) {
+		for (m = 0; m < 9; m++) {
 			di = si;
 			bx = si + 4;
-			for(n = 0; n < 3; n++) {
-				for(o = 0; o < 5; o++) {
+			for (n = 0; n < 3; n++) {
+				for (o = 0; o < 5; o++) {
 					SiS_WriteDAC(SiS_Pr, DACData, sf, n,
-						table[di], table[bx], table[si]);
+						     table[di], table[bx],
+						     table[si]);
 					si++;
 				}
 				si -= 2;
-				for(o = 0; o < 3; o++) {
+				for (o = 0; o < 3; o++) {
 					SiS_WriteDAC(SiS_Pr, DACData, sf, n,
-						table[di], table[si], table[bx]);
+						     table[di], table[si],
+						     table[bx]);
 					si--;
 				}
 			}
-		si += 5;
+			si += 5;
 		}
 	}
 }
@@ -929,7 +849,7 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi
 
 static void
 SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-					unsigned short ModeIdIndex)
+		 unsigned short ModeIdIndex)
 {
 	unsigned short StandTableIndex, rrti;
 
@@ -970,11 +890,10 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 /*                 SiSSetMode()              */
 /*********************************************/
 
-int
-SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
+int SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
 {
 	unsigned short ModeIdIndex;
-	unsigned long  BaseAddr = SiS_Pr->IOAddress;
+	unsigned long BaseAddr = SiS_Pr->IOAddress;
 
 	SiSUSB_InitPtr(SiS_Pr);
 	SiSUSBRegInit(SiS_Pr, BaseAddr);
@@ -990,7 +909,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
 	ModeNo &= 0x7f;
 
 	SiS_Pr->SiS_ModeType =
-		SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
+	    SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag & ModeTypeMask;
 
 	SiS_Pr->SiS_SetFlag = LowModeTests;
 
@@ -1008,8 +927,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
 	return 1;
 }
 
-int
-SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
+int SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
 {
 	unsigned short ModeNo = 0;
 	int i;
@@ -1041,7 +959,3 @@ SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
 }
 
 #endif /* INCL_SISUSB_CON */
-
-
-
-

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 657 - 657
drivers/usb/misc/sisusbvga/sisusb_init.h


+ 68 - 76
drivers/usb/misc/sisusbvga/sisusb_struct.h

@@ -44,7 +44,7 @@
  * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * Author: 	Thomas Winischhofer <thomas@winischhofer.net>
+ * Author:	Thomas Winischhofer <thomas@winischhofer.net>
  *
  */
 
@@ -52,85 +52,78 @@
 #define _SISUSB_STRUCT_H_
 
 struct SiS_St {
-	unsigned char	St_ModeID;
-	unsigned short	St_ModeFlag;
-	unsigned char	St_StTableIndex;
-	unsigned char	St_CRT2CRTC;
-	unsigned char	St_ResInfo;
-	unsigned char	VB_StTVFlickerIndex;
-	unsigned char	VB_StTVEdgeIndex;
-	unsigned char	VB_StTVYFilterIndex;
-	unsigned char	St_PDC;
+	unsigned char St_ModeID;
+	unsigned short St_ModeFlag;
+	unsigned char St_StTableIndex;
+	unsigned char St_CRT2CRTC;
+	unsigned char St_ResInfo;
+	unsigned char VB_StTVFlickerIndex;
+	unsigned char VB_StTVEdgeIndex;
+	unsigned char VB_StTVYFilterIndex;
+	unsigned char St_PDC;
 };
 
-struct SiS_StandTable
-{
-	unsigned char	CRT_COLS;
-	unsigned char	ROWS;
-	unsigned char	CHAR_HEIGHT;
-	unsigned short	CRT_LEN;
-	unsigned char	SR[4];
-	unsigned char	MISC;
-	unsigned char	CRTC[0x19];
-	unsigned char	ATTR[0x14];
-	unsigned char	GRC[9];
+struct SiS_StandTable {
+	unsigned char CRT_COLS;
+	unsigned char ROWS;
+	unsigned char CHAR_HEIGHT;
+	unsigned short CRT_LEN;
+	unsigned char SR[4];
+	unsigned char MISC;
+	unsigned char CRTC[0x19];
+	unsigned char ATTR[0x14];
+	unsigned char GRC[9];
 };
 
 struct SiS_StResInfo_S {
-	unsigned short	HTotal;
-	unsigned short	VTotal;
+	unsigned short HTotal;
+	unsigned short VTotal;
 };
 
-struct SiS_Ext
-{
-	unsigned char	Ext_ModeID;
-	unsigned short	Ext_ModeFlag;
-	unsigned short	Ext_VESAID;
-	unsigned char	Ext_RESINFO;
-	unsigned char	VB_ExtTVFlickerIndex;
-	unsigned char	VB_ExtTVEdgeIndex;
-	unsigned char	VB_ExtTVYFilterIndex;
-	unsigned char	VB_ExtTVYFilterIndexROM661;
-	unsigned char	REFindex;
-	char		ROMMODEIDX661;
+struct SiS_Ext {
+	unsigned char Ext_ModeID;
+	unsigned short Ext_ModeFlag;
+	unsigned short Ext_VESAID;
+	unsigned char Ext_RESINFO;
+	unsigned char VB_ExtTVFlickerIndex;
+	unsigned char VB_ExtTVEdgeIndex;
+	unsigned char VB_ExtTVYFilterIndex;
+	unsigned char VB_ExtTVYFilterIndexROM661;
+	unsigned char REFindex;
+	char ROMMODEIDX661;
 };
 
-struct SiS_Ext2
-{
-	unsigned short	Ext_InfoFlag;
-	unsigned char	Ext_CRT1CRTC;
-	unsigned char	Ext_CRTVCLK;
-	unsigned char	Ext_CRT2CRTC;
-	unsigned char	Ext_CRT2CRTC_NS;
-	unsigned char	ModeID;
-	unsigned short	XRes;
-	unsigned short	YRes;
-	unsigned char	Ext_PDC;
-	unsigned char	Ext_FakeCRT2CRTC;
-	unsigned char	Ext_FakeCRT2Clk;
+struct SiS_Ext2 {
+	unsigned short Ext_InfoFlag;
+	unsigned char Ext_CRT1CRTC;
+	unsigned char Ext_CRTVCLK;
+	unsigned char Ext_CRT2CRTC;
+	unsigned char Ext_CRT2CRTC_NS;
+	unsigned char ModeID;
+	unsigned short XRes;
+	unsigned short YRes;
+	unsigned char Ext_PDC;
+	unsigned char Ext_FakeCRT2CRTC;
+	unsigned char Ext_FakeCRT2Clk;
 };
 
-struct SiS_CRT1Table
-{
-	unsigned char	CR[17];
+struct SiS_CRT1Table {
+	unsigned char CR[17];
 };
 
-struct SiS_VCLKData
-{
-	unsigned char	SR2B,SR2C;
-	unsigned short	CLOCK;
+struct SiS_VCLKData {
+	unsigned char SR2B, SR2C;
+	unsigned short CLOCK;
 };
 
-struct SiS_ModeResInfo
-{
-	unsigned short	HTotal;
-	unsigned short	VTotal;
-	unsigned char	XChar;
-	unsigned char	YChar;
+struct SiS_ModeResInfo {
+	unsigned short HTotal;
+	unsigned short VTotal;
+	unsigned char XChar;
+	unsigned char YChar;
 };
 
-struct SiS_Private
-{
+struct SiS_Private {
 	void *sisusb;
 
 	unsigned long IOAddress;
@@ -151,19 +144,18 @@ struct SiS_Private
 	unsigned long SiS_P3da;
 	unsigned long SiS_Part1Port;
 
-	unsigned char	SiS_MyCR63;
-	unsigned short	SiS_CRT1Mode;
-	unsigned short	SiS_ModeType;
-	unsigned short	SiS_SetFlag;
-
-	const struct SiS_StandTable	*SiS_StandTable;
-	const struct SiS_St		*SiS_SModeIDTable;
-	const struct SiS_Ext		*SiS_EModeIDTable;
-	const struct SiS_Ext2		*SiS_RefIndex;
-	const struct SiS_CRT1Table	*SiS_CRT1Table;
-	const struct SiS_VCLKData	*SiS_VCLKData;
-	const struct SiS_ModeResInfo	*SiS_ModeResInfo;
+	unsigned char SiS_MyCR63;
+	unsigned short SiS_CRT1Mode;
+	unsigned short SiS_ModeType;
+	unsigned short SiS_SetFlag;
+
+	const struct SiS_StandTable *SiS_StandTable;
+	const struct SiS_St *SiS_SModeIDTable;
+	const struct SiS_Ext *SiS_EModeIDTable;
+	const struct SiS_Ext2 *SiS_RefIndex;
+	const struct SiS_CRT1Table *SiS_CRT1Table;
+	const struct SiS_VCLKData *SiS_VCLKData;
+	const struct SiS_ModeResInfo *SiS_ModeResInfo;
 };
 
 #endif
-

+ 23 - 19
drivers/usb/mon/mon_bin.c

@@ -172,6 +172,10 @@ static inline struct mon_bin_hdr *MON_OFF2HDR(const struct mon_reader_bin *rp,
 
 #define MON_RING_EMPTY(rp)	((rp)->b_cnt == 0)
 
+static unsigned char xfer_to_pipe[4] = {
+	PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
+};
+
 static struct class *mon_bin_class;
 static dev_t mon_bin_dev0;
 static struct cdev mon_bin_cdev;
@@ -354,13 +358,9 @@ static inline char mon_bin_get_setup(unsigned char *setupb,
     const struct urb *urb, char ev_type)
 {
 
-	if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+	if (!usb_endpoint_xfer_control(&urb->ep->desc) || ev_type != 'S')
 		return '-';
 
-	if (urb->dev->bus->uses_dma &&
-	    (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
-		return mon_dmapeek(setupb, urb->setup_dma, SETUP_LEN);
-	}
 	if (urb->setup_packet == NULL)
 		return 'Z';
 
@@ -386,13 +386,15 @@ static char mon_bin_get_data(const struct mon_reader_bin *rp,
 }
 
 static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
-    char ev_type)
+    char ev_type, int status)
 {
+	const struct usb_endpoint_descriptor *epd = &urb->ep->desc;
 	unsigned long flags;
 	struct timeval ts;
 	unsigned int urb_length;
 	unsigned int offset;
 	unsigned int length;
+	unsigned char dir;
 	struct mon_bin_hdr *ep;
 	char data_tag = 0;
 
@@ -410,16 +412,19 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
 	if (length >= rp->b_size/5)
 		length = rp->b_size/5;
 
-	if (usb_pipein(urb->pipe)) {
+	if (usb_urb_dir_in(urb)) {
 		if (ev_type == 'S') {
 			length = 0;
 			data_tag = '<';
 		}
+		/* Cannot rely on endpoint number in case of control ep.0 */
+		dir = USB_DIR_IN;
 	} else {
 		if (ev_type == 'C') {
 			length = 0;
 			data_tag = '>';
 		}
+		dir = 0;
 	}
 
 	if (rp->mmap_active)
@@ -440,15 +445,14 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
 	 */
 	memset(ep, 0, PKT_SIZE);
 	ep->type = ev_type;
-	ep->xfer_type = usb_pipetype(urb->pipe);
-	/* We use the fact that usb_pipein() returns 0x80 */
-	ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
-	ep->devnum = usb_pipedevice(urb->pipe);
+	ep->xfer_type = xfer_to_pipe[usb_endpoint_type(epd)];
+	ep->epnum = dir | usb_endpoint_num(epd);
+	ep->devnum = urb->dev->devnum;
 	ep->busnum = urb->dev->bus->busnum;
 	ep->id = (unsigned long) urb;
 	ep->ts_sec = ts.tv_sec;
 	ep->ts_usec = ts.tv_usec;
-	ep->status = urb->status;
+	ep->status = status;
 	ep->len_urb = urb_length;
 	ep->len_cap = length;
 
@@ -471,13 +475,13 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
 static void mon_bin_submit(void *data, struct urb *urb)
 {
 	struct mon_reader_bin *rp = data;
-	mon_bin_event(rp, urb, 'S');
+	mon_bin_event(rp, urb, 'S', -EINPROGRESS);
 }
 
-static void mon_bin_complete(void *data, struct urb *urb)
+static void mon_bin_complete(void *data, struct urb *urb, int status)
 {
 	struct mon_reader_bin *rp = data;
-	mon_bin_event(rp, urb, 'C');
+	mon_bin_event(rp, urb, 'C', status);
 }
 
 static void mon_bin_error(void *data, struct urb *urb, int error)
@@ -500,10 +504,10 @@ static void mon_bin_error(void *data, struct urb *urb, int error)
 
 	memset(ep, 0, PKT_SIZE);
 	ep->type = 'E';
-	ep->xfer_type = usb_pipetype(urb->pipe);
-	/* We use the fact that usb_pipein() returns 0x80 */
-	ep->epnum = usb_pipeendpoint(urb->pipe) | usb_pipein(urb->pipe);
-	ep->devnum = usb_pipedevice(urb->pipe);
+	ep->xfer_type = xfer_to_pipe[usb_endpoint_type(&urb->ep->desc)];
+	ep->epnum = usb_urb_dir_in(urb) ? USB_DIR_IN : 0;
+	ep->epnum |= usb_endpoint_num(&urb->ep->desc);
+	ep->devnum = urb->dev->devnum;
 	ep->busnum = urb->dev->bus->busnum;
 	ep->id = (unsigned long) urb;
 	ep->status = error;

+ 8 - 17
drivers/usb/mon/mon_main.c

@@ -129,7 +129,8 @@ static void mon_submit_error(struct usb_bus *ubus, struct urb *urb, int error)
 
 /*
  */
-static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb)
+static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb,
+		int status)
 {
 	unsigned long flags;
 	struct list_head *pos;
@@ -139,28 +140,18 @@ static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb)
 	mbus->cnt_events++;
 	list_for_each (pos, &mbus->r_list) {
 		r = list_entry(pos, struct mon_reader, r_link);
-		r->rnf_complete(r->r_data, urb);
+		r->rnf_complete(r->r_data, urb, status);
 	}
 	spin_unlock_irqrestore(&mbus->lock, flags);
 }
 
-static void mon_complete(struct usb_bus *ubus, struct urb *urb)
+static void mon_complete(struct usb_bus *ubus, struct urb *urb, int status)
 {
 	struct mon_bus *mbus;
 
-	mbus = ubus->mon_bus;
-	if (mbus == NULL) {
-		/*
-		 * This should not happen.
-		 * At this point we do not even know the bus number...
-		 */
-		printk(KERN_ERR TAG ": Null mon bus in URB, pipe 0x%x\n",
-		    urb->pipe);
-		return;
-	}
-
-	mon_bus_complete(mbus, urb);
-	mon_bus_complete(&mon_bus0, urb);
+	if ((mbus = ubus->mon_bus) != NULL)
+		mon_bus_complete(mbus, urb, status);
+	mon_bus_complete(&mon_bus0, urb, status);
 }
 
 /* int (*unlink_urb) (struct urb *urb, int status); */
@@ -170,7 +161,7 @@ static void mon_complete(struct usb_bus *ubus, struct urb *urb)
  */
 static void mon_stop(struct mon_bus *mbus)
 {
-	struct usb_bus *ubus = mbus->u_bus;
+	struct usb_bus *ubus;
 	struct list_head *p;
 
 	if (mbus == &mon_bus0) {

+ 37 - 35
drivers/usb/mon/mon_text.c

@@ -50,10 +50,13 @@ struct mon_iso_desc {
 struct mon_event_text {
 	struct list_head e_link;
 	int type;		/* submit, complete, etc. */
-	unsigned int pipe;	/* Pipe */
 	unsigned long id;	/* From pointer, most of the time */
 	unsigned int tstamp;
 	int busnum;
+	char devnum;
+	char epnum;
+	char is_in;
+	char xfertype;
 	int length;		/* Depends on type: xfer length or act length */
 	int status;
 	int interval;
@@ -121,13 +124,9 @@ static inline char mon_text_get_setup(struct mon_event_text *ep,
     struct urb *urb, char ev_type, struct mon_bus *mbus)
 {
 
-	if (!usb_pipecontrol(urb->pipe) || ev_type != 'S')
+	if (ep->xfertype != USB_ENDPOINT_XFER_CONTROL || ev_type != 'S')
 		return '-';
 
-	if (urb->dev->bus->uses_dma &&
-	    (urb->transfer_flags & URB_NO_SETUP_DMA_MAP)) {
-		return mon_dmapeek(ep->setup, urb->setup_dma, SETUP_MAX);
-	}
 	if (urb->setup_packet == NULL)
 		return 'Z';	/* '0' would be not as pretty. */
 
@@ -138,14 +137,12 @@ static inline char mon_text_get_setup(struct mon_event_text *ep,
 static inline char mon_text_get_data(struct mon_event_text *ep, struct urb *urb,
     int len, char ev_type, struct mon_bus *mbus)
 {
-	int pipe = urb->pipe;
-
 	if (len <= 0)
 		return 'L';
 	if (len >= DATA_MAX)
 		len = DATA_MAX;
 
-	if (usb_pipein(pipe)) {
+	if (ep->is_in) {
 		if (ev_type != 'C')
 			return '<';
 	} else {
@@ -186,7 +183,7 @@ static inline unsigned int mon_get_timestamp(void)
 }
 
 static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
-    char ev_type)
+    char ev_type, int status)
 {
 	struct mon_event_text *ep;
 	unsigned int stamp;
@@ -203,24 +200,28 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
 	}
 
 	ep->type = ev_type;
-	ep->pipe = urb->pipe;
 	ep->id = (unsigned long) urb;
 	ep->busnum = urb->dev->bus->busnum;
+	ep->devnum = urb->dev->devnum;
+	ep->epnum = usb_endpoint_num(&urb->ep->desc);
+	ep->xfertype = usb_endpoint_type(&urb->ep->desc);
+	ep->is_in = usb_urb_dir_in(urb);
 	ep->tstamp = stamp;
 	ep->length = (ev_type == 'S') ?
 	    urb->transfer_buffer_length : urb->actual_length;
 	/* Collecting status makes debugging sense for submits, too */
-	ep->status = urb->status;
+	ep->status = status;
 
-	if (usb_pipeint(urb->pipe)) {
+	if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
 		ep->interval = urb->interval;
-	} else if (usb_pipeisoc(urb->pipe)) {
+	} else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
 		ep->interval = urb->interval;
 		ep->start_frame = urb->start_frame;
 		ep->error_count = urb->error_count;
 	}
 	ep->numdesc = urb->number_of_packets;
-	if (usb_pipeisoc(urb->pipe) && urb->number_of_packets > 0) {
+	if (ep->xfertype == USB_ENDPOINT_XFER_ISOC &&
+			urb->number_of_packets > 0) {
 		if ((ndesc = urb->number_of_packets) > ISODESC_MAX)
 			ndesc = ISODESC_MAX;
 		fp = urb->iso_frame_desc;
@@ -247,13 +248,13 @@ static void mon_text_event(struct mon_reader_text *rp, struct urb *urb,
 static void mon_text_submit(void *data, struct urb *urb)
 {
 	struct mon_reader_text *rp = data;
-	mon_text_event(rp, urb, 'S');
+	mon_text_event(rp, urb, 'S', -EINPROGRESS);
 }
 
-static void mon_text_complete(void *data, struct urb *urb)
+static void mon_text_complete(void *data, struct urb *urb, int status)
 {
 	struct mon_reader_text *rp = data;
-	mon_text_event(rp, urb, 'C');
+	mon_text_event(rp, urb, 'C', status);
 }
 
 static void mon_text_error(void *data, struct urb *urb, int error)
@@ -268,9 +269,12 @@ static void mon_text_error(void *data, struct urb *urb, int error)
 	}
 
 	ep->type = 'E';
-	ep->pipe = urb->pipe;
 	ep->id = (unsigned long) urb;
 	ep->busnum = 0;
+	ep->devnum = urb->dev->devnum;
+	ep->epnum = usb_endpoint_num(&urb->ep->desc);
+	ep->xfertype = usb_endpoint_type(&urb->ep->desc);
+	ep->is_in = usb_urb_dir_in(urb);
 	ep->tstamp = 0;
 	ep->length = 0;
 	ep->status = error;
@@ -413,10 +417,10 @@ static ssize_t mon_text_read_u(struct file *file, char __user *buf,
 	mon_text_read_head_u(rp, &ptr, ep);
 	if (ep->type == 'E') {
 		mon_text_read_statset(rp, &ptr, ep);
-	} else if (usb_pipeisoc(ep->pipe)) {
+	} else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
 		mon_text_read_isostat(rp, &ptr, ep);
 		mon_text_read_isodesc(rp, &ptr, ep);
-	} else if (usb_pipeint(ep->pipe)) {
+	} else if (ep->xfertype == USB_ENDPOINT_XFER_INT) {
 		mon_text_read_intstat(rp, &ptr, ep);
 	} else {
 		mon_text_read_statset(rp, &ptr, ep);
@@ -468,18 +472,17 @@ static void mon_text_read_head_t(struct mon_reader_text *rp,
 {
 	char udir, utype;
 
-	udir = usb_pipein(ep->pipe) ? 'i' : 'o';
-	switch (usb_pipetype(ep->pipe)) {
-	case PIPE_ISOCHRONOUS:	utype = 'Z'; break;
-	case PIPE_INTERRUPT:	utype = 'I'; break;
-	case PIPE_CONTROL:	utype = 'C'; break;
+	udir = (ep->is_in ? 'i' : 'o');
+	switch (ep->xfertype) {
+	case USB_ENDPOINT_XFER_ISOC:	utype = 'Z'; break;
+	case USB_ENDPOINT_XFER_INT:	utype = 'I'; break;
+	case USB_ENDPOINT_XFER_CONTROL:	utype = 'C'; break;
 	default: /* PIPE_BULK */  utype = 'B';
 	}
 	p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
 	    "%lx %u %c %c%c:%03u:%02u",
 	    ep->id, ep->tstamp, ep->type,
-	    utype, udir,
-	    usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+	    utype, udir, ep->devnum, ep->epnum);
 }
 
 static void mon_text_read_head_u(struct mon_reader_text *rp,
@@ -487,18 +490,17 @@ static void mon_text_read_head_u(struct mon_reader_text *rp,
 {
 	char udir, utype;
 
-	udir = usb_pipein(ep->pipe) ? 'i' : 'o';
-	switch (usb_pipetype(ep->pipe)) {
-	case PIPE_ISOCHRONOUS:	utype = 'Z'; break;
-	case PIPE_INTERRUPT:	utype = 'I'; break;
-	case PIPE_CONTROL:	utype = 'C'; break;
+	udir = (ep->is_in ? 'i' : 'o');
+	switch (ep->xfertype) {
+	case USB_ENDPOINT_XFER_ISOC:	utype = 'Z'; break;
+	case USB_ENDPOINT_XFER_INT:	utype = 'I'; break;
+	case USB_ENDPOINT_XFER_CONTROL:	utype = 'C'; break;
 	default: /* PIPE_BULK */  utype = 'B';
 	}
 	p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
 	    "%lx %u %c %c%c:%d:%03u:%u",
 	    ep->id, ep->tstamp, ep->type,
-	    utype, udir,
-	    ep->busnum, usb_pipedevice(ep->pipe), usb_pipeendpoint(ep->pipe));
+	    utype, udir, ep->busnum, ep->devnum, ep->epnum);
 }
 
 static void mon_text_read_statset(struct mon_reader_text *rp,

+ 1 - 1
drivers/usb/mon/usb_mon.h

@@ -46,7 +46,7 @@ struct mon_reader {
 
 	void (*rnf_submit)(void *data, struct urb *urb);
 	void (*rnf_error)(void *data, struct urb *urb, int error);
-	void (*rnf_complete)(void *data, struct urb *urb);
+	void (*rnf_complete)(void *data, struct urb *urb, int status);
 };
 
 void mon_reader_add(struct mon_bus *mbus, struct mon_reader *r);

+ 10 - 0
drivers/usb/serial/Kconfig

@@ -92,6 +92,16 @@ config USB_SERIAL_BELKIN
 	  To compile this driver as a module, choose M here: the
 	  module will be called belkin_sa.
 
+config USB_SERIAL_CH341
+	tristate "USB Winchiphead CH341 Single Port Serial Driver"
+	depends on USB_SERIAL
+	help
+	  Say Y here if you want to use a Winchiphead CH341 single port
+	  USB to serial adapter.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ch341.
+
 config USB_SERIAL_WHITEHEAT
 	tristate "USB ConnectTech WhiteHEAT Serial Driver"
 	depends on USB_SERIAL

+ 1 - 0
drivers/usb/serial/Makefile

@@ -15,6 +15,7 @@ obj-$(CONFIG_USB_SERIAL_AIRCABLE)		+= aircable.o
 obj-$(CONFIG_USB_SERIAL_AIRPRIME)		+= airprime.o
 obj-$(CONFIG_USB_SERIAL_ARK3116)		+= ark3116.o
 obj-$(CONFIG_USB_SERIAL_BELKIN)			+= belkin_sa.o
+obj-$(CONFIG_USB_SERIAL_CH341)			+= ch341.o
 obj-$(CONFIG_USB_SERIAL_CP2101)			+= cp2101.o
 obj-$(CONFIG_USB_SERIAL_CYBERJACK)		+= cyberjack.o
 obj-$(CONFIG_USB_SERIAL_CYPRESS_M8)		+= cypress_m8.o

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

@@ -172,11 +172,6 @@ static void ark3116_set_termios(struct usb_serial_port *port,
 
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
-	if (!port->tty || !port->tty->termios) {
-		dbg("%s - no tty structures", __FUNCTION__);
-		return;
-	}
-
 	spin_lock_irqsave(&priv->lock, flags);
 	if (!priv->termios_initialized) {
 		*(port->tty->termios) = tty_std_termios;

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

@@ -36,6 +36,16 @@ static int usb_serial_device_match (struct device *dev, struct device_driver *dr
 	return 0;
 }
 
+static ssize_t show_port_number(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct usb_serial_port *port = to_usb_serial_port(dev);
+
+	return sprintf(buf, "%d\n", port->number - port->serial->minor);
+}
+
+static DEVICE_ATTR(port_number, S_IRUGO, show_port_number, NULL);
+
 static int usb_serial_device_probe (struct device *dev)
 {
 	struct usb_serial_driver *driver;
@@ -62,6 +72,10 @@ static int usb_serial_device_probe (struct device *dev)
 			goto exit;
 	}
 
+	retval = device_create_file(dev, &dev_attr_port_number);
+	if (retval)
+		goto exit;
+
 	minor = port->number;
 	tty_register_device (usb_serial_tty_driver, minor, dev);
 	dev_info(&port->serial->dev->dev, 
@@ -84,6 +98,8 @@ static int usb_serial_device_remove (struct device *dev)
 		return -ENODEV;
 	}
 
+	device_remove_file(&port->dev, &dev_attr_port_number);
+
 	driver = port->serial->type;
 	if (driver->port_remove) {
 		if (!try_module_get(driver->driver.owner)) {

+ 354 - 0
drivers/usb/serial/ch341.c

@@ -0,0 +1,354 @@
+/*
+ * Copyright 2007, Frank A Kingswood <frank@kingswood-consulting.co.uk>
+ *
+ * ch341.c implements a serial port driver for the Winchiphead CH341.
+ *
+ * The CH341 device can be used to implement an RS232 asynchronous
+ * serial port, an IEEE-1284 parallel printer port or a memory-like
+ * interface. In all cases the CH341 supports an I2C interface as well.
+ * This driver only supports the asynchronous serial interface.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+#include <linux/serial.h>
+
+#define DEFAULT_BAUD_RATE 2400
+#define DEFAULT_TIMEOUT   1000
+
+static int debug;
+
+static struct usb_device_id id_table [] = {
+	{ USB_DEVICE(0x4348, 0x5523) },
+	{ },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+struct ch341_private {
+	unsigned baud_rate;
+	u8 dtr;
+	u8 rts;
+};
+
+static int ch341_control_out(struct usb_device *dev, u8 request,
+			     u16 value, u16 index)
+{
+	int r;
+	dbg("ch341_control_out(%02x,%02x,%04x,%04x)", USB_DIR_OUT|0x40,
+		(int)request, (int)value, (int)index);
+
+	r = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), request,
+			    USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+			    value, index, NULL, 0, DEFAULT_TIMEOUT);
+
+	return r;
+}
+
+static int ch341_control_in(struct usb_device *dev,
+			    u8 request, u16 value, u16 index,
+			    char *buf, unsigned bufsize)
+{
+	int r;
+	dbg("ch341_control_in(%02x,%02x,%04x,%04x,%p,%u)", USB_DIR_IN|0x40,
+		(int)request, (int)value, (int)index, buf, (int)bufsize);
+
+	r = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), request,
+			    USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+			    value, index, buf, bufsize, DEFAULT_TIMEOUT);
+	return r;
+}
+
+static int ch341_set_baudrate(struct usb_device *dev,
+			      struct ch341_private *priv)
+{
+	short a, b;
+	int r;
+
+	dbg("ch341_set_baudrate(%d)", priv->baud_rate);
+	switch (priv->baud_rate) {
+	case 2400:
+		a = 0xd901;
+		b = 0x0038;
+		break;
+	case 4800:
+		a = 0x6402;
+		b = 0x001f;
+		break;
+	case 9600:
+		a = 0xb202;
+		b = 0x0013;
+		break;
+	case 19200:
+		a = 0xd902;
+		b = 0x000d;
+		break;
+	case 38400:
+		a = 0x6403;
+		b = 0x000a;
+		break;
+	case 115200:
+		a = 0xcc03;
+		b = 0x0008;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	r = ch341_control_out(dev, 0x9a, 0x1312, a);
+	if (!r)
+		r = ch341_control_out(dev, 0x9a, 0x0f2c, b);
+
+	return r;
+}
+
+static int ch341_set_handshake(struct usb_device *dev,
+			       struct ch341_private *priv)
+{
+	dbg("ch341_set_handshake(%d,%d)", priv->dtr, priv->rts);
+	return ch341_control_out(dev, 0xa4,
+		~((priv->dtr?1<<5:0)|(priv->rts?1<<6:0)), 0);
+}
+
+static int ch341_get_status(struct usb_device *dev)
+{
+	char *buffer;
+	int r;
+	const unsigned size = 8;
+
+	dbg("ch341_get_status()");
+
+	buffer = kmalloc(size, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	r = ch341_control_in(dev, 0x95, 0x0706, 0, buffer, size);
+	if ( r < 0)
+		goto out;
+
+	/* Not having the datasheet for the CH341, we ignore the bytes returned
+	 * from the device. Return error if the device did not respond in time.
+	 */
+	r = 0;
+
+out:	kfree(buffer);
+	return r;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int ch341_configure(struct usb_device *dev, struct ch341_private *priv)
+{
+	char *buffer;
+	int r;
+	const unsigned size = 8;
+
+	dbg("ch341_configure()");
+
+	buffer = kmalloc(size, GFP_KERNEL);
+	if (!buffer)
+		return -ENOMEM;
+
+	/* expect two bytes 0x27 0x00 */
+	r = ch341_control_in(dev, 0x5f, 0, 0, buffer, size);
+	if (r < 0)
+		goto out;
+
+	r = ch341_control_out(dev, 0xa1, 0, 0);
+	if (r < 0)
+		goto out;
+
+	r = ch341_set_baudrate(dev, priv);
+	if (r < 0)
+		goto out;
+
+	/* expect two bytes 0x56 0x00 */
+	r = ch341_control_in(dev, 0x95, 0x2518, 0, buffer, size);
+	if (r < 0)
+		goto out;
+
+	r = ch341_control_out(dev, 0x9a, 0x2518, 0x0050);
+	if (r < 0)
+		goto out;
+
+	/* expect 0xff 0xee */
+	r = ch341_get_status(dev);
+	if (r < 0)
+		goto out;
+
+	r = ch341_control_out(dev, 0xa1, 0x501f, 0xd90a);
+	if (r < 0)
+		goto out;
+
+	r = ch341_set_baudrate(dev, priv);
+	if (r < 0)
+		goto out;
+
+	r = ch341_set_handshake(dev, priv);
+	if (r < 0)
+		goto out;
+
+	/* expect 0x9f 0xee */
+	r = ch341_get_status(dev);
+
+out:	kfree(buffer);
+	return r;
+}
+
+/* allocate private data */
+static int ch341_attach(struct usb_serial *serial)
+{
+	struct ch341_private *priv;
+	int r;
+
+	dbg("ch341_attach()");
+
+	/* private data */
+	priv = kzalloc(sizeof(struct ch341_private), GFP_KERNEL);
+	if (!priv)
+		return -ENOMEM;
+
+	priv->baud_rate = DEFAULT_BAUD_RATE;
+	priv->dtr = 1;
+	priv->rts = 1;
+
+	r = ch341_configure(serial->dev, priv);
+	if (r < 0)
+		goto error;
+
+	usb_set_serial_port_data(serial->port[0], priv);
+	return 0;
+
+error:	kfree(priv);
+	return r;
+}
+
+/* open this device, set default parameters */
+static int ch341_open(struct usb_serial_port *port, struct file *filp)
+{
+	struct usb_serial *serial = port->serial;
+	struct ch341_private *priv = usb_get_serial_port_data(serial->port[0]);
+	int r;
+
+	dbg("ch341_open()");
+
+	priv->baud_rate = DEFAULT_BAUD_RATE;
+	priv->dtr = 1;
+	priv->rts = 1;
+
+	r = ch341_configure(serial->dev, priv);
+	if (r)
+		goto out;
+
+	r = ch341_set_handshake(serial->dev, priv);
+	if (r)
+		goto out;
+
+	r = ch341_set_baudrate(serial->dev, priv);
+	if (r)
+		goto out;
+
+	r = usb_serial_generic_open(port, filp);
+
+out:	return r;
+}
+
+/* Old_termios contains the original termios settings and
+ * tty->termios contains the new setting to be used.
+ */
+static void ch341_set_termios(struct usb_serial_port *port,
+			      struct ktermios *old_termios)
+{
+	struct ch341_private *priv = usb_get_serial_port_data(port);
+	struct tty_struct *tty = port->tty;
+	unsigned baud_rate;
+
+	dbg("ch341_set_termios()");
+
+	if (!tty || !tty->termios)
+		return;
+
+	baud_rate = tty_get_baud_rate(tty);
+
+	switch (baud_rate) {
+	case 2400:
+	case 4800:
+	case 9600:
+	case 19200:
+	case 38400:
+	case 115200:
+		priv->baud_rate = baud_rate;
+		break;
+	default:
+		dbg("Rate %d not supported, using %d",
+			baud_rate, DEFAULT_BAUD_RATE);
+		priv->baud_rate = DEFAULT_BAUD_RATE;
+	}
+
+	ch341_set_baudrate(port->serial->dev, priv);
+
+	/* Unimplemented:
+	 * (cflag & CSIZE) : data bits [5, 8]
+	 * (cflag & PARENB) : parity {NONE, EVEN, ODD}
+	 * (cflag & CSTOPB) : stop bits [1, 2]
+	 */
+}
+
+static struct usb_driver ch341_driver = {
+	.name		= "ch341",
+	.probe		= usb_serial_probe,
+	.disconnect	= usb_serial_disconnect,
+	.id_table	= id_table,
+	.no_dynamic_id	= 1,
+};
+
+static struct usb_serial_driver ch341_device = {
+	.driver = {
+		.owner	= THIS_MODULE,
+		.name	= "ch341-uart",
+	},
+	.id_table         = id_table,
+	.usb_driver       = &ch341_driver,
+	.num_interrupt_in = NUM_DONT_CARE,
+	.num_bulk_in      = 1,
+	.num_bulk_out     = 1,
+	.num_ports        = 1,
+	.open             = ch341_open,
+	.set_termios      = ch341_set_termios,
+	.attach           = ch341_attach,
+};
+
+static int __init ch341_init(void)
+{
+	int retval;
+
+	retval = usb_serial_register(&ch341_device);
+	if (retval)
+		return retval;
+	retval = usb_register(&ch341_driver);
+	if (retval)
+		usb_serial_deregister(&ch341_device);
+	return retval;
+}
+
+static void __exit ch341_exit(void)
+{
+	usb_deregister(&ch341_driver);
+	usb_serial_deregister(&ch341_device);
+}
+
+module_init(ch341_init);
+module_exit(ch341_exit);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
+/* EOF ch341.c */

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

@@ -53,6 +53,7 @@ static void cp2101_shutdown(struct usb_serial*);
 static int debug;
 
 static struct usb_device_id id_table [] = {
+	{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
 	{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
 	{ USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
 	{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 Cable */
@@ -521,7 +522,7 @@ static void cp2101_set_termios (struct usb_serial_port *port,
 
 	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__);
 		return;
 	}

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

@@ -1169,7 +1169,9 @@ static void remove_sysfs_attrs(struct usb_serial_port *port)
 	/* XXX see create_sysfs_attrs */
 	if (priv->chip_type != SIO) {
 		device_remove_file(&port->dev, &dev_attr_event_char);
-		if (priv->chip_type == FT232BM || priv->chip_type == FT2232C) {
+		if (priv->chip_type == FT232BM ||
+		    priv->chip_type == FT2232C ||
+		    priv->chip_type == FT232RL) {
 			device_remove_file(&port->dev, &dev_attr_latency_timer);
 		}
 	}
@@ -2102,6 +2104,7 @@ static int ftdi_tiocmget (struct usb_serial_port *port, struct file *file)
 	case FT8U232AM:
 	case FT232BM:
 	case FT2232C:
+	case FT232RL:
 		/* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
 		   format as the data returned from the in point */
 		if ((ret = usb_control_msg(port->serial->dev,

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

@@ -24,26 +24,6 @@ static struct usb_device_id id_table [] = {
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static int funsoft_ioctl(struct usb_serial_port *port, struct file *file,
-			 unsigned int cmd, unsigned long arg)
-{
-	struct ktermios t;
-
-	dbg("%s - port %d, cmd 0x%04x", __FUNCTION__, port->number, cmd);
-
-	if (cmd == TCSETSF) {
-		if (user_termios_to_kernel_termios(&t, (struct termios __user *)arg))
-			return -EFAULT;
-
-		dbg("%s - iflag:%x oflag:%x cflag:%x lflag:%x", __FUNCTION__,
-		    t.c_iflag, t.c_oflag, t.c_cflag, t.c_lflag);
-
-		if (!(t.c_lflag & ICANON))
-			return -EINVAL;
-	}
-	return -ENOIOCTLCMD;
-}
-
 static struct usb_driver funsoft_driver = {
 	.name =		"funsoft",
 	.probe =	usb_serial_probe,
@@ -63,7 +43,6 @@ static struct usb_serial_driver funsoft_device = {
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,
 	.num_ports =		1,
-	.ioctl =		funsoft_ioctl,
 };
 
 static int __init funsoft_init(void)

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

@@ -256,6 +256,7 @@ static struct usb_device_id ipaq_id_table [] = {
 	{ USB_DEVICE(0x04DD, 0x9121) }, /* SHARP WS004SH USB Modem */
 	{ USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */
 	{ USB_DEVICE(0x04DD, 0x9151) }, /* SHARP S01SH USB Modem */
+	{ USB_DEVICE(0x04DD, 0x91AC) }, /* SHARP WS011SH USB Modem */
 	{ USB_DEVICE(0x04E8, 0x5F00) }, /* Samsung NEXiO USB Sync */
 	{ USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */
 	{ USB_DEVICE(0x04E8, 0x5F02) }, /* Samsung NEXiO USB Sync */
@@ -646,11 +647,13 @@ static int ipaq_open(struct usb_serial_port *port, struct file *filp)
 	kfree(port->bulk_out_buffer);
 	port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
 	if (port->bulk_in_buffer == NULL) {
+		port->bulk_out_buffer = NULL; /* prevent double free */
 		goto enomem;
 	}
 	port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
 	if (port->bulk_out_buffer == NULL) {
 		kfree(port->bulk_in_buffer);
+		port->bulk_in_buffer = NULL;
 		goto enomem;
 	}
 	port->read_urb->transfer_buffer = port->bulk_in_buffer;

+ 18 - 10
drivers/usb/serial/kl5kusb105.c

@@ -728,24 +728,32 @@ static void klsi_105_set_termios (struct usb_serial_port *port,
 #endif
 		}
 		
-		switch(cflag & CBAUD) {
-		case B0: /* handled below */
+		switch(tty_get_baud_rate(port->tty)) {
+		case 0: /* handled below */
 			break;
-		case B1200: priv->cfg.baudrate = kl5kusb105a_sio_b1200;
+		case 1200:
+			priv->cfg.baudrate = kl5kusb105a_sio_b1200;
 			break;
-		case B2400: priv->cfg.baudrate = kl5kusb105a_sio_b2400;
+		case 2400:
+			priv->cfg.baudrate = kl5kusb105a_sio_b2400;
 			break;
-		case B4800: priv->cfg.baudrate = kl5kusb105a_sio_b4800;
+		case 4800:
+			priv->cfg.baudrate = kl5kusb105a_sio_b4800;
 			break;
-		case B9600: priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+		case 9600:
+			priv->cfg.baudrate = kl5kusb105a_sio_b9600;
 			break;
-		case B19200: priv->cfg.baudrate = kl5kusb105a_sio_b19200;
+		case 19200:
+			priv->cfg.baudrate = kl5kusb105a_sio_b19200;
 			break;
-		case B38400: priv->cfg.baudrate = kl5kusb105a_sio_b38400;
+		case 38400:
+			priv->cfg.baudrate = kl5kusb105a_sio_b38400;
 			break;
-		case B57600: priv->cfg.baudrate = kl5kusb105a_sio_b57600;
+		case 57600:
+			priv->cfg.baudrate = kl5kusb105a_sio_b57600;
 			break;
-		case B115200: priv->cfg.baudrate = kl5kusb105a_sio_b115200;
+		case 115200:
+			priv->cfg.baudrate = kl5kusb105a_sio_b115200;
 			break;
 		default:
 			err("KLSI USB->Serial converter:"

+ 55 - 89
drivers/usb/serial/kobil_sct.c

@@ -82,6 +82,7 @@ static int  kobil_tiocmset(struct usb_serial_port *port, struct file *file,
 			   unsigned int set, unsigned int clear);
 static void kobil_read_int_callback( struct urb *urb );
 static void kobil_write_callback( struct urb *purb );
+static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old);
 
 
 static struct usb_device_id id_table [] = {
@@ -119,6 +120,7 @@ static struct usb_serial_driver kobil_device = {
 	.attach =		kobil_startup,
 	.shutdown =		kobil_shutdown,
 	.ioctl =		kobil_ioctl,
+	.set_termios =		kobil_set_termios,
 	.tiocmget =		kobil_tiocmget,
 	.tiocmset =		kobil_tiocmset,
 	.open =			kobil_open,
@@ -137,7 +139,6 @@ struct kobil_private {
 	int cur_pos; // index of the next char to send in buf
 	__u16 device_type;
 	int line_state;
-	struct ktermios internal_termios;
 };
 
 
@@ -216,7 +217,7 @@ static void kobil_shutdown (struct usb_serial *serial)
 
 static int kobil_open (struct usb_serial_port *port, struct file *filp)
 {
-	int i, result = 0;
+	int result = 0;
 	struct kobil_private *priv;
 	unsigned char *transfer_buffer;
 	int transfer_buffer_length = 8;
@@ -242,16 +243,6 @@ static int kobil_open (struct usb_serial_port *port, struct file *filp)
 	port->tty->termios->c_iflag = IGNBRK | IGNPAR | IXOFF;
 	port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D)
 	
-	// set up internal termios structure 
-	priv->internal_termios.c_iflag = port->tty->termios->c_iflag;
-	priv->internal_termios.c_oflag = port->tty->termios->c_oflag;
-	priv->internal_termios.c_cflag = port->tty->termios->c_cflag;
-	priv->internal_termios.c_lflag = port->tty->termios->c_lflag;
-
-	for (i=0; i<NCCS; i++) {
-		priv->internal_termios.c_cc[i] = port->tty->termios->c_cc[i];
-	}
-	
 	// allocate memory for transfer buffer
 	transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
 	if (! transfer_buffer) {
@@ -607,102 +598,79 @@ static int  kobil_tiocmset(struct usb_serial_port *port, struct file *file,
 	return (result < 0) ? result : 0;
 }
 
-
-static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
-			unsigned int cmd, unsigned long arg)
+static void kobil_set_termios(struct usb_serial_port *port, struct ktermios *old)
 {
 	struct kobil_private * priv;
 	int result;
 	unsigned short urb_val = 0;
-	unsigned char *transfer_buffer;
-	int transfer_buffer_length = 8;
-	char *settings;
-	void __user *user_arg = (void __user *)arg;
+	int c_cflag = port->tty->termios->c_cflag;
+	speed_t speed;
+	void * settings;
 
 	priv = usb_get_serial_port_data(port);
-	if ((priv->device_type == KOBIL_USBTWIN_PRODUCT_ID) || (priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)) {
+	if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
 		// This device doesn't support ioctl calls
-		return 0;
-	}
-
-	switch (cmd) {
-	case TCGETS:   // 0x5401
-		if (!access_ok(VERIFY_WRITE, user_arg, sizeof(struct ktermios))) {
-			dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
-			return -EFAULT;
-		}
-		if (kernel_termios_to_user_termios((struct ktermios __user *)arg,
-						   &priv->internal_termios))
-			return -EFAULT;
-		return 0;
-
-	case TCSETS:   // 0x5402
-		if (!(port->tty->termios)) {
-			dbg("%s - port %d Error: port->tty->termios is NULL", __FUNCTION__, port->number);
-			return -ENOTTY;
-		}
-		if (!access_ok(VERIFY_READ, user_arg, sizeof(struct ktermios))) {
-			dbg("%s - port %d Error in access_ok", __FUNCTION__, port->number);
-			return -EFAULT;
-		}
-		if (user_termios_to_kernel_termios(&priv->internal_termios,
-						   (struct ktermios __user *)arg))
-			return -EFAULT;
-		
-		settings = kzalloc(50, GFP_KERNEL);
-		if (! settings) {
-			return -ENOBUFS;
-		}
+		return;
 
-		switch (priv->internal_termios.c_cflag & CBAUD) {
-		case B1200:
+	switch (speed = tty_get_baud_rate(port->tty)) {
+		case 1200:
 			urb_val = SUSBCR_SBR_1200;
-			strcat(settings, "1200 ");
 			break;
-		case B9600:
+		case 9600:
 		default:
 			urb_val = SUSBCR_SBR_9600;
-			strcat(settings, "9600 ");
 			break;
-		}
+	}
+	urb_val |= (c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
+
+	settings = kzalloc(50, GFP_KERNEL);
+	if (! settings)
+		return;
 
-		urb_val |= (priv->internal_termios.c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits : SUSBCR_SPASB_1StopBit;
-		strcat(settings, (priv->internal_termios.c_cflag & CSTOPB) ? "2 StopBits " : "1 StopBit ");
+	sprintf(settings, "%d ", speed);
 
-		if (priv->internal_termios.c_cflag & PARENB) {
-			if  (priv->internal_termios.c_cflag & PARODD) {
-				urb_val |= SUSBCR_SPASB_OddParity;
-				strcat(settings, "Odd Parity");
-			} else {
-				urb_val |= SUSBCR_SPASB_EvenParity;
-				strcat(settings, "Even Parity");
-			}
+	if (c_cflag & PARENB) {
+		if  (c_cflag & PARODD) {
+			urb_val |= SUSBCR_SPASB_OddParity;
+			strcat(settings, "Odd Parity");
 		} else {
-			urb_val |= SUSBCR_SPASB_NoParity;
-			strcat(settings, "No Parity");
+			urb_val |= SUSBCR_SPASB_EvenParity;
+			strcat(settings, "Even Parity");
 		}
-		dbg("%s - port %d setting port to: %s", __FUNCTION__, port->number, settings );
+	} else {
+		urb_val |= SUSBCR_SPASB_NoParity;
+		strcat(settings, "No Parity");
+	}
 
-		result = usb_control_msg( port->serial->dev, 
-					  usb_rcvctrlpipe(port->serial->dev, 0 ), 
-					  SUSBCRequest_SetBaudRateParityAndStopBits,
-					  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
-					  urb_val,
-					  0,
-					  settings,
-					  0,
-					  KOBIL_TIMEOUT
-			);
+	result = usb_control_msg( port->serial->dev,
+				  usb_rcvctrlpipe(port->serial->dev, 0 ),
+				  SUSBCRequest_SetBaudRateParityAndStopBits,
+				  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
+				  urb_val,
+				  0,
+				  settings,
+				  0,
+				  KOBIL_TIMEOUT
+		);
+	kfree(settings);
+}
 
-		dbg("%s - port %d Send set_baudrate URB returns: %i", __FUNCTION__, port->number, result);
-		kfree(settings);
+static int kobil_ioctl(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg)
+{
+	struct kobil_private * priv = usb_get_serial_port_data(port);
+	unsigned char *transfer_buffer;
+	int transfer_buffer_length = 8;
+	int result;
+
+	if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID || priv->device_type == KOBIL_KAAN_SIM_PRODUCT_ID)
+		// This device doesn't support ioctl calls
 		return 0;
 
+	switch (cmd) {
 	case TCFLSH:   // 0x540B
 		transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL);
-		if (! transfer_buffer) {
+		if (! transfer_buffer)
 		 	return -ENOBUFS;
-		}
 
 		result = usb_control_msg( port->serial->dev, 
 		 			  usb_rcvctrlpipe(port->serial->dev, 0 ), 
@@ -716,15 +684,13 @@ static int  kobil_ioctl(struct usb_serial_port *port, struct file *file,
 			);
 		
 		dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result);
-
 		kfree(transfer_buffer);
-		return ((result < 0) ? -EFAULT : 0);
-
+		return (result < 0) ? -EFAULT : 0;
+	default:
+		return -ENOIOCTLCMD;
 	}
-	return -ENOIOCTLCMD;
 }
 
-
 static int __init kobil_init (void)
 {
 	int retval;

+ 14 - 14
drivers/usb/serial/mct_u232.c

@@ -206,20 +206,20 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial, speed_t value
 		}
 	} else {
 		switch (value) {
-			case 300: break;
-			case 600: break;
-			case 1200: break;
-			case 2400: break;
-			case 4800: break;
-			case 9600: break;
-			case 19200: break;
-			case 38400: break;
-			case 57600: break;
-			case 115200: break;
-			default:
-				err("MCT USB-RS232: unsupported baudrate request 0x%x,"
-				    " using default of B9600", value);
-				value = 9600;
+		case 300: break;
+		case 600: break;
+		case 1200: break;
+		case 2400: break;
+		case 4800: break;
+		case 9600: break;
+		case 19200: break;
+		case 38400: break;
+		case 57600: break;
+		case 115200: break;
+		default:
+			err("MCT USB-RS232: unsupported baudrate request 0x%x,"
+			    " using default of B9600", value);
+			value = 9600;
 		}
 		return 115200/value;
 	}

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