瀏覽代碼

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 年之前
父節點
當前提交
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
   See http://www.uuhaus.de/linux/palmconnect.html for up-to-date
   information on this driver.
   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
 Generic Serial driver
 
 
   If your device is not one of the above listed devices, compatible with
   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.
 Verify that bus sockets are present.
 
 
 # ls /sys/kernel/debug/usbmon
 # 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
 2. Find which bus connects to the desired device
 
 
 Run "cat /proc/bus/usb/devices", and find the T-line which corresponds to
 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
 # 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
 This process will be reading until killed. Naturally, the output can be
 redirected to a desirable location. This is preferred, because it is going
 redirected to a desirable location. This is preferred, because it is going
 to be quite long.
 to be quite long.

+ 7 - 0
MAINTAINERS

@@ -677,6 +677,13 @@ P:	Haavard Skinnemoen
 M:	hskinnemoen@atmel.com
 M:	hskinnemoen@atmel.com
 S:	Supported
 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
 ATMEL WIRELESS DRIVER
 P:	Simon Kelley
 P:	Simon Kelley
 M:	simon@thekelleys.org.uk
 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/pata_platform.h>
 #include <linux/irq.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 #include <asm/dma.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.h>
 #include <asm/reboot.h>

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

@@ -40,7 +40,7 @@
 #include <linux/irq.h>
 #include <linux/irq.h>
 #include <asm/dma.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/bfin5xx_spi.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 
 
 #include <linux/spi/ad7877.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/pata_platform.h>
 #include <linux/irq.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/interrupt.h>
-#include <linux/usb_sl811.h>
+#include <linux/usb/sl811.h>
 #include <asm/dma.h>
 #include <asm/dma.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/bfin5xx_spi.h>
 #include <asm/reboot.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_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_ATM)		+= atm/
 obj-$(CONFIG_USB_SPEEDTOUCH)	+= 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;
 	int rbuflen = ((rsize - 1) / stride + 1) * CMD_PACKET_SIZE;
 
 
 	if (wbuflen > PAGE_SIZE || rbuflen > PAGE_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;
 		ret = -ENOMEM;
 		goto fail;
 		goto fail;
 	}
 	}
@@ -493,8 +495,9 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
 	init_completion(&instance->rcv_done);
 	init_completion(&instance->rcv_done);
 	ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL);
 	ret = usb_submit_urb(instance->rcv_urb, GFP_KERNEL);
 	if (ret < 0) {
 	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;
 		goto fail;
 	}
 	}
 
 
@@ -510,27 +513,29 @@ static int cxacru_cm(struct cxacru_data *instance, enum cxacru_cm_request cm,
 	init_completion(&instance->snd_done);
 	init_completion(&instance->snd_done);
 	ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL);
 	ret = usb_submit_urb(instance->snd_urb, GFP_KERNEL);
 	if (ret < 0) {
 	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;
 		goto fail;
 	}
 	}
 
 
 	ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL);
 	ret = cxacru_start_wait_urb(instance->snd_urb, &instance->snd_done, NULL);
 	if (ret < 0) {
 	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;
 		goto fail;
 	}
 	}
 
 
 	ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen);
 	ret = cxacru_start_wait_urb(instance->rcv_urb, &instance->rcv_done, &actlen);
 	if (ret < 0) {
 	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;
 		goto fail;
 	}
 	}
 	if (actlen % CMD_PACKET_SIZE || !actlen) {
 	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;
 		ret = -EIO;
 		goto fail;
 		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 */
 	/* 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) {
 	for (offb = offd = 0; offd < rsize && offb < actlen; offb += CMD_PACKET_SIZE) {
 		if (rbuf[offb] != cm) {
 		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;
 			ret = -EIO;
 			goto fail;
 			goto fail;
 		}
 		}
 		if (rbuf[offb + 1] != CM_STATUS_SUCCESS) {
 		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;
 			ret = -EIO;
 			goto fail;
 			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; ) {
 	for (offb = 0; offb < len; ) {
 		int l = le32_to_cpu(buf[offb++]);
 		int l = le32_to_cpu(buf[offb++]);
 		if (l > stride || l > (len - offb) / 2) {
 		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;
 			ret = -EIO;
 			goto cleanup;
 			goto cleanup;
 		}
 		}
 		while (l--) {
 		while (l--) {
 			offd = le32_to_cpu(buf[offb++]);
 			offd = le32_to_cpu(buf[offb++]);
 			if (offd >= size) {
 			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;
 				ret = -EIO;
 				goto cleanup;
 				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;
 	unsigned char *buffer;
 	struct usbatm_data *usbatm = instance->usbatm;
 	struct usbatm_data *usbatm = instance->usbatm;
-	struct usb_interface *intf;
 	struct usb_device *usb_dev = usbatm->usb_dev;
 	struct usb_device *usb_dev = usbatm->usb_dev;
 	int actual_length;
 	int actual_length;
 	int ret = 0;
 	int ret = 0;
@@ -265,7 +264,7 @@ static int speedtch_upload_firmware(struct speedtch_instance_data *instance,
 		goto out;
 		goto out;
 	}
 	}
 
 
-	if (!(intf = usb_ifnum_to_if(usb_dev, 2))) {
+	if (!usb_ifnum_to_if(usb_dev, 2)) {
 		ret = -ENODEV;
 		ret = -ENODEV;
 		usb_dbg(usbatm, "%s: interface not found!\n", __func__);
 		usb_dbg(usbatm, "%s: interface not found!\n", __func__);
 		goto out_free;
 		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.12 - add hpoj.sourceforge.net ioctls (David Paschal)
  *	v0.13 - alloc space for statusbuf (<status> not on stack);
  *	v0.13 - alloc space for statusbuf (<status> not on stack);
  *		use usb_buffer_alloc() for read buf & write buf;
  *		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
 #define USBLP_DEVICE_ID_SIZE	1024
 
 
 /* ioctls: */
 /* ioctls: */
-#define LPGETSTATUS		0x060b		/* same as in drivers/char/lp.c */
 #define IOCNR_GET_DEVICE_ID		1
 #define IOCNR_GET_DEVICE_ID		1
 #define IOCNR_GET_PROTOCOLS		2
 #define IOCNR_GET_PROTOCOLS		2
 #define IOCNR_SET_PROTOCOL		3
 #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_MINORS		16
 #define USBLP_MINOR_BASE	0
 #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_FIRST_PROTOCOL	1
 #define USBLP_LAST_PROTOCOL	3
 #define USBLP_LAST_PROTOCOL	3
@@ -159,10 +159,12 @@ struct usblp {
 	int			wstatus;	/* bytes written or error */
 	int			wstatus;	/* bytes written or error */
 	int			rstatus;	/* bytes ready or error */
 	int			rstatus;	/* bytes ready or error */
 	unsigned int		quirks;			/* quirks flags */
 	unsigned int		quirks;			/* quirks flags */
+	unsigned int		flags;			/* mode flags */
 	unsigned char		used;			/* True if open */
 	unsigned char		used;			/* True if open */
 	unsigned char		present;		/* True if not disconnected */
 	unsigned char		present;		/* True if not disconnected */
 	unsigned char		bidir;			/* interface is bidirectional */
 	unsigned char		bidir;			/* interface is bidirectional */
 	unsigned char		sleeping;		/* interface is suspended */
 	unsigned char		sleeping;		/* interface is suspended */
+	unsigned char		no_paper;		/* Paper Out happened */
 	unsigned char		*device_id_string;	/* IEEE 1284 DEVICE ID string (ptr) */
 	unsigned char		*device_id_string;	/* IEEE 1284 DEVICE ID string (ptr) */
 							/* first 2 bytes are (big-endian) length */
 							/* 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,
 	retval = usb_control_msg(usblp->dev,
 		dir ? usb_rcvctrlpipe(usblp->dev, 0) : usb_sndctrlpipe(usblp->dev, 0),
 		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",
 	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);
 		request, !!dir, recip, value, index, len, retval);
 	return retval < 0 ? retval : 0;
 	return retval < 0 ? retval : 0;
@@ -325,13 +327,11 @@ static void usblp_bulk_write(struct urb *urb)
 		usblp->wstatus = status;
 		usblp->wstatus = status;
 	else
 	else
 		usblp->wstatus = urb->actual_length;
 		usblp->wstatus = urb->actual_length;
+	usblp->no_paper = 0;
 	usblp->wcomplete = 1;
 	usblp->wcomplete = 1;
 	wake_up(&usblp->wwait);
 	wake_up(&usblp->wwait);
 	spin_unlock(&usblp->lock);
 	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);
 	usb_free_urb(urb);
 }
 }
 
 
@@ -346,16 +346,17 @@ static int usblp_check_status(struct usblp *usblp, int err)
 	unsigned char status, newerr = 0;
 	unsigned char status, newerr = 0;
 	int error;
 	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())
 		if (printk_ratelimit())
 			printk(KERN_ERR
 			printk(KERN_ERR
 				"usblp%d: error %d reading printer status\n",
 				"usblp%d: error %d reading printer status\n",
 				usblp->minor, error);
 				usblp->minor, error);
 		return 0;
 		return 0;
 	}
 	}
-
 	status = *usblp->statusbuf;
 	status = *usblp->statusbuf;
+	mutex_unlock(&usblp->mut);
 
 
 	if (~status & LP_PERRORP)
 	if (~status & LP_PERRORP)
 		newerr = 3;
 		newerr = 3;
@@ -411,18 +412,10 @@ static int usblp_open(struct inode *inode, struct file *file)
 		goto out;
 		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);
 	retval = usb_autopm_get_interface(intf);
 	if (retval < 0)
 	if (retval < 0)
@@ -463,6 +456,8 @@ static int usblp_release(struct inode *inode, struct file *file)
 {
 {
 	struct usblp *usblp = file->private_data;
 	struct usblp *usblp = file->private_data;
 
 
+	usblp->flags &= ~LP_ABORT;
+
 	mutex_lock (&usblp_mutex);
 	mutex_lock (&usblp_mutex);
 	usblp->used = 0;
 	usblp->used = 0;
 	if (usblp->present) {
 	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->rwait, wait);
 	poll_wait(file, &usblp->wwait, wait);
 	poll_wait(file, &usblp->wwait, wait);
 	spin_lock_irqsave(&usblp->lock, flags);
 	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);
 	spin_unlock_irqrestore(&usblp->lock, flags);
 	return ret;
 	return ret;
 }
 }
@@ -675,6 +670,13 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 					retval = -EFAULT;
 					retval = -EFAULT;
 				break;
 				break;
 
 
+			case LPABORT:
+				if (arg)
+					usblp->flags |= LP_ABORT;
+				else
+					usblp->flags &= ~LP_ABORT;
+				break;
+
 			default:
 			default:
 				retval = -ENOTTY;
 				retval = -ENOTTY;
 		}
 		}
@@ -684,10 +686,30 @@ done:
 	return retval;
 	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)
 static ssize_t usblp_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 {
 {
 	struct usblp *usblp = file->private_data;
 	struct usblp *usblp = file->private_data;
-	char *writebuf;
 	struct urb *writeurb;
 	struct urb *writeurb;
 	int rv;
 	int rv;
 	int transfer_length;
 	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;
 			transfer_length = USBLP_BUF_SIZE;
 
 
 		rv = -ENOMEM;
 		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;
 			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);
 		usb_anchor_urb(writeurb, &usblp->urbs);
 
 
-		if (copy_from_user(writebuf,
+		if (copy_from_user(writeurb->transfer_buffer,
 				   buffer + writecount, transfer_length)) {
 				   buffer + writecount, transfer_length)) {
 			rv = -EFAULT;
 			rv = -EFAULT;
 			goto raise_badaddr;
 			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) {
 		if ((rv = usb_submit_urb(writeurb, GFP_KERNEL)) < 0) {
 			usblp->wstatus = 0;
 			usblp->wstatus = 0;
 			spin_lock_irq(&usblp->lock);
 			spin_lock_irq(&usblp->lock);
+			usblp->no_paper = 0;
 			usblp->wcomplete = 1;
 			usblp->wcomplete = 1;
 			wake_up(&usblp->wwait);
 			wake_up(&usblp->wwait);
 			spin_unlock_irq(&usblp->lock);
 			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. */
 				/* Presume that it's going to complete well. */
 				writecount += transfer_length;
 				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. */
 			/* Leave URB dangling, to be cleaned on close. */
 			goto collect_error;
 			goto collect_error;
 		}
 		}
 
 
 		if (usblp->wstatus < 0) {
 		if (usblp->wstatus < 0) {
-			usblp_check_status(usblp, 0);
 			rv = -EIO;
 			rv = -EIO;
 			goto collect_error;
 			goto collect_error;
 		}
 		}
@@ -771,8 +793,6 @@ raise_badaddr:
 	usb_unanchor_urb(writeurb);
 	usb_unanchor_urb(writeurb);
 	usb_free_urb(writeurb);
 	usb_free_urb(writeurb);
 raise_urb:
 raise_urb:
-	kfree(writebuf);
-raise_buf:
 raise_wait:
 raise_wait:
 collect_error:		/* Out of raise sequence */
 collect_error:		/* Out of raise sequence */
 	mutex_unlock(&usblp->wmut);
 	mutex_unlock(&usblp->wmut);
@@ -838,32 +858,36 @@ done:
  * when O_NONBLOCK is set. So, applications setting O_NONBLOCK must use
  * 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.
  * 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.
  * 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)
 static int usblp_wwait(struct usblp *usblp, int nonblock)
 {
 {
 	DECLARE_WAITQUEUE(waita, current);
 	DECLARE_WAITQUEUE(waita, current);
 	int rc;
 	int rc;
+	int err = 0;
 
 
 	add_wait_queue(&usblp->wwait, &waita);
 	add_wait_queue(&usblp->wwait, &waita);
 	for (;;) {
 	for (;;) {
+		set_current_state(TASK_INTERRUPTIBLE);
 		if (mutex_lock_interruptible(&usblp->mut)) {
 		if (mutex_lock_interruptible(&usblp->mut)) {
 			rc = -EINTR;
 			rc = -EINTR;
 			break;
 			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);
 		mutex_unlock(&usblp->mut);
-		if (rc == 0)
+		if (rc <= 0)
 			break;
 			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);
 	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&usblp->wwait, &waita);
 	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)
 int usb_get_configuration(struct usb_device *dev)
 {
 {
 	struct device *ddev = &dev->dev;
 	struct device *ddev = &dev->dev;
 	int ncfg = dev->descriptor.bNumConfigurations;
 	int ncfg = dev->descriptor.bNumConfigurations;
-	int result = -ENOMEM;
+	int result = 0;
 	unsigned int cfgno, length;
 	unsigned int cfgno, length;
 	unsigned char *buffer;
 	unsigned char *buffer;
 	unsigned char *bigbuffer;
 	unsigned char *bigbuffer;
  	struct usb_config_descriptor *desc;
  	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) {
 	if (ncfg > USB_MAXCONFIG) {
 		dev_warn(ddev, "too many configurations: %d, "
 		dev_warn(ddev, "too many configurations: %d, "
 		    "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
 		    "using maximum allowed: %d\n", ncfg, USB_MAXCONFIG);
@@ -545,14 +557,15 @@ int usb_get_configuration(struct usb_device *dev)
 		goto err2;
 		goto err2;
 	desc = (struct usb_config_descriptor *)buffer;
 	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
 		/* We grab just the first descriptor so we know how long
 		 * the whole configuration is */
 		 * the whole configuration is */
 		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
 		result = usb_get_descriptor(dev, USB_DT_CONFIG, cfgno,
 		    buffer, USB_DT_CONFIG_SIZE);
 		    buffer, USB_DT_CONFIG_SIZE);
 		if (result < 0) {
 		if (result < 0) {
 			dev_err(ddev, "unable to read config index %d "
 			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_err(ddev, "chopping to %d config(s)\n", cfgno);
 			dev->descriptor.bNumConfigurations = cfgno;
 			dev->descriptor.bNumConfigurations = cfgno;
 			break;
 			break;
@@ -599,6 +612,7 @@ int usb_get_configuration(struct usb_device *dev)
 
 
 err:
 err:
 	kfree(buffer);
 	kfree(buffer);
+out_not_authorized:
 	dev->descriptor.bNumConfigurations = cfgno;
 	dev->descriptor.bNumConfigurations = cfgno;
 err2:
 err2:
 	if (result == -ENOMEM)
 	if (result == -ENOMEM)

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

@@ -71,6 +71,7 @@ struct async {
 	void __user *userbuffer;
 	void __user *userbuffer;
 	void __user *userurb;
 	void __user *userurb;
 	struct urb *urb;
 	struct urb *urb;
+	int status;
 	u32 secid;
 	u32 secid;
 };
 };
 
 
@@ -289,10 +290,8 @@ static void snoop_urb(struct urb *urb, void __user *userurb)
 	if (!usbfs_snoop)
 	if (!usbfs_snoop)
 		return;
 		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, "userurb=%p\n", userurb);
 	dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n",
 	dev_info(&urb->dev->dev, "transfer_buffer_length=%d\n",
 		 urb->transfer_buffer_length);
 		 urb->transfer_buffer_length);
@@ -312,9 +311,10 @@ static void async_completed(struct urb *urb)
         spin_lock(&ps->lock);
         spin_lock(&ps->lock);
         list_move_tail(&as->asynclist, &ps->async_completed);
         list_move_tail(&as->asynclist, &ps->async_completed);
         spin_unlock(&ps->lock);
         spin_unlock(&ps->lock);
+	as->status = urb->status;
 	if (as->signr) {
 	if (as->signr) {
 		sinfo.si_signo = 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_code = SI_ASYNCIO;
 		sinfo.si_addr = as->userurb;
 		sinfo.si_addr = as->userurb;
 		kill_pid_info_as_uid(as->signr, &sinfo, as->pid, as->uid,
 		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;
 	struct usb_ctrlrequest *dr = NULL;
 	unsigned int u, totlen, isofrmlen;
 	unsigned int u, totlen, isofrmlen;
 	int ret, ifnum = -1;
 	int ret, ifnum = -1;
+	int is_in;
 
 
 	if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
 	if (uurb->flags & ~(USBDEVFS_URB_ISO_ASAP|USBDEVFS_URB_SHORT_NOT_OK|
 			   URB_NO_FSBR|URB_ZERO_PACKET))
 			   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)))
 		if ((ret = checkintf(ps, ifnum)))
 			return ret;
 			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)
 	if (!ep)
 		return -ENOENT;
 		return -ENOENT;
 	switch(uurb->type) {
 	switch(uurb->type) {
 	case USBDEVFS_URB_TYPE_CONTROL:
 	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;
 			return -EINVAL;
 		/* min 8 byte setup packet, max 8 byte setup plus an arbitrary data stage */
 		/* 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))
 		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);
 			kfree(dr);
 			return ret;
 			return ret;
 		}
 		}
-		uurb->endpoint = (uurb->endpoint & ~USB_ENDPOINT_DIR_MASK) | (dr->bRequestType & USB_ENDPOINT_DIR_MASK);
 		uurb->number_of_packets = 0;
 		uurb->number_of_packets = 0;
 		uurb->buffer_length = le16_to_cpup(&dr->wLength);
 		uurb->buffer_length = le16_to_cpup(&dr->wLength);
 		uurb->buffer += 8;
 		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);
 			kfree(dr);
 			return -EFAULT;
 			return -EFAULT;
 		}
 		}
 		snoop(&ps->dev->dev, "control urb: bRequest=%02x "
 		snoop(&ps->dev->dev, "control urb: bRequest=%02x "
 			"bRrequestType=%02x wValue=%04x "
 			"bRrequestType=%02x wValue=%04x "
 			"wIndex=%04x wLength=%04x\n",
 			"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;
 		break;
 
 
 	case USBDEVFS_URB_TYPE_BULK:
 	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_CONTROL:
 		case USB_ENDPOINT_XFER_ISOC:
 		case USB_ENDPOINT_XFER_ISOC:
 			return -EINVAL;
 			return -EINVAL;
@@ -977,7 +989,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 		uurb->number_of_packets = 0;
 		uurb->number_of_packets = 0;
 		if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
 		if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
 			return -EINVAL;
 			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;
 			return -EFAULT;
 		snoop(&ps->dev->dev, "bulk urb\n");
 		snoop(&ps->dev->dev, "bulk urb\n");
 		break;
 		break;
@@ -986,8 +999,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 		/* arbitrary limit */
 		/* arbitrary limit */
 		if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128)
 		if (uurb->number_of_packets < 1 || uurb->number_of_packets > 128)
 			return -EINVAL;
 			return -EINVAL;
-		if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-				!= USB_ENDPOINT_XFER_ISOC)
+		if (!usb_endpoint_xfer_isoc(&ep->desc))
 			return -EINVAL;
 			return -EINVAL;
 		isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets;
 		isofrmlen = sizeof(struct usbdevfs_iso_packet_desc) * uurb->number_of_packets;
 		if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
 		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:
 	case USBDEVFS_URB_TYPE_INTERRUPT:
 		uurb->number_of_packets = 0;
 		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;
 			return -EINVAL;
 		if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
 		if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
 			return -EINVAL;
 			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;
 			return -EFAULT;
 		snoop(&ps->dev->dev, "interrupt urb\n");
 		snoop(&ps->dev->dev, "interrupt urb\n");
 		break;
 		break;
@@ -1039,8 +1051,11 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
         as->urb->dev = ps->dev;
         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->transfer_buffer_length = uurb->buffer_length;
 	as->urb->setup_packet = (unsigned char*)dr;
 	as->urb->setup_packet = (unsigned char*)dr;
 	as->urb->start_frame = uurb->start_frame;
 	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->uid = current->uid;
 	as->euid = current->euid;
 	as->euid = current->euid;
 	security_task_getsecid(current, &as->secid);
 	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);
 			free_async(as);
 			return -EFAULT;
 			return -EFAULT;
 		}
 		}
 	}
 	}
-	snoop(&as->urb->dev->dev, "submit urb\n");
 	snoop_urb(as->urb, as->userurb);
 	snoop_urb(as->urb, as->userurb);
         async_newpending(as);
         async_newpending(as);
         if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
         if ((ret = usb_submit_urb(as->urb, GFP_KERNEL))) {
@@ -1119,14 +1134,14 @@ static int processcompl(struct async *as, void __user * __user *arg)
 	if (as->userbuffer)
 	if (as->userbuffer)
 		if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
 		if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
 			return -EFAULT;
 			return -EFAULT;
-	if (put_user(urb->status, &userurb->status))
+	if (put_user(as->status, &userurb->status))
 		return -EFAULT;
 		return -EFAULT;
 	if (put_user(urb->actual_length, &userurb->actual_length))
 	if (put_user(urb->actual_length, &userurb->actual_length))
 		return -EFAULT;
 		return -EFAULT;
 	if (put_user(urb->error_count, &userurb->error_count))
 	if (put_user(urb->error_count, &userurb->error_count))
 		return -EFAULT;
 		return -EFAULT;
 
 
-	if (usb_pipeisoc(urb->pipe)) {
+	if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
 		for (i = 0; i < urb->number_of_packets; i++) {
 		for (i = 0; i < urb->number_of_packets; i++) {
 			if (put_user(urb->iso_frame_desc[i].actual_length,
 			if (put_user(urb->iso_frame_desc[i].actual_length,
 				     &userurb->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 (as->userbuffer)
 		if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
 		if (copy_to_user(as->userbuffer, urb->transfer_buffer, urb->transfer_buffer_length))
 			return -EFAULT;
 			return -EFAULT;
-	if (put_user(urb->status, &userurb->status))
+	if (put_user(as->status, &userurb->status))
 		return -EFAULT;
 		return -EFAULT;
 	if (put_user(urb->actual_length, &userurb->actual_length))
 	if (put_user(urb->actual_length, &userurb->actual_length))
 		return -EFAULT;
 		return -EFAULT;
 	if (put_user(urb->error_count, &userurb->error_count))
 	if (put_user(urb->error_count, &userurb->error_count))
 		return -EFAULT;
 		return -EFAULT;
 
 
-	if (usb_pipeisoc(urb->pipe)) {
+	if (usb_endpoint_xfer_isoc(&urb->ep->desc)) {
 		for (i = 0; i < urb->number_of_packets; i++) {
 		for (i = 0; i < urb->number_of_packets; i++) {
 			if (put_user(urb->iso_frame_desc[i].actual_length,
 			if (put_user(urb->iso_frame_desc[i].actual_length,
 				     &userurb->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);
 	intf = to_usb_interface(dev);
 	udev = interface_to_usbdev(intf);
 	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);
 	id = usb_match_id(intf, driver->id_table);
 	if (!id)
 	if (!id)
 		id = usb_match_dynamic_id(intf, driver);
 		id = usb_match_dynamic_id(intf, driver);
@@ -945,11 +950,11 @@ done:
 #ifdef	CONFIG_USB_SUSPEND
 #ifdef	CONFIG_USB_SUSPEND
 
 
 /* Internal routine to check whether we may autosuspend a device. */
 /* 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;
 	int			i;
 	struct usb_interface	*intf;
 	struct usb_interface	*intf;
-	unsigned long		suspend_time;
+	unsigned long		suspend_time, j;
 
 
 	/* For autosuspend, fail fast if anything is in use or autosuspend
 	/* For autosuspend, fail fast if anything is in use or autosuspend
 	 * is disabled.  Also fail if any interfaces require remote wakeup
 	 * 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
 	/* 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)) {
 		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,
 			queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
-				round_jiffies_relative(suspend_time - jiffies));
-			}
+				round_jiffies_relative(suspend_time - j));
+		}
 		return -EAGAIN;
 		return -EAGAIN;
 	}
 	}
 	return 0;
 	return 0;
@@ -1012,7 +1017,7 @@ static int autosuspend_check(struct usb_device *udev)
 
 
 #else
 #else
 
 
-static inline int autosuspend_check(struct usb_device *udev)
+static inline int autosuspend_check(struct usb_device *udev, int reschedule)
 {
 {
 	return 0;
 	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);
 	udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
 
 
 	if (udev->auto_pm) {
 	if (udev->auto_pm) {
-		status = autosuspend_check(udev);
+		status = autosuspend_check(udev, 0);
 		if (status < 0)
 		if (status < 0)
 			goto done;
 			goto done;
 	}
 	}
@@ -1083,15 +1088,8 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
 				break;
 				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);
 		status = usb_suspend_device(udev, msg);
-	}
 
 
 	/* If the suspend failed, resume interfaces that did get suspended */
 	/* If the suspend failed, resume interfaces that did get suspended */
 	if (status != 0) {
 	if (status != 0) {
@@ -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 */
 		/* Try another autosuspend when the interfaces aren't busy */
 		if (udev->auto_pm)
 		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 {
 	} else {
 		cancel_delayed_work(&udev->autosuspend);
 		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);
 			usb_autosuspend_device(parent);
 	}
 	}
 
 
@@ -1156,6 +1166,7 @@ static int usb_resume_both(struct usb_device *udev)
 		status = -ENODEV;
 		status = -ENODEV;
 		goto done;
 		goto done;
 	}
 	}
+	udev->can_submit = 1;
 
 
 	/* Propagate the resume up the tree, if necessary */
 	/* Propagate the resume up the tree, if necessary */
 	if (udev->state == USB_STATE_SUSPENDED) {
 	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)
 static int usb_suspend(struct device *dev, pm_message_t message)
 {
 {
+	struct usb_device	*udev;
+
 	if (!is_usb_device(dev))	/* Ignore PM for interfaces */
 	if (!is_usb_device(dev))	/* Ignore PM for interfaces */
 		return 0;
 		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)
 static int usb_resume(struct device *dev)
@@ -1542,13 +1565,14 @@ static int usb_resume(struct device *dev)
 		return 0;
 		return 0;
 	udev = to_usb_device(dev);
 	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))
 		if (!(udev->reset_resume && udev->do_remote_wakeup))
-			return -EPERM;
+			return -EHOSTUNREACH;
 	}
 	}
 	return usb_external_resume_device(udev);
 	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);
 	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);
 	endpoint_free_minor(ep_dev);
 	kfree(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;
 		&& desc->bInterfaceProtocol == 1;
 }
 }
 
 
-static int choose_configuration(struct usb_device *udev)
+int usb_choose_configuration(struct usb_device *udev)
 {
 {
 	int i;
 	int i;
 	int num_configs;
 	int num_configs;
@@ -161,17 +161,20 @@ static int generic_probe(struct usb_device *udev)
 	/* Choose and set the configuration.  This registers the interfaces
 	/* Choose and set the configuration.  This registers the interfaces
 	 * with the driver core and lets interface drivers bind to them.
 	 * 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);
 					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 device state == configured ... usable */
 	usb_notify_add_device(udev);
 	usb_notify_add_device(udev);
 
 
@@ -203,8 +206,13 @@ static int generic_suspend(struct usb_device *udev, pm_message_t msg)
 	 */
 	 */
 	if (!udev->parent)
 	if (!udev->parent)
 		rc = hcd_bus_suspend(udev);
 		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
 	else
 		rc = usb_port_suspend(udev);
 		rc = usb_port_suspend(udev);
+
 	return rc;
 	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;
 	const u8	*bufp = tbuf;
 	int		len = 0;
 	int		len = 0;
 	int		patch_wakeup = 0;
 	int		patch_wakeup = 0;
-	unsigned long	flags;
-	int		status = 0;
+	int		status;
 	int		n;
 	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;
 	cmd = (struct usb_ctrlrequest *) urb->setup_packet;
 	typeReq  = (cmd->bRequestType << 8) | cmd->bRequest;
 	typeReq  = (cmd->bRequestType << 8) | cmd->bRequest;
 	wValue   = le16_to_cpu (cmd->wValue);
 	wValue   = le16_to_cpu (cmd->wValue);
@@ -523,13 +531,18 @@ error:
 	}
 	}
 
 
 	/* any errors get returned through the urb completion */
 	/* 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;
 	return 0;
 }
 }
 
 
@@ -559,31 +572,23 @@ void usb_hcd_poll_rh_status(struct usb_hcd *hcd)
 	if (length > 0) {
 	if (length > 0) {
 
 
 		/* try to complete the status urb */
 		/* 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;
 		urb = hcd->status_urb;
 		if (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;
 			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
 	/* 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);
 	int		len = 1 + (urb->dev->maxchild / 8);
 
 
 	spin_lock_irqsave (&hcd_root_hub_lock, flags);
 	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");
 		dev_dbg (hcd->self.controller, "not queuing rh status urb\n");
 		retval = -EINVAL;
 		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);
 	spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
 	return retval;
 	return retval;
 }
 }
 
 
 static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)
 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);
 		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 rh_call_control (hcd, urb);
 	return -EINVAL;
 	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
 /* Unlinks of root-hub control URBs are legal, but they don't do anything
  * since these URBs always execute synchronously.
  * 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;
 	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 */
 		;	/* Do nothing */
 
 
 	} else {				/* Status URB */
 	} else {				/* Status URB */
 		if (!hcd->uses_new_polling)
 		if (!hcd->uses_new_polling)
 			del_timer (&hcd->rh_timer);
 			del_timer (&hcd->rh_timer);
-		local_irq_save (flags);
-		spin_lock (&hcd_root_hub_lock);
 		if (urb == hcd->status_urb) {
 		if (urb == hcd->status_urb) {
 			hcd->status_urb = NULL;
 			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;
 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)
 static int usb_register_bus(struct usb_bus *bus)
 {
 {
+	int result = -E2BIG;
 	int busnum;
 	int busnum;
 
 
 	mutex_lock(&usb_bus_list_lock);
 	mutex_lock(&usb_bus_list_lock);
 	busnum = find_next_zero_bit (busmap.busmap, USB_MAXBUS, 1);
 	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);
 		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->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);
 	class_set_devdata(bus->class_dev, bus);
 
 
 	/* Add it to the local list of buses */
 	/* 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);
 	usb_notify_add_bus(bus);
 
 
-	dev_info (bus->controller, "new USB bus registered, assigned bus number %d\n", bus->busnum);
+	dev_info (bus->controller, "new USB bus registered, assigned bus "
+		  "number %d\n", bus->busnum);
 	return 0;
 	return 0;
+
+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_RUNNING:
 	case HC_STATE_RESUMING:
 	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;
 		break;
 	default:
 	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.
 	 * 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->transfer_flags & URB_NO_SETUP_DMA_MAP))
 			urb->setup_dma = dma_map_single (
 			urb->setup_dma = dma_map_single (
 					hcd->self.controller,
 					hcd->self.controller,
@@ -1017,20 +1133,75 @@ int usb_hcd_submit_urb (struct urb *urb, gfp_t mem_flags)
 					hcd->self.controller,
 					hcd->self.controller,
 					urb->transfer_buffer,
 					urb->transfer_buffer,
 					urb->transfer_buffer_length,
 					urb->transfer_buffer_length,
-					usb_pipein (urb->pipe)
+					usb_urb_dir_in(urb)
 					    ? DMA_FROM_DEVICE
 					    ? DMA_FROM_DEVICE
 					    : DMA_TO_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);
 		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;
 	return status;
 }
 }
@@ -1042,24 +1213,19 @@ done:
  * soon as practical.  we've already set up the urb's return status,
  * soon as practical.  we've already set up the urb's return status,
  * but we can't know if the callback completed already.
  * 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;
 	int		value;
 
 
 	if (is_root_hub(urb->dev))
 	if (is_root_hub(urb->dev))
-		value = usb_rh_urb_dequeue (hcd, urb);
+		value = usb_rh_urb_dequeue(hcd, urb, status);
 	else {
 	else {
 
 
 		/* The only reason an HCD might fail this call is if
 		/* The only reason an HCD might fail this call is if
 		 * it has not yet fully queued the urb to begin with.
 		 * it has not yet fully queued the urb to begin with.
 		 * Such failures should be harmless. */
 		 * 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;
 	return value;
 }
 }
 
 
@@ -1071,88 +1237,17 @@ unlink1 (struct usb_hcd *hcd, struct urb *urb)
  */
  */
 int usb_hcd_unlink_urb (struct urb *urb, int status)
 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);
 	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)
 	if (retval == 0)
 		retval = -EINPROGRESS;
 		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;
 	return retval;
 }
 }
 
 
@@ -1162,6 +1257,7 @@ done:
  * usb_hcd_giveback_urb - return URB from HCD to device driver
  * usb_hcd_giveback_urb - return URB from HCD to device driver
  * @hcd: host controller returning the URB
  * @hcd: host controller returning the URB
  * @urb: urb being returned to the USB device driver.
  * @urb: urb being returned to the USB device driver.
+ * @status: completion status code for the URB.
  * Context: in_interrupt()
  * Context: in_interrupt()
  *
  *
  * This hands the URB from HCD to its USB device driver, using its
  * 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;
  * (and is done using urb->hcpriv).  It also released all HCD locks;
  * the device driver won't cause problems if it frees, modifies,
  * the device driver won't cause problems if it frees, modifies,
  * or resubmits this URB.
  * 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);
 	usb_unanchor_urb(urb);
 
 
 	/* pass ownership to the completion handler */
 	/* pass ownership to the completion handler */
+	urb->status = status;
 	urb->complete (urb);
 	urb->complete (urb);
 	atomic_dec (&urb->use_count);
 	atomic_dec (&urb->use_count);
 	if (unlikely (urb->reject))
 	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_host_endpoint *ep)
 {
 {
 	struct usb_hcd		*hcd;
 	struct usb_hcd		*hcd;
 	struct urb		*urb;
 	struct urb		*urb;
 
 
+	if (!ep)
+		return;
+	might_sleep();
 	hcd = bus_to_hcd(udev->bus);
 	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:
 rescan:
-	spin_lock(&hcd_urb_list_lock);
+	spin_lock_irq(&hcd_urb_list_lock);
 	list_for_each_entry (urb, &ep->urb_list, urb_list) {
 	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;
 			continue;
 		usb_get_urb (urb);
 		usb_get_urb (urb);
+		is_in = usb_urb_dir_in(urb);
 		spin_unlock(&hcd_urb_list_lock);
 		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);
 		usb_put_urb (urb);
 
 
 		/* list contents may have changed */
 		/* list contents may have changed */
 		goto rescan;
 		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)) {
 	while (!list_empty (&ep->urb_list)) {
 		spin_lock_irq(&hcd_urb_list_lock);
 		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 */
 /* called in any context */
@@ -1525,7 +1636,6 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
 	hcd->driver = driver;
 	hcd->driver = driver;
 	hcd->product_desc = (driver->product_desc) ? driver->product_desc :
 	hcd->product_desc = (driver->product_desc) ? driver->product_desc :
 			"USB Host Controller";
 			"USB Host Controller";
-
 	return hcd;
 	return hcd;
 }
 }
 EXPORT_SYMBOL (usb_create_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);
 	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);
 	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 
 
 	/* HC is in reset state, but accessible.  Now do the one-time init,
 	/* 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)
 	if ((retval = register_root_hub(hcd)) != 0)
 		goto err_register_root_hub;
 		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)
 	if (hcd->uses_new_polling && hcd->poll_rh)
 		usb_hcd_poll_rh_status(hcd);
 		usb_hcd_poll_rh_status(hcd);
 	return retval;
 	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:
 err_register_root_hub:
 	hcd->driver->stop(hcd);
 	hcd->driver->stop(hcd);
 err_hcd_driver_start:
 err_hcd_driver_start:
@@ -1691,6 +1812,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
 	cancel_work_sync(&hcd->wakeup_work);
 	cancel_work_sync(&hcd->wakeup_work);
 #endif
 #endif
 
 
+	sysfs_remove_group(&hcd->self.root_hub->dev.kobj, &usb_bus_attr_group);
 	mutex_lock(&usb_bus_list_lock);
 	mutex_lock(&usb_bus_list_lock);
 	usb_disconnect(&hcd->self.root_hub);
 	usb_disconnect(&hcd->self.root_hub);
 	mutex_unlock(&usb_bus_list_lock);
 	mutex_unlock(&usb_bus_list_lock);

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

@@ -19,6 +19,8 @@
 
 
 #ifdef __KERNEL__
 #ifdef __KERNEL__
 
 
+#include <linux/rwsem.h>
+
 /* This file contains declarations of usbcore internals that are mostly
 /* This file contains declarations of usbcore internals that are mostly
  * used or exposed by Host Controller Drivers.
  * 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.
  * 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.
  * 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_rh:1;	/* poll for rh status? */
 	unsigned		poll_pending:1;	/* status has changed? */
 	unsigned		poll_pending:1;	/* status has changed? */
 	unsigned		wireless:1;	/* Wireless USB HCD */
 	unsigned		wireless:1;	/* Wireless USB HCD */
+	unsigned		authorized_default:1;
 
 
 	int			irq;		/* irq allocated */
 	int			irq;		/* irq allocated */
 	void __iomem		*regs;		/* device memory/io */
 	void __iomem		*regs;		/* device memory/io */
@@ -182,11 +191,10 @@ struct hc_driver {
 	int	(*get_frame_number) (struct usb_hcd *hcd);
 	int	(*get_frame_number) (struct usb_hcd *hcd);
 
 
 	/* manage i/o requests, device state */
 	/* 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 */
 	/* hw synch, freeing endpoint resources that urb_dequeue can't */
 	void 	(*endpoint_disable)(struct usb_hcd *hcd,
 	void 	(*endpoint_disable)(struct usb_hcd *hcd,
@@ -204,10 +212,18 @@ struct hc_driver {
 		/* Needed only if port-change IRQs are level-triggered */
 		/* 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_submit_urb (struct urb *urb, gfp_t mem_flags);
 extern int usb_hcd_unlink_urb (struct urb *urb, int status);
 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);
 		struct usb_host_endpoint *ep);
 extern int usb_hcd_get_frame_number (struct usb_device *udev);
 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 {
 struct usb_mon_operations {
 	void (*urb_submit)(struct usb_bus *bus, struct urb *urb);
 	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_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); */
 	/* 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);
 		(*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)
 	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);
 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(struct usb_bus *bus, struct urb *urb) {}
 static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
 static inline void usbmon_urb_submit_error(struct usb_bus *bus, struct urb *urb,
     int error) {}
     int error) {}
-static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb) {}
+static inline void usbmon_urb_complete(struct usb_bus *bus, struct urb *urb,
+		int status) {}
 
 
 #endif /* CONFIG_USB_MON */
 #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"))
 		: (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 "
 		"try the other device initialization scheme if the "
 		"first one fails");
 		"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)
 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)
 static void hub_irq(struct urb *urb)
 {
 {
 	struct usb_hub *hub = urb->context;
 	struct usb_hub *hub = urb->context;
-	int status;
+	int status = urb->status;
 	int i;
 	int i;
 	unsigned long bits;
 	unsigned long bits;
 
 
-	switch (urb->status) {
+	switch (status) {
 	case -ENOENT:		/* synchronous unlink */
 	case -ENOENT:		/* synchronous unlink */
 	case -ECONNRESET:	/* async unlink */
 	case -ECONNRESET:	/* async unlink */
 	case -ESHUTDOWN:	/* hardware going away */
 	case -ESHUTDOWN:	/* hardware going away */
@@ -359,10 +365,10 @@ static void hub_irq(struct urb *urb)
 
 
 	default:		/* presumably an error */
 	default:		/* presumably an error */
 		/* Cause a hub reset after 10 consecutive errors */
 		/* 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)
 		if ((++hub->nerrors < 10) || hub->error)
 			goto resubmit;
 			goto resubmit;
-		hub->error = urb->status;
+		hub->error = status;
 		/* FALL THROUGH */
 		/* FALL THROUGH */
 
 
 	/* let khubd handle things */
 	/* let khubd handle things */
@@ -1220,54 +1226,14 @@ static inline void show_string(struct usb_device *udev, char *id, char *string)
 #endif
 #endif
 
 
 /**
 /**
- * usb_new_device - perform initial device setup (usbcore-internal)
+ * usb_configure_device_otg - FIXME (usbcore-internal)
  * @udev: newly addressed device (in ADDRESS state)
  * @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
 #ifdef	CONFIG_USB_OTG
 	/*
 	/*
@@ -1329,8 +1295,82 @@ int usb_new_device(struct usb_device *udev)
 		err = -ENOTSUPP;
 		err = -ENOTSUPP;
 		goto fail;
 		goto fail;
 	}
 	}
+fail:
 #endif
 #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 */
 	/* export the usbdev device-node for libusb */
 	udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
 	udev->dev.devt = MKDEV(USB_DEVICE_MAJOR,
 			(((udev->bus->busnum-1) * 128) + (udev->devnum-1)));
 			(((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);
 	err = device_add(&udev->dev);
 	if (err) {
 	if (err) {
 		dev_err(&udev->dev, "can't device_add, error %d\n", err);
 		dev_err(&udev->dev, "can't device_add, error %d\n", err);
-		if (udev->parent)
-			usb_autosuspend_device(udev->parent);
 		goto fail;
 		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;
 	return err;
 
 
 fail:
 fail:
 	usb_set_device_state(udev, USB_STATE_NOTATTACHED);
 	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,
 static int hub_port_status(struct usb_hub *hub, int port1,
 			       u16 *status, u16 *change)
 			       u16 *status, u16 *change)
 {
 {
@@ -1460,6 +1587,11 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 {
 {
 	int i, status;
 	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 */
 	/* Reset the port */
 	for (i = 0; i < PORT_RESET_TRIES; i++) {
 	for (i = 0; i < PORT_RESET_TRIES; i++) {
 		status = set_port_feature(hub->hdev,
 		status = set_port_feature(hub->hdev,
@@ -1481,6 +1613,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 		case 0:
 		case 0:
 			/* TRSTRCY = 10 ms; plus some extra */
 			/* TRSTRCY = 10 ms; plus some extra */
 			msleep(10 + 40);
 			msleep(10 + 40);
+		  	udev->devnum = 0;	/* Device now at address 0 */
 			/* FALL THROUGH */
 			/* FALL THROUGH */
 		case -ENOTCONN:
 		case -ENOTCONN:
 		case -ENODEV:
 		case -ENODEV:
@@ -1490,7 +1623,7 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 			usb_set_device_state(udev, status
 			usb_set_device_state(udev, status
 					? USB_STATE_NOTATTACHED
 					? USB_STATE_NOTATTACHED
 					: USB_STATE_DEFAULT);
 					: USB_STATE_DEFAULT);
-			return status;
+			goto done;
 		}
 		}
 
 
 		dev_dbg (hub->intfdev,
 		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",
 		"Cannot enable port %i.  Maybe the USB cable is bad?\n",
 		port1);
 		port1);
 
 
+ done:
+	up_read(&ehci_cf_port_reset_rwsem);
 	return status;
 	return status;
 }
 }
 
 
@@ -1833,14 +1968,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
 		struct usb_device	*udev;
 		struct usb_device	*udev;
 
 
 		udev = hdev->children [port1-1];
 		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)
 			if (!hdev->auto_pm)
 				dev_dbg(&intf->dev, "port %d nyet suspended\n",
 				dev_dbg(&intf->dev, "port %d nyet suspended\n",
 						port1);
 						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_IN);
 	usb_disable_endpoint(udev, 0 + USB_DIR_OUT);
 	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_sndaddr0pipe()	(PIPE_CONTROL << 30)
 #define usb_rcvaddr0pipe()	((PIPE_CONTROL << 30) | USB_DIR_IN)
 #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;
 	int retval;
 
 
-	if (udev->devnum == 0)
+	if (devnum <= 1)
 		return -EINVAL;
 		return -EINVAL;
 	if (udev->state == USB_STATE_ADDRESS)
 	if (udev->state == USB_STATE_ADDRESS)
 		return 0;
 		return 0;
 	if (udev->state != USB_STATE_DEFAULT)
 	if (udev->state != USB_STATE_DEFAULT)
 		return -EINVAL;
 		return -EINVAL;
 	retval = usb_control_msg(udev, usb_sndaddr0pipe(),
 	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);
 		NULL, 0, USB_CTRL_SET_TIMEOUT);
 	if (retval == 0) {
 	if (retval == 0) {
+		udev->devnum = devnum;	/* Device now using proper address */
 		usb_set_device_state(udev, USB_STATE_ADDRESS);
 		usb_set_device_state(udev, USB_STATE_ADDRESS);
 		ep0_reinit(udev);
 		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;
 	unsigned		delay = HUB_SHORT_RESET_TIME;
 	enum usb_device_speed	oldspeed = udev->speed;
 	enum usb_device_speed	oldspeed = udev->speed;
 	char 			*speed, *type;
 	char 			*speed, *type;
+	int			devnum = udev->devnum;
 
 
 	/* root hub ports have a slightly longer reset period
 	/* root hub ports have a slightly longer reset period
 	 * (from USB 2.0 spec, section 7.1.7.5)
 	 * (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;
 		goto fail;
 	}
 	}
 	oldspeed = udev->speed;
 	oldspeed = udev->speed;
-  
+
 	/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
 	/* USB 2.0 section 5.5.3 talks about ep0 maxpacket ...
 	 * it's fixed size except for full speed devices.
 	 * it's fixed size except for full speed devices.
 	 * For Wireless USB devices, ep0 max packet is always 512 (tho
 	 * 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,
 	dev_info (&udev->dev,
 		  "%s %s speed %sUSB device using %s and address %d\n",
 		  "%s %s speed %sUSB device using %s and address %d\n",
 		  (udev->config) ? "reset" : "new", speed, type,
 		  (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  */
 	/* Set up TT records, if needed  */
 	if (hdev->tt) {
 	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) {
 		for (j = 0; j < SET_ADDRESS_TRIES; ++j) {
-			retval = hub_set_address(udev);
+			retval = hub_set_address(udev, devnum);
 			if (retval >= 0)
 			if (retval >= 0)
 				break;
 				break;
 			msleep(200);
 			msleep(200);
@@ -2210,7 +2340,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 		if (retval < 0) {
 		if (retval < 0) {
 			dev_err(&udev->dev,
 			dev_err(&udev->dev,
 				"device not accepting address %d, error %d\n",
 				"device not accepting address %d, error %d\n",
-				udev->devnum, retval);
+				devnum, retval);
 			goto fail;
 			goto fail;
 		}
 		}
  
  
@@ -2263,8 +2393,10 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 	retval = 0;
 	retval = 0;
 
 
 fail:
 fail:
-	if (retval)
+	if (retval) {
 		hub_port_disable(hub, port1, 0);
 		hub_port_disable(hub, port1, 0);
+		udev->devnum = devnum;	/* for disconnect processing */
+	}
 	mutex_unlock(&usb_address0_mutex);
 	mutex_unlock(&usb_address0_mutex);
 	return retval;
 	return retval;
 }
 }
@@ -2699,9 +2831,9 @@ static void hub_events(void)
 				clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
 				clear_hub_feature(hdev, C_HUB_LOCAL_POWER);
 				if (hubstatus & HUB_STATUS_LOCAL_POWER)
 				if (hubstatus & HUB_STATUS_LOCAL_POWER)
 					/* FIXME: Is this always true? */
 					/* FIXME: Is this always true? */
-					hub->limited_power = 0;
-				else
 					hub->limited_power = 1;
 					hub->limited_power = 1;
+				else
+					hub->limited_power = 0;
 			}
 			}
 			if (hubchange & HUB_CHANGE_OVERCURRENT) {
 			if (hubchange & HUB_CHANGE_OVERCURRENT) {
 				dev_dbg (hub_dev, "overcurrent change\n");
 				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,
 		dev_dbg(&urb->dev->dev,
 			"%s timed out on ep%d%s len=%d/%d\n",
 			"%s timed out on ep%d%s len=%d/%d\n",
 			current->comm,
 			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->actual_length,
 			urb->transfer_buffer_length);
 			urb->transfer_buffer_length);
 	} else
 	} else
@@ -250,7 +250,8 @@ static void sg_clean (struct usb_sg_request *io)
 		io->urbs = NULL;
 		io->urbs = NULL;
 	}
 	}
 	if (io->dev->dev.dma_mask != 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;
 	io->dev = NULL;
 }
 }
 
 
@@ -278,8 +279,8 @@ static void sg_complete (struct urb *urb)
 		dev_err (io->dev->bus->controller,
 		dev_err (io->dev->bus->controller,
 			"dev %s ep%d%s scatterlist error %d/%d\n",
 			"dev %s ep%d%s scatterlist error %d/%d\n",
 			io->dev->devpath,
 			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);
 			status, io->status);
 		// BUG ();
 		// BUG ();
 	}
 	}
@@ -379,7 +380,8 @@ int usb_sg_init (
 	 */
 	 */
 	dma = (dev->dev.dma_mask != NULL);
 	dma = (dev->dev.dma_mask != NULL);
 	if (dma)
 	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
 	else
 		io->entries = nents;
 		io->entries = nents;
 
 
@@ -1013,8 +1015,11 @@ void usb_disable_endpoint(struct usb_device *dev, unsigned int epaddr)
 		ep = dev->ep_in[epnum];
 		ep = dev->ep_in[epnum];
 		dev->ep_in[epnum] = NULL;
 		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.
  * Resets the endpoint toggle, and sets dev->ep_{in,out} pointers.
  * For control endpoints, both the input and output sides are handled.
  * 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);
 		usb_settoggle(dev, epnum, 1, 0);
 		dev->ep_out[epnum] = ep;
 		dev->ep_out[epnum] = ep;
 	}
 	}
-	if (!usb_endpoint_out(epaddr) || is_control) {
+	if (!is_out || is_control) {
 		usb_settoggle(dev, epnum, 0, 0);
 		usb_settoggle(dev, epnum, 0, 0);
 		dev->ep_in[epnum] = ep;
 		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;
 	struct usb_host_interface *alt;
 	int ret;
 	int ret;
 	int manual = 0;
 	int manual = 0;
+	int changed;
 
 
 	if (dev->state == USB_STATE_SUSPENDED)
 	if (dev->state == USB_STATE_SUSPENDED)
 		return -EHOSTUNREACH;
 		return -EHOSTUNREACH;
@@ -1210,7 +1214,8 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
 	 */
 	 */
 
 
 	/* prevent submissions using previous endpoint settings */
 	/* prevent submissions using previous endpoint settings */
-	if (device_is_registered(&iface->dev))
+	changed = (iface->cur_altsetting != alt);
+	if (changed && device_is_registered(&iface->dev))
 		usb_remove_sysfs_intf_files(iface);
 		usb_remove_sysfs_intf_files(iface);
 	usb_disable_interface(dev, 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.)
 	 * (Likewise, EP0 never "halts" on well designed devices.)
 	 */
 	 */
 	usb_enable_interface(dev, iface);
 	usb_enable_interface(dev, iface);
-	if (device_is_registered(&iface->dev))
+	if (changed && device_is_registered(&iface->dev))
 		usb_create_sysfs_intf_files(iface);
 		usb_create_sysfs_intf_files(iface);
 
 
 	return 0;
 	return 0;
@@ -1328,7 +1333,7 @@ int usb_reset_configuration(struct usb_device *dev)
 	return 0;
 	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 *intf = to_usb_interface(dev);
 	struct usb_interface_cache *intfc =
 	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
  * channels are available independently; and choosing between open
  * standard device protocols (like CDC) or proprietary ones.
  * 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,
  * Note that USB has an additional level of device configurability,
  * associated with interfaces.  That configurability is accessed using
  * associated with interfaces.  That configurability is accessed using
  * usb_set_interface().
  * usb_set_interface().
@@ -1502,7 +1510,7 @@ int usb_set_configuration(struct usb_device *dev, int configuration)
 	struct usb_interface **new_interfaces = NULL;
 	struct usb_interface **new_interfaces = NULL;
 	int n, nintf;
 	int n, nintf;
 
 
-	if (configuration == -1)
+	if (dev->authorized == 0 || configuration == -1)
 		configuration = 0;
 		configuration = 0;
 	else {
 	else {
 		for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
 		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 },
 	{ USB_DEVICE(0x0204, 0x6025), .driver_info = USB_QUIRK_RESET_RESUME },
 	/* HP 5300/5370C scanner */
 	/* HP 5300/5370C scanner */
 	{ USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
 	{ USB_DEVICE(0x03f0, 0x0701), .driver_info = USB_QUIRK_STRING_FETCH_255 },
-	/* 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 */
 	/* INTEL VALUE SSD */
 	{ USB_DEVICE(0x8086, 0xf1a5), .driver_info = USB_QUIRK_RESET_RESUME },
 	{ 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 */
 	/* M-Systems Flash Disk Pioneers */
 	{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
 	{ 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 */
 	/* Philips PSC805 audio device */
 	{ USB_DEVICE(0x0471, 0x0155), .driver_info = USB_QUIRK_RESET_RESUME },
 	{ 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 */
 	/* SKYMEDI USB_DRIVE */
 	{ USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
 	{ USB_DEVICE(0x1516, 0x8628), .driver_info = USB_QUIRK_RESET_RESUME },
 
 
 	{ }  /* terminating entry must be last */
 	{ }  /* 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)
 static const struct usb_device_id *find_id(struct usb_device *udev)
 {
 {
 	const struct usb_device_id *id = usb_quirk_list;
 	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",
 		dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
 				udev->quirks);
 				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 */
 	/* By default, disable autosuspend for all non-hubs */
 #ifdef	CONFIG_USB_SUSPEND
 #ifdef	CONFIG_USB_SUSPEND
 	if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
 	if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
-		udev->autosuspend_delay = -1;
+		udev->autosuspend_disabled = 1;
 #endif
 #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 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)
 #if defined(CONFIG_USB_PERSIST) || defined(CONFIG_USB_SUSPEND)
 static const char power_group[] = "power";
 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(bNumConfigurations, "%d\n")
 usb_descriptor_attr(bMaxPacketSize0, "%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[] = {
 static struct attribute *dev_attrs[] = {
 	/* current configuration's attributes */
 	/* current configuration's attributes */
 	&dev_attr_configuration.attr,
 	&dev_attr_configuration.attr,
@@ -420,6 +468,7 @@ static struct attribute *dev_attrs[] = {
 	&dev_attr_bConfigurationValue.attr,
 	&dev_attr_bConfigurationValue.attr,
 	&dev_attr_bmAttributes.attr,
 	&dev_attr_bmAttributes.attr,
 	&dev_attr_bMaxPower.attr,
 	&dev_attr_bMaxPower.attr,
+	&dev_attr_urbnum.attr,
 	/* device attributes */
 	/* device attributes */
 	&dev_attr_idVendor.attr,
 	&dev_attr_idVendor.attr,
 	&dev_attr_idProduct.attr,
 	&dev_attr_idProduct.attr,
@@ -435,6 +484,7 @@ static struct attribute *dev_attrs[] = {
 	&dev_attr_version.attr,
 	&dev_attr_version.attr,
 	&dev_attr_maxchild.attr,
 	&dev_attr_maxchild.attr,
 	&dev_attr_quirks.attr,
 	&dev_attr_quirks.attr,
+	&dev_attr_authorized.attr,
 	NULL,
 	NULL,
 };
 };
 static struct attribute_group dev_attr_grp = {
 static struct attribute_group dev_attr_grp = {

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

@@ -3,6 +3,7 @@
 #include <linux/bitops.h>
 #include <linux/bitops.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/init.h>
 #include <linux/init.h>
+#include <linux/log2.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
 #include <linux/wait.h>
 #include <linux/wait.h>
 #include "hcd.h"
 #include "hcd.h"
@@ -38,7 +39,6 @@ void usb_init_urb(struct urb *urb)
 	if (urb) {
 	if (urb) {
 		memset(urb, 0, sizeof(*urb));
 		memset(urb, 0, sizeof(*urb));
 		kref_init(&urb->kref);
 		kref_init(&urb->kref);
-		spin_lock_init(&urb->lock);
 		INIT_LIST_HEAD(&urb->anchor_list);
 		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 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)
 	if (!urb || urb->hcpriv || !urb->complete)
 		return -EINVAL;
 		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;
 		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->status = -EINPROGRESS;
 	urb->actual_length = 0;
 	urb->actual_length = 0;
 
 
 	/* Lots of sanity checks, so HCDs can rely on clean data
 	/* Lots of sanity checks, so HCDs can rely on clean data
 	 * and don't need to duplicate tests
 	 * and don't need to duplicate tests
 	 */
 	 */
-	pipe = urb->pipe;
-	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) {
 	if (max <= 0) {
 		dev_dbg(&dev->dev,
 		dev_dbg(&dev->dev,
 			"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
 			"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",
-			usb_pipeendpoint(pipe), is_out ? "out" : "in",
+			usb_endpoint_num(&ep->desc), is_out ? "out" : "in",
 			__FUNCTION__, max);
 			__FUNCTION__, max);
 		return -EMSGSIZE;
 		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.
 	 * but drivers only control those sizes for ISO.
 	 * while we're checking, initialize return status.
 	 * while we're checking, initialize return status.
 	 */
 	 */
-	if (temp == PIPE_ISOCHRONOUS) {
+	if (xfertype == USB_ENDPOINT_XFER_ISOC) {
 		int	n, len;
 		int	n, len;
 
 
 		/* "high bandwidth" mode, 1-3 packets/uframe? */
 		/* "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 */
 	/* enforce simple/standard policy */
 	allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_SETUP_DMA_MAP |
 	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)
 		if (is_out)
 			allowed |= URB_ZERO_PACKET;
 			allowed |= URB_ZERO_PACKET;
 		/* FALLTHROUGH */
 		/* FALLTHROUGH */
-	case PIPE_CONTROL:
+	case USB_ENDPOINT_XFER_CONTROL:
 		allowed |= URB_NO_FSBR;	/* only affects UHCI */
 		allowed |= URB_NO_FSBR;	/* only affects UHCI */
 		/* FALLTHROUGH */
 		/* FALLTHROUGH */
 	default:			/* all non-iso endpoints */
 	default:			/* all non-iso endpoints */
 		if (!is_out)
 		if (!is_out)
 			allowed |= URB_SHORT_NOT_OK;
 			allowed |= URB_SHORT_NOT_OK;
 		break;
 		break;
-	case PIPE_ISOCHRONOUS:
+	case USB_ENDPOINT_XFER_ISOC:
 		allowed |= URB_ISO_ASAP;
 		allowed |= URB_ISO_ASAP;
 		break;
 		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
 	 * supports different values... this uses EHCI/UHCI defaults (and
 	 * EHCI can use smaller non-default values).
 	 * 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? */
 		/* too small? */
 		if (urb->interval <= 0)
 		if (urb->interval <= 0)
 			return -EINVAL;
 			return -EINVAL;
@@ -405,29 +419,27 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 			// NOTE usb handles 2^15
 			// NOTE usb handles 2^15
 			if (urb->interval > (1024 * 8))
 			if (urb->interval > (1024 * 8))
 				urb->interval = 1024 * 8;
 				urb->interval = 1024 * 8;
-			temp = 1024 * 8;
+			max = 1024 * 8;
 			break;
 			break;
 		case USB_SPEED_FULL:	/* units are frames/msec */
 		case USB_SPEED_FULL:	/* units are frames/msec */
 		case USB_SPEED_LOW:
 		case USB_SPEED_LOW:
-			if (temp == PIPE_INTERRUPT) {
+			if (xfertype == USB_ENDPOINT_XFER_INT) {
 				if (urb->interval > 255)
 				if (urb->interval > 255)
 					return -EINVAL;
 					return -EINVAL;
 				// NOTE ohci only handles up to 32
 				// NOTE ohci only handles up to 32
-				temp = 128;
+				max = 128;
 			} else {
 			} else {
 				if (urb->interval > 1024)
 				if (urb->interval > 1024)
 					urb->interval = 1024;
 					urb->interval = 1024;
 				// NOTE usb and ohci handle up to 2^15
 				// NOTE usb and ohci handle up to 2^15
-				temp = 1024;
+				max = 1024;
 			}
 			}
 			break;
 			break;
 		default:
 		default:
 			return -EINVAL;
 			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);
 	return usb_hcd_submit_urb(urb, mem_flags);
@@ -496,8 +508,10 @@ int usb_unlink_urb(struct urb *urb)
 {
 {
 	if (!urb)
 	if (!urb)
 		return -EINVAL;
 		return -EINVAL;
-	if (!(urb->dev && urb->dev->bus))
+	if (!urb->dev)
 		return -ENODEV;
 		return -ENODEV;
+	if (!urb->ep)
+		return -EIDRM;
 	return usb_hcd_unlink_urb(urb, -ECONNRESET);
 	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)
 void usb_kill_urb(struct urb *urb)
 {
 {
+	static DEFINE_MUTEX(reject_mutex);
+
 	might_sleep();
 	might_sleep();
-	if (!(urb && urb->dev && urb->dev->bus))
+	if (!(urb && urb->dev && urb->ep))
 		return;
 		return;
-	spin_lock_irq(&urb->lock);
+	mutex_lock(&reject_mutex);
 	++urb->reject;
 	++urb->reject;
-	spin_unlock_irq(&urb->lock);
+	mutex_unlock(&reject_mutex);
 
 
 	usb_hcd_unlink_urb(urb, -ENOENT);
 	usb_hcd_unlink_urb(urb, -ENOENT);
 	wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
 	wait_event(usb_kill_urb_queue, atomic_read(&urb->use_count) == 0);
 
 
-	spin_lock_irq(&urb->lock);
+	mutex_lock(&reject_mutex);
 	--urb->reject;
 	--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 */
 #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)
  * usb_alloc_dev - usb device constructor (usbcore-internal)
  * @parent: hub to which device is connected; null to allocate a root hub
  * @parent: hub to which device is connected; null to allocate a root hub
@@ -239,6 +248,8 @@ struct usb_device *
 usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
 usb_alloc_dev(struct usb_device *parent, struct usb_bus *bus, unsigned port1)
 {
 {
 	struct usb_device *dev;
 	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);
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
 	if (!dev)
 	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;
 	dev->dev.dma_mask = bus->controller->dma_mask;
 	set_dev_node(&dev->dev, dev_to_node(bus->controller));
 	set_dev_node(&dev->dev, dev_to_node(bus->controller));
 	dev->state = USB_STATE_ATTACHED;
 	dev->state = USB_STATE_ATTACHED;
+	atomic_set(&dev->urbnum, 0);
 
 
 	INIT_LIST_HEAD(&dev->ep0.urb_list);
 	INIT_LIST_HEAD(&dev->ep0.urb_list);
 	dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
 	dev->ep0.desc.bLength = USB_DT_ENDPOINT_SIZE;
 	dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
 	dev->ep0.desc.bDescriptorType = USB_DT_ENDPOINT;
 	/* ep0 maxpacket comes later, from device descriptor */
 	/* 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
 	/* Save readable and stable topology id, distinguishing devices
 	 * by location for diagnostics, tools, driver model, etc.  The
 	 * 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;
 		dev->dev.parent = bus->controller;
 		sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
 		sprintf(&dev->dev.bus_id[0], "usb%d", bus->busnum);
+		root_hub = 1;
 	} else {
 	} else {
 		/* match any labeling on the hubs; it's one-based */
 		/* match any labeling on the hubs; it's one-based */
 		if (parent->devpath[0] == '0')
 		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);
 	INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
 	dev->autosuspend_delay = usb_autosuspend_delay * HZ;
 	dev->autosuspend_delay = usb_autosuspend_delay * HZ;
 #endif
 #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;
 	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
  * usb_buffer_map_sg - create scatterlist DMA mapping(s) for an endpoint
  * @dev: device to which the scatterlist will be mapped
  * @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
  * @sg: the scatterlist to map
  * @nents: the number of entries in the scatterlist
  * @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().
  * 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 scatterlist *sg, int nents)
 {
 {
 	struct usb_bus		*bus;
 	struct usb_bus		*bus;
 	struct device		*controller;
 	struct device		*controller;
 
 
 	if (!dev
 	if (!dev
-			|| usb_pipecontrol(pipe)
 			|| !(bus = dev->bus)
 			|| !(bus = dev->bus)
 			|| !(controller = bus->controller)
 			|| !(controller = bus->controller)
 			|| !controller->dma_mask)
 			|| !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
 	// FIXME generic api broken like pci, can't report errors
 	return dma_map_sg(controller, sg, nents,
 	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
 /* 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)
  * usb_buffer_dmasync_sg - synchronize DMA and CPU view of scatterlist buffer(s)
  * @dev: device to which the scatterlist will be mapped
  * @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
  * @sg: the scatterlist to synchronize
  * @n_hw_ents: the positive return value from usb_buffer_map_sg
  * @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
  * Use this when you are re-using a scatterlist's data buffers for
  * another USB request.
  * 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 scatterlist *sg, int n_hw_ents)
 {
 {
 	struct usb_bus		*bus;
 	struct usb_bus		*bus;
@@ -819,20 +838,20 @@ void usb_buffer_dmasync_sg(const struct usb_device *dev, unsigned pipe,
 		return;
 		return;
 
 
 	dma_sync_sg(controller, sg, n_hw_ents,
 	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
 #endif
 
 
 /**
 /**
  * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
  * usb_buffer_unmap_sg - free DMA mapping(s) for a scatterlist
  * @dev: device to which the scatterlist will be mapped
  * @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
  * @sg: the scatterlist to unmap
  * @n_hw_ents: the positive return value from usb_buffer_map_sg
  * @n_hw_ents: the positive return value from usb_buffer_map_sg
  *
  *
  * Reverses the effect of 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 scatterlist *sg, int n_hw_ents)
 {
 {
 	struct usb_bus		*bus;
 	struct usb_bus		*bus;
@@ -845,7 +864,7 @@ void usb_buffer_unmap_sg(const struct usb_device *dev, unsigned pipe,
 		return;
 		return;
 
 
 	dma_unmap_sg(controller, sg, n_hw_ents,
 	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 */
 /* 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);
 				struct usb_device *udev);
 extern void usb_remove_ep_files(struct usb_host_endpoint *endpoint);
 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_endpoint (struct usb_device *dev, unsigned int epaddr);
 extern void usb_disable_interface (struct usb_device *dev,
 extern void usb_disable_interface (struct usb_device *dev,
 		struct usb_interface *intf);
 		struct usb_interface *intf);
 extern void usb_release_interface_cache(struct kref *ref);
 extern void usb_release_interface_cache(struct kref *ref);
 extern void usb_disable_device (struct usb_device *dev, int skip_ep0);
 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 void usb_detect_quirks(struct usb_device *udev);
 
 
 extern int usb_get_device_descriptor(struct usb_device *dev,
 extern int usb_get_device_descriptor(struct usb_device *dev,
 		unsigned int size);
 		unsigned int size);
 extern char *usb_cache_string(struct usb_device *udev, int index);
 extern char *usb_cache_string(struct usb_device *udev, int index);
 extern int usb_set_configuration(struct usb_device *dev, int configuration);
 extern int usb_set_configuration(struct usb_device *dev, int configuration);
+extern int usb_choose_configuration(struct usb_device *udev);
 
 
 extern void usb_kick_khubd(struct usb_device *dev);
 extern void usb_kick_khubd(struct usb_device *dev);
 extern int usb_match_device(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"
 	   driver on a new board.   Enable these files by choosing "Y"
 	   here.  If in doubt, or to conserve kernel memory, say "N".
 	   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
 config	USB_GADGET_SELECTED
 	boolean
 	boolean
 
 
@@ -103,6 +114,20 @@ config USB_AMD5536UDC
 	default USB_GADGET
 	default USB_GADGET
 	select USB_GADGET_SELECTED
 	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
 config USB_GADGET_FSL_USB2
 	boolean "Freescale Highspeed USB DR Peripheral Controller"
 	boolean "Freescale Highspeed USB DR Peripheral Controller"
 	depends on MPC834x || PPC_MPC831x
 	depends on MPC834x || PPC_MPC831x
@@ -228,7 +253,6 @@ config USB_LH7A40X
 	default USB_GADGET
 	default USB_GADGET
 	select USB_GADGET_SELECTED
 	select USB_GADGET_SELECTED
 
 
-
 config USB_GADGET_OMAP
 config USB_GADGET_OMAP
 	boolean "OMAP USB Device Controller"
 	boolean "OMAP USB Device Controller"
 	depends on ARCH_OMAP
 	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_LH7A40X)	+= lh7a40x_udc.o
 obj-$(CONFIG_USB_S3C2410)	+= s3c2410_udc.o
 obj-$(CONFIG_USB_S3C2410)	+= s3c2410_udc.o
 obj-$(CONFIG_USB_AT91)		+= at91_udc.o
 obj-$(CONFIG_USB_AT91)		+= at91_udc.o
+obj-$(CONFIG_USB_ATMEL_USBA)	+= atmel_usba_udc.o
 obj-$(CONFIG_USB_FSL_USB2)	+= fsl_usb2_udc.o
 obj-$(CONFIG_USB_FSL_USB2)	+= fsl_usb2_udc.o
 obj-$(CONFIG_USB_M66592)	+= m66592-udc.o
 obj-$(CONFIG_USB_M66592)	+= m66592-udc.o
 
 

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

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

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

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

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

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

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

@@ -19,40 +19,18 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  * 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/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/utsname.h>
 #include <linux/device.h>
 #include <linux/device.h>
-#include <linux/moduleparam.h>
 #include <linux/ctype.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/ch9.h>
 #include <linux/usb/cdc.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"
 #include "gadget_chips.h"
 
 
@@ -356,15 +334,15 @@ module_param (qmult, uint, S_IRUGO|S_IWUSR);
 #define qlen(gadget) \
 #define qlen(gadget) \
 	(DEFAULT_QLEN*((gadget->speed == USB_SPEED_HIGH) ? qmult : 1))
 	(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)
 static inline int BITRATE(struct usb_gadget *g)
 {
 {
 	return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS;
 	return (g->speed == USB_SPEED_HIGH) ? HS_BPS : FS_BPS;
 }
 }
 
 
 #else	/* full speed (low speed doesn't do bulk) */
 #else	/* full speed (low speed doesn't do bulk) */
+
+#define qmult		1
+
 #define	DEVSPEED	USB_SPEED_FULL
 #define	DEVSPEED	USB_SPEED_FULL
 
 
 #define qlen(gadget) DEFAULT_QLEN
 #define qlen(gadget) DEFAULT_QLEN
@@ -390,7 +368,7 @@ static inline int BITRATE(struct usb_gadget *g)
 	do { } while (0)
 	do { } while (0)
 #endif /* DEBUG */
 #endif /* DEBUG */
 
 
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
 #define VDEBUG	DEBUG
 #define VDEBUG	DEBUG
 #else
 #else
 #define VDEBUG(dev,fmt,args...) \
 #define VDEBUG(dev,fmt,args...) \
@@ -830,8 +808,6 @@ static const struct usb_descriptor_header *fs_rndis_function [] = {
 };
 };
 #endif
 #endif
 
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-
 /*
 /*
  * usb 2.0 devices need to expose both high speed and full speed
  * usb 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at 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. */
 /* 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.
  * complications: class descriptors, and an altsetting.
  */
  */
 static int
 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;
 	int					len;
 	const struct usb_config_descriptor	*config;
 	const struct usb_config_descriptor	*config;
 	const struct usb_descriptor_header	**function;
 	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)
 #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)
 	if (index >= device_desc.bNumConfigurations)
 		return -EINVAL;
 		return -EINVAL;
@@ -1217,7 +1187,7 @@ eth_set_config (struct eth_dev *dev, unsigned number, gfp_t gfp_flags)
 		if (number)
 		if (number)
 			eth_reset_config (dev);
 			eth_reset_config (dev);
 		usb_gadget_vbus_draw(dev->gadget,
 		usb_gadget_vbus_draw(dev->gadget,
-				dev->gadget->is_otg ? 8 : 100);
+				gadget_is_otg(dev->gadget) ? 8 : 100);
 	} else {
 	} else {
 		char *speed;
 		char *speed;
 		unsigned power;
 		unsigned power;
@@ -1399,24 +1369,22 @@ eth_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 			value = min (wLength, (u16) sizeof device_desc);
 			value = min (wLength, (u16) sizeof device_desc);
 			memcpy (req->buf, &device_desc, value);
 			memcpy (req->buf, &device_desc, value);
 			break;
 			break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 		case USB_DT_DEVICE_QUALIFIER:
 		case USB_DT_DEVICE_QUALIFIER:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 				break;
 			value = min (wLength, (u16) sizeof dev_qualifier);
 			value = min (wLength, (u16) sizeof dev_qualifier);
 			memcpy (req->buf, &dev_qualifier, value);
 			memcpy (req->buf, &dev_qualifier, value);
 			break;
 			break;
 
 
 		case USB_DT_OTHER_SPEED_CONFIG:
 		case USB_DT_OTHER_SPEED_CONFIG:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 				break;
 			// FALLTHROUGH
 			// FALLTHROUGH
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
 		case USB_DT_CONFIG:
 		case USB_DT_CONFIG:
-			value = config_buf (gadget->speed, req->buf,
+			value = config_buf(gadget, req->buf,
 					wValue >> 8,
 					wValue >> 8,
 					wValue & 0xff,
 					wValue & 0xff,
-					gadget->is_otg);
+					gadget_is_otg(gadget));
 			if (value >= 0)
 			if (value >= 0)
 				value = min (wLength, (u16) value);
 				value = min (wLength, (u16) value);
 			break;
 			break;
@@ -1585,12 +1553,12 @@ done_set_intf:
 				&& rndis_control_intf.bInterfaceNumber
 				&& rndis_control_intf.bInterfaceNumber
 					== wIndex) {
 					== wIndex) {
 			u8 *buf;
 			u8 *buf;
+			u32 n;
 
 
 			/* return the result */
 			/* return the result */
-			buf = rndis_get_next_response (dev->rndis_config,
-						       &value);
+			buf = rndis_get_next_response(dev->rndis_config, &n);
 			if (buf) {
 			if (buf) {
-				memcpy (req->buf, buf, value);
+				memcpy(req->buf, buf, n);
 				req->complete = rndis_response_complete;
 				req->complete = rndis_response_complete;
 				rndis_free_response(dev->rndis_config, buf);
 				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);
 	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);
 	req = container_of (dev->tx_reqs.next, struct usb_request, list);
 	list_del (&req->list);
 	list_del (&req->list);
+
+	/* temporarily stop TX queue when the freelist empties */
 	if (list_empty (&dev->tx_reqs))
 	if (list_empty (&dev->tx_reqs))
 		netif_stop_queue (net);
 		netif_stop_queue (net);
 	spin_unlock_irqrestore(&dev->req_lock, flags);
 	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;
 	req->length = length;
 
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
 	/* throttle highspeed IRQ rate back slightly */
 	/* 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);
 	retval = usb_ep_queue (dev->in_ep, req, GFP_ATOMIC);
 	switch (retval) {
 	switch (retval) {
@@ -2188,8 +2167,7 @@ static int eth_stop (struct net_device *net)
 	}
 	}
 
 
 	if (rndis_active(dev)) {
 	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);
 		(void) rndis_signal_disconnect (dev->rndis_config);
 	}
 	}
 
 
@@ -2443,26 +2421,28 @@ autoconf_fail:
 	if (rndis)
 	if (rndis)
 		device_desc.bNumConfigurations = 2;
 		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 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
-#endif	/* DUALSPEED */
+	}
 
 
-	if (gadget->is_otg) {
+	if (gadget_is_otg(gadget)) {
 		otg_descriptor.bmAttributes |= USB_OTG_HNP,
 		otg_descriptor.bmAttributes |= USB_OTG_HNP,
 		eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 		eth_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 		eth_config.bMaxPower = 4;
 		eth_config.bMaxPower = 4;
@@ -2598,12 +2578,11 @@ fail0:
 		if (rndis_set_param_dev (dev->rndis_config, dev->net,
 		if (rndis_set_param_dev (dev->rndis_config, dev->net,
 					 &dev->stats, &dev->cdc_filter))
 					 &dev->stats, &dev->cdc_filter))
 			goto fail0;
 			goto fail0;
-		if (rndis_set_param_vendor (dev->rndis_config, vendorID,
-					    manufacturer))
+		if (rndis_set_param_vendor(dev->rndis_config, vendorID,
+					manufacturer))
 			goto fail0;
 			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;
 			goto fail0;
 		INFO (dev, "RNDIS ready\n");
 		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
  * 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.
  * All rights reserved.
  *
  *
  * Redistribution and use in source and binary forms, with or without
  * 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/blkdev.h>
-#include <linux/compiler.h>
 #include <linux/completion.h>
 #include <linux/completion.h>
 #include <linux/dcache.h>
 #include <linux/dcache.h>
 #include <linux/delay.h>
 #include <linux/delay.h>
@@ -235,18 +229,10 @@
 #include <linux/fcntl.h>
 #include <linux/fcntl.h>
 #include <linux/file.h>
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
 #include <linux/kref.h>
 #include <linux/kref.h>
 #include <linux/kthread.h>
 #include <linux/kthread.h>
 #include <linux/limits.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/rwsem.h>
-#include <linux/sched.h>
-#include <linux/signal.h>
 #include <linux/slab.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <linux/spinlock.h>
 #include <linux/string.h>
 #include <linux/string.h>
@@ -254,7 +240,7 @@
 #include <linux/utsname.h>
 #include <linux/utsname.h>
 
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 
 #include "gadget_chips.h"
 #include "gadget_chips.h"
 
 
@@ -263,7 +249,7 @@
 
 
 #define DRIVER_DESC		"File-backed Storage Gadget"
 #define DRIVER_DESC		"File-backed Storage Gadget"
 #define DRIVER_NAME		"g_file_storage"
 #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 longname[] = DRIVER_DESC;
 static const char shortname[] = DRIVER_NAME;
 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
 #ifdef DEBUG
-#define DBG(fsg,fmt,args...) \
-	xprintk(fsg , KERN_DEBUG , fmt , ## args)
 #define LDBG(lun,fmt,args...) \
 #define LDBG(lun,fmt,args...) \
-	yprintk(lun , KERN_DEBUG , fmt , ## args)
+	dev_dbg(&(lun)->dev , fmt , ## args)
 #define MDBG(fmt,args...) \
 #define MDBG(fmt,args...) \
 	printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args)
 	printk(KERN_DEBUG DRIVER_NAME ": " fmt , ## args)
 #else
 #else
-#define DBG(fsg,fmt,args...) \
-	do { } while (0)
 #define LDBG(lun,fmt,args...) \
 #define LDBG(lun,fmt,args...) \
 	do { } while (0)
 	do { } while (0)
 #define MDBG(fmt,args...) \
 #define MDBG(fmt,args...) \
 	do { } while (0)
 	do { } while (0)
-#undef VERBOSE
+#undef VERBOSE_DEBUG
 #undef DUMP_MSGS
 #undef DUMP_MSGS
 #endif /* DEBUG */
 #endif /* DEBUG */
 
 
-#ifdef VERBOSE
-#define VDBG	DBG
+#ifdef VERBOSE_DEBUG
 #define VLDBG	LDBG
 #define VLDBG	LDBG
 #else
 #else
-#define VDBG(fsg,fmt,args...) \
-	do { } while (0)
 #define VLDBG(lun,fmt,args...) \
 #define VLDBG(lun,fmt,args...) \
 	do { } while (0)
 	do { } while (0)
-#endif /* VERBOSE */
+#endif /* VERBOSE_DEBUG */
 
 
-#define ERROR(fsg,fmt,args...) \
-	xprintk(fsg , KERN_ERR , fmt , ## args)
 #define LERROR(lun,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...) \
 #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...) \
 #define LINFO(lun,fmt,args...) \
-	yprintk(lun , KERN_INFO , fmt , ## args)
+	dev_info(&(lun)->dev , fmt , ## args)
 
 
 #define MINFO(fmt,args...) \
 #define MINFO(fmt,args...) \
 	printk(KERN_INFO DRIVER_NAME ": " 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 {
 static struct {
 	char		*file[MAX_LUNS];
 	char		*file[MAX_LUNS];
 	int		ro[MAX_LUNS];
 	int		ro[MAX_LUNS];
-	int		num_filenames;
-	int		num_ros;
+	unsigned int	num_filenames;
+	unsigned int	num_ros;
 	unsigned int	nluns;
 	unsigned int	nluns;
 
 
 	int		removable;
 	int		removable;
@@ -578,7 +555,7 @@ struct lun {
 
 
 #define backing_file_is_open(curlun)	((curlun)->filp != NULL)
 #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);
 	return container_of(dev, struct lun, dev);
 }
 }
@@ -711,13 +688,13 @@ struct fsg_dev {
 
 
 typedef void (*fsg_routine_t)(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);
 	return (fsg->state > FSG_STATE_IDLE);
 }
 }
 
 
 /* Make bulk-out requests be divisible by the maxpacket size */
 /* 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)
 		struct fsg_buffhd *bh, unsigned int length)
 {
 {
 	unsigned int	rem;
 	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,
 static void dump_msg(struct fsg_dev *fsg, const char *label,
 		const u8 *buf, unsigned int length)
 		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
 #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)
 		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 */
 #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 */
 /* 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]);
 	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) |
 	return ((u32) buf[0] << 24) | ((u32) buf[1] << 16) |
 			((u32) buf[2] << 8) | ((u32) buf[3]);
 			((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[0] = val >> 8;
 	buf[1] = val;
 	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[0] = val >> 24;
 	buf[1] = val >> 16;
 	buf[1] = val >> 16;
@@ -950,8 +913,6 @@ static const struct usb_descriptor_header *fs_function[] = {
 #define FS_FUNCTION_PRE_EP_ENTRIES	2
 #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
  * USB 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at 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
 #define HS_FUNCTION_PRE_EP_ENTRIES	2
 
 
 /* Maxpacket and other transfer characteristics vary by speed. */
 /* 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
 /* 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,
 static int populate_config_buf(struct usb_gadget *gadget,
 		u8 *buf, u8 type, unsigned index)
 		u8 *buf, u8 type, unsigned index)
 {
 {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 	enum usb_device_speed			speed = gadget->speed;
 	enum usb_device_speed			speed = gadget->speed;
-#endif
 	int					len;
 	int					len;
 	const struct usb_descriptor_header	**function;
 	const struct usb_descriptor_header	**function;
 
 
 	if (index > 0)
 	if (index > 0)
 		return -EINVAL;
 		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;
 		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;
 		function = hs_function;
 	else
 	else
-#endif
 		function = fs_function;
 		function = fs_function;
 
 
 	/* for now, don't advertise srp-only devices */
 	/* for now, don't advertise srp-only devices */
-	if (!gadget->is_otg)
+	if (!gadget_is_otg(gadget))
 		function++;
 		function++;
 
 
 	len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, 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;
 			value = sizeof device_desc;
 			memcpy(req->buf, &device_desc, value);
 			memcpy(req->buf, &device_desc, value);
 			break;
 			break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 		case USB_DT_DEVICE_QUALIFIER:
 		case USB_DT_DEVICE_QUALIFIER:
 			VDBG(fsg, "get device qualifier\n");
 			VDBG(fsg, "get device qualifier\n");
-			if (!fsg->gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(fsg->gadget))
 				break;
 				break;
 			value = sizeof dev_qualifier;
 			value = sizeof dev_qualifier;
 			memcpy(req->buf, &dev_qualifier, value);
 			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:
 		case USB_DT_OTHER_SPEED_CONFIG:
 			VDBG(fsg, "get other-speed config descriptor\n");
 			VDBG(fsg, "get other-speed config descriptor\n");
-			if (!fsg->gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(fsg->gadget))
 				break;
 				break;
 			goto get_config;
 			goto get_config;
-#endif
 		case USB_DT_CONFIG:
 		case USB_DT_CONFIG:
 			VDBG(fsg, "get configuration descriptor\n");
 			VDBG(fsg, "get configuration descriptor\n");
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-		get_config:
-#endif
+get_config:
 			value = populate_config_buf(fsg->gadget,
 			value = populate_config_buf(fsg->gadget,
 					req->buf,
 					req->buf,
 					w_value >> 8,
 					w_value >> 8,
@@ -1646,7 +1599,8 @@ static int do_read(struct fsg_dev *fsg)
 		/* Wait for the next buffer to become available */
 		/* Wait for the next buffer to become available */
 		bh = fsg->next_buffhd_to_fill;
 		bh = fsg->next_buffhd_to_fill;
 		while (bh->state != BUF_STATE_EMPTY) {
 		while (bh->state != BUF_STATE_EMPTY) {
-			if ((rc = sleep_thread(fsg)) != 0)
+			rc = sleep_thread(fsg);
+			if (rc)
 				return rc;
 				return rc;
 		}
 		}
 
 
@@ -1885,7 +1839,8 @@ static int do_write(struct fsg_dev *fsg)
 		}
 		}
 
 
 		/* Wait for something to happen */
 		/* Wait for something to happen */
-		if ((rc = sleep_thread(fsg)) != 0)
+		rc = sleep_thread(fsg);
+		if (rc)
 			return rc;
 			return rc;
 	}
 	}
 
 
@@ -2369,7 +2324,8 @@ static int pad_with_zeros(struct fsg_dev *fsg)
 
 
 		/* Wait for the next buffer to be free */
 		/* Wait for the next buffer to be free */
 		while (bh->state != BUF_STATE_EMPTY) {
 		while (bh->state != BUF_STATE_EMPTY) {
-			if ((rc = sleep_thread(fsg)) != 0)
+			rc = sleep_thread(fsg);
+			if (rc)
 				return rc;
 				return rc;
 		}
 		}
 
 
@@ -2429,7 +2385,8 @@ static int throw_away_data(struct fsg_dev *fsg)
 		}
 		}
 
 
 		/* Otherwise wait for something to happen */
 		/* Otherwise wait for something to happen */
-		if ((rc = sleep_thread(fsg)) != 0)
+		rc = sleep_thread(fsg);
+		if (rc)
 			return rc;
 			return rc;
 	}
 	}
 	return 0;
 	return 0;
@@ -2551,7 +2508,8 @@ static int send_status(struct fsg_dev *fsg)
 	/* Wait for the next buffer to become available */
 	/* Wait for the next buffer to become available */
 	bh = fsg->next_buffhd_to_fill;
 	bh = fsg->next_buffhd_to_fill;
 	while (bh->state != BUF_STATE_EMPTY) {
 	while (bh->state != BUF_STATE_EMPTY) {
-		if ((rc = sleep_thread(fsg)) != 0)
+		rc = sleep_thread(fsg);
+		if (rc)
 			return 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 */
 	/* Wait for the next buffer to become available for data or status */
 	bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
 	bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill;
 	while (bh->state != BUF_STATE_EMPTY) {
 	while (bh->state != BUF_STATE_EMPTY) {
-		if ((rc = sleep_thread(fsg)) != 0)
+		rc = sleep_thread(fsg);
+		if (rc)
 			return rc;
 			return rc;
-		}
+	}
 	fsg->phase_error = 0;
 	fsg->phase_error = 0;
 	fsg->short_packet_received = 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? */
 	/* Is the CBW meaningful? */
 	if (cbw->Lun >= MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG ||
 	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, "
 		DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
 				"cmdlen %u\n",
 				"cmdlen %u\n",
 				cbw->Lun, cbw->Flags, cbw->Length);
 				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 */
 		/* Wait for the next buffer to become available */
 		bh = fsg->next_buffhd_to_fill;
 		bh = fsg->next_buffhd_to_fill;
 		while (bh->state != BUF_STATE_EMPTY) {
 		while (bh->state != BUF_STATE_EMPTY) {
-			if ((rc = sleep_thread(fsg)) != 0)
+			rc = sleep_thread(fsg);
+			if (rc)
 				return rc;
 				return rc;
-			}
+		}
 
 
 		/* Queue a request to read a Bulk-only CBW */
 		/* Queue a request to read a Bulk-only CBW */
 		set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN);
 		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 */
 		/* Wait for the CBW to arrive */
 		while (bh->state != BUF_STATE_FULL) {
 		while (bh->state != BUF_STATE_FULL) {
-			if ((rc = sleep_thread(fsg)) != 0)
+			rc = sleep_thread(fsg);
+			if (rc)
 				return rc;
 				return rc;
-			}
+		}
 		smp_rmb();
 		smp_rmb();
 		rc = received_cbw(fsg, bh);
 		rc = received_cbw(fsg, bh);
 		bh->state = BUF_STATE_EMPTY;
 		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 */
 		/* Wait for the next command to arrive */
 		while (fsg->cbbuf_cmnd_size == 0) {
 		while (fsg->cbbuf_cmnd_size == 0) {
-			if ((rc = sleep_thread(fsg)) != 0)
+			rc = sleep_thread(fsg);
+			if (rc)
 				return rc;
 				return rc;
-			}
+		}
 
 
 		/* Is the previous status interrupt request still busy?
 		/* Is the previous status interrupt request still busy?
 		 * The host is allowed to skip reading the status,
 		 * 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);
 	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 lun	*curlun = dev_to_lun(dev);
 	struct fsg_dev	*fsg = dev_get_drvdata(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);
 	down_read(&fsg->filesem);
 	if (backing_file_is_open(curlun)) {	// Get the complete pathname
 	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))
 		if (IS_ERR(p))
 			rc = PTR_ERR(p);
 			rc = PTR_ERR(p);
 		else {
 		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;
 	ssize_t		rc = count;
 	struct lun	*curlun = dev_to_lun(dev);
 	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;
 	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 lun	*curlun = dev_to_lun(dev);
 	struct fsg_dev	*fsg = dev_get_drvdata(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 */
 	/* Find out how many LUNs there should be */
 	i = mod_data.nluns;
 	i = mod_data.nluns;
 	if (i == 0)
 	if (i == 0)
-		i = max(mod_data.num_filenames, 1);
+		i = max(mod_data.num_filenames, 1u);
 	if (i > MAX_LUNS) {
 	if (i > MAX_LUNS) {
 		ERROR(fsg, "invalid number of LUNs: %d\n", i);
 		ERROR(fsg, "invalid number of LUNs: %d\n", i);
 		rc = -EINVAL;
 		rc = -EINVAL;
@@ -3944,21 +3909,23 @@ static int __init fsg_bind(struct usb_gadget *gadget)
 	intf_desc.bInterfaceProtocol = mod_data.transport_type;
 	intf_desc.bInterfaceProtocol = mod_data.transport_type;
 	fs_function[i + FS_FUNCTION_PRE_EP_ENTRIES] = NULL;
 	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;
 		otg_desc.bmAttributes |= USB_OTG_HNP;
-	}
 
 
 	rc = -ENOMEM;
 	rc = -ENOMEM;
 
 

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

@@ -35,7 +35,7 @@
 #include <linux/moduleparam.h>
 #include <linux/moduleparam.h>
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/usb/otg.h>
 #include <linux/dma-mapping.h>
 #include <linux/dma-mapping.h>
 #include <linux/platform_device.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)
 static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA)
 {
 {
-#ifdef CONFIG_USB_OTG
 	struct fsl_udc *udc;
 	struct fsl_udc *udc;
 
 
 	udc = container_of(gadget, struct fsl_udc, gadget);
 	udc = container_of(gadget, struct fsl_udc, gadget);
-
 	if (udc->transceiver)
 	if (udc->transceiver)
 		return otg_set_power(udc->transceiver, mA);
 		return otg_set_power(udc->transceiver, mA);
-#endif
 	return -ENOTSUPP;
 	return -ENOTSUPP;
 }
 }
 
 
@@ -1120,7 +1117,7 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)
 	return 0;
 	return 0;
 }
 }
 
 
-/* defined in usb_gadget.h */
+/* defined in gadget.h */
 static struct usb_gadget_ops fsl_gadget_ops = {
 static struct usb_gadget_ops fsl_gadget_ops = {
 	.get_frame = fsl_get_frame,
 	.get_frame = fsl_get_frame,
 	.wakeup = fsl_wakeup,
 	.wakeup = fsl_wakeup,
@@ -1321,7 +1318,7 @@ static void setup_received_irq(struct fsl_udc *udc,
 				| USB_TYPE_STANDARD)) {
 				| USB_TYPE_STANDARD)) {
 			/* Note: The driver has not include OTG support yet.
 			/* Note: The driver has not include OTG support yet.
 			 * This will be set when OTG support is added */
 			 * This will be set when OTG support is added */
-			if (!udc->gadget.is_otg)
+			if (!gadget_is_otg(udc->gadget))
 				break;
 				break;
 			else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
 			else if (setup->bRequest == USB_DEVICE_B_HNP_ENABLE)
 				udc->gadget.b_hnp_enable = 1;
 				udc->gadget.b_hnp_enable = 1;
@@ -1330,6 +1327,8 @@ static void setup_received_irq(struct fsl_udc *udc,
 			else if (setup->bRequest ==
 			else if (setup->bRequest ==
 					USB_DEVICE_A_ALT_HNP_SUPPORT)
 					USB_DEVICE_A_ALT_HNP_SUPPORT)
 				udc->gadget.a_alt_hnp_support = 1;
 				udc->gadget.a_alt_hnp_support = 1;
+			else
+				break;
 			rc = 0;
 			rc = 0;
 		} else
 		} else
 			break;
 			break;
@@ -1840,10 +1839,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 	if (!driver || driver != udc_controller->driver || !driver->unbind)
 	if (!driver || driver != udc_controller->driver || !driver->unbind)
 		return -EINVAL;
 		return -EINVAL;
 
 
-#ifdef CONFIG_USB_OTG
 	if (udc_controller->transceiver)
 	if (udc_controller->transceiver)
 		(void)otg_set_peripheral(udc_controller->transceiver, 0);
 		(void)otg_set_peripheral(udc_controller->transceiver, 0);
-#endif
 
 
 	/* stop DR, disable intr */
 	/* stop DR, disable intr */
 	dr_controller_stop(udc_controller);
 	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
  * 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/kernel.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
 #include <linux/utsname.h>
 #include <linux/utsname.h>
 #include <linux/device.h>
 #include <linux/device.h>
-#include <linux/moduleparam.h>
 
 
 #include <sound/driver.h>
 #include <sound/driver.h>
 #include <sound/core.h>
 #include <sound/core.h>
@@ -36,7 +30,7 @@
 #include <sound/rawmidi.h>
 #include <sound/rawmidi.h>
 
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 #include <linux/usb/audio.h>
 #include <linux/usb/audio.h>
 #include <linux/usb/midi.h>
 #include <linux/usb/midi.h>
 
 
@@ -139,30 +133,16 @@ struct gmidi_device {
 static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req);
 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;
 static unsigned buflen = 256;
@@ -425,7 +405,7 @@ static int config_buf(struct usb_gadget *gadget,
 	return len;
 	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;
 	struct usb_request	*req;
 
 
@@ -455,7 +435,7 @@ static const uint8_t gmidi_cin_length[] = {
  * Receives a chunk of MIDI data.
  * Receives a chunk of MIDI data.
  */
  */
 static void gmidi_read_data(struct usb_ep *ep, int cable,
 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;
 	struct gmidi_device *dev = ep->driver_data;
 	/* cable is ignored, because for now we only have one. */
 	/* 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;
 	int err = 0;
 	struct usb_request *req;
 	struct usb_request *req;
-	struct usb_ep* ep;
+	struct usb_ep *ep;
 	unsigned i;
 	unsigned i;
 
 
 	err = usb_ep_enable(dev->in_ep, &bulk_in_desc);
 	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) {
 	if (gadget_is_sa1100(gadget) && dev->config) {
 		/* tx fifo is full, but we can't clear it...*/
 		/* 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;
 		return -ESPIPE;
 	}
 	}
 	gmidi_reset_config(dev);
 	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)
 static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget)
 {
 {
 	struct gmidi_device *dev = get_gadget_data(gadget);
 	struct gmidi_device *dev = get_gadget_data(gadget);
-	struct snd_card* card;
+	struct snd_card *card;
 
 
 	DBG(dev, "unbind\n");
 	DBG(dev, "unbind\n");
 
 
@@ -867,12 +847,12 @@ static int gmidi_snd_free(struct snd_device *device)
 	return 0;
 	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)
 					uint8_t p1, uint8_t p2, uint8_t p3)
 {
 {
 	unsigned length = req->length;
 	unsigned length = req->length;
+	u8 *buf = (u8 *)req->buf + length;
 
 
-	uint8_t* buf = (uint8_t*)req->buf + length;
 	buf[0] = p0;
 	buf[0] = p0;
 	buf[1] = p1;
 	buf[1] = p1;
 	buf[2] = p2;
 	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.
  * 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;
 	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) {
 	if (!ep) {
 		return;
 		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)
 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);
 	gmidi_transmit(dev, NULL);
 }
 }
 
 
 static int gmidi_in_open(struct snd_rawmidi_substream *substream)
 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");
 	VDBG(dev, "gmidi_in_open\n");
 	dev->in_substream = substream;
 	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)
 static int gmidi_in_close(struct snd_rawmidi_substream *substream)
 {
 {
+	struct gmidi_device *dev = substream->rmidi->private_data;
+
 	VDBG(dev, "gmidi_in_close\n");
 	VDBG(dev, "gmidi_in_close\n");
 	return 0;
 	return 0;
 }
 }
 
 
 static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
 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);
 	VDBG(dev, "gmidi_in_trigger %d\n", up);
 	dev->in_port.active = 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)
 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");
 	VDBG(dev, "gmidi_out_open\n");
 	dev->out_substream = substream;
 	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)
 static int gmidi_out_close(struct snd_rawmidi_substream *substream)
 {
 {
+	struct gmidi_device *dev = substream->rmidi->private_data;
+
 	VDBG(dev, "gmidi_out_close\n");
 	VDBG(dev, "gmidi_out_close\n");
 	return 0;
 	return 0;
 }
 }
 
 
 static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up)
 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);
 	VDBG(dev, "gmidi_out_trigger %d\n", up);
 	if (up) {
 	if (up) {

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

@@ -37,7 +37,7 @@
 #include <linux/proc_fs.h>
 #include <linux/proc_fs.h>
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 
 #include <asm/byteorder.h>
 #include <asm/byteorder.h>
 #include <asm/io.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/init.h>
 #include <linux/module.h>
 #include <linux/module.h>
@@ -38,7 +37,7 @@
 #include <linux/moduleparam.h>
 #include <linux/moduleparam.h>
 
 
 #include <linux/usb/gadgetfs.h>
 #include <linux/usb/gadgetfs.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 
 
 
 /*
 /*
@@ -253,7 +252,7 @@ static const char *CHIP;
 	do { } while (0)
 	do { } while (0)
 #endif /* DEBUG */
 #endif /* DEBUG */
 
 
-#ifdef VERBOSE
+#ifdef VERBOSE_DEBUG
 #define VDEBUG	DBG
 #define VDEBUG	DBG
 #else
 #else
 #define VDEBUG(dev,fmt,args...) \
 #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 */
 			/* assume that was SET_CONFIGURATION */
 			if (dev->current_config) {
 			if (dev->current_config) {
 				unsigned power;
 				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;
 					power = dev->hs_config->bMaxPower;
 				else
 				else
-#endif
 					power = dev->config->bMaxPower;
 					power = dev->config->bMaxPower;
 				usb_gadget_vbus_draw(dev->gadget, 2 * power);
 				usb_gadget_vbus_draw(dev->gadget, 2 * power);
 			}
 			}
@@ -1355,24 +1355,21 @@ static int
 config_buf (struct dev_data *dev, u8 type, unsigned index)
 config_buf (struct dev_data *dev, u8 type, unsigned index)
 {
 {
 	int		len;
 	int		len;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	int		hs;
-#endif
+	int		hs = 0;
 
 
 	/* only one configuration */
 	/* only one configuration */
 	if (index > 0)
 	if (index > 0)
 		return -EINVAL;
 		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) {
 	if (hs) {
 		dev->req->buf = dev->hs_config;
 		dev->req->buf = dev->hs_config;
 		len = le16_to_cpu(dev->hs_config->wTotalLength);
 		len = le16_to_cpu(dev->hs_config->wTotalLength);
-	} else
-#endif
-	{
+	} else {
 		dev->req->buf = dev->config;
 		dev->req->buf = dev->config;
 		len = le16_to_cpu(dev->config->wTotalLength);
 		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);
 	spin_lock (&dev->lock);
 	dev->setup_abort = 0;
 	dev->setup_abort = 0;
 	if (dev->state == STATE_DEV_UNCONNECTED) {
 	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);
 			spin_unlock(&dev->lock);
 			ERROR (dev, "no high speed config??\n");
 			ERROR (dev, "no high speed config??\n");
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
-#endif	/* CONFIG_USB_GADGET_DUALSPEED */
 
 
 		dev->state = STATE_DEV_CONNECTED;
 		dev->state = STATE_DEV_CONNECTED;
 		dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
 		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
 			// user mode expected to disable endpoints
 		} else {
 		} else {
 			u8	config, power;
 			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;
 				config = dev->hs_config->bConfigurationValue;
 				power = dev->hs_config->bMaxPower;
 				power = dev->hs_config->bMaxPower;
-			} else
-#endif
-			{
+			} else {
 				config = dev->config->bConfigurationValue;
 				config = dev->config->bConfigurationValue;
 				power = dev->config->bMaxPower;
 				power = dev->config->bMaxPower;
 			}
 			}

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

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

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

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

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

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

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

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

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

@@ -54,7 +54,7 @@
 #include <asm/hardware.h>
 #include <asm/hardware.h>
 
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 
 #include <asm/mach/udc_pxa2xx.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/seq_file.h>
 
 
 #include <linux/usb.h>
 #include <linux/usb.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 
 #include <asm/byteorder.h>
 #include <asm/byteorder.h>
 #include <asm/io.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/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/utsname.h>
-#include <linux/wait.h>
-#include <linux/proc_fs.h>
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/tty.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.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/ch9.h>
 #include <linux/usb/cdc.h>
 #include <linux/usb/cdc.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 
 #include "gadget_chips.h"
 #include "gadget_chips.h"
 
 
@@ -89,30 +70,29 @@
 #define GS_DEFAULT_PARITY		USB_CDC_NO_PARITY
 #define GS_DEFAULT_PARITY		USB_CDC_NO_PARITY
 #define GS_DEFAULT_CHAR_FORMAT		USB_CDC_1_STOP_BITS
 #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 */
 /* debug settings */
-#ifdef GS_DEBUG
+#ifdef DEBUG
 static int debug = 1;
 static int debug = 1;
+#else
+#define	debug 0
+#endif
 
 
 #define gs_debug(format, arg...) \
 #define gs_debug(format, arg...) \
 	do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
 	do { if (debug) printk(KERN_DEBUG format, ## arg); } while(0)
 #define gs_debug_level(level, format, arg...) \
 #define gs_debug_level(level, format, arg...) \
 	do { if (debug>=level) printk(KERN_DEBUG format, ## arg); } while(0)
 	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.
 /* 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 */
 /* the port structure holds info for each port, one for each minor number */
 struct gs_port {
 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 */
 	struct tty_struct	*port_tty;	/* pointer to tty struct */
 	spinlock_t		port_lock;
 	spinlock_t		port_lock;
-	int 			port_num;
+	int			port_num;
 	int			port_open_count;
 	int			port_open_count;
 	int			port_in_use;	/* open/close in progress */
 	int			port_in_use;	/* open/close in progress */
 	wait_queue_head_t	port_write_wait;/* waiting to write */
 	wait_queue_head_t	port_write_wait;/* waiting to write */
@@ -188,7 +168,7 @@ static void __exit gs_module_exit(void);
 /* tty driver */
 /* tty driver */
 static int gs_open(struct tty_struct *tty, struct file *file);
 static int gs_open(struct tty_struct *tty, struct file *file);
 static void gs_close(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);
 	const unsigned char *buf, int count);
 static void gs_put_char(struct tty_struct *tty, unsigned char ch);
 static void gs_put_char(struct tty_struct *tty, unsigned char ch);
 static void gs_flush_chars(struct tty_struct *tty);
 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 void gs_disconnect(struct usb_gadget *gadget);
 static int gs_set_config(struct gs_dev *dev, unsigned config);
 static int gs_set_config(struct gs_dev *dev, unsigned config);
 static void gs_reset_config(struct gs_dev *dev);
 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);
 		u8 type, unsigned int index, int is_otg);
 
 
 static struct usb_request *gs_alloc_req(struct usb_ep *ep, unsigned int len,
 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 = {
 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 = {
 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 = {
 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 */
 	.bMasterInterface0 =	0,	/* index of control interface */
 	.bSlaveInterface0 =	1,	/* index of data interface */
 	.bSlaveInterface0 =	1,	/* index of data interface */
 };
 };
- 
+
 static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = {
 static struct usb_endpoint_descriptor gs_fullspeed_notify_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 	.bDescriptorType =	USB_DT_ENDPOINT,
@@ -482,7 +462,6 @@ static const struct usb_descriptor_header *gs_acm_fullspeed_function[] = {
 	NULL,
 	NULL,
 };
 };
 
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 static struct usb_endpoint_descriptor gs_highspeed_notify_desc = {
 static struct usb_endpoint_descriptor gs_highspeed_notify_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 	.bDescriptorType =	USB_DT_ENDPOINT,
@@ -536,15 +515,13 @@ static const struct usb_descriptor_header *gs_acm_highspeed_function[] = {
 	NULL,
 	NULL,
 };
 };
 
 
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
-
 
 
 /* Module */
 /* Module */
 MODULE_DESCRIPTION(GS_LONG_NAME);
 MODULE_DESCRIPTION(GS_LONG_NAME);
 MODULE_AUTHOR("Al Borchers");
 MODULE_AUTHOR("Al Borchers");
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
 
 
-#ifdef GS_DEBUG
+#ifdef DEBUG
 module_param(debug, int, S_IRUGO|S_IWUSR);
 module_param(debug, int, S_IRUGO|S_IWUSR);
 MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
 MODULE_PARM_DESC(debug, "Enable debugging, 0=off, 1=on");
 #endif
 #endif
@@ -915,7 +892,8 @@ static void gs_put_char(struct tty_struct *tty, unsigned char ch)
 		return;
 		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);
 	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);
 		len = gs_send_packet(dev, req->buf, ep->maxpacket);
 
 
 		if (len > 0) {
 		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);
 			list_del(&req_entry->re_entry);
 			req->length = len;
 			req->length = len;
 			spin_unlock_irqrestore(&dev->dev_lock, flags);
 			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) {
 	switch(req->status) {
 	case 0:
 	case 0:
- 		/* normal completion */
+		/* normal completion */
 		gs_recv_packet(dev, req->buf, req->actual);
 		gs_recv_packet(dev, req->buf, req->actual);
 requeue:
 requeue:
 		req->length = ep->maxpacket;
 		req->length = ep->maxpacket;
@@ -1406,23 +1388,24 @@ static int __init gs_bind(struct usb_gadget *gadget)
 		? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
 		? USB_CLASS_COMM : USB_CLASS_VENDOR_SPEC;
 	gs_device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 	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);
 	usb_gadget_set_selfpowered(gadget);
 
 
-	if (gadget->is_otg) {
+	if (gadget_is_otg(gadget)) {
 		gs_otg_descriptor.bmAttributes |= USB_OTG_HNP,
 		gs_otg_descriptor.bmAttributes |= USB_OTG_HNP,
 		gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 		gs_bulk_config_desc.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 		gs_acm_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;
 			dev->dev_ctrl_req = NULL;
 		}
 		}
 		gs_free_ports(dev);
 		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);
 		kfree(dev);
 		set_gadget_data(gadget, NULL);
 		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);
 			memcpy(req->buf, &gs_device_desc, ret);
 			break;
 			break;
 
 
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 		case USB_DT_DEVICE_QUALIFIER:
 		case USB_DT_DEVICE_QUALIFIER:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 				break;
 			ret = min(wLength,
 			ret = min(wLength,
 				(u16)sizeof(struct usb_qualifier_descriptor));
 				(u16)sizeof(struct usb_qualifier_descriptor));
@@ -1580,14 +1568,13 @@ static int gs_setup_standard(struct usb_gadget *gadget,
 			break;
 			break;
 
 
 		case USB_DT_OTHER_SPEED_CONFIG:
 		case USB_DT_OTHER_SPEED_CONFIG:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 				break;
 			/* fall through */
 			/* fall through */
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
 		case USB_DT_CONFIG:
 		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,
 				wValue >> 8, wValue & 0xff,
-				gadget->is_otg);
+				gadget_is_otg(gadget));
 			if (ret >= 0)
 			if (ret >= 0)
 				ret = min(wLength, (u16)ret);
 				ret = min(wLength, (u16)ret);
 			break;
 			break;
@@ -1827,8 +1814,7 @@ static int gs_set_config(struct gs_dev *dev, unsigned config)
 
 
 		if (EP_NOTIFY_NAME
 		if (EP_NOTIFY_NAME
 		&& strcmp(ep->name, EP_NOTIFY_NAME) == 0) {
 		&& 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_highspeed_notify_desc,
 				&gs_fullspeed_notify_desc);
 				&gs_fullspeed_notify_desc);
 			ret = usb_ep_enable(ep,ep_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) {
 		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);
 				&gs_fullspeed_in_desc);
 			ret = usb_ep_enable(ep,ep_desc);
 			ret = usb_ep_enable(ep,ep_desc);
 			if (ret == 0) {
 			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) {
 		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_highspeed_out_desc,
 				&gs_fullspeed_out_desc);
 				&gs_fullspeed_out_desc);
 			ret = usb_ep_enable(ep,ep_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
  * Builds the config descriptors in the given buffer and returns the
  * length, or a negative error number.
  * 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)
 	u8 type, unsigned int index, int is_otg)
 {
 {
 	int len;
 	int len;
-	int high_speed;
+	int high_speed = 0;
 	const struct usb_config_descriptor *config_desc;
 	const struct usb_config_descriptor *config_desc;
 	const struct usb_descriptor_header **function;
 	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;
 		return -EINVAL;
 
 
 	/* other speed switches high and full speed */
 	/* 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) {
 	if (use_acm) {
 		config_desc = &gs_acm_config_desc;
 		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 {
 	} else {
 		config_desc = &gs_bulk_config_desc;
 		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 */
 	/* 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/init.h>
 
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 
 #include <asm/unaligned.h>
 #include <asm/unaligned.h>
 
 

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

@@ -1,38 +1,22 @@
 /*
 /*
  * zero.c -- Gadget Zero, for USB development
  * zero.c -- Gadget Zero, for USB development
  *
  *
- * Copyright (C) 2003-2004 David Brownell
+ * Copyright (C) 2003-2007 David Brownell
  * All rights reserved.
  * 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
  * Many drivers will only have one configuration, letting them be much
  * simpler if they also don't support high speed operation (like this
  * simpler if they also don't support high speed operation (like this
  * driver does).
  * 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/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/utsname.h>
 #include <linux/device.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/ch9.h>
-#include <linux/usb_gadget.h>
+#include <linux/usb/gadget.h>
 
 
 #include "gadget_chips.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 shortname [] = "zero";
 static const char longname [] = "Gadget Zero";
 static const char longname [] = "Gadget Zero";
@@ -131,30 +103,16 @@ struct zero_dev {
 	struct timer_list	resume;
 	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,
 	NULL,
 };
 };
 
 
-#ifdef	CONFIG_USB_GADGET_DUALSPEED
-
 /*
 /*
  * usb 2.0 devices need to expose both high speed and full speed
  * usb 2.0 devices need to expose both high speed and full speed
  * descriptors, unless they only run at 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. */
 /* 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 strings, in UTF-8 */
 static struct usb_string		strings [] = {
 static struct usb_string		strings [] = {
@@ -435,30 +394,29 @@ config_buf (struct usb_gadget *gadget,
 	int				is_source_sink;
 	int				is_source_sink;
 	int				len;
 	int				len;
 	const struct usb_descriptor_header **function;
 	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 */
 	/* two configurations will always be index 0 and index 1 */
 	if (index > 1)
 	if (index > 1)
 		return -EINVAL;
 		return -EINVAL;
 	is_source_sink = loopdefault ? (index == 1) : (index == 0);
 	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)
 	if (hs)
 		function = is_source_sink
 		function = is_source_sink
 			? hs_source_sink_function
 			? hs_source_sink_function
 			: hs_loopback_function;
 			: hs_loopback_function;
 	else
 	else
-#endif
 		function = is_source_sink
 		function = is_source_sink
 			? fs_source_sink_function
 			? fs_source_sink_function
 			: fs_loopback_function;
 			: fs_loopback_function;
 
 
 	/* for now, don't advertise srp-only devices */
 	/* for now, don't advertise srp-only devices */
-	if (!gadget->is_otg)
+	if (!gadget_is_otg(gadget))
 		function++;
 		function++;
 
 
 	len = usb_gadget_config_buf (is_source_sink
 	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  */
 /* optionally require specific source/sink data patterns  */
 
 
 static int
 static int
@@ -534,12 +505,7 @@ check_read_data (
 	return 0;
 	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;
 	unsigned	i;
 	u8		*buf = req->buf;
 	u8		*buf = req->buf;
@@ -566,16 +532,16 @@ static void source_sink_complete (struct usb_ep *ep, struct usb_request *req)
 
 
 	switch (status) {
 	switch (status) {
 
 
-	case 0: 			/* normal completion? */
+	case 0:				/* normal completion? */
 		if (ep == dev->out_ep) {
 		if (ep == dev->out_ep) {
 			check_read_data (dev, ep, req);
 			check_read_data (dev, ep, req);
 			memset (req->buf, 0x55, req->length);
 			memset (req->buf, 0x55, req->length);
 		} else
 		} else
-			reinit_write_data (dev, ep, req);
+			reinit_write_data(ep, req);
 		break;
 		break;
 
 
 	/* this endpoint is normally active while we're configured */
 	/* 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 -ECONNRESET:		/* request dequeued */
 	case -ESHUTDOWN:		/* disconnect from host */
 	case -ESHUTDOWN:		/* disconnect from host */
 		VDBG (dev, "%s gone (%d), %d/%d\n", ep->name, status,
 		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;
 	struct usb_request	*req;
 	int			status;
 	int			status;
@@ -621,11 +586,11 @@ source_sink_start_ep (struct usb_ep *ep, gfp_t gfp_flags)
 	req->complete = source_sink_complete;
 	req->complete = source_sink_complete;
 
 
 	if (strcmp (ep->name, EP_IN_NAME) == 0)
 	if (strcmp (ep->name, EP_IN_NAME) == 0)
-		reinit_write_data (ep->driver_data, ep, req);
+		reinit_write_data(ep, req);
 	else
 	else
 		memset (req->buf, 0x55, req->length);
 		memset (req->buf, 0x55, req->length);
 
 
-	status = usb_ep_queue (ep, req, gfp_flags);
+	status = usb_ep_queue(ep, req, GFP_ATOMIC);
 	if (status) {
 	if (status) {
 		struct zero_dev	*dev = ep->driver_data;
 		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;
 	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;
 	int			result = 0;
 	struct usb_ep		*ep;
 	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);
 			result = usb_ep_enable (ep, d);
 			if (result == 0) {
 			if (result == 0) {
 				ep->driver_data = dev;
 				ep->driver_data = dev;
-				if (source_sink_start_ep(ep, gfp_flags)
-						!= NULL) {
+				if (source_sink_start_ep(ep) != NULL) {
 					dev->in_ep = ep;
 					dev->in_ep = ep;
 					continue;
 					continue;
 				}
 				}
@@ -668,8 +631,7 @@ set_source_sink_config (struct zero_dev *dev, gfp_t gfp_flags)
 			result = usb_ep_enable (ep, d);
 			result = usb_ep_enable (ep, d);
 			if (result == 0) {
 			if (result == 0) {
 				ep->driver_data = dev;
 				ep->driver_data = dev;
-				if (source_sink_start_ep(ep, gfp_flags)
-						!= NULL) {
+				if (source_sink_start_ep(ep) != NULL) {
 					dev->out_ep = ep;
 					dev->out_ep = ep;
 					continue;
 					continue;
 				}
 				}
@@ -701,7 +663,7 @@ static void loopback_complete (struct usb_ep *ep, struct usb_request *req)
 
 
 	switch (status) {
 	switch (status) {
 
 
-	case 0: 			/* normal completion? */
+	case 0:				/* normal completion? */
 		if (ep == dev->out_ep) {
 		if (ep == dev->out_ep) {
 			/* loop this OUT packet back IN to the host */
 			/* loop this OUT packet back IN to the host */
 			req->zero = (req->actual < req->length);
 			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
 	 * rely on the hardware driver to clean up on disconnect or
 	 * endpoint disable.
 	 * endpoint disable.
 	 */
 	 */
-	case -ECONNABORTED: 		/* hardware forced ep reset */
+	case -ECONNABORTED:		/* hardware forced ep reset */
 	case -ECONNRESET:		/* request dequeued */
 	case -ECONNRESET:		/* request dequeued */
 	case -ESHUTDOWN:		/* disconnect from host */
 	case -ESHUTDOWN:		/* disconnect from host */
 		free_ep_req (ep, req);
 		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;
 	int			result = 0;
 	struct usb_ep		*ep;
 	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
  * code can do, perhaps by disallowing more than one configuration or
  * by limiting configuration choices (like the pxa2xx).
  * 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;
 	int			result = 0;
 	struct usb_gadget	*gadget = dev->gadget;
 	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) {
 	if (gadget_is_sa1100 (gadget) && dev->config) {
 		/* tx fifo is full, but we can't clear it...*/
 		/* 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;
 		return -ESPIPE;
 	}
 	}
 	zero_reset_config (dev);
 	zero_reset_config (dev);
 
 
 	switch (number) {
 	switch (number) {
 	case CONFIG_SOURCE_SINK:
 	case CONFIG_SOURCE_SINK:
-		result = set_source_sink_config (dev, gfp_flags);
+		result = set_source_sink_config(dev);
 		break;
 		break;
 	case CONFIG_LOOPBACK:
 	case CONFIG_LOOPBACK:
-		result = set_loopback_config (dev, gfp_flags);
+		result = set_loopback_config(dev);
 		break;
 		break;
 	default:
 	default:
 		result = -EINVAL;
 		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_LOW:	speed = "low"; break;
 		case USB_SPEED_FULL:	speed = "full"; break;
 		case USB_SPEED_FULL:	speed = "full"; break;
 		case USB_SPEED_HIGH:	speed = "high"; break;
 		case USB_SPEED_HIGH:	speed = "high"; break;
-		default: 		speed = "?"; break;
+		default:		speed = "?"; break;
 		}
 		}
 
 
 		dev->config = number;
 		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);
 			value = min (w_length, (u16) sizeof device_desc);
 			memcpy (req->buf, &device_desc, value);
 			memcpy (req->buf, &device_desc, value);
 			break;
 			break;
-#ifdef CONFIG_USB_GADGET_DUALSPEED
 		case USB_DT_DEVICE_QUALIFIER:
 		case USB_DT_DEVICE_QUALIFIER:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 				break;
 			value = min (w_length, (u16) sizeof dev_qualifier);
 			value = min (w_length, (u16) sizeof dev_qualifier);
 			memcpy (req->buf, &dev_qualifier, value);
 			memcpy (req->buf, &dev_qualifier, value);
 			break;
 			break;
 
 
 		case USB_DT_OTHER_SPEED_CONFIG:
 		case USB_DT_OTHER_SPEED_CONFIG:
-			if (!gadget->is_dualspeed)
+			if (!gadget_is_dualspeed(gadget))
 				break;
 				break;
 			// FALLTHROUGH
 			// FALLTHROUGH
-#endif /* CONFIG_USB_GADGET_DUALSPEED */
 		case USB_DT_CONFIG:
 		case USB_DT_CONFIG:
 			value = config_buf (gadget, req->buf,
 			value = config_buf (gadget, req->buf,
 					w_value >> 8,
 					w_value >> 8,
@@ -984,7 +942,7 @@ zero_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 		else
 		else
 			VDBG (dev, "HNP inactive\n");
 			VDBG (dev, "HNP inactive\n");
 		spin_lock (&dev->lock);
 		spin_lock (&dev->lock);
-		value = zero_set_config (dev, w_value, GFP_ATOMIC);
+		value = zero_set_config(dev, w_value);
 		spin_unlock (&dev->lock);
 		spin_unlock (&dev->lock);
 		break;
 		break;
 	case USB_REQ_GET_CONFIGURATION:
 	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.
 			 * use this "reset the config" shortcut.
 			 */
 			 */
 			zero_reset_config (dev);
 			zero_reset_config (dev);
-			zero_set_config (dev, config, GFP_ATOMIC);
+			zero_set_config(dev, config);
 			value = 0;
 			value = 0;
 		}
 		}
 		spin_unlock (&dev->lock);
 		spin_unlock (&dev->lock);
@@ -1163,7 +1121,7 @@ autoconf_fail:
 	}
 	}
 	EP_IN_NAME = ep->name;
 	EP_IN_NAME = ep->name;
 	ep->driver_data = ep;	/* claim */
 	ep->driver_data = ep;	/* claim */
-	
+
 	ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
 	ep = usb_ep_autoconfig (gadget, &fs_sink_desc);
 	if (!ep)
 	if (!ep)
 		goto autoconf_fail;
 		goto autoconf_fail;
@@ -1207,16 +1165,18 @@ autoconf_fail:
 
 
 	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 	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,
 		otg_descriptor.bmAttributes |= USB_OTG_HNP,
 		source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 		source_sink_config.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
 		loopback_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,
 	.suspend	= zero_suspend,
 	.resume		= zero_resume,
 	.resume		= zero_resume,
 
 
-	.driver 	= {
+	.driver		= {
 		.name		= (char *) shortname,
 		.name		= (char *) shortname,
 		.owner		= THIS_MODULE,
 		.owner		= THIS_MODULE,
 	},
 	},
 };
 };
 
 
-MODULE_AUTHOR ("David Brownell");
-MODULE_LICENSE ("Dual BSD/GPL");
+MODULE_AUTHOR("David Brownell");
+MODULE_LICENSE("GPL");
 
 
 
 
 static int __init init (void)
 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);
 	return usb_gadget_register_driver (&zero_driver);
 }
 }
 module_init (init);
 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.
 	  Enables support for PCI-bus plug-in USB controller cards.
 	  If unsure, say Y.
 	  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
 config USB_OHCI_BIG_ENDIAN_DESC
 	bool
 	bool
 	depends on USB_OHCI_HCD
 	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_status_data = ehci_hub_status_data,
 	.hub_control = ehci_hub_control,
 	.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
 	 * are explicitly handed to companion controller(s), so no TT is
 	 * involved with the root hub.  (Except where one is integrated,
 	 * involved with the root hub.  (Except where one is integrated,
 	 * and there's no companion controller unless maybe for USB OTG.)
 	 * 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;
 	hcd->state = HC_STATE_RUNNING;
 	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
 	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
 	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
 	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
+	up_write(&ehci_cf_port_reset_rwsem);
 
 
 	temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
 	temp = HC_VERSION(ehci_readl(ehci, &ehci->caps->hc_capbase));
 	ehci_info (ehci,
 	ehci_info (ehci,
@@ -719,7 +727,6 @@ dead:
  */
  */
 static int ehci_urb_enqueue (
 static int ehci_urb_enqueue (
 	struct usb_hcd	*hcd,
 	struct usb_hcd	*hcd,
-	struct usb_host_endpoint *ep,
 	struct urb	*urb,
 	struct urb	*urb,
 	gfp_t		mem_flags
 	gfp_t		mem_flags
 ) {
 ) {
@@ -734,12 +741,12 @@ static int ehci_urb_enqueue (
 	default:
 	default:
 		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
 		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
 			return -ENOMEM;
 			return -ENOMEM;
-		return submit_async (ehci, ep, urb, &qtd_list, mem_flags);
+		return submit_async(ehci, urb, &qtd_list, mem_flags);
 
 
 	case PIPE_INTERRUPT:
 	case PIPE_INTERRUPT:
 		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
 		if (!qh_urb_transaction (ehci, urb, &qtd_list, mem_flags))
 			return -ENOMEM;
 			return -ENOMEM;
-		return intr_submit (ehci, ep, urb, &qtd_list, mem_flags);
+		return intr_submit(ehci, urb, &qtd_list, mem_flags);
 
 
 	case PIPE_ISOCHRONOUS:
 	case PIPE_ISOCHRONOUS:
 		if (urb->dev->speed == USB_SPEED_HIGH)
 		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
  * 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_hcd		*ehci = hcd_to_ehci (hcd);
 	struct ehci_qh		*qh;
 	struct ehci_qh		*qh;
 	unsigned long		flags;
 	unsigned long		flags;
+	int			rc;
 
 
 	spin_lock_irqsave (&ehci->lock, flags);
 	spin_lock_irqsave (&ehci->lock, flags);
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
+		goto done;
+
 	switch (usb_pipetype (urb->pipe)) {
 	switch (usb_pipetype (urb->pipe)) {
 	// case PIPE_CONTROL:
 	// case PIPE_CONTROL:
 	// case PIPE_BULK:
 	// case PIPE_BULK:
@@ -838,7 +850,7 @@ static int ehci_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
 	}
 	}
 done:
 done:
 	spin_unlock_irqrestore (&ehci->lock, flags);
 	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)
 	if (!retval)
 		ehci_dbg(ehci, "MWI active\n");
 		ehci_dbg(ehci, "MWI active\n");
 
 
-	ehci_port_power(ehci, 0);
-
 	return 0;
 	return 0;
 }
 }
 
 
@@ -156,8 +154,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
 		break;
 		break;
 	}
 	}
 
 
-	if (ehci_is_TDI(ehci))
-		ehci_reset(ehci);
+	ehci_reset(ehci);
 
 
 	/* at least the Genesys GL880S needs fixup here */
 	/* at least the Genesys GL880S needs fixup here */
 	temp = HCS_N_CC(ehci->hcs_params) * HCS_N_PCC(ehci->hcs_params);
 	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_status_data = ehci_hub_status_data,
 	.hub_control = ehci_hub_control,
 	.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)
 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)
 	if (result)
 		return result;
 		return result;
 
 
-	ehci_port_power(ehci, 0);
+	ehci_reset(ehci);
 
 
 	return result;
 	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 ehci_hcd *ehci,
 	struct urb *urb,
 	struct urb *urb,
 	size_t length,
 	size_t length,
 	u32 token
 	u32 token
 )
 )
 {
 {
+	int	status = -EINPROGRESS;
+
 	/* count IN/OUT bytes, not SETUP (even short packets) */
 	/* count IN/OUT bytes, not SETUP (even short packets) */
 	if (likely (QTD_PID (token) != 2))
 	if (likely (QTD_PID (token) != 2))
 		urb->actual_length += length - QTD_LENGTH (token);
 		urb->actual_length += length - QTD_LENGTH (token);
 
 
 	/* don't modify error codes */
 	/* 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 */
 	/* force cleanup after short read; not always an error */
 	if (unlikely (IS_SHORT_READ (token)))
 	if (unlikely (IS_SHORT_READ (token)))
-		urb->status = -EREMOTEIO;
+		status = -EREMOTEIO;
 
 
 	/* serious "can't proceed" faults reported by the hardware */
 	/* serious "can't proceed" faults reported by the hardware */
 	if (token & QTD_STS_HALT) {
 	if (token & QTD_STS_HALT) {
 		if (token & QTD_STS_BABBLE) {
 		if (token & QTD_STS_BABBLE) {
 			/* FIXME "must" disable babbling device's port too */
 			/* FIXME "must" disable babbling device's port too */
-			urb->status = -EOVERFLOW;
+			status = -EOVERFLOW;
 		} else if (token & QTD_STS_MMF) {
 		} else if (token & QTD_STS_MMF) {
 			/* fs/ls interrupt xfer missed the complete-split */
 			/* fs/ls interrupt xfer missed the complete-split */
-			urb->status = -EPROTO;
+			status = -EPROTO;
 		} else if (token & QTD_STS_DBE) {
 		} 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 */
 				? -ENOSR  /* hc couldn't read data */
 				: -ECOMM; /* hc couldn't write data */
 				: -ECOMM; /* hc couldn't write data */
 		} else if (token & QTD_STS_XACT) {
 		} else if (token & QTD_STS_XACT) {
 			/* timeout, bad crc, wrong PID, etc; retried */
 			/* timeout, bad crc, wrong PID, etc; retried */
 			if (QTD_CERR (token))
 			if (QTD_CERR (token))
-				urb->status = -EPIPE;
+				status = -EPIPE;
 			else {
 			else {
 				ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n",
 				ehci_dbg (ehci, "devpath %s ep%d%s 3strikes\n",
 					urb->dev->devpath,
 					urb->dev->devpath,
 					usb_pipeendpoint (urb->pipe),
 					usb_pipeendpoint (urb->pipe),
 					usb_pipein (urb->pipe) ? "in" : "out");
 					usb_pipein (urb->pipe) ? "in" : "out");
-				urb->status = -EPROTO;
+				status = -EPROTO;
 			}
 			}
 		/* CERR nonzero + no errors + halt --> stall */
 		/* CERR nonzero + no errors + halt --> stall */
 		} else if (QTD_CERR (token))
 		} else if (QTD_CERR (token))
-			urb->status = -EPIPE;
+			status = -EPIPE;
 		else	/* unknown */
 		else	/* unknown */
-			urb->status = -EPROTO;
+			status = -EPROTO;
 
 
 		ehci_vdbg (ehci,
 		ehci_vdbg (ehci,
 			"dev%d ep%d%s qtd token %08x --> status %d\n",
 			"dev%d ep%d%s qtd token %08x --> status %d\n",
 			usb_pipedevice (urb->pipe),
 			usb_pipedevice (urb->pipe),
 			usb_pipeendpoint (urb->pipe),
 			usb_pipeendpoint (urb->pipe),
 			usb_pipein (urb->pipe) ? "in" : "out",
 			usb_pipein (urb->pipe) ? "in" : "out",
-			token, urb->status);
+			token, status);
 
 
 		/* if async CSPLIT failed, try cleaning out the TT buffer */
 		/* if async CSPLIT failed, try cleaning out the TT buffer */
-		if (urb->status != -EPIPE
+		if (status != -EPIPE
 				&& urb->dev->tt && !usb_pipeint (urb->pipe)
 				&& urb->dev->tt && !usb_pipeint (urb->pipe)
 				&& ((token & QTD_STS_MMF) != 0
 				&& ((token & QTD_STS_MMF) != 0
 					|| QTD_CERR(token) == 0)
 					|| QTD_CERR(token) == 0)
@@ -212,10 +214,12 @@ static void qtd_copy_status (
 			usb_hub_tt_clear_buffer (urb->dev, urb->pipe);
 			usb_hub_tt_clear_buffer (urb->dev, urb->pipe);
 		}
 		}
 	}
 	}
+
+	return status;
 }
 }
 
 
 static void
 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)
 __releases(ehci->lock)
 __acquires(ehci->lock)
 __acquires(ehci->lock)
 {
 {
@@ -231,25 +235,13 @@ __acquires(ehci->lock)
 		qh_put (qh);
 		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
 #ifdef EHCI_URB_TRACE
 	ehci_dbg (ehci,
 	ehci_dbg (ehci,
@@ -257,13 +249,14 @@ __acquires(ehci->lock)
 		__FUNCTION__, urb->dev->devpath, urb,
 		__FUNCTION__, urb->dev->devpath, urb,
 		usb_pipeendpoint (urb->pipe),
 		usb_pipeendpoint (urb->pipe),
 		usb_pipein (urb->pipe) ? "in" : "out",
 		usb_pipein (urb->pipe) ? "in" : "out",
-		urb->status,
+		status,
 		urb->actual_length, urb->transfer_buffer_length);
 		urb->actual_length, urb->transfer_buffer_length);
 #endif
 #endif
 
 
 	/* complete() can reenter this HCD */
 	/* complete() can reenter this HCD */
+	usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
 	spin_unlock (&ehci->lock);
 	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);
 	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 ehci_qtd		*last = NULL, *end = qh->dummy;
 	struct list_head	*entry, *tmp;
 	struct list_head	*entry, *tmp;
+	int			last_status = -EINPROGRESS;
 	int			stopped;
 	int			stopped;
 	unsigned		count = 0;
 	unsigned		count = 0;
 	int			do_status = 0;
 	int			do_status = 0;
@@ -311,6 +305,7 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
 		struct ehci_qtd	*qtd;
 		struct ehci_qtd	*qtd;
 		struct urb	*urb;
 		struct urb	*urb;
 		u32		token = 0;
 		u32		token = 0;
+		int		qtd_status;
 
 
 		qtd = list_entry (entry, struct ehci_qtd, qtd_list);
 		qtd = list_entry (entry, struct ehci_qtd, qtd_list);
 		urb = qtd->urb;
 		urb = qtd->urb;
@@ -318,11 +313,12 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
 		/* clean up any state from previous QTD ...*/
 		/* clean up any state from previous QTD ...*/
 		if (last) {
 		if (last) {
 			if (likely (last->urb != urb)) {
 			if (likely (last->urb != urb)) {
-				ehci_urb_done (ehci, last->urb);
+				ehci_urb_done(ehci, last->urb, last_status);
 				count++;
 				count++;
 			}
 			}
 			ehci_qtd_free (ehci, last);
 			ehci_qtd_free (ehci, last);
 			last = NULL;
 			last = NULL;
+			last_status = -EINPROGRESS;
 		}
 		}
 
 
 		/* ignore urbs submitted during completions we reported */
 		/* ignore urbs submitted during completions we reported */
@@ -358,13 +354,14 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
 			stopped = 1;
 			stopped = 1;
 
 
 			if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)))
 			if (unlikely (!HC_IS_RUNNING (ehci_to_hcd(ehci)->state)))
-				urb->status = -ESHUTDOWN;
+				last_status = -ESHUTDOWN;
 
 
 			/* ignore active urbs unless some previous qtd
 			/* ignore active urbs unless some previous qtd
 			 * for the urb faulted (including short read) or
 			 * for the urb faulted (including short read) or
 			 * its urb was canceled.  we may patch qh or qtds.
 			 * its urb was canceled.  we may patch qh or qtds.
 			 */
 			 */
-			if (likely (urb->status == -EINPROGRESS))
+			if (likely(last_status == -EINPROGRESS &&
+					!urb->unlinked))
 				continue;
 				continue;
 
 
 			/* issue status after short control reads */
 			/* issue status after short control reads */
@@ -392,11 +389,14 @@ halt:
 		}
 		}
 
 
 		/* remove it from the queue */
 		/* 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) {
 		if (stopped && qtd->qtd_list.prev != &qh->qtd_list) {
 			last = list_entry (qtd->qtd_list.prev,
 			last = list_entry (qtd->qtd_list.prev,
@@ -409,7 +409,7 @@ halt:
 
 
 	/* last urb's completion might still need calling */
 	/* last urb's completion might still need calling */
 	if (likely (last != NULL)) {
 	if (likely (last != NULL)) {
-		ehci_urb_done (ehci, last->urb);
+		ehci_urb_done(ehci, last->urb, last_status);
 		count++;
 		count++;
 		ehci_qtd_free (ehci, last);
 		ehci_qtd_free (ehci, last);
 	}
 	}
@@ -913,7 +913,6 @@ static struct ehci_qh *qh_append_tds (
 static int
 static int
 submit_async (
 submit_async (
 	struct ehci_hcd		*ehci,
 	struct ehci_hcd		*ehci,
-	struct usb_host_endpoint *ep,
 	struct urb		*urb,
 	struct urb		*urb,
 	struct list_head	*qtd_list,
 	struct list_head	*qtd_list,
 	gfp_t			mem_flags
 	gfp_t			mem_flags
@@ -922,10 +921,10 @@ submit_async (
 	int			epnum;
 	int			epnum;
 	unsigned long		flags;
 	unsigned long		flags;
 	struct ehci_qh		*qh = NULL;
 	struct ehci_qh		*qh = NULL;
-	int			rc = 0;
+	int			rc;
 
 
 	qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
 	qtd = list_entry (qtd_list->next, struct ehci_qtd, qtd_list);
-	epnum = ep->desc.bEndpointAddress;
+	epnum = urb->ep->desc.bEndpointAddress;
 
 
 #ifdef EHCI_URB_TRACE
 #ifdef EHCI_URB_TRACE
 	ehci_dbg (ehci,
 	ehci_dbg (ehci,
@@ -933,7 +932,7 @@ submit_async (
 		__FUNCTION__, urb->dev->devpath, urb,
 		__FUNCTION__, urb->dev->devpath, urb,
 		epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
 		epnum & 0x0f, (epnum & USB_DIR_IN) ? "in" : "out",
 		urb->transfer_buffer_length,
 		urb->transfer_buffer_length,
-		qtd, ep->hcpriv);
+		qtd, urb->ep->hcpriv);
 #endif
 #endif
 
 
 	spin_lock_irqsave (&ehci->lock, flags);
 	spin_lock_irqsave (&ehci->lock, flags);
@@ -942,9 +941,13 @@ submit_async (
 		rc = -ESHUTDOWN;
 		rc = -ESHUTDOWN;
 		goto done;
 		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)) {
 	if (unlikely(qh == NULL)) {
+		usb_hcd_unlink_urb_from_ep(ehci_to_hcd(ehci), urb);
 		rc = -ENOMEM;
 		rc = -ENOMEM;
 		goto done;
 		goto done;
 	}
 	}

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

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

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

@@ -277,12 +277,11 @@ static void preproc_atl_queue(struct isp116x *isp116x)
   processed urbs.
   processed urbs.
 */
 */
 static void finish_request(struct isp116x *isp116x, struct isp116x_ep *ep,
 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)
 __releases(isp116x->lock) __acquires(isp116x->lock)
 {
 {
 	unsigned i;
 	unsigned i;
 
 
-	urb->hcpriv = NULL;
 	ep->error_count = 0;
 	ep->error_count = 0;
 
 
 	if (usb_pipecontrol(urb->pipe))
 	if (usb_pipecontrol(urb->pipe))
@@ -290,8 +289,9 @@ __releases(isp116x->lock) __acquires(isp116x->lock)
 
 
 	urb_dbg(urb, "Finish");
 	urb_dbg(urb, "Finish");
 
 
+	usb_hcd_unlink_urb_from_ep(isp116x_to_hcd(isp116x), urb);
 	spin_unlock(&isp116x->lock);
 	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);
 	spin_lock(&isp116x->lock);
 
 
 	/* take idle endpoints out of the schedule */
 	/* take idle endpoints out of the schedule */
@@ -445,12 +445,7 @@ static void postproc_atl_queue(struct isp116x *isp116x)
 			if (PTD_GET_ACTIVE(ptd)
 			if (PTD_GET_ACTIVE(ptd)
 			    || (cc != TD_CC_NOERROR && cc < 0x0E))
 			    || (cc != TD_CC_NOERROR && cc < 0x0E))
 				break;
 				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;
 			ep->nextpid = 0;
 			break;
 			break;
 		default:
 		default:
@@ -458,14 +453,8 @@ static void postproc_atl_queue(struct isp116x *isp116x)
 		}
 		}
 
 
  done:
  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,
 static int isp116x_urb_enqueue(struct usb_hcd *hcd,
-			       struct usb_host_endpoint *hep, struct urb *urb,
+			       struct urb *urb,
 			       gfp_t mem_flags)
 			       gfp_t mem_flags)
 {
 {
 	struct isp116x *isp116x = hcd_to_isp116x(hcd);
 	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 is_out = !usb_pipein(pipe);
 	int type = usb_pipetype(pipe);
 	int type = usb_pipetype(pipe);
 	int epnum = usb_pipeendpoint(pipe);
 	int epnum = usb_pipeendpoint(pipe);
+	struct usb_host_endpoint *hep = urb->ep;
 	struct isp116x_ep *ep = NULL;
 	struct isp116x_ep *ep = NULL;
 	unsigned long flags;
 	unsigned long flags;
 	int i;
 	int i;
@@ -705,7 +695,12 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
 	if (!HC_IS_RUNNING(hcd->state)) {
 	if (!HC_IS_RUNNING(hcd->state)) {
 		kfree(ep);
 		kfree(ep);
 		ret = -ENODEV;
 		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)
 	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;
 	urb->hcpriv = hep;
 	start_atl_transfers(isp116x);
 	start_atl_transfers(isp116x);
 
 
       fail:
       fail:
+	if (ret)
+		usb_hcd_unlink_urb_from_ep(hcd, urb);
+      fail_not_linked:
 	spin_unlock_irqrestore(&isp116x->lock, flags);
 	spin_unlock_irqrestore(&isp116x->lock, flags);
 	return ret;
 	return ret;
 }
 }
@@ -825,20 +817,21 @@ static int isp116x_urb_enqueue(struct usb_hcd *hcd,
 /*
 /*
    Dequeue URBs.
    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 isp116x *isp116x = hcd_to_isp116x(hcd);
 	struct usb_host_endpoint *hep;
 	struct usb_host_endpoint *hep;
 	struct isp116x_ep *ep, *ep_act;
 	struct isp116x_ep *ep, *ep_act;
 	unsigned long flags;
 	unsigned long flags;
+	int rc;
 
 
 	spin_lock_irqsave(&isp116x->lock, flags);
 	spin_lock_irqsave(&isp116x->lock, flags);
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
+		goto done;
+
 	hep = urb->hcpriv;
 	hep = urb->hcpriv;
-	/* URB already unlinked (or never linked)? */
-	if (!hep) {
-		spin_unlock_irqrestore(&isp116x->lock, flags);
-		return 0;
-	}
 	ep = hep->hcpriv;
 	ep = hep->hcpriv;
 	WARN_ON(hep != ep->hep);
 	WARN_ON(hep != ep->hep);
 
 
@@ -855,10 +848,10 @@ static int isp116x_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
 			}
 			}
 
 
 	if (urb)
 	if (urb)
-		finish_request(isp116x, ep, urb);
-
+		finish_request(isp116x, ep, urb, status);
+ done:
 	spin_unlock_irqrestore(&isp116x->lock, flags);
 	spin_unlock_irqrestore(&isp116x->lock, flags);
-	return 0;
+	return rc;
 }
 }
 
 
 static void isp116x_endpoint_disable(struct usb_hcd *hcd,
 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
  * small: 0) header + data packets 1) just header
  */
  */
 static void __maybe_unused
 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;
 	unsigned int pipe= urb->pipe;
 
 
@@ -34,7 +34,7 @@ urb_print (struct urb * urb, char * str, int small)
 	}
 	}
 
 
 #ifndef	OHCI_VERBOSE_DEBUG
 #ifndef	OHCI_VERBOSE_DEBUG
-	if (urb->status != 0)
+	if (status != 0)
 #endif
 #endif
 	dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d",
 	dbg("%s %p dev=%d ep=%d%s-%s flags=%x len=%d/%d stat=%d",
 		    str,
 		    str,
@@ -46,7 +46,7 @@ urb_print (struct urb * urb, char * str, int small)
 		    urb->transfer_flags,
 		    urb->transfer_flags,
 		    urb->actual_length,
 		    urb->actual_length,
 		    urb->transfer_buffer_length,
 		    urb->transfer_buffer_length,
-		    urb->status);
+		    status);
 
 
 #ifdef	OHCI_VERBOSE_DEBUG
 #ifdef	OHCI_VERBOSE_DEBUG
 	if (!small) {
 	if (!small) {
@@ -66,7 +66,7 @@ urb_print (struct urb * urb, char * str, int small)
 						urb->transfer_buffer_length: urb->actual_length;
 						urb->transfer_buffer_length: urb->actual_length;
 			for (i = 0; i < 16 && i < len; i++)
 			for (i = 0; i < 16 && i < len; i++)
 				printk (" %02x", ((__u8 *) urb->transfer_buffer) [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
 #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 int ohci_init (struct ohci_hcd *ohci);
 static void ohci_stop (struct usb_hcd *hcd);
 static void ohci_stop (struct usb_hcd *hcd);
 static int ohci_restart (struct ohci_hcd *ohci);
 static int ohci_restart (struct ohci_hcd *ohci);
-static void ohci_quirk_nec_worker (struct work_struct *work);
 
 
 #include "ohci-hub.c"
 #include "ohci-hub.c"
 #include "ohci-dbg.c"
 #include "ohci-dbg.c"
@@ -118,7 +117,6 @@ MODULE_PARM_DESC (no_handshake, "true (not default) disables BIOS handshake");
  */
  */
 static int ohci_urb_enqueue (
 static int ohci_urb_enqueue (
 	struct usb_hcd	*hcd,
 	struct usb_hcd	*hcd,
-	struct usb_host_endpoint *ep,
 	struct urb	*urb,
 	struct urb	*urb,
 	gfp_t		mem_flags
 	gfp_t		mem_flags
 ) {
 ) {
@@ -131,11 +129,11 @@ static int ohci_urb_enqueue (
 	int		retval = 0;
 	int		retval = 0;
 
 
 #ifdef OHCI_VERBOSE_DEBUG
 #ifdef OHCI_VERBOSE_DEBUG
-	urb_print (urb, "SUB", usb_pipein (pipe));
+	urb_print(urb, "SUB", usb_pipein(pipe), -EINPROGRESS);
 #endif
 #endif
 
 
 	/* every endpoint has a ed, locate and maybe (re)initialize it */
 	/* 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;
 		return -ENOMEM;
 
 
 	/* for the private part of the URB we need the number of TDs (size) */
 	/* 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;
 		retval = -ENODEV;
 		goto fail;
 		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;
 		goto fail;
-	}
 
 
 	/* schedule the ed if needed */
 	/* schedule the ed if needed */
 	if (ed->state == ED_IDLE) {
 	if (ed->state == ED_IDLE) {
 		retval = ed_schedule (ohci, ed);
 		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) {
 		if (ed->type == PIPE_ISOCHRONOUS) {
 			u16	frame = ohci_frame_no(ohci);
 			u16	frame = ohci_frame_no(ohci);
 
 
@@ -239,8 +232,6 @@ static int ohci_urb_enqueue (
 	urb->hcpriv = urb_priv;
 	urb->hcpriv = urb_priv;
 	td_submit_urb (ohci, urb);
 	td_submit_urb (ohci, urb);
 
 
-fail0:
-	spin_unlock (&urb->lock);
 fail:
 fail:
 	if (retval)
 	if (retval)
 		urb_free_priv (ohci, urb_priv);
 		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
  * asynchronously, and we might be dealing with an urb that's
  * partially transferred, or an ED with other urbs being unlinked.
  * 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);
 	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
 	unsigned long		flags;
 	unsigned long		flags;
+	int			rc;
 
 
 #ifdef OHCI_VERBOSE_DEBUG
 #ifdef OHCI_VERBOSE_DEBUG
-	urb_print (urb, "UNLINK", 1);
+	urb_print(urb, "UNLINK", 1, status);
 #endif
 #endif
 
 
 	spin_lock_irqsave (&ohci->lock, flags);
 	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;
 		urb_priv_t  *urb_priv;
 
 
 		/* Unless an IRQ completed the unlink while it was being
 		/* 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.
 		 * any more ... just clean up every urb's memory.
 		 */
 		 */
 		if (urb->hcpriv)
 		if (urb->hcpriv)
-			finish_urb (ohci, urb);
+			finish_urb(ohci, urb, status);
 	}
 	}
 	spin_unlock_irqrestore (&ohci->lock, flags);
 	spin_unlock_irqrestore (&ohci->lock, flags);
-	return 0;
+	return rc;
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -314,6 +309,8 @@ rescan:
 	if (!HC_IS_RUNNING (hcd->state)) {
 	if (!HC_IS_RUNNING (hcd->state)) {
 sanitize:
 sanitize:
 		ed->state = ED_IDLE;
 		ed->state = ED_IDLE;
+		if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
+			ohci->eds_scheduled--;
 		finish_unlinks (ohci, 0);
 		finish_unlinks (ohci, 0);
 	}
 	}
 
 
@@ -321,7 +318,12 @@ sanitize:
 	case ED_UNLINK:		/* wait for hw to finish? */
 	case ED_UNLINK:		/* wait for hw to finish? */
 		/* major IRQ delivery trouble loses INTR_SF too... */
 		/* major IRQ delivery trouble loses INTR_SF too... */
 		if (limit-- == 0) {
 		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;
 			goto sanitize;
 		}
 		}
 		spin_unlock_irqrestore (&ohci->lock, flags);
 		spin_unlock_irqrestore (&ohci->lock, flags);
@@ -379,6 +381,93 @@ ohci_shutdown (struct usb_hcd *hcd)
 	(void) ohci_readl (ohci, &ohci->regs->control);
 	(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
  * HC functions
  *-------------------------------------------------------------------------*/
  *-------------------------------------------------------------------------*/
@@ -616,6 +705,15 @@ retry:
 	mdelay ((temp >> 23) & 0x1fe);
 	mdelay ((temp >> 23) & 0x1fe);
 	hcd->state = HC_STATE_RUNNING;
 	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);
 	ohci_dump (ohci, 1);
 
 
 	return 0;
 	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_hcd		*ohci = hcd_to_ohci (hcd);
 	struct ohci_regs __iomem *regs = ohci->regs;
 	struct ohci_regs __iomem *regs = ohci->regs;
- 	int			ints; 
+	int			ints;
 
 
 	/* we can eliminate a (slow) ohci_readl()
 	/* 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)
 	if ((ohci->hcca->done_head != 0)
 			&& ! (hc32_to_cpup (ohci, &ohci->hcca->done_head)
 			&& ! (hc32_to_cpup (ohci, &ohci->hcca->done_head)
 				& 0x01)) {
 				& 0x01)) {
@@ -651,7 +750,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
 
 
 	if (ints & OHCI_INTR_UE) {
 	if (ints & OHCI_INTR_UE) {
 		// e.g. due to PCI Master/Target Abort
 		// 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
 			/* Workaround for a silicon bug in some NEC chips used
 			 * in Apple's PowerBooks. Adapted from Darwin code.
 			 * 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);
 			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 */
 	/* could track INTR_SO to reduce available PCI/... bandwidth */
 
 
 	/* handle any pending URB/ED unlinks, leaving INTR_SF enabled
 	/* 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);
 	spin_lock (&ohci->lock);
 	if (ohci->ed_rm_list)
 	if (ohci->ed_rm_list)
 		finish_unlinks (ohci, ohci_frame_no(ohci));
 		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))
 			&& HC_IS_RUNNING(hcd->state))
 		ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);
 		ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);
 	spin_unlock (&ohci->lock);
 	spin_unlock (&ohci->lock);
@@ -751,6 +877,9 @@ static void ohci_stop (struct usb_hcd *hcd)
 	free_irq(hcd->irq, hcd);
 	free_irq(hcd->irq, hcd);
 	hcd->irq = -1;
 	hcd->irq = -1;
 
 
+	if (quirk_zfmicro(ohci))
+		del_timer(&ohci->unlink_watchdog);
+
 	remove_debug_files (ohci);
 	remove_debug_files (ohci);
 	ohci_mem_cleanup (ohci);
 	ohci_mem_cleanup (ohci);
 	if (ohci->hcca) {
 	if (ohci->hcca) {
@@ -798,9 +927,8 @@ static int ohci_restart (struct ohci_hcd *ohci)
 					ed, ed->state);
 					ed, ed->state);
 		}
 		}
 
 
-		spin_lock (&urb->lock);
-		urb->status = -ESHUTDOWN;
-		spin_unlock (&urb->lock);
+		if (!urb->unlinked)
+			urb->unlinked = -ESHUTDOWN;
 	}
 	}
 	finish_unlinks (ohci, 0);
 	finish_unlinks (ohci, 0);
 	spin_unlock_irq(&ohci->lock);
 	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
 #define DRIVER_INFO DRIVER_VERSION " " DRIVER_DESC
 
 
 MODULE_AUTHOR (DRIVER_AUTHOR);
 MODULE_AUTHOR (DRIVER_AUTHOR);
@@ -926,11 +1033,17 @@ MODULE_LICENSE ("GPL");
 #define PS3_SYSTEM_BUS_DRIVER	ps3_ohci_driver
 #define PS3_SYSTEM_BUS_DRIVER	ps3_ohci_driver
 #endif
 #endif
 
 
+#ifdef CONFIG_USB_OHCI_HCD_SSB
+#include "ohci-ssb.c"
+#define SSB_OHCI_DRIVER		ssb_ohci_driver
+#endif
+
 #if	!defined(PCI_DRIVER) &&		\
 #if	!defined(PCI_DRIVER) &&		\
 	!defined(PLATFORM_DRIVER) &&	\
 	!defined(PLATFORM_DRIVER) &&	\
 	!defined(OF_PLATFORM_DRIVER) &&	\
 	!defined(OF_PLATFORM_DRIVER) &&	\
 	!defined(SA1111_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"
 #error "missing bus glue for ohci-hcd"
 #endif
 #endif
 
 
@@ -975,10 +1088,20 @@ static int __init ohci_hcd_mod_init(void)
 		goto error_pci;
 		goto error_pci;
 #endif
 #endif
 
 
+#ifdef SSB_OHCI_DRIVER
+	retval = ssb_driver_register(&SSB_OHCI_DRIVER);
+	if (retval)
+		goto error_ssb;
+#endif
+
 	return retval;
 	return retval;
 
 
 	/* Error path */
 	/* Error path */
+#ifdef SSB_OHCI_DRIVER
+ error_ssb:
+#endif
 #ifdef PCI_DRIVER
 #ifdef PCI_DRIVER
+	pci_unregister_driver(&PCI_DRIVER);
  error_pci:
  error_pci:
 #endif
 #endif
 #ifdef SA1111_DRIVER
 #ifdef SA1111_DRIVER
@@ -1003,6 +1126,9 @@ module_init(ohci_hcd_mod_init);
 
 
 static void __exit ohci_hcd_mod_exit(void)
 static void __exit ohci_hcd_mod_exit(void)
 {
 {
+#ifdef SSB_OHCI_DRIVER
+	ssb_driver_unregister(&SSB_OHCI_DRIVER);
+#endif
 #ifdef PCI_DRIVER
 #ifdef PCI_DRIVER
 	pci_unregister_driver(&PCI_DRIVER);
 	pci_unregister_driver(&PCI_DRIVER);
 #endif
 #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;
 	ohci->next_statechange = jiffies;
 	spin_lock_init (&ohci->lock);
 	spin_lock_init (&ohci->lock);
 	INIT_LIST_HEAD (&ohci->pending);
 	INIT_LIST_HEAD (&ohci->pending);
-	INIT_WORK (&ohci->nec_work, ohci_quirk_nec_worker);
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/

+ 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);
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 
 
 	ohci->flags |= OHCI_QUIRK_ZFMICRO;
 	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;
 	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.
 /* 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)
 static int ohci_quirk_nec(struct usb_hcd *hcd)
 {
 {
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 	struct ohci_hcd	*ohci = hcd_to_ohci (hcd);
 
 
 	ohci->flags |= OHCI_QUIRK_NEC;
 	ohci->flags |= OHCI_QUIRK_NEC;
+	INIT_WORK(&ohci->nec_work, ohci_quirk_nec_worker);
 	ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n");
 	ohci_dbg (ohci, "enabled NEC chipset lost interrupt quirk\n");
 
 
 	return 0;
 	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);
 	ohci = hcd_to_ohci(hcd);
-	if (is_bigendian)
+	if (is_bigendian) {
 		ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
 		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);
 	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 = hcd_to_ohci(hcd);
 	ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC;
 	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);
 	ohci_hcd_init(ohci);
 
 
 	retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
 	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.
  * PRECONDITION:  ohci lock held, irqs blocked.
  */
  */
 static void
 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)
 __releases(ohci->lock)
 __acquires(ohci->lock)
 __acquires(ohci->lock)
 {
 {
 	// ASSERT (urb->hcpriv != 0);
 	// ASSERT (urb->hcpriv != 0);
 
 
 	urb_free_priv (ohci, urb->hcpriv);
 	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)) {
 	switch (usb_pipetype (urb->pipe)) {
 	case PIPE_ISOCHRONOUS:
 	case PIPE_ISOCHRONOUS:
@@ -70,12 +56,13 @@ __acquires(ohci->lock)
 	}
 	}
 
 
 #ifdef OHCI_VERBOSE_DEBUG
 #ifdef OHCI_VERBOSE_DEBUG
-	urb_print (urb, "RET", usb_pipeout (urb->pipe));
+	urb_print(urb, "RET", usb_pipeout (urb->pipe), status);
 #endif
 #endif
 
 
 	/* urb->complete() can reenter this HCD */
 	/* urb->complete() can reenter this HCD */
+	usb_hcd_unlink_urb_from_ep(ohci_to_hcd(ohci), urb);
 	spin_unlock (&ohci->lock);
 	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);
 	spin_lock (&ohci->lock);
 
 
 	/* stop periodic dma if it's not needed */
 	/* 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_prev = NULL;
 	ed->ed_next = NULL;
 	ed->ed_next = NULL;
 	ed->hwNextED = 0;
 	ed->hwNextED = 0;
+	if (quirk_zfmicro(ohci)
+			&& (ed->type == PIPE_INTERRUPT)
+			&& !(ohci->eds_scheduled++))
+		mod_timer(&ohci->unlink_watchdog, round_jiffies_relative(HZ));
 	wmb ();
 	wmb ();
 
 
 	/* we care about rm_list when setting CLE/BLE in case the HC was at
 	/* 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
  * 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);
 	u32	tdINFO = hc32_to_cpup (ohci, &td->hwINFO);
 	int	cc = 0;
 	int	cc = 0;
+	int	status = -EINPROGRESS;
 
 
 	list_del (&td->td_list);
 	list_del (&td->td_list);
 
 
 	/* ISO ... drivers see per-TD length/status */
 	/* ISO ... drivers see per-TD length/status */
 	if (tdINFO & TD_ISO) {
 	if (tdINFO & TD_ISO) {
-		u16	tdPSW = ohci_hwPSW (ohci, td, 0);
+		u16	tdPSW = ohci_hwPSW(ohci, td, 0);
 		int	dlen = 0;
 		int	dlen = 0;
 
 
 		/* NOTE:  assumes FC in tdINFO == 0, and that
 		/* 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;
 		cc = (tdPSW >> 12) & 0xF;
 		if (tdINFO & TD_CC)	/* hc didn't touch? */
 		if (tdINFO & TD_CC)	/* hc didn't touch? */
-			return;
+			return status;
 
 
 		if (usb_pipeout (urb->pipe))
 		if (usb_pipeout (urb->pipe))
 			dlen = urb->iso_frame_desc [td->index].length;
 			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
 		if (cc == TD_DATAUNDERRUN
 				&& !(urb->transfer_flags & URB_SHORT_NOT_OK))
 				&& !(urb->transfer_flags & URB_SHORT_NOT_OK))
 			cc = TD_CC_NOERROR;
 			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 */
 		/* count all non-empty packets except control SETUP packet */
 		if ((type != PIPE_CONTROL || td->index != 0) && tdBE != 0) {
 		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->actual_length,
 				urb->transfer_buffer_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;
 	struct urb		*urb = td->urb;
+	urb_priv_t		*urb_priv = urb->hcpriv;
 	struct ed		*ed = td->ed;
 	struct ed		*ed = td->ed;
 	struct list_head	*tmp = td->td_list.next;
 	struct list_head	*tmp = td->td_list.next;
 	__hc32			toggle = ed->hwHeadP & cpu_to_hc32 (ohci, ED_C);
 	__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 ();
 	wmb ();
 	ed->hwHeadP &= ~cpu_to_hc32 (ohci, ED_H);
 	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) {
 	while (tmp != &ed->td_list) {
 		struct td	*next;
 		struct td	*next;
-		__hc32		info;
 
 
 		next = list_entry (tmp, struct td, td_list);
 		next = list_entry (tmp, struct td, td_list);
 		tmp = next->td_list.next;
 		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
 		 * then we need to leave the control STATUS packet queued
 		 * and clear ED_SKIP.
 		 * 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;
 		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),
 			hc32_to_cpu (ohci, td->hwINFO),
 			cc, cc_to_error [cc]);
 			cc, cc_to_error [cc]);
 	}
 	}
-
-	return rev;
 }
 }
 
 
 /* replies to the request have to be on a FIFO basis so
 /* 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
 		if (cc != TD_CC_NOERROR
 				&& (td->ed->hwHeadP & cpu_to_hc32 (ohci, ED_H)))
 				&& (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->next_dl_td = td_rev;
 		td_rev = td;
 		td_rev = td;
@@ -940,8 +919,12 @@ skip_ed:
 								TD_MASK;
 								TD_MASK;
 
 
 				/* INTR_WDH may need to clean up first */
 				/* 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 = td->urb;
 			urb_priv = td->urb->hcpriv;
 			urb_priv = td->urb->hcpriv;
 
 
-			if (urb->status == -EINPROGRESS) {
+			if (!urb->unlinked) {
 				prev = &td->hwNextTD;
 				prev = &td->hwNextTD;
 				continue;
 				continue;
 			}
 			}
@@ -990,7 +973,7 @@ rescan_this:
 			/* if URB is done, clean up */
 			/* if URB is done, clean up */
 			if (urb_priv->td_cnt == urb_priv->length) {
 			if (urb_priv->td_cnt == urb_priv->length) {
 				modified = completed = 1;
 				modified = completed = 1;
-				finish_urb (ohci, urb);
+				finish_urb(ohci, urb, 0);
 			}
 			}
 		}
 		}
 		if (completed && !list_empty (&ed->td_list))
 		if (completed && !list_empty (&ed->td_list))
@@ -998,6 +981,8 @@ rescan_this:
 
 
 		/* ED's now officially unlinked, hc doesn't see */
 		/* ED's now officially unlinked, hc doesn't see */
 		ed->state = ED_IDLE;
 		ed->state = ED_IDLE;
+		if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
+			ohci->eds_scheduled--;
 		ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
 		ed->hwHeadP &= ~cpu_to_hc32(ohci, ED_H);
 		ed->hwNextED = 0;
 		ed->hwNextED = 0;
 		wmb ();
 		wmb ();
@@ -1021,7 +1006,7 @@ rescan_this:
 
 
 		if (ohci->ed_controltail) {
 		if (ohci->ed_controltail) {
 			command |= OHCI_CLF;
 			command |= OHCI_CLF;
-			if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+			if (quirk_zfmicro(ohci))
 				mdelay(1);
 				mdelay(1);
 			if (!(ohci->hc_control & OHCI_CTRL_CLE)) {
 			if (!(ohci->hc_control & OHCI_CTRL_CLE)) {
 				control |= OHCI_CTRL_CLE;
 				control |= OHCI_CTRL_CLE;
@@ -1031,7 +1016,7 @@ rescan_this:
 		}
 		}
 		if (ohci->ed_bulktail) {
 		if (ohci->ed_bulktail) {
 			command |= OHCI_BLF;
 			command |= OHCI_BLF;
-			if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+			if (quirk_zfmicro(ohci))
 				mdelay(1);
 				mdelay(1);
 			if (!(ohci->hc_control & OHCI_CTRL_BLE)) {
 			if (!(ohci->hc_control & OHCI_CTRL_BLE)) {
 				control |= OHCI_CTRL_BLE;
 				control |= OHCI_CTRL_BLE;
@@ -1043,13 +1028,13 @@ rescan_this:
 		/* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */
 		/* CLE/BLE to enable, CLF/BLF to (maybe) kickstart */
 		if (control) {
 		if (control) {
 			ohci->hc_control |= control;
 			ohci->hc_control |= control;
-			if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+			if (quirk_zfmicro(ohci))
 				mdelay(1);
 				mdelay(1);
 			ohci_writel (ohci, ohci->hc_control,
 			ohci_writel (ohci, ohci->hc_control,
 					&ohci->regs->control);
 					&ohci->regs->control);
 		}
 		}
 		if (command) {
 		if (command) {
-			if (ohci->flags & OHCI_QUIRK_ZFMICRO)
+			if (quirk_zfmicro(ohci))
 				mdelay(1);
 				mdelay(1);
 			ohci_writel (ohci, command, &ohci->regs->cmdstatus);
 			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.
  * Process normal completions (error or success) and clean the schedules.
  *
  *
  * This is the main path for handing urbs back to drivers.  The only other
  * 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
 static void
 dl_done_list (struct ohci_hcd *ohci)
 dl_done_list (struct ohci_hcd *ohci)
@@ -1074,44 +1108,7 @@ dl_done_list (struct ohci_hcd *ohci)
 
 
 	while (td) {
 	while (td) {
 		struct td	*td_next = td->next_dl_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;
 		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_BE_MMIO	0x10			/* BE registers */
 #define	OHCI_QUIRK_ZFMICRO	0x20			/* Compaq ZFMicro chipset*/
 #define	OHCI_QUIRK_ZFMICRO	0x20			/* Compaq ZFMicro chipset*/
 #define	OHCI_QUIRK_NEC		0x40			/* lost interrupts */
 #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
 	// there are also chip quirks/bugs in init logic
 
 
 	struct work_struct	nec_work;	/* Worker for NEC quirk */
 	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 */
 /* convert between an hcd pointer and the corresponding ohci_hcd */
 static inline struct ohci_hcd *hcd_to_ohci (struct usb_hcd *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
 /* HCCA frame number is 16 bits, but is accessed as 32 bits since not all
  * hardware handles 16 bit reads.  That creates a different confusion on
  * hardware handles 16 bit reads.  That creates a different confusion on
  * some big-endian SOC implementations.  Same thing happens with PSW access.
  * some big-endian SOC implementations.  Same thing happens with PSW access.
- *
- * FIXME: Deal with that as a runtime quirk when STB03xxx is ported over
- * to arch/powerpc
  */
  */
 
 
-#ifdef CONFIG_STB03xxx
-#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
 #else
-#define OHCI_BE_FRAME_NO_SHIFT	0
+#define big_endian_frame_no_quirk(ohci)	0
 #endif
 #endif
 
 
 static inline u16 ohci_frame_no(const struct ohci_hcd *ohci)
 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;
 	u32 tmp;
 	if (big_endian_desc(ohci)) {
 	if (big_endian_desc(ohci)) {
 		tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
 		tmp = be32_to_cpup((__force __be32 *)&ohci->hcca->frame_no);
-		tmp >>= OHCI_BE_FRAME_NO_SHIFT;
+		if (!big_endian_frame_no_quirk(ohci))
+			tmp >>= 16;
 	} else
 	} else
 		tmp = le32_to_cpup((__force __le32 *)&ohci->hcca->frame_no);
 		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);
 		kfree(td);
 
 
 		if (urb) {
 		if (urb) {
-			urb->status = -ENODEV;
-			urb->hcpriv = NULL;
+			usb_hcd_unlink_urb_from_ep(r8a66597_to_hcd(r8a66597),
+					urb);
+
 			spin_unlock(&r8a66597->lock);
 			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);
 			spin_lock(&r8a66597->lock);
 		}
 		}
 		break;
 		break;
@@ -832,7 +834,7 @@ static void init_pipe_info(struct r8a66597 *r8a66597, struct urb *urb,
 	info.pipenum = get_empty_pipenum(r8a66597, ep);
 	info.pipenum = get_empty_pipenum(r8a66597, ep);
 	info.address = get_urb_to_r8a66597_addr(r8a66597, urb);
 	info.address = get_urb_to_r8a66597_addr(r8a66597, urb);
 	info.epnum = ep->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
 	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
 	info.type = get_r8a66597_type(ep->bmAttributes
 				      & USB_ENDPOINT_XFERTYPE_MASK);
 				      & USB_ENDPOINT_XFERTYPE_MASK);
 	info.bufnum = get_bufnum(info.pipenum);
 	info.bufnum = get_bufnum(info.pipenum);
@@ -923,7 +925,7 @@ static void prepare_setup_packet(struct r8a66597 *r8a66597,
 	r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
 	r8a66597_write(r8a66597, ~(SIGN | SACK), INTSTS1);
 
 
 	for (i = 0; i < 4; i++) {
 	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;
 		setup_addr += 2;
 	}
 	}
 	r8a66597_write(r8a66597, SUREQ, DCPCTR);
 	r8a66597_write(r8a66597, SUREQ, DCPCTR);
@@ -1032,6 +1034,15 @@ static void prepare_status_packet(struct r8a66597 *r8a66597,
 	pipe_start(r8a66597, td->pipe);
 	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 */
 /* this function must be called with interrupt disabled */
 static int start_transfer(struct r8a66597 *r8a66597, struct r8a66597_td *td)
 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) {
 	switch (td->type) {
 	case USB_PID_SETUP:
 	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->set_address = 1;
 			td->urb->setup_packet[2] = alloc_usb_address(r8a66597,
 			td->urb->setup_packet[2] = alloc_usb_address(r8a66597,
 								     td->urb);
 								     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 */
 /* 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;
 	int restart = 0;
 	struct usb_hcd *hcd = r8a66597_to_hcd(r8a66597);
 	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);
 	r8a66597->timeout_map &= ~(1 << pipenum);
 
 
 	if (likely(td)) {
 	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]);
 			r8a66597->address_map &= ~(1 << urb->setup_packet[2]);
 
 
 		pipe_toggle_save(r8a66597, td->pipe, urb);
 		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))
 		if (usb_pipeisoc(urb->pipe))
 			urb->start_frame = r8a66597_get_frame(hcd);
 			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);
 		spin_unlock(&r8a66597->lock);
-		usb_hcd_giveback_urb(hcd, urb);
+		usb_hcd_giveback_urb(hcd, urb, status);
 		spin_lock(&r8a66597->lock);
 		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)
 static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
 {
 {
 	u16 tmp;
 	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 r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
 	struct urb *urb;
 	struct urb *urb;
 	int finish = 0;
 	int finish = 0;
+	int status = 0;
 
 
 	if (unlikely(!td))
 	if (unlikely(!td))
 		return;
 		return;
@@ -1170,17 +1175,15 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
 	fifo_change_from_pipe(r8a66597, td->pipe);
 	fifo_change_from_pipe(r8a66597, td->pipe);
 	tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
 	tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
 	if (unlikely((tmp & FRDY) == 0)) {
 	if (unlikely((tmp & FRDY) == 0)) {
-		urb->status = -EPIPE;
 		pipe_stop(r8a66597, td->pipe);
 		pipe_stop(r8a66597, td->pipe);
 		pipe_irq_disable(r8a66597, pipenum);
 		pipe_irq_disable(r8a66597, pipenum);
 		err("in fifo not ready (%d)", pipenum);
 		err("in fifo not ready (%d)", pipenum);
-		finish_request(r8a66597, td, pipenum, td->urb);
+		finish_request(r8a66597, td, pipenum, td->urb, -EPIPE);
 		return;
 		return;
 	}
 	}
 
 
 	/* prepare parameters */
 	/* prepare parameters */
 	rcv_len = tmp & DTLN;
 	rcv_len = tmp & DTLN;
-	bufsize = td->maxpacket;
 	if (usb_pipeisoc(urb->pipe)) {
 	if (usb_pipeisoc(urb->pipe)) {
 		buf = (u16 *)(urb->transfer_buffer +
 		buf = (u16 *)(urb->transfer_buffer +
 				urb->iso_frame_desc[td->iso_cnt].offset);
 				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;
 		buf = (void *)urb->transfer_buffer + urb->actual_length;
 		urb_len = urb->transfer_buffer_length - 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 */
 	/* update parameters */
 	urb->actual_length += size;
 	urb->actual_length += size;
 	if (rcv_len == 0)
 	if (rcv_len == 0)
 		td->zero_packet = 1;
 		td->zero_packet = 1;
-	if ((size % td->maxpacket) > 0) {
+	if (rcv_len < bufsize) {
 		td->short_packet = 1;
 		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)) {
 	if (usb_pipeisoc(urb->pipe)) {
 		urb->iso_frame_desc[td->iso_cnt].actual_length = size;
 		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++;
 		td->iso_cnt++;
+		finish = 0;
 	}
 	}
 
 
 	/* check transfer finish */
 	/* check transfer finish */
-	if (check_transfer_finish(td, urb)) {
+	if (finish || check_transfer_finish(td, urb)) {
 		pipe_stop(r8a66597, td->pipe);
 		pipe_stop(r8a66597, td->pipe);
 		pipe_irq_disable(r8a66597, pipenum);
 		pipe_irq_disable(r8a66597, pipenum);
 		finish = 1;
 		finish = 1;
@@ -1226,11 +1231,8 @@ static void packet_read(struct r8a66597 *r8a66597, u16 pipenum)
 					   buf, size);
 					   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)
 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);
 	fifo_change_from_pipe(r8a66597, td->pipe);
 	tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
 	tmp = r8a66597_read(r8a66597, td->pipe->fifoctr);
 	if (unlikely((tmp & FRDY) == 0)) {
 	if (unlikely((tmp & FRDY) == 0)) {
-		urb->status = -EPIPE;
 		pipe_stop(r8a66597, td->pipe);
 		pipe_stop(r8a66597, td->pipe);
 		pipe_irq_disable(r8a66597, pipenum);
 		pipe_irq_disable(r8a66597, pipenum);
 		err("out write fifo not ready. (%d)", pipenum);
 		err("out write fifo not ready. (%d)", pipenum);
-		finish_request(r8a66597, td, pipenum, td->urb);
+		finish_request(r8a66597, td, pipenum, urb, -EPIPE);
 		return;
 		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 r8a66597_td *td = r8a66597_get_td(r8a66597, 0);
 	struct urb *urb;
 	struct urb *urb;
@@ -1310,49 +1311,41 @@ static void check_next_phase(struct r8a66597 *r8a66597)
 	switch (td->type) {
 	switch (td->type) {
 	case USB_PID_IN:
 	case USB_PID_IN:
 	case USB_PID_OUT:
 	case USB_PID_OUT:
-		if (urb->status != -EINPROGRESS) {
-			finish = 1;
-			break;
-		}
 		if (check_transfer_finish(td, urb))
 		if (check_transfer_finish(td, urb))
 			td->type = USB_PID_ACK;
 			td->type = USB_PID_ACK;
 		break;
 		break;
 	case USB_PID_SETUP:
 	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;
 			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;
 			td->type = USB_PID_OUT;
 		else
 		else
 			td->type = USB_PID_IN;
 			td->type = USB_PID_IN;
 		break;
 		break;
 	case USB_PID_ACK:
 	case USB_PID_ACK:
 		finish = 1;
 		finish = 1;
-		if (urb->status == -EINPROGRESS)
-			urb->status = 0;
 		break;
 		break;
 	}
 	}
 
 
-	if (finish)
-		finish_request(r8a66597, td, 0, urb);
+	if (finish || status != 0 || urb->unlinked)
+		finish_request(r8a66597, td, 0, urb, status);
 	else
 	else
 		start_transfer(r8a66597, td);
 		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);
 	struct r8a66597_td *td = r8a66597_get_td(r8a66597, pipenum);
 
 
-	if (td && td->urb) {
+	if (td) {
 		u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID;
 		u16 pid = r8a66597_read(r8a66597, td->pipe->pipectr) & PID;
 
 
 		if (pid == PID_NAK)
 		if (pid == PID_NAK)
-			td->urb->status = -ECONNRESET;
+			return -ECONNRESET;
 		else
 		else
-			td->urb->status = -EPIPE;
+			return -EPIPE;
 	}
 	}
+	return 0;
 }
 }
 
 
 static void irq_pipe_ready(struct r8a66597 *r8a66597)
 static void irq_pipe_ready(struct r8a66597 *r8a66597)
@@ -1371,7 +1364,7 @@ static void irq_pipe_ready(struct r8a66597 *r8a66597)
 			packet_read(r8a66597, 0);
 			packet_read(r8a66597, 0);
 		else
 		else
 			pipe_irq_disable(r8a66597, 0);
 			pipe_irq_disable(r8a66597, 0);
-		check_next_phase(r8a66597);
+		check_next_phase(r8a66597, 0);
 	}
 	}
 
 
 	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
 	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);
 		td = r8a66597_get_td(r8a66597, 0);
 		if (td && td->type != USB_PID_OUT)
 		if (td && td->type != USB_PID_OUT)
 			disable_irq_empty(r8a66597, 0);
 			disable_irq_empty(r8a66597, 0);
-		check_next_phase(r8a66597);
+		check_next_phase(r8a66597, 0);
 	}
 	}
 
 
 	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
 	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) {
 			if ((tmp & INBUFM) == 0) {
 				disable_irq_empty(r8a66597, pipenum);
 				disable_irq_empty(r8a66597, pipenum);
 				pipe_irq_disable(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 check;
 	u16 pipenum;
 	u16 pipenum;
 	u16 mask;
 	u16 mask;
+	int status;
 
 
 	mask = r8a66597_read(r8a66597, NRDYSTS)
 	mask = r8a66597_read(r8a66597, NRDYSTS)
 	       & r8a66597_read(r8a66597, NRDYENB);
 	       & r8a66597_read(r8a66597, NRDYENB);
 	r8a66597_write(r8a66597, ~mask, NRDYSTS);
 	r8a66597_write(r8a66597, ~mask, NRDYSTS);
 	if (mask & NRDY0) {
 	if (mask & NRDY0) {
 		cfifo_change(r8a66597, 0);
 		cfifo_change(r8a66597, 0);
-		set_urb_error(r8a66597, 0);
+		status = get_urb_error(r8a66597, 0);
 		pipe_irq_disable(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++) {
 	for (pipenum = 1; pipenum < R8A66597_MAX_NUM_PIPE; pipenum++) {
@@ -1452,10 +1445,10 @@ static void irq_pipe_nrdy(struct r8a66597 *r8a66597)
 			if (unlikely(!td))
 			if (unlikely(!td))
 				continue;
 				continue;
 
 
-			set_urb_error(r8a66597, pipenum);
+			status = get_urb_error(r8a66597, pipenum);
 			pipe_irq_disable(r8a66597, pipenum);
 			pipe_irq_disable(r8a66597, pipenum);
 			pipe_stop(r8a66597, td->pipe);
 			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 intsts0, intsts1, intsts2;
 	u16 intenb0, intenb1, intenb2;
 	u16 intenb0, intenb1, intenb2;
 	u16 mask0, mask1, mask2;
 	u16 mask0, mask1, mask2;
+	int status;
 
 
 	spin_lock(&r8a66597->lock);
 	spin_lock(&r8a66597->lock);
 
 
@@ -1518,12 +1512,12 @@ static irqreturn_t r8a66597_irq(struct usb_hcd *hcd)
 		}
 		}
 		if (mask1 & SIGN) {
 		if (mask1 & SIGN) {
 			r8a66597_write(r8a66597, ~SIGN, INTSTS1);
 			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) {
 		if (mask1 & SACK) {
 			r8a66597_write(r8a66597, ~SACK, INTSTS1);
 			r8a66597_write(r8a66597, ~SACK, INTSTS1);
-			check_next_phase(r8a66597);
+			check_next_phase(r8a66597, 0);
 		}
 		}
 	}
 	}
 	if (mask0) {
 	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,
 static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
-				struct usb_host_endpoint *hep,
 				struct urb *urb,
 				struct urb *urb,
 				gfp_t mem_flags)
 				gfp_t mem_flags)
 {
 {
+	struct usb_host_endpoint *hep = urb->ep;
 	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
 	struct r8a66597 *r8a66597 = hcd_to_r8a66597(hcd);
 	struct r8a66597_td *td = NULL;
 	struct r8a66597_td *td = NULL;
-	int ret = 0, request = 0;
+	int ret, request = 0;
 	unsigned long flags;
 	unsigned long flags;
 
 
 	spin_lock_irqsave(&r8a66597->lock, flags);
 	spin_lock_irqsave(&r8a66597->lock, flags);
 	if (!get_urb_to_r8a66597_dev(r8a66597, urb)) {
 	if (!get_urb_to_r8a66597_dev(r8a66597, urb)) {
 		ret = -ENODEV;
 		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) {
 	if (!hep->hcpriv) {
 		hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe),
 		hep->hcpriv = kzalloc(sizeof(struct r8a66597_pipe),
 				GFP_ATOMIC);
 				GFP_ATOMIC);
@@ -1761,15 +1759,7 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
 	if (list_empty(&r8a66597->pipe_queue[td->pipenum]))
 	if (list_empty(&r8a66597->pipe_queue[td->pipenum]))
 		request = 1;
 		request = 1;
 	list_add_tail(&td->queue, &r8a66597->pipe_queue[td->pipenum]);
 	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;
 	urb->hcpriv = td;
-	spin_unlock(&urb->lock);
 
 
 	if (request) {
 	if (request) {
 		ret = start_transfer(r8a66597, td);
 		ret = start_transfer(r8a66597, td);
@@ -1781,26 +1771,36 @@ static int r8a66597_urb_enqueue(struct usb_hcd *hcd,
 		set_td_timer(r8a66597, td);
 		set_td_timer(r8a66597, td);
 
 
 error:
 error:
+	if (ret)
+		usb_hcd_unlink_urb_from_ep(hcd, urb);
+error_not_linked:
 	spin_unlock_irqrestore(&r8a66597->lock, flags);
 	spin_unlock_irqrestore(&r8a66597->lock, flags);
 	return ret;
 	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 *r8a66597 = hcd_to_r8a66597(hcd);
 	struct r8a66597_td *td;
 	struct r8a66597_td *td;
 	unsigned long flags;
 	unsigned long flags;
+	int rc;
 
 
 	spin_lock_irqsave(&r8a66597->lock, flags);
 	spin_lock_irqsave(&r8a66597->lock, flags);
+	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (rc)
+		goto done;
+
 	if (urb->hcpriv) {
 	if (urb->hcpriv) {
 		td = urb->hcpriv;
 		td = urb->hcpriv;
 		pipe_stop(r8a66597, td->pipe);
 		pipe_stop(r8a66597, td->pipe);
 		pipe_irq_disable(r8a66597, td->pipenum);
 		pipe_irq_disable(r8a66597, td->pipenum);
 		disable_irq_empty(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);
 	spin_unlock_irqrestore(&r8a66597->lock, flags);
-	return 0;
+	return rc;
 }
 }
 
 
 static void r8a66597_endpoint_disable(struct usb_hcd *hcd,
 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);
 	td = r8a66597_get_td(r8a66597, pipenum);
 	if (td)
 	if (td)
 		urb = td->urb;
 		urb = td->urb;
-	done(r8a66597, td, pipenum, urb);
+	finish_request(r8a66597, td, pipenum, urb, -ESHUTDOWN);
 	kfree(hep->hcpriv);
 	kfree(hep->hcpriv);
 	hep->hcpriv = NULL;
 	hep->hcpriv = NULL;
 	spin_unlock_irqrestore(&r8a66597->lock, flags);
 	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:
 	case GetPortStatus:
 		if (wIndex > R8A66597_MAX_ROOT_HUB)
 		if (wIndex > R8A66597_MAX_ROOT_HUB)
 			goto error;
 			goto error;
-		*(u32 *)buf = rh->port;
+		*(u32 *)buf = cpu_to_le32(rh->port);
 		break;
 		break;
 	case SetPortFeature:
 	case SetPortFeature:
 		if (wIndex > R8A66597_MAX_ROOT_HUB)
 		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);
 	struct usb_hcd		*hcd = r8a66597_to_hcd(r8a66597);
 
 
 	del_timer_sync(&r8a66597->rh_timer);
 	del_timer_sync(&r8a66597->rh_timer);
-	iounmap((void *)r8a66597->reg);
 	usb_remove_hcd(hcd);
 	usb_remove_hcd(hcd);
+	iounmap((void *)r8a66597->reg);
 	usb_put_hcd(hcd);
 	usb_put_hcd(hcd);
 	return 0;
 	return 0;
 }
 }

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

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

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

@@ -51,7 +51,6 @@
 #include <linux/usb.h>
 #include <linux/usb.h>
 #include <linux/workqueue.h>
 #include <linux/workqueue.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
-#include <linux/pci_ids.h>
 #include <linux/mutex.h>
 #include <linux/mutex.h>
 #include <asm/io.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/irq.h>
@@ -184,7 +183,7 @@ struct u132_ring {
 struct u132 {
 struct u132 {
         struct kref kref;
         struct kref kref;
         struct list_head u132_list;
         struct list_head u132_list;
-        struct semaphore sw_lock;
+        struct mutex sw_lock;
         struct semaphore scheduler_lock;
         struct semaphore scheduler_lock;
         struct u132_platform_data *board;
         struct u132_platform_data *board;
         struct platform_device *platform_dev;
         struct platform_device *platform_dev;
@@ -493,20 +492,20 @@ static void u132_hcd_monitor_work(struct work_struct *work)
                 return;
                 return;
         } else {
         } else {
                 int retval;
                 int retval;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 retval = read_roothub_info(u132);
                 retval = read_roothub_info(u132);
                 if (retval) {
                 if (retval) {
                         struct usb_hcd *hcd = u132_to_hcd(u132);
                         struct usb_hcd *hcd = u132_to_hcd(u132);
                         u132_disable(u132);
                         u132_disable(u132);
                         u132->going = 1;
                         u132->going = 1;
-                        up(&u132->sw_lock);
+                        mutex_unlock(&u132->sw_lock);
                         usb_hc_died(hcd);
                         usb_hc_died(hcd);
                         ftdi_elan_gone_away(u132->platform_dev);
                         ftdi_elan_gone_away(u132->platform_dev);
                         u132_monitor_put_kref(u132);
                         u132_monitor_put_kref(u132);
                         return;
                         return;
                 } else {
                 } else {
                         u132_monitor_requeue_work(u132, 500);
                         u132_monitor_requeue_work(u132, 500);
-                        up(&u132->sw_lock);
+                        mutex_unlock(&u132->sw_lock);
                         return;
                         return;
                 }
                 }
         }
         }
@@ -519,9 +518,8 @@ static void u132_hcd_giveback_urb(struct u132 *u132, struct u132_endp *endp,
         unsigned long irqs;
         unsigned long irqs;
         struct usb_hcd *hcd = u132_to_hcd(u132);
         struct usb_hcd *hcd = u132_to_hcd(u132);
         urb->error_count = 0;
         urb->error_count = 0;
-        urb->status = status;
-        urb->hcpriv = NULL;
         spin_lock_irqsave(&endp->queue_lock.slock, irqs);
         spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
         endp->queue_next += 1;
         endp->queue_next += 1;
         if (ENDP_QUEUE_SIZE > --endp->queue_size) {
         if (ENDP_QUEUE_SIZE > --endp->queue_size) {
                 endp->active = 0;
                 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);
         u132_ring_queue_work(u132, ring, 0);
         up(&u132->scheduler_lock);
         up(&u132->scheduler_lock);
         u132_endp_put_kref(u132, endp);
         u132_endp_put_kref(u132, endp);
-        usb_hcd_giveback_urb(hcd, urb);
+	usb_hcd_giveback_urb(hcd, urb, status);
         return;
         return;
 }
 }
 
 
@@ -559,9 +557,8 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
         unsigned long irqs;
         unsigned long irqs;
         struct usb_hcd *hcd = u132_to_hcd(u132);
         struct usb_hcd *hcd = u132_to_hcd(u132);
         urb->error_count = 0;
         urb->error_count = 0;
-        urb->status = status;
-        urb->hcpriv = NULL;
         spin_lock_irqsave(&endp->queue_lock.slock, irqs);
         spin_lock_irqsave(&endp->queue_lock.slock, irqs);
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
         endp->queue_next += 1;
         endp->queue_next += 1;
         if (ENDP_QUEUE_SIZE > --endp->queue_size) {
         if (ENDP_QUEUE_SIZE > --endp->queue_size) {
                 endp->active = 0;
                 endp->active = 0;
@@ -576,7 +573,7 @@ static void u132_hcd_abandon_urb(struct u132 *u132, struct u132_endp *endp,
                 endp->active = 0;
                 endp->active = 0;
                 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                 spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                 kfree(urbq);
                 kfree(urbq);
-        } usb_hcd_giveback_urb(hcd, urb);
+	} usb_hcd_giveback_urb(hcd, urb, status);
         return;
         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);
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
                 return;
         } else if (u132->going > 0) {
         } 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);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer + urb->actual_length;
                 u8 *u = urb->transfer_buffer + urb->actual_length;
                 u8 *b = buf;
                 u8 *b = buf;
@@ -717,10 +714,10 @@ static void u132_hcd_interrupt_recv(void *data, struct urb *urb, u8 *buf,
                         return;
                         return;
                 }
                 }
         } else {
         } 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);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
                 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);
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
                 return;
         } else if (u132->going > 0) {
         } 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);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 struct u132_ring *ring = endp->ring;
                 urb->actual_length += len;
                 urb->actual_length += len;
                 endp->toggle_bits = toggle_bits;
                 endp->toggle_bits = toggle_bits;
@@ -769,10 +766,10 @@ static void u132_hcd_bulk_output_sent(void *data, struct urb *urb, u8 *buf,
                         return;
                         return;
                 }
                 }
         } else {
         } 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);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
                 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);
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
                 return;
         } else if (u132->going > 0) {
         } 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);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer + urb->actual_length;
                 u8 *u = urb->transfer_buffer + urb->actual_length;
                 u8 *b = buf;
                 u8 *b = buf;
@@ -872,10 +869,10 @@ static void u132_hcd_bulk_input_recv(void *data, struct urb *urb, u8 *buf,
                         return;
                         return;
                 }
                 }
         } else {
         } 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);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
                 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);
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
                 return;
         } else if (u132->going > 0) {
         } 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);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 up(&u132->scheduler_lock);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
                 return;
         } else {
         } 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);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
                 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);
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
                 return;
         } else if (u132->going > 0) {
         } 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);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 struct u132_ring *ring = endp->ring;
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer;
                 u8 *u = urb->transfer_buffer;
                 u8 *b = buf;
                 u8 *b = buf;
@@ -981,10 +978,10 @@ static void u132_hcd_configure_input_recv(void *data, struct urb *urb, u8 *buf,
                         return;
                         return;
                 }
                 }
         } else {
         } 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);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
                 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);
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
                 return;
         } else if (u132->going > 0) {
         } 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);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 up(&u132->scheduler_lock);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
                 return;
         } else {
         } 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);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
                 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);
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
                 return;
         } else if (u132->going > 0) {
         } 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);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 if (usb_pipein(urb->pipe)) {
                 if (usb_pipein(urb->pipe)) {
                         int retval;
                         int retval;
                         struct u132_ring *ring = endp->ring;
                         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;
                         return;
                 }
                 }
         } else {
         } 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);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
                 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);
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
                 return;
         } else if (u132->going > 0) {
         } 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);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 u132->addr[0].address = 0;
                 u132->addr[0].address = 0;
                 endp->usb_addr = udev->usb_addr;
                 endp->usb_addr = udev->usb_addr;
                 up(&u132->scheduler_lock);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
                 return;
         } else {
         } 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);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
                 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);
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
                 return;
         } else if (u132->going > 0) {
         } 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);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 int retval;
                 int retval;
                 struct u132_ring *ring = endp->ring;
                 struct u132_ring *ring = endp->ring;
                 up(&u132->scheduler_lock);
                 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);
                         u132_hcd_giveback_urb(u132, endp, urb, retval);
                 return;
                 return;
         } else {
         } 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);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
                 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);
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
                 return;
         } else if (u132->going > 0) {
         } 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);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 up(&u132->scheduler_lock);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
                 return;
         } else {
         } 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);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
                 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);
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
                 return;
         } else if (u132->going > 0) {
         } 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);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 int retval;
                 int retval;
                 struct u132_ring *ring = endp->ring;
                 struct u132_ring *ring = endp->ring;
                 u8 *u = urb->transfer_buffer;
                 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);
                         u132_hcd_giveback_urb(u132, endp, urb, retval);
                 return;
                 return;
         } else {
         } 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);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
                 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);
                 u132_hcd_giveback_urb(u132, endp, urb, -EINTR);
                 return;
                 return;
         } else if (u132->going > 0) {
         } 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);
                 up(&u132->scheduler_lock);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 u132_hcd_giveback_urb(u132, endp, urb, -ENODEV);
                 return;
                 return;
-        } else if (urb->status == -EINPROGRESS) {
+	} else if (!urb->unlinked) {
                 int retval;
                 int retval;
                 struct u132_ring *ring = endp->ring;
                 struct u132_ring *ring = endp->ring;
                 up(&u132->scheduler_lock);
                 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);
                         u132_hcd_giveback_urb(u132, endp, urb, retval);
                 return;
                 return;
         } else {
         } 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);
                 up(&u132->scheduler_lock);
-                u132_hcd_giveback_urb(u132, endp, urb, urb->status);
+		u132_hcd_giveback_urb(u132, endp, urb, 0);
                 return;
                 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"
                 dev_err(&u132->platform_dev->dev, "device hcd=%p is being remov"
                         "ed\n", hcd);
                         "ed\n", hcd);
         } else {
         } else {
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 msleep(100);
                 msleep(100);
                 u132_power(u132, 0);
                 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;
                         (pdev->dev.platform_data))->vendor;
                 u16 device = ((struct u132_platform_data *)
                 u16 device = ((struct u132_platform_data *)
                         (pdev->dev.platform_data))->device;
                         (pdev->dev.platform_data))->device;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 msleep(10);
                 msleep(10);
                 if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
                 if (vendor == PCI_VENDOR_ID_AMD && device == 0x740c) {
                         u132->flags = OHCI_QUIRK_AMD756;
                         u132->flags = OHCI_QUIRK_AMD756;
@@ -1845,7 +1842,7 @@ static int u132_hcd_start(struct usb_hcd *hcd)
                         u132->going = 1;
                         u132->going = 1;
                 }
                 }
                 msleep(100);
                 msleep(100);
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
                 return retval;
                 return retval;
         } else {
         } else {
                 dev_err(&u132->platform_dev->dev, "platform_device missing\n");
                 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;
                 return -ESHUTDOWN;
         } else {
         } else {
                 int retval;
                 int retval;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 retval = u132_init(u132);
                 retval = u132_init(u132);
                 if (retval) {
                 if (retval) {
                         u132_disable(u132);
                         u132_disable(u132);
                         u132->going = 1;
                         u132->going = 1;
                 }
                 }
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
                 return retval;
                 return retval;
         }
         }
 }
 }
 
 
 static int create_endpoint_and_queue_int(struct u132 *u132,
 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,
         struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
         gfp_t mem_flags)
         gfp_t mem_flags)
 {
 {
         struct u132_ring *ring;
         struct u132_ring *ring;
         unsigned long irqs;
         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) {
         if (!endp) {
                 return -ENOMEM;
                 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);
         INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
-        spin_lock_init(&endp->queue_lock.slock);
         INIT_LIST_HEAD(&endp->urb_more);
         INIT_LIST_HEAD(&endp->urb_more);
         ring = endp->ring = &u132->ring[0];
         ring = endp->ring = &u132->ring[0];
         if (ring->curr_endp) {
         if (ring->curr_endp) {
@@ -1906,7 +1915,7 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
         endp->delayed = 0;
         endp->delayed = 0;
         endp->endp_number = endp_number;
         endp->endp_number = endp_number;
         endp->u132 = u132;
         endp->u132 = u132;
-        endp->hep = hep;
+	endp->hep = urb->ep;
         endp->pipetype = usb_pipetype(urb->pipe);
         endp->pipetype = usb_pipetype(urb->pipe);
         u132_endp_init_kref(u132, endp);
         u132_endp_init_kref(u132, endp);
         if (usb_pipein(urb->pipe)) {
         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);
                 u132_udev_get_kref(u132, udev);
         }
         }
         urb->hcpriv = u132;
         urb->hcpriv = u132;
-        spin_lock_irqsave(&endp->queue_lock.slock, irqs);
         endp->delayed = 1;
         endp->delayed = 1;
         endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
         endp->jiffies = jiffies + msecs_to_jiffies(urb->interval);
         endp->udev_number = address;
         endp->udev_number = address;
@@ -1940,8 +1948,8 @@ static int create_endpoint_and_queue_int(struct u132 *u132,
         return 0;
         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,
         struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
         u8 usb_endp, u8 address)
         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,
 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,
         struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp, u8 address,
         gfp_t mem_flags)
         gfp_t mem_flags)
 {
 {
         int ring_number;
         int ring_number;
         struct u132_ring *ring;
         struct u132_ring *ring;
         unsigned long irqs;
         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) {
         if (!endp) {
                 return -ENOMEM;
                 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);
         INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
-        spin_lock_init(&endp->queue_lock.slock);
         INIT_LIST_HEAD(&endp->urb_more);
         INIT_LIST_HEAD(&endp->urb_more);
         endp->dequeueing = 0;
         endp->dequeueing = 0;
         endp->edset_flush = 0;
         endp->edset_flush = 0;
@@ -1987,7 +2007,7 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
         endp->delayed = 0;
         endp->delayed = 0;
         endp->endp_number = endp_number;
         endp->endp_number = endp_number;
         endp->u132 = u132;
         endp->u132 = u132;
-        endp->hep = hep;
+	endp->hep = urb->ep;
         endp->pipetype = usb_pipetype(urb->pipe);
         endp->pipetype = usb_pipetype(urb->pipe);
         u132_endp_init_kref(u132, endp);
         u132_endp_init_kref(u132, endp);
         if (usb_pipein(urb->pipe)) {
         if (usb_pipein(urb->pipe)) {
@@ -2016,7 +2036,6 @@ static int create_endpoint_and_queue_bulk(struct u132 *u132,
         }
         }
         ring->length += 1;
         ring->length += 1;
         urb->hcpriv = u132;
         urb->hcpriv = u132;
-        spin_lock_irqsave(&endp->queue_lock.slock, irqs);
         endp->udev_number = address;
         endp->udev_number = address;
         endp->usb_addr = usb_addr;
         endp->usb_addr = usb_addr;
         endp->usb_endp = usb_endp;
         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,
 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,
         struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
         u8 usb_endp, u8 address)
         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,
 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,
         struct usb_device *usb_dev, u8 usb_addr, u8 usb_endp,
         gfp_t mem_flags)
         gfp_t mem_flags)
 {
 {
         struct u132_ring *ring;
         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) {
         if (!endp) {
                 return -ENOMEM;
                 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);
         INIT_DELAYED_WORK(&endp->scheduler, u132_hcd_endp_work_scheduler);
-        spin_lock_init(&endp->queue_lock.slock);
         INIT_LIST_HEAD(&endp->urb_more);
         INIT_LIST_HEAD(&endp->urb_more);
         ring = endp->ring = &u132->ring[0];
         ring = endp->ring = &u132->ring[0];
         if (ring->curr_endp) {
         if (ring->curr_endp) {
@@ -2080,11 +2112,10 @@ static int create_endpoint_and_queue_control(struct u132 *u132,
         endp->delayed = 0;
         endp->delayed = 0;
         endp->endp_number = endp_number;
         endp->endp_number = endp_number;
         endp->u132 = u132;
         endp->u132 = u132;
-        endp->hep = hep;
+	endp->hep = urb->ep;
         u132_endp_init_kref(u132, endp);
         u132_endp_init_kref(u132, endp);
         u132_endp_get_kref(u132, endp);
         u132_endp_get_kref(u132, endp);
         if (usb_addr == 0) {
         if (usb_addr == 0) {
-                unsigned long irqs;
                 u8 address = u132->addr[usb_addr].address;
                 u8 address = u132->addr[usb_addr].address;
                 struct u132_udev *udev = &u132->udev[address];
                 struct u132_udev *udev = &u132->udev[address];
                 endp->udev_number = 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_in[usb_endp] = endp_number;
                 udev->endp_number_out[usb_endp] = endp_number;
                 udev->endp_number_out[usb_endp] = endp_number;
                 urb->hcpriv = u132;
                 urb->hcpriv = u132;
-                spin_lock_irqsave(&endp->queue_lock.slock, irqs);
                 endp->queue_size = 1;
                 endp->queue_size = 1;
                 endp->queue_last = 0;
                 endp->queue_last = 0;
                 endp->queue_next = 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);
                 u132_endp_queue_work(u132, endp, 0);
                 return 0;
                 return 0;
         } else {                /*(usb_addr > 0) */
         } else {                /*(usb_addr > 0) */
-                unsigned long irqs;
                 u8 address = u132->addr[usb_addr].address;
                 u8 address = u132->addr[usb_addr].address;
                 struct u132_udev *udev = &u132->udev[address];
                 struct u132_udev *udev = &u132->udev[address];
                 endp->udev_number = 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_in[usb_endp] = endp_number;
                 udev->endp_number_out[usb_endp] = endp_number;
                 udev->endp_number_out[usb_endp] = endp_number;
                 urb->hcpriv = u132;
                 urb->hcpriv = u132;
-                spin_lock_irqsave(&endp->queue_lock.slock, irqs);
                 endp->queue_size = 1;
                 endp->queue_size = 1;
                 endp->queue_last = 0;
                 endp->queue_last = 0;
                 endp->queue_next = 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,
 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,
         struct usb_device *usb_dev, struct u132_endp *endp, u8 usb_addr,
         u8 usb_endp)
         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);
         struct u132 *u132 = hcd_to_u132(hcd);
         if (irqs_disabled()) {
         if (irqs_disabled()) {
@@ -2249,8 +2277,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                         , u132->going);
                         , u132->going);
                 return -ENODEV;
                 return -ENODEV;
         } else if (u132->going > 0) {
         } 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;
                 return -ESHUTDOWN;
         } else {
         } else {
                 u8 usb_addr = usb_pipedevice(urb->pipe);
                 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) {
                 if (usb_pipetype(urb->pipe) == PIPE_INTERRUPT) {
                         u8 address = u132->addr[usb_addr].address;
                         u8 address = u132->addr[usb_addr].address;
                         struct u132_udev *udev = &u132->udev[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;
                         urb->actual_length = 0;
                         if (endp) {
                         if (endp) {
                                 unsigned long irqs;
                                 unsigned long irqs;
                                 int retval;
                                 int retval;
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                         irqs);
                                         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,
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
                                         irqs);
                                         irqs);
                                 if (retval) {
                                 if (retval) {
@@ -2283,8 +2319,8 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                                 return -EINVAL;
                                 return -EINVAL;
                         } else {        /*(endp == NULL) */
                         } else {        /*(endp == NULL) */
                                 return create_endpoint_and_queue_int(u132, udev,
                                 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) {
                 } else if (usb_pipetype(urb->pipe) == PIPE_ISOCHRONOUS) {
                         dev_err(&u132->platform_dev->dev, "the hardware does no"
                         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) {
                 } else if (usb_pipetype(urb->pipe) == PIPE_BULK) {
                         u8 address = u132->addr[usb_addr].address;
                         u8 address = u132->addr[usb_addr].address;
                         struct u132_udev *udev = &u132->udev[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;
                         urb->actual_length = 0;
                         if (endp) {
                         if (endp) {
                                 unsigned long irqs;
                                 unsigned long irqs;
                                 int retval;
                                 int retval;
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                         irqs);
                                         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,
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
                                         irqs);
                                         irqs);
                                 if (retval) {
                                 if (retval) {
@@ -2315,10 +2359,10 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                                 return -EINVAL;
                                 return -EINVAL;
                         } else
                         } else
                                 return create_endpoint_and_queue_bulk(u132,
                                 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);
                                         usb_endp, address, mem_flags);
                 } else {
                 } else {
-                        struct u132_endp *endp = hep->hcpriv;
+                        struct u132_endp *endp = urb->ep->hcpriv;
                         u16 urb_size = 8;
                         u16 urb_size = 8;
                         u8 *b = urb->setup_packet;
                         u8 *b = urb->setup_packet;
                         int i = 0;
                         int i = 0;
@@ -2341,9 +2385,16 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                                 int retval;
                                 int retval;
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                 spin_lock_irqsave(&endp->queue_lock.slock,
                                         irqs);
                                         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,
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
                                         irqs);
                                         irqs);
                                 if (retval) {
                                 if (retval) {
@@ -2356,7 +2407,7 @@ static int u132_urb_enqueue(struct usb_hcd *hcd, struct usb_host_endpoint *hep,
                                 return -EINVAL;
                                 return -EINVAL;
                         } else
                         } else
                                 return create_endpoint_and_queue_control(u132,
                                 return create_endpoint_and_queue_control(u132,
-                                        hep, urb, usb_dev, usb_addr, usb_endp,
+					urb, usb_dev, usb_addr, usb_endp,
                                         mem_flags);
                                         mem_flags);
                 }
                 }
         }
         }
@@ -2375,8 +2426,7 @@ static int dequeue_from_overflow_chain(struct u132 *u132,
                         list_del(scan);
                         list_del(scan);
                         endp->queue_size -= 1;
                         endp->queue_size -= 1;
                         urb->error_count = 0;
                         urb->error_count = 0;
-                        urb->hcpriv = NULL;
-                        usb_hcd_giveback_urb(hcd, urb);
+			usb_hcd_giveback_urb(hcd, urb, 0);
                         return 0;
                         return 0;
                 } else
                 } else
                         continue;
                         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,
 static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
-        struct urb *urb)
+		struct urb *urb, int status)
 {
 {
         unsigned long irqs;
         unsigned long irqs;
+	int rc;
+
         spin_lock_irqsave(&endp->queue_lock.slock, irqs);
         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) {
         if (endp->queue_size == 0) {
                 dev_err(&u132->platform_dev->dev, "urb=%p not found in endp[%d]"
                 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,
                         "=%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;
                         endp->edset_flush = 1;
                         u132_endp_queue_work(u132, endp, 0);
                         u132_endp_queue_work(u132, endp, 0);
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
-                        urb->hcpriv = NULL;
                         return 0;
                         return 0;
                 } else {
                 } else {
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                         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;
                         return 0;
                 }
                 }
         } else {
         } else {
@@ -2439,6 +2495,8 @@ static int u132_endp_urb_dequeue(struct u132 *u132, struct u132_endp *endp,
                 }
                 }
                 if (urb_slot) {
                 if (urb_slot) {
                         struct usb_hcd *hcd = u132_to_hcd(u132);
                         struct usb_hcd *hcd = u132_to_hcd(u132);
+
+			usb_hcd_unlink_urb_from_ep(hcd, urb);
                         endp->queue_size -= 1;
                         endp->queue_size -= 1;
                         if (list_empty(&endp->urb_more)) {
                         if (list_empty(&endp->urb_more)) {
                                 spin_unlock_irqrestore(&endp->queue_lock.slock,
                                 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);
                                         irqs);
                                 kfree(urbq);
                                 kfree(urbq);
                         } urb->error_count = 0;
                         } urb->error_count = 0;
-                        urb->hcpriv = NULL;
-                        usb_hcd_giveback_urb(hcd, urb);
+			usb_hcd_giveback_urb(hcd, urb, status);
                         return 0;
                         return 0;
                 } else if (list_empty(&endp->urb_more)) {
                 } else if (list_empty(&endp->urb_more)) {
                         dev_err(&u132->platform_dev->dev, "urb=%p not found in "
                         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);
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                         return -EINVAL;
                         return -EINVAL;
                 } else {
                 } 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);
                                 urb);
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                         spin_unlock_irqrestore(&endp->queue_lock.slock, irqs);
                         return retval;
                         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);
         struct u132 *u132 = hcd_to_u132(hcd);
         if (u132->going > 2) {
         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)) {
                 if (usb_pipein(urb->pipe)) {
                         u8 endp_number = udev->endp_number_in[usb_endp];
                         u8 endp_number = udev->endp_number_in[usb_endp];
                         struct u132_endp *endp = u132->endp[endp_number - 1];
                         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 {
                 } else {
                         u8 endp_number = udev->endp_number_out[usb_endp];
                         u8 endp_number = udev->endp_number_out[usb_endp];
                         struct u132_endp *endp = u132->endp[endp_number - 1];
                         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;
                 return -ESHUTDOWN;
         } else {
         } else {
                 int retval = 0;
                 int retval = 0;
-                down(&u132->sw_lock);
+                mutex_lock(&u132->sw_lock);
                 switch (typeReq) {
                 switch (typeReq) {
                 case ClearHubFeature:
                 case ClearHubFeature:
                         switch (wValue) {
                         switch (wValue) {
@@ -2868,7 +2928,7 @@ static int u132_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
                       stall:retval = -EPIPE;
                       stall:retval = -EPIPE;
                         break;
                         break;
                 }
                 }
-                up(&u132->sw_lock);
+                mutex_unlock(&u132->sw_lock);
                 return retval;
                 return retval;
         }
         }
 }
 }
@@ -3004,7 +3064,7 @@ static int __devexit u132_remove(struct platform_device *pdev)
                         dev_err(&u132->platform_dev->dev, "removing device u132"
                         dev_err(&u132->platform_dev->dev, "removing device u132"
 				".%d\n", u132->sequence_num);
 				".%d\n", u132->sequence_num);
                         msleep(100);
                         msleep(100);
-                        down(&u132->sw_lock);
+                        mutex_lock(&u132->sw_lock);
                         u132_monitor_cancel_work(u132);
                         u132_monitor_cancel_work(u132);
                         while (rings-- > 0) {
                         while (rings-- > 0) {
                                 struct u132_ring *ring = &u132->ring[rings];
                                 struct u132_ring *ring = &u132->ring[rings];
@@ -3017,7 +3077,7 @@ static int __devexit u132_remove(struct platform_device *pdev)
                         u132->going += 1;
                         u132->going += 1;
                         printk(KERN_INFO "removing device u132.%d\n",
                         printk(KERN_INFO "removing device u132.%d\n",
                                 u132->sequence_num);
                                 u132->sequence_num);
-                        up(&u132->sw_lock);
+                        mutex_unlock(&u132->sw_lock);
                         usb_remove_hcd(hcd);
                         usb_remove_hcd(hcd);
                         u132_u132_put_kref(u132);
                         u132_u132_put_kref(u132);
                         return 0;
                         return 0;
@@ -3037,7 +3097,7 @@ static void u132_initialise(struct u132 *u132, struct platform_device *pdev)
         u132->platform_dev = pdev;
         u132->platform_dev = pdev;
         u132->power = 0;
         u132->power = 0;
         u132->reset = 0;
         u132->reset = 0;
-        init_MUTEX(&u132->sw_lock);
+        mutex_init(&u132->sw_lock);
         init_MUTEX(&u132->scheduler_lock);
         init_MUTEX(&u132->scheduler_lock);
         while (rings-- > 0) {
         while (rings-- > 0) {
                 struct u132_ring *ring = &u132->ring[rings];
                 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;
                 ring->curr_endp = NULL;
                 INIT_DELAYED_WORK(&ring->scheduler,
                 INIT_DELAYED_WORK(&ring->scheduler,
 				  u132_hcd_ring_work_scheduler);
 				  u132_hcd_ring_work_scheduler);
-        } down(&u132->sw_lock);
+        } mutex_lock(&u132->sw_lock);
         INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work);
         INIT_DELAYED_WORK(&u132->monitor, u132_hcd_monitor_work);
         while (ports-- > 0) {
         while (ports-- > 0) {
                 struct u132_port *port = &u132->port[ports];
                 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) {
         while (endps-- > 0) {
                 u132->endp[endps] = NULL;
                 u132->endp[endps] = NULL;
         }
         }
-        up(&u132->sw_lock);
+        mutex_unlock(&u132->sw_lock);
         return;
         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, "%s%s", ptype, (urbp->fsbr ? " FSBR" : ""));
 	out += sprintf(out, " Actlen=%d", urbp->urb->actual_length);
 	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");
 	out += sprintf(out, "\n");
 
 
 	i = nactive = ninactive = 0;
 	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 phase;			/* Between 0 and period-1 */
 	short load;			/* Periodic time requirement, in us */
 	short load;			/* Periodic time requirement, in us */
 	unsigned int iso_frame;		/* Frame # for iso_packet_desc */
 	unsigned int iso_frame;		/* Frame # for iso_packet_desc */
-	int iso_status;			/* Status for Isochronous URBs */
 
 
 	int state;			/* QH_STATE_xxx; see above */
 	int state;			/* QH_STATE_xxx; see above */
 	int type;			/* Queue type (control, bulk, etc) */
 	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 */
 /* Some special IDs */
 
 
 #define PCI_VENDOR_ID_GENESYS		0x17a0
 #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);
 		uhci_free_td(uhci, td);
 	}
 	}
 
 
-	urbp->urb->hcpriv = NULL;
 	kmem_cache_free(uhci_up_cachep, urbp);
 	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)) {
 	if (list_empty(&qh->queue)) {
 		qh->iso_packet_desc = &urb->iso_frame_desc[0];
 		qh->iso_packet_desc = &urb->iso_frame_desc[0];
 		qh->iso_frame = urb->start_frame;
 		qh->iso_frame = urb->start_frame;
-		qh->iso_status = 0;
 	}
 	}
 
 
 	qh->skel = SKEL_ISO;
 	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->actual_length = actlength;
 			qh->iso_packet_desc->status = status;
 			qh->iso_packet_desc->status = status;
 		}
 		}
-
-		if (status) {
+		if (status)
 			urb->error_count++;
 			urb->error_count++;
-			qh->iso_status = status;
-		}
 
 
 		uhci_remove_td_from_urbp(td);
 		uhci_remove_td_from_urbp(td);
 		uhci_free_td(uhci, td);
 		uhci_free_td(uhci, td);
 		qh->iso_frame += qh->period;
 		qh->iso_frame += qh->period;
 		++qh->iso_packet_desc;
 		++qh->iso_packet_desc;
 	}
 	}
-	return qh->iso_status;
+	return 0;
 }
 }
 
 
 static int uhci_urb_enqueue(struct usb_hcd *hcd,
 static int uhci_urb_enqueue(struct usb_hcd *hcd,
-		struct usb_host_endpoint *hep,
 		struct urb *urb, gfp_t mem_flags)
 		struct urb *urb, gfp_t mem_flags)
 {
 {
 	int ret;
 	int ret;
@@ -1387,19 +1381,19 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
 
 
 	spin_lock_irqsave(&uhci->lock, flags);
 	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;
 	ret = -ENOMEM;
 	urbp = uhci_alloc_urb_priv(uhci, urb);
 	urbp = uhci_alloc_urb_priv(uhci, urb);
 	if (!urbp)
 	if (!urbp)
 		goto done;
 		goto done;
 
 
-	if (hep->hcpriv)
-		qh = (struct uhci_qh *) hep->hcpriv;
+	if (urb->ep->hcpriv)
+		qh = urb->ep->hcpriv;
 	else {
 	else {
-		qh = uhci_alloc_qh(uhci, urb->dev, hep);
+		qh = uhci_alloc_qh(uhci, urb->dev, urb->ep);
 		if (!qh)
 		if (!qh)
 			goto err_no_qh;
 			goto err_no_qh;
 	}
 	}
@@ -1440,27 +1434,29 @@ static int uhci_urb_enqueue(struct usb_hcd *hcd,
 err_submit_failed:
 err_submit_failed:
 	if (qh->state == QH_STATE_IDLE)
 	if (qh->state == QH_STATE_IDLE)
 		uhci_make_qh_idle(uhci, qh);	/* Reclaim unused QH */
 		uhci_make_qh_idle(uhci, qh);	/* Reclaim unused QH */
-
 err_no_qh:
 err_no_qh:
 	uhci_free_urb_priv(uhci, urbp);
 	uhci_free_urb_priv(uhci, urbp);
-
 done:
 done:
+	if (ret)
+		usb_hcd_unlink_urb_from_ep(hcd, urb);
+done_not_linked:
 	spin_unlock_irqrestore(&uhci->lock, flags);
 	spin_unlock_irqrestore(&uhci->lock, flags);
 	return ret;
 	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);
 	struct uhci_hcd *uhci = hcd_to_uhci(hcd);
 	unsigned long flags;
 	unsigned long flags;
-	struct urb_priv *urbp;
 	struct uhci_qh *qh;
 	struct uhci_qh *qh;
+	int rc;
 
 
 	spin_lock_irqsave(&uhci->lock, flags);
 	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;
 		goto done;
-	qh = urbp->qh;
+
+	qh = ((struct urb_priv *) urb->hcpriv)->qh;
 
 
 	/* Remove Isochronous TDs from the frame list ASAP */
 	/* Remove Isochronous TDs from the frame list ASAP */
 	if (qh->type == USB_ENDPOINT_XFER_ISOC) {
 	if (qh->type == USB_ENDPOINT_XFER_ISOC) {
@@ -1477,14 +1473,14 @@ static int uhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
 
 
 done:
 done:
 	spin_unlock_irqrestore(&uhci->lock, flags);
 	spin_unlock_irqrestore(&uhci->lock, flags);
-	return 0;
+	return rc;
 }
 }
 
 
 /*
 /*
  * Finish unlinking an URB and give it back
  * Finish unlinking an URB and give it back
  */
  */
 static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh,
 static void uhci_giveback_urb(struct uhci_hcd *uhci, struct uhci_qh *qh,
-		struct urb *urb)
+		struct urb *urb, int status)
 __releases(uhci->lock)
 __releases(uhci->lock)
 __acquires(uhci->lock)
 __acquires(uhci->lock)
 {
 {
@@ -1497,13 +1493,6 @@ __acquires(uhci->lock)
 		 * unlinked first.  Regardless, don't confuse people with a
 		 * unlinked first.  Regardless, don't confuse people with a
 		 * negative length. */
 		 * negative length. */
 		urb->actual_length = max(urb->actual_length, 0);
 		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,
 	/* 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_packet_desc = &nurb->iso_frame_desc[0];
 		qh->iso_frame = nurb->start_frame;
 		qh->iso_frame = nurb->start_frame;
-		qh->iso_status = 0;
 	}
 	}
 
 
 	/* Take the URB off the QH's queue.  If the queue is now empty,
 	/* 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);
 	uhci_free_urb_priv(uhci, urbp);
+	usb_hcd_unlink_urb_from_ep(uhci_to_hcd(uhci), urb);
 
 
 	spin_unlock(&uhci->lock);
 	spin_unlock(&uhci->lock);
-	usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb);
+	usb_hcd_giveback_urb(uhci_to_hcd(uhci), urb, status);
 	spin_lock(&uhci->lock);
 	spin_lock(&uhci->lock);
 
 
 	/* If the queue is now empty, we can unlink the QH and give up its
 	/* 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)
 		if (status == -EINPROGRESS)
 			break;
 			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
 		/* Dequeued but completed URBs can't be given back unless
 		 * the QH is stopped or has finished unlinking. */
 		 * the QH is stopped or has finished unlinking. */
-		if (status == ECONNRESET) {
+		if (urb->unlinked) {
 			if (QH_FINISHED_UNLINKING(qh))
 			if (QH_FINISHED_UNLINKING(qh))
 				qh->is_stopped = 1;
 				qh->is_stopped = 1;
 			else if (!qh->is_stopped)
 			else if (!qh->is_stopped)
 				return;
 				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;
 			break;
 	}
 	}
 
 
@@ -1599,7 +1581,7 @@ static void uhci_scan_qh(struct uhci_hcd *uhci, struct uhci_qh *qh)
 restart:
 restart:
 	list_for_each_entry(urbp, &qh->queue, node) {
 	list_for_each_entry(urbp, &qh->queue, node) {
 		urb = urbp->urb;
 		urb = urbp->urb;
-		if (urb->status != -EINPROGRESS) {
+		if (urb->unlinked) {
 
 
 			/* Fix up the TD links and save the toggles for
 			/* Fix up the TD links and save the toggles for
 			 * non-Isochronous queues.  For Isochronous queues,
 			 * non-Isochronous queues.  For Isochronous queues,
@@ -1608,7 +1590,7 @@ restart:
 				qh->is_stopped = 0;
 				qh->is_stopped = 0;
 				return;
 				return;
 			}
 			}
-			uhci_giveback_urb(uhci, qh, urb);
+			uhci_giveback_urb(uhci, qh, urb, 0);
 			goto restart;
 			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);
 	spin_lock(&dev->buflock);
 
 
 	if (status != 0) {
 	if (status != 0) {
-		if ((status != -ENOENT) && (status != -ECONNRESET)) {
+		if ((status != -ENOENT) && (status != -ECONNRESET) &&
+			(status != -ESHUTDOWN)) {
 			dbg(1," %s : nonzero status received: %d",
 			dbg(1," %s : nonzero status received: %d",
 			    __FUNCTION__, status);
 			    __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) {
 	if (retval != 2) {
 		dev_err(&udev->dev, "First magic command failed: %d.\n",
 		dev_err(&udev->dev, "First magic command failed: %d.\n",
 			retval);
 			retval);
-		return retval;
+		goto exit;
 	}
 	}
 
 
 	dbg(&udev->dev, "Sending second magic command\n");
 	dbg(&udev->dev, "Sending second magic command\n");
@@ -80,7 +80,7 @@ static int magic_charge(struct usb_device *udev)
 	if (retval != 0) {
 	if (retval != 0) {
 		dev_err(&udev->dev, "Second magic command failed: %d.\n",
 		dev_err(&udev->dev, "Second magic command failed: %d.\n",
 			retval);
 			retval);
-		return retval;
+		goto exit;
 	}
 	}
 
 
 	dbg(&udev->dev, "Calling set_configuration\n");
 	dbg(&udev->dev, "Calling set_configuration\n");
@@ -88,6 +88,8 @@ static int magic_charge(struct usb_device *udev)
 	if (retval)
 	if (retval)
 		dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
 		dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
 
 
+exit:
+	kfree(dummy_buffer);
 	return retval;
 	return retval;
 }
 }
 
 
@@ -112,6 +114,7 @@ static int magic_dual_mode(struct usb_device *udev)
 	if (retval)
 	if (retval)
 		dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
 		dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
 
 
+	kfree(dummy_buffer);
 	return retval;
 	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;
         size_t buffer_size;
         int i;
         int i;
         int retval = -ENOMEM;
         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");
                 printk(KERN_ERR "Out of memory\n");
                 return -ENOMEM;
                 return -ENOMEM;
         }
         }
-        memset(ftdi, 0x00, sizeof(struct usb_ftdi));
+
         mutex_lock(&ftdi_module_lock);
         mutex_lock(&ftdi_module_lock);
         list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
         list_add_tail(&ftdi->ftdi_list, &ftdi_static_list);
         ftdi->sequence_num = ++ftdi_instances;
         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
  * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * * 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.address = 0x00000194;
 			   packet.data    = addr;
 			   packet.data    = addr;
 			   ret = sisusb_send_bridge_packet(sisusb, 10,
 			   ret = sisusb_send_bridge_packet(sisusb, 10,
-			   					&packet, 0);
+								&packet, 0);
 			   packet.header  = 0x001f;
 			   packet.header  = 0x001f;
 			   packet.address = 0x00000190;
 			   packet.address = 0x00000190;
 			   packet.data    = (length & ~3);
 			   packet.data    = (length & ~3);
 			   ret |= sisusb_send_bridge_packet(sisusb, 10,
 			   ret |= sisusb_send_bridge_packet(sisusb, 10,
-			   					&packet, 0);
+								&packet, 0);
 			   if (sisusb->flagb0 != 0x16) {
 			   if (sisusb->flagb0 != 0x16) {
 				packet.header  = 0x001f;
 				packet.header  = 0x001f;
 				packet.address = 0x00000180;
 				packet.address = 0x00000180;
@@ -1003,23 +1003,17 @@ static int sisusb_write_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
 			if (ret) {
 			if (ret) {
 				msgcount++;
 				msgcount++;
 				if (msgcount < 500)
 				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)
 				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);
 			addr += (*bytes_written);
 			length -= (*bytes_written);
 			length -= (*bytes_written);
 	    }
 	    }
 
 
 	    if (ret)
 	    if (ret)
-	    	break;
+		break;
 
 
 	}
 	}
 
 
@@ -1261,51 +1255,10 @@ static int sisusb_read_mem_bulk(struct sisusb_usb_data *sisusb, u32 addr,
 				addr += 4;
 				addr += 4;
 				length -= 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)
 	    if (ret)
-	    	break;
+		break;
 	}
 	}
 
 
 	return ret;
 	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));
 	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
 int
 sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
 sisusb_copy_memory(struct sisusb_usb_data *sisusb, char *src,
 			u32 dest, int length, size_t *bytes_written)
 			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);
     sisusb_copy_memory(sisusb, srcbuffer, sisusb->vrambase, 7, &dummy);
 
 
     for(i = 1; i <= 7; i++) {
     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);
 	sisusb_read_memory(sisusb, destbuffer, sisusb->vrambase, i, &dummy);
 	for(j = 0; j < i; j++) {
 	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 SETIREGAND(r,i,a)	sisusb_setidxregand(sisusb, r, i, a)
 #define SETIREGANDOR(r,i,a,o)	sisusb_setidxregandor(sisusb, r, i, a, o)
 #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 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 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
 static int
 sisusb_triggersr16(struct sisusb_usb_data *sisusb, u8 ramtype)
 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(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;
 	return ret;
 }
 }
@@ -2168,17 +2105,12 @@ sisusb_init_gfxcore(struct sisusb_usb_data *sisusb)
 		if (ramtype <= 1) {
 		if (ramtype <= 1) {
 			ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
 			ret |= sisusb_get_sdram_size(sisusb, &iret, bw, chab);
 			if (iret) {
 			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);
 				ret |= SETIREG(SISSR,0x14,0x31);
 				/* TODO */
 				/* TODO */
 			}
 			}
 		} else {
 		} 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);
 			ret |= SETIREG(SISSR,0x14,0x31);
 			/* *** TODO *** */
 			/* *** TODO *** */
 		}
 		}
@@ -2249,8 +2181,7 @@ sisusb_get_ramconfig(struct sisusb_usb_data *sisusb)
 		break;
 		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);
 			ramtypetext2[ramtype], bw);
 }
 }
 
 
@@ -2509,11 +2440,8 @@ sisusb_open(struct inode *inode, struct file *file)
 	struct usb_interface *interface;
 	struct usb_interface *interface;
 	int subminor = iminor(inode);
 	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;
 		return -ENODEV;
-	}
 
 
 	if (!(sisusb = usb_get_intfdata(interface)))
 	if (!(sisusb = usb_get_intfdata(interface)))
 		return -ENODEV;
 		return -ENODEV;
@@ -2534,18 +2462,12 @@ sisusb_open(struct inode *inode, struct file *file)
 		if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
 		if (sisusb->sisusb_dev->speed == USB_SPEED_HIGH) {
 			if (sisusb_init_gfxdevice(sisusb, 0)) {
 			if (sisusb_init_gfxdevice(sisusb, 0)) {
 				mutex_unlock(&sisusb->lock);
 				mutex_unlock(&sisusb->lock);
-				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;
 				return -EIO;
 			}
 			}
 		} else {
 		} else {
 			mutex_unlock(&sisusb->lock);
 			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;
 			return -EIO;
 		}
 		}
 	}
 	}
@@ -2586,7 +2508,6 @@ static int
 sisusb_release(struct inode *inode, struct file *file)
 sisusb_release(struct inode *inode, struct file *file)
 {
 {
 	struct sisusb_usb_data *sisusb;
 	struct sisusb_usb_data *sisusb;
-	int myminor;
 
 
 	if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
 	if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
 		return -ENODEV;
 		return -ENODEV;
@@ -2599,8 +2520,6 @@ sisusb_release(struct inode *inode, struct file *file)
 			sisusb_kill_all_busy(sisusb);
 			sisusb_kill_all_busy(sisusb);
 	}
 	}
 
 
-	myminor = sisusb->minor;
-
 	sisusb->isopen = 0;
 	sisusb->isopen = 0;
 	file->private_data = NULL;
 	file->private_data = NULL;
 
 
@@ -2942,7 +2861,7 @@ static int
 sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
 sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
 							unsigned long arg)
 							unsigned long arg)
 {
 {
-	int 	retval, port, length;
+	int	retval, port, length;
 	u32	address;
 	u32	address;
 
 
 	/* All our commands require the device
 	/* All our commands require the device
@@ -3065,12 +2984,12 @@ sisusb_handle_command(struct sisusb_usb_data *sisusb, struct sisusb_command *y,
 
 
 static int
 static int
 sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 sisusb_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
-	     						unsigned long arg)
+							unsigned long arg)
 {
 {
 	struct sisusb_usb_data *sisusb;
 	struct sisusb_usb_data *sisusb;
 	struct sisusb_info x;
 	struct sisusb_info x;
 	struct sisusb_command y;
 	struct sisusb_command y;
-	int 	retval = 0;
+	int	retval = 0;
 	u32 __user *argp = (u32 __user *)arg;
 	u32 __user *argp = (u32 __user *)arg;
 
 
 	if (!(sisusb = (struct sisusb_usb_data *)file->private_data))
 	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:
 		case SISUSB_GET_CONFIG:
 
 
-			x.sisusb_id   	    = SISUSB_ID;
+			x.sisusb_id	    = SISUSB_ID;
 			x.sisusb_version    = SISUSB_VERSION;
 			x.sisusb_version    = SISUSB_VERSION;
 			x.sisusb_revision   = SISUSB_REVISION;
 			x.sisusb_revision   = SISUSB_REVISION;
 			x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
 			x.sisusb_patchlevel = SISUSB_PATCHLEVEL;
@@ -3164,7 +3083,7 @@ static const struct file_operations usb_sisusb_fops = {
 	.release =	sisusb_release,
 	.release =	sisusb_release,
 	.read =		sisusb_read,
 	.read =		sisusb_read,
 	.write =	sisusb_write,
 	.write =	sisusb_write,
-	.llseek = 	sisusb_lseek,
+	.llseek =	sisusb_lseek,
 #ifdef SISUSB_NEW_CONFIG_COMPAT
 #ifdef SISUSB_NEW_CONFIG_COMPAT
 	.compat_ioctl = sisusb_compat_ioctl,
 	.compat_ioctl = sisusb_compat_ioctl,
 #endif
 #endif
@@ -3183,17 +3102,13 @@ static int sisusb_probe(struct usb_interface *intf,
 	struct usb_device *dev = interface_to_usbdev(intf);
 	struct usb_device *dev = interface_to_usbdev(intf);
 	struct sisusb_usb_data *sisusb;
 	struct sisusb_usb_data *sisusb;
 	int retval = 0, i;
 	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);
 		dev->devnum);
 
 
 	/* Allocate memory for our private */
 	/* Allocate memory for our private */
 	if (!(sisusb = kzalloc(sizeof(*sisusb), GFP_KERNEL))) {
 	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;
 		return -ENOMEM;
 	}
 	}
 	kref_init(&sisusb->kref);
 	kref_init(&sisusb->kref);
@@ -3202,8 +3117,7 @@ static int sisusb_probe(struct usb_interface *intf,
 
 
 	/* Register device */
 	/* Register device */
 	if ((retval = usb_register_dev(intf, &usb_sisusb_class))) {
 	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);
 			dev->devnum);
 		retval = -ENODEV;
 		retval = -ENODEV;
 		goto error_1;
 		goto error_1;
@@ -3221,7 +3135,7 @@ static int sisusb_probe(struct usb_interface *intf,
 	sisusb->ibufsize = SISUSB_IBUF_SIZE;
 	sisusb->ibufsize = SISUSB_IBUF_SIZE;
 	if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
 	if (!(sisusb->ibuf = usb_buffer_alloc(dev, SISUSB_IBUF_SIZE,
 					GFP_KERNEL, &sisusb->transfer_dma_in))) {
 					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;
 		retval = -ENOMEM;
 		goto error_2;
 		goto error_2;
 	}
 	}
@@ -3233,7 +3147,7 @@ static int sisusb_probe(struct usb_interface *intf,
 					GFP_KERNEL,
 					GFP_KERNEL,
 					&sisusb->transfer_dma_out[i]))) {
 					&sisusb->transfer_dma_out[i]))) {
 			if (i == 0) {
 			if (i == 0) {
-				printk(memfail, "output", sisusb->minor);
+				dev_err(&sisusb->sisusb_dev->dev, "Failed to allocate memory for output buffer\n");
 				retval = -ENOMEM;
 				retval = -ENOMEM;
 				goto error_3;
 				goto error_3;
 			}
 			}
@@ -3245,9 +3159,7 @@ static int sisusb_probe(struct usb_interface *intf,
 
 
 	/* Allocate URBs */
 	/* Allocate URBs */
 	if (!(sisusb->sisurbin = usb_alloc_urb(0, GFP_KERNEL))) {
 	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;
 		retval = -ENOMEM;
 		goto error_3;
 		goto error_3;
 	}
 	}
@@ -3255,9 +3167,7 @@ static int sisusb_probe(struct usb_interface *intf,
 
 
 	for (i = 0; i < sisusb->numobufs; i++) {
 	for (i = 0; i < sisusb->numobufs; i++) {
 		if (!(sisusb->sisurbout[i] = usb_alloc_urb(0, GFP_KERNEL))) {
 		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;
 			retval = -ENOMEM;
 			goto error_4;
 			goto error_4;
 		}
 		}
@@ -3266,15 +3176,12 @@ static int sisusb_probe(struct usb_interface *intf,
 		sisusb->urbstatus[i] = 0;
 		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
 #ifdef INCL_SISUSB_CON
 	/* Allocate our SiS_Pr */
 	/* Allocate our SiS_Pr */
 	if (!(sisusb->SiS_Pr = kmalloc(sizeof(struct SiS_Private), GFP_KERNEL))) {
 	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
 #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_GET_CONFIG,      NULL);
 	ret |= register_ioctl32_conversion(SISUSB_COMMAND,         NULL);
 	ret |= register_ioctl32_conversion(SISUSB_COMMAND,         NULL);
 	if (ret)
 	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
 	else
 		sisusb->ioctl32registered = 1;
 		sisusb->ioctl32registered = 1;
 	}
 	}
@@ -3315,23 +3219,17 @@ static int sisusb_probe(struct usb_interface *intf,
 			initscreen = 0;
 			initscreen = 0;
 #endif
 #endif
 		if (sisusb_init_gfxdevice(sisusb, initscreen))
 		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
 	} 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;
 	sisusb->ready = 1;
 
 
 #ifdef SISUSBENDIANTEST
 #ifdef SISUSBENDIANTEST
-	printk(KERN_DEBUG "sisusb: *** RWTEST ***\n");
+	dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST ***\n");
 	sisusb_testreadwrite(sisusb);
 	sisusb_testreadwrite(sisusb);
-	printk(KERN_DEBUG "sisusb: *** RWTEST END ***\n");
+	dev_dbg(&sisusb->sisusb_dev->dev, "*** RWTEST END ***\n");
 #endif
 #endif
 
 
 #ifdef INCL_SISUSB_CON
 #ifdef INCL_SISUSB_CON
@@ -3354,7 +3252,6 @@ error_1:
 static void sisusb_disconnect(struct usb_interface *intf)
 static void sisusb_disconnect(struct usb_interface *intf)
 {
 {
 	struct sisusb_usb_data *sisusb;
 	struct sisusb_usb_data *sisusb;
-	int minor;
 
 
 	/* This should *not* happen */
 	/* This should *not* happen */
 	if (!(sisusb = usb_get_intfdata(intf)))
 	if (!(sisusb = usb_get_intfdata(intf)))
@@ -3364,8 +3261,6 @@ static void sisusb_disconnect(struct usb_interface *intf)
 	sisusb_console_exit(sisusb);
 	sisusb_console_exit(sisusb);
 #endif
 #endif
 
 
-	minor = sisusb->minor;
-
 	usb_deregister_dev(intf, &usb_sisusb_class);
 	usb_deregister_dev(intf, &usb_sisusb_class);
 
 
 	mutex_lock(&sisusb->lock);
 	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_GET_CONFIG);
 		ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
 		ret |= unregister_ioctl32_conversion(SISUSB_COMMAND);
 		if (ret) {
 		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
 #endif
@@ -3400,7 +3292,7 @@ static void sisusb_disconnect(struct usb_interface *intf)
 	/* decrement our usage count */
 	/* decrement our usage count */
 	kref_put(&sisusb->kref, sisusb_delete);
 	kref_put(&sisusb->kref, sisusb_delete);
 
 
-	printk(KERN_INFO "sisusbvga[%d]: Disconnected\n", minor);
+	dev_info(&sisusb->sisusb_dev->dev, "Disconnected\n");
 }
 }
 
 
 static struct usb_device_id sisusb_table [] = {
 static struct usb_device_id sisusb_table [] = {
@@ -3424,22 +3316,12 @@ static struct usb_driver sisusb_driver = {
 
 
 static int __init usb_sisusb_init(void)
 static int __init usb_sisusb_init(void)
 {
 {
-	int retval;
 
 
 #ifdef INCL_SISUSB_CON
 #ifdef INCL_SISUSB_CON
 	sisusb_init_concode();
 	sisusb_init_concode();
 #endif
 #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)
 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:
  * 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>
 #include <linux/mutex.h>
 
 
 /* For older kernels, support for text consoles is by default
 /* 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 */
 /* Version Information */
 
 
 #define SISUSB_VERSION		0
 #define SISUSB_VERSION		0
-#define SISUSB_REVISION 	0
+#define SISUSB_REVISION		0
 #define SISUSB_PATCHLEVEL	8
 #define SISUSB_PATCHLEVEL	8
 
 
 /* Include console and mode switching code? */
 /* Include console and mode switching code? */
@@ -74,7 +72,7 @@
 #define SISUSB_IBUF_SIZE  0x01000
 #define SISUSB_IBUF_SIZE  0x01000
 #define SISUSB_OBUF_SIZE  0x10000	/* fixed */
 #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:
 /* About endianness:
  *
  *
@@ -93,7 +91,7 @@
  */
  */
 
 
 #ifdef __BIG_ENDIAN
 #ifdef __BIG_ENDIAN
-#define SISUSB_CORRECT_ENDIANNESS_PACKET(p) 		\
+#define SISUSB_CORRECT_ENDIANNESS_PACKET(p)		\
 	do {						\
 	do {						\
 		p->header  = cpu_to_le16(p->header);	\
 		p->header  = cpu_to_le16(p->header);	\
 		p->address = cpu_to_le32(p->address);	\
 		p->address = cpu_to_le32(p->address);	\
@@ -105,7 +103,7 @@
 
 
 struct sisusb_usb_data;
 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;
 	struct sisusb_usb_data *sisusb;
 	int urbindex;
 	int urbindex;
 	int *actual_length;
 	int *actual_length;
@@ -116,16 +114,16 @@ struct sisusb_usb_data {
 	struct usb_interface *interface;
 	struct usb_interface *interface;
 	struct kref kref;
 	struct kref kref;
 	wait_queue_head_t wait_q;	/* for syncind and timeouts */
 	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
 #ifdef SISUSB_OLD_CONFIG_COMPAT
 	int ioctl32registered;
 	int ioctl32registered;
 #endif
 #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 */
 	char *obuf[NUMOBUFS], *ibuf;	/* transfer buffers */
 	int obufsize, ibufsize;
 	int obufsize, ibufsize;
 	dma_addr_t transfer_dma_out[NUMOBUFS];
 	dma_addr_t transfer_dma_out[NUMOBUFS];
@@ -136,13 +134,13 @@ struct sisusb_usb_data {
 	unsigned char completein;
 	unsigned char completein;
 	struct sisusb_urb_context urbout_context[NUMOBUFS];
 	struct sisusb_urb_context urbout_context[NUMOBUFS];
 	unsigned long flagb0;
 	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 long mmiobase;
 	unsigned int mmiosize;
 	unsigned int mmiosize;
 	unsigned long ioportbase;
 	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 chipid, chipvendor;
 	unsigned short chiprevision;
 	unsigned short chiprevision;
 #ifdef INCL_SISUSB_CON
 #ifdef INCL_SISUSB_CON
@@ -152,7 +150,7 @@ struct sisusb_usb_data {
 	int haveconsole, con_first, con_last;
 	int haveconsole, con_first, con_last;
 	int havethisconsole[MAX_NR_CONSOLES];
 	int havethisconsole[MAX_NR_CONSOLES];
 	int textmodedestroyed;
 	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 cur_start_addr, con_rolled_over;
 	int sisusb_cursor_loc, bad_cursor_pos;
 	int sisusb_cursor_loc, bad_cursor_pos;
 	int sisusb_cursor_size_from;
 	int sisusb_cursor_size_from;
@@ -197,7 +195,7 @@ struct sisusb_packet {
 	unsigned short header;
 	unsigned short header;
 	u32 address;
 	u32 address;
 	u32 data;
 	u32 data;
-} __attribute__((__packed__));
+} __attribute__ ((__packed__));
 
 
 #define CLEARPACKET(packet) memset(packet, 0, 10)
 #define CLEARPACKET(packet) memset(packet, 0, 10)
 
 
@@ -265,36 +263,36 @@ struct sisusb_packet {
 
 
 /* Structure argument for SISUSB_GET_INFO ioctl  */
 /* Structure argument for SISUSB_GET_INFO ioctl  */
 struct sisusb_info {
 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 {
 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 */
 #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_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_SETMODE	0x09	/* Set a display mode (data3 = SiS mode) */
 #define SUCMD_SETVESAMODE 0x0a	/* Set a display mode (data3 = VESA 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_SIZE	_IOR(0xF3,0x3E,__u32)
 #define SISUSB_GET_CONFIG	_IOR(0xF3,0x3F,struct sisusb_info)
 #define SISUSB_GET_CONFIG	_IOR(0xF3,0x3F,struct sisusb_info)
 
 
-
 #endif /* SISUSB_H */
 #endif /* SISUSB_H */
-

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

@@ -52,6 +52,7 @@
 #include <linux/kernel.h>
 #include <linux/kernel.h>
 #include <linux/signal.h>
 #include <linux/signal.h>
 #include <linux/fs.h>
 #include <linux/fs.h>
+#include <linux/usb.h>
 #include <linux/tty.h>
 #include <linux/tty.h>
 #include <linux/console.h>
 #include <linux/console.h>
 #include <linux/string.h>
 #include <linux/string.h>
@@ -373,14 +374,6 @@ sisusbcon_putc(struct vc_data *c, int ch, int y, int x)
 		return;
 		return;
 
 
 	/* sisusb->lock is down */
 	/* 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)) {
 	if (sisusb_is_inactive(c, sisusb)) {
 		mutex_unlock(&sisusb->lock);
 		mutex_unlock(&sisusb->lock);
 		return;
 		return;
@@ -490,10 +483,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx,
 	struct sisusb_usb_data *sisusb;
 	struct sisusb_usb_data *sisusb;
 	ssize_t written;
 	ssize_t written;
 	int cols, length;
 	int cols, length;
-#if 0
-	u16 *src, *dest;
-	int i;
-#endif
 
 
 	if (width <= 0 || height <= 0)
 	if (width <= 0 || height <= 0)
 		return;
 		return;
@@ -505,41 +494,6 @@ sisusbcon_bmove(struct vc_data *c, int sy, int sx,
 
 
 	cols = sisusb->sisusb_num_columns;
 	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)) {
 	if (sisusb_is_inactive(c, sisusb)) {
 		mutex_unlock(&sisusb->lock);
 		mutex_unlock(&sisusb->lock);
 		return;
 		return;
@@ -584,7 +538,7 @@ sisusbcon_switch(struct vc_data *c)
 	 */
 	 */
 	if (c->vc_origin == (unsigned long)c->vc_screenbuf) {
 	if (c->vc_origin == (unsigned long)c->vc_screenbuf) {
 		mutex_unlock(&sisusb->lock);
 		mutex_unlock(&sisusb->lock);
-		printk(KERN_DEBUG "sisusb: ASSERT ORIGIN != SCREENBUF!\n");
+		dev_dbg(&sisusb->sisusb_dev->dev, "ASSERT ORIGIN != SCREENBUF!\n");
 		return 0;
 		return 0;
 	}
 	}
 
 
@@ -1475,7 +1429,7 @@ static const struct consw sisusb_dummy_con = {
 int
 int
 sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
 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);
 	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) */
 	/* Set up text mode (and upload  default font) */
 	if (sisusb_reset_text_mode(sisusb, 1)) {
 	if (sisusb_reset_text_mode(sisusb, 1)) {
 		mutex_unlock(&sisusb->lock);
 		mutex_unlock(&sisusb->lock);
-		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;
 		return 1;
 	}
 	}
 
 
@@ -1531,9 +1483,7 @@ sisusb_console_init(struct sisusb_usb_data *sisusb, int first, int last)
 	/* Allocate screen buffer */
 	/* Allocate screen buffer */
 	if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
 	if (!(sisusb->scrbuf = (unsigned long)vmalloc(sisusb->scrbuf_size))) {
 		mutex_unlock(&sisusb->lock);
 		mutex_unlock(&sisusb->lock);
-		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;
 		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
  * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * * 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            */
 /*         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           */
 /*          HELPER: SetReg, GetReg           */
@@ -165,21 +74,20 @@ SiSUSB_GetModeID(int HDisplay, int VDisplay, int Depth)
 
 
 static void
 static void
 SiS_SetReg(struct SiS_Private *SiS_Pr, unsigned long port,
 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);
 	sisusb_setidxreg(SiS_Pr->sisusb, port, index, data);
 }
 }
 
 
 static void
 static void
 SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port,
 SiS_SetRegByte(struct SiS_Private *SiS_Pr, unsigned long port,
-						unsigned short data)
+	       unsigned short data)
 {
 {
 	sisusb_setreg(SiS_Pr->sisusb, port, data);
 	sisusb_setreg(SiS_Pr->sisusb, port, data);
 }
 }
 
 
 static unsigned char
 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;
 	u8 data;
 
 
@@ -200,22 +108,22 @@ SiS_GetRegByte(struct SiS_Private *SiS_Pr, unsigned long port)
 
 
 static void
 static void
 SiS_SetRegANDOR(struct SiS_Private *SiS_Pr, unsigned long port,
 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);
 	sisusb_setidxregandor(SiS_Pr->sisusb, port, index, DataAND, DataOR);
 }
 }
 
 
 static void
 static void
 SiS_SetRegAND(struct SiS_Private *SiS_Pr, unsigned long port,
 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);
 	sisusb_setidxregand(SiS_Pr->sisusb, port, index, DataAND);
 }
 }
 
 
 static void
 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);
 	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        */
 /*      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);
 	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        */
 /*        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_P3c4 = BaseAddr + 0x14;
 	SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
 	SiS_Pr->SiS_P3d4 = BaseAddr + 0x24;
@@ -258,8 +164,7 @@ SiSUSBRegInit(struct SiS_Private *SiS_Pr, unsigned long BaseAddr)
 /*             HELPER: GetSysFlags           */
 /*             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;
 	SiS_Pr->SiS_MyCR63 = 0x63;
 }
 }
@@ -268,8 +173,7 @@ SiS_GetSysFlags(struct SiS_Private *SiS_Pr)
 /*         HELPER: Init PCI & Engines        */
 /*         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);
 	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x20, 0xa1);
 	/*  - Enable 2D (0x40)
 	/*  - Enable 2D (0x40)
@@ -285,8 +189,7 @@ SiSInitPCIetc(struct SiS_Private *SiS_Pr)
 /*        HELPER: SET SEGMENT REGISTERS      */
 /*        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;
 	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);
 	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;
 	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);
 	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_SetSegRegLower(SiS_Pr, value);
 	SiS_SetSegRegUpper(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);
 	SiS_SetSegmentReg(SiS_Pr, 0);
 }
 }
@@ -337,14 +237,12 @@ SiS_SetSegmentRegOver(struct SiS_Private *SiS_Pr, unsigned short value)
 	SiS_SetSegmentReg(SiS_Pr, 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);
 	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_ResetSegmentReg(SiS_Pr);
 	SiS_ResetSegmentRegOver(SiS_Pr);
 	SiS_ResetSegmentRegOver(SiS_Pr);
@@ -356,7 +254,7 @@ SiS_ResetSegmentRegisters(struct SiS_Private *SiS_Pr)
 
 
 static int
 static int
 SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
 SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
-						unsigned short *ModeIdIndex)
+		 unsigned short *ModeIdIndex)
 {
 {
 	if ((*ModeNo) <= 0x13) {
 	if ((*ModeNo) <= 0x13) {
 
 
@@ -367,12 +265,14 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
 
 
 	} else {
 	} 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;
 				break;
 
 
-			if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID == 0xFF)
+			if (SiS_Pr->SiS_EModeIDTable[*ModeIdIndex].Ext_ModeID ==
+			    0xFF)
 				return 0;
 				return 0;
 		}
 		}
 
 
@@ -385,8 +285,7 @@ SiS_SearchModeID(struct SiS_Private *SiS_Pr, unsigned short *ModeNo,
 /*            HELPER: ENABLE CRT1            */
 /*            HELPER: ENABLE CRT1            */
 /*********************************************/
 /*********************************************/
 
 
-static void
-SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
+static void SiS_HandleCRT1(struct SiS_Private *SiS_Pr)
 {
 {
 	/* Enable CRT1 gating */
 	/* Enable CRT1 gating */
 	SiS_SetRegAND(SiS_Pr, SiS_Pr->SiS_P3d4, SiS_Pr->SiS_MyCR63, 0xbf);
 	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
 static unsigned short
 SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 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;
 	unsigned short modeflag;
 	short index;
 	short index;
 
 
@@ -411,7 +310,8 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 	}
 	}
 
 
 	index = (modeflag & ModeTypeMask) - ModeEGA;
 	index = (modeflag & ModeTypeMask) - ModeEGA;
-	if (index < 0) index = 0;
+	if (index < 0)
+		index = 0;
 	return ColorDepth[index];
 	return ColorDepth[index];
 }
 }
 
 
@@ -421,7 +321,7 @@ SiS_GetColorDepth(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 
 static unsigned short
 static unsigned short
 SiS_GetOffset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 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;
 	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;
 	SRdata = SiS_Pr->SiS_StandTable[StandTableIndex].SR[0] | 0x20;
 	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x01, SRdata);
 	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);
 		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);
 	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];
 		CRTCdata = SiS_Pr->SiS_StandTable[StandTableIndex].CRTC[i];
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, i, CRTCdata);
 		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 char ARdata;
 	unsigned short i;
 	unsigned short i;
 
 
-	for(i = 0; i <= 0x13; i++) {
+	for (i = 0; i <= 0x13; i++) {
 		ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
 		ARdata = SiS_Pr->SiS_StandTable[StandTableIndex].ATTR[i];
 		SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
 		SiS_GetRegByte(SiS_Pr, SiS_Pr->SiS_P3da);
 		SiS_SetRegByte(SiS_Pr, SiS_Pr->SiS_P3c0, i);
 		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 char GRdata;
 	unsigned short i;
 	unsigned short i;
 
 
-	for(i = 0; i <= 0x08; i++) {
+	for (i = 0; i <= 0x08; i++) {
 		GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i];
 		GRdata = SiS_Pr->SiS_StandTable[StandTableIndex].GRC[i];
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3ce, i, GRdata);
 		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         */
 /*          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;
 	int i;
 
 
-	for(i = 0x0A; i <= 0x0E; i++) {
+	for (i = 0x0A; i <= 0x0E; i++) {
 		SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, i, 0x00);
 		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
 static unsigned short
 SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-					unsigned short ModeIdIndex)
+	       unsigned short ModeIdIndex)
 {
 {
 	unsigned short rrti, i, index, temp;
 	unsigned short rrti, i, index, temp;
 
 
 	if (ModeNo <= 0x13)
 	if (ModeNo <= 0x13)
 		return 0xFFFF;
 		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;
 	rrti = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].REFindex;
 	ModeNo = SiS_Pr->SiS_RefIndex[rrti].ModeID;
 	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)
 		if (SiS_Pr->SiS_RefIndex[rrti + i].ModeID != ModeNo)
 			break;
 			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)
 		if (temp < SiS_Pr->SiS_ModeType)
 			break;
 			break;
 
 
 		i++;
 		i++;
 		index--;
 		index--;
-	} while(index != 0xFFFF);
+	} while (index != 0xFFFF);
 
 
 	i--;
 	i--;
 
 
@@ -597,8 +498,7 @@ SiS_GetRatePtr(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 /*                  SYNC                     */
 /*                  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;
 	unsigned short sync = SiS_Pr->SiS_RefIndex[rrti].Ext_InfoFlag >> 8;
 	sync &= 0xC0;
 	sync &= 0xC0;
@@ -612,39 +512,40 @@ SiS_SetCRT1Sync(struct SiS_Private *SiS_Pr, unsigned short rrti)
 
 
 static void
 static void
 SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 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;
 	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;
 	modeflag = SiS_Pr->SiS_EModeIDTable[ModeIdIndex].Ext_ModeFlag;
 
 
 	index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRT1CRTC;
 	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_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_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_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_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;
 	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;
 	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);
 	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3d4, 0x09, 0x5F, temp);
 
 
 	if (SiS_Pr->SiS_ModeType > ModeVGA)
 	if (SiS_Pr->SiS_ModeType > ModeVGA)
@@ -659,10 +560,10 @@ SiS_SetCRT1CRTC(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 
 static void
 static void
 SiS_SetCRT1Offset(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 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 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;
 	unsigned short temp;
 
 
 	temp = (du >> 8) & 0x0f;
 	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));
 	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x13, (du & 0xFF));
 
 
-	if (infoflag & InterlaceMode) du >>= 1;
+	if (infoflag & InterlaceMode)
+		du >>= 1;
 
 
 	du <<= 5;
 	du <<= 5;
 	temp = (du >> 8) & 0xff;
 	temp = (du >> 8) & 0xff;
-	if (du & 0xff) temp++;
+	if (du & 0xff)
+		temp++;
 	temp++;
 	temp++;
 	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3c4, 0x10, 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
 static void
 SiS_SetCRT1VCLK(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 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 index = SiS_Pr->SiS_RefIndex[rrti].Ext_CRTVCLK;
 	unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B;
 	unsigned short clka = SiS_Pr->SiS_VCLKData[index].SR2B;
 	unsigned short clkb = SiS_Pr->SiS_VCLKData[index].SR2C;
 	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
 static void
 SiS_SetCRT1FIFO_310(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 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;
 	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
 static void
 SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-							unsigned short rrti)
+		 unsigned short rrti)
 {
 {
 	unsigned short data = 0, VCLK = 0, index = 0;
 	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;
 		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);
 	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x32, 0xf3, data);
 
 
 	if (VCLK >= 166)
 	if (VCLK >= 166)
@@ -758,7 +662,7 @@ SiS_SetVCLKState(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 
 
 static void
 static void
 SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 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;
 	unsigned short data, infoflag = 0, modeflag;
 
 
@@ -778,17 +682,22 @@ SiS_SetCRT1ModeRegs(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 			data |= 0x02;
 			data |= 0x02;
 			data |= ((SiS_Pr->SiS_ModeType - ModeVGA) << 2);
 			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);
 	SiS_SetRegANDOR(SiS_Pr, SiS_Pr->SiS_P3c4, 0x06, 0xC0, data);
 
 
 	data = 0;
 	data = 0;
 	if (infoflag & InterlaceMode) {
 	if (infoflag & InterlaceMode) {
 		/* data = (Hsync / 8) - ((Htotal / 8) / 2) + 3 */
 		/* 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;
 		data = hrs - (hto >> 1) + 3;
 	}
 	}
 	SiS_SetReg(SiS_Pr, SiS_Pr->SiS_P3d4, 0x19, (data & 0xFF));
 	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
 static void
 SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
 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;
 	unsigned short d1, d2, d3;
 
 
 	switch (dl) {
 	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, (d1 << shiftflag));
 	SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag));
 	SiS_SetRegByte(SiS_Pr, DACData, (d2 << shiftflag));
@@ -850,7 +765,8 @@ SiS_WriteDAC(struct SiS_Private *SiS_Pr, unsigned long DACData,
 }
 }
 
 
 static void
 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 data, data2, time, i, j, k, m, n, o;
 	unsigned short si, di, bx, sf;
 	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);
 	SiS_SetRegByte(SiS_Pr, DACAddr, 0x00);
 
 
-	for(i = 0; i < j; i++) {
+	for (i = 0; i < j; i++) {
 		data = table[i];
 		data = table[i];
-		for(k = 0; k < 3; k++) {
+		for (k = 0; k < 3; k++) {
 			data2 = 0;
 			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));
 			SiS_SetRegByte(SiS_Pr, DACData, (data2 << sf));
 			data >>= 2;
 			data >>= 2;
 		}
 		}
 	}
 	}
 
 
 	if (time == 256) {
 	if (time == 256) {
-		for(i = 16; i < 32; i++) {
+		for (i = 16; i < 32; i++) {
 			data = table[i] << sf;
 			data = table[i] << sf;
-			for(k = 0; k < 3; k++)
+			for (k = 0; k < 3; k++)
 				SiS_SetRegByte(SiS_Pr, DACData, data);
 				SiS_SetRegByte(SiS_Pr, DACData, data);
 		}
 		}
 		si = 32;
 		si = 32;
-		for(m = 0; m < 9; m++) {
+		for (m = 0; m < 9; m++) {
 			di = si;
 			di = si;
 			bx = si + 4;
 			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,
 					SiS_WriteDAC(SiS_Pr, DACData, sf, n,
-						table[di], table[bx], table[si]);
+						     table[di], table[bx],
+						     table[si]);
 					si++;
 					si++;
 				}
 				}
 				si -= 2;
 				si -= 2;
-				for(o = 0; o < 3; o++) {
+				for (o = 0; o < 3; o++) {
 					SiS_WriteDAC(SiS_Pr, DACData, sf, n,
 					SiS_WriteDAC(SiS_Pr, DACData, sf, n,
-						table[di], table[si], table[bx]);
+						     table[di], table[si],
+						     table[bx]);
 					si--;
 					si--;
 				}
 				}
 			}
 			}
-		si += 5;
+			si += 5;
 		}
 		}
 	}
 	}
 }
 }
@@ -929,7 +849,7 @@ SiS_LoadDAC(struct SiS_Private *SiS_Pr, unsigned short ModeNo, unsigned short mi
 
 
 static void
 static void
 SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
-					unsigned short ModeIdIndex)
+		 unsigned short ModeIdIndex)
 {
 {
 	unsigned short StandTableIndex, rrti;
 	unsigned short StandTableIndex, rrti;
 
 
@@ -970,11 +890,10 @@ SiS_SetCRT1Group(struct SiS_Private *SiS_Pr, unsigned short ModeNo,
 /*                 SiSSetMode()              */
 /*                 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 short ModeIdIndex;
-	unsigned long  BaseAddr = SiS_Pr->IOAddress;
+	unsigned long BaseAddr = SiS_Pr->IOAddress;
 
 
 	SiSUSB_InitPtr(SiS_Pr);
 	SiSUSB_InitPtr(SiS_Pr);
 	SiSUSBRegInit(SiS_Pr, BaseAddr);
 	SiSUSBRegInit(SiS_Pr, BaseAddr);
@@ -990,7 +909,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
 	ModeNo &= 0x7f;
 	ModeNo &= 0x7f;
 
 
 	SiS_Pr->SiS_ModeType =
 	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;
 	SiS_Pr->SiS_SetFlag = LowModeTests;
 
 
@@ -1008,8 +927,7 @@ SiSUSBSetMode(struct SiS_Private *SiS_Pr, unsigned short ModeNo)
 	return 1;
 	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;
 	unsigned short ModeNo = 0;
 	int i;
 	int i;
@@ -1041,7 +959,3 @@ SiSUSBSetVESAMode(struct SiS_Private *SiS_Pr, unsigned short VModeNo)
 }
 }
 
 
 #endif /* INCL_SISUSB_CON */
 #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
  * * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  * * 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_
 #define _SISUSB_STRUCT_H_
 
 
 struct SiS_St {
 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 {
 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;
 	void *sisusb;
 
 
 	unsigned long IOAddress;
 	unsigned long IOAddress;
@@ -151,19 +144,18 @@ struct SiS_Private
 	unsigned long SiS_P3da;
 	unsigned long SiS_P3da;
 	unsigned long SiS_Part1Port;
 	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
 #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)
 #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 struct class *mon_bin_class;
 static dev_t mon_bin_dev0;
 static dev_t mon_bin_dev0;
 static struct cdev mon_bin_cdev;
 static struct cdev mon_bin_cdev;
@@ -354,13 +358,9 @@ static inline char mon_bin_get_setup(unsigned char *setupb,
     const struct urb *urb, char ev_type)
     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 '-';
 		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)
 	if (urb->setup_packet == NULL)
 		return 'Z';
 		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,
 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;
 	unsigned long flags;
 	struct timeval ts;
 	struct timeval ts;
 	unsigned int urb_length;
 	unsigned int urb_length;
 	unsigned int offset;
 	unsigned int offset;
 	unsigned int length;
 	unsigned int length;
+	unsigned char dir;
 	struct mon_bin_hdr *ep;
 	struct mon_bin_hdr *ep;
 	char data_tag = 0;
 	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)
 	if (length >= rp->b_size/5)
 		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') {
 		if (ev_type == 'S') {
 			length = 0;
 			length = 0;
 			data_tag = '<';
 			data_tag = '<';
 		}
 		}
+		/* Cannot rely on endpoint number in case of control ep.0 */
+		dir = USB_DIR_IN;
 	} else {
 	} else {
 		if (ev_type == 'C') {
 		if (ev_type == 'C') {
 			length = 0;
 			length = 0;
 			data_tag = '>';
 			data_tag = '>';
 		}
 		}
+		dir = 0;
 	}
 	}
 
 
 	if (rp->mmap_active)
 	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);
 	memset(ep, 0, PKT_SIZE);
 	ep->type = ev_type;
 	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->busnum = urb->dev->bus->busnum;
 	ep->id = (unsigned long) urb;
 	ep->id = (unsigned long) urb;
 	ep->ts_sec = ts.tv_sec;
 	ep->ts_sec = ts.tv_sec;
 	ep->ts_usec = ts.tv_usec;
 	ep->ts_usec = ts.tv_usec;
-	ep->status = urb->status;
+	ep->status = status;
 	ep->len_urb = urb_length;
 	ep->len_urb = urb_length;
 	ep->len_cap = 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)
 static void mon_bin_submit(void *data, struct urb *urb)
 {
 {
 	struct mon_reader_bin *rp = data;
 	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;
 	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)
 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);
 	memset(ep, 0, PKT_SIZE);
 	ep->type = 'E';
 	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->busnum = urb->dev->bus->busnum;
 	ep->id = (unsigned long) urb;
 	ep->id = (unsigned long) urb;
 	ep->status = error;
 	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;
 	unsigned long flags;
 	struct list_head *pos;
 	struct list_head *pos;
@@ -139,28 +140,18 @@ static void mon_bus_complete(struct mon_bus *mbus, struct urb *urb)
 	mbus->cnt_events++;
 	mbus->cnt_events++;
 	list_for_each (pos, &mbus->r_list) {
 	list_for_each (pos, &mbus->r_list) {
 		r = list_entry(pos, struct mon_reader, r_link);
 		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);
 	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;
 	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); */
 /* 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)
 static void mon_stop(struct mon_bus *mbus)
 {
 {
-	struct usb_bus *ubus = mbus->u_bus;
+	struct usb_bus *ubus;
 	struct list_head *p;
 	struct list_head *p;
 
 
 	if (mbus == &mon_bus0) {
 	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 mon_event_text {
 	struct list_head e_link;
 	struct list_head e_link;
 	int type;		/* submit, complete, etc. */
 	int type;		/* submit, complete, etc. */
-	unsigned int pipe;	/* Pipe */
 	unsigned long id;	/* From pointer, most of the time */
 	unsigned long id;	/* From pointer, most of the time */
 	unsigned int tstamp;
 	unsigned int tstamp;
 	int busnum;
 	int busnum;
+	char devnum;
+	char epnum;
+	char is_in;
+	char xfertype;
 	int length;		/* Depends on type: xfer length or act length */
 	int length;		/* Depends on type: xfer length or act length */
 	int status;
 	int status;
 	int interval;
 	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)
     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 '-';
 		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)
 	if (urb->setup_packet == NULL)
 		return 'Z';	/* '0' would be not as pretty. */
 		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,
 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 len, char ev_type, struct mon_bus *mbus)
 {
 {
-	int pipe = urb->pipe;
-
 	if (len <= 0)
 	if (len <= 0)
 		return 'L';
 		return 'L';
 	if (len >= DATA_MAX)
 	if (len >= DATA_MAX)
 		len = DATA_MAX;
 		len = DATA_MAX;
 
 
-	if (usb_pipein(pipe)) {
+	if (ep->is_in) {
 		if (ev_type != 'C')
 		if (ev_type != 'C')
 			return '<';
 			return '<';
 	} else {
 	} 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,
 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;
 	struct mon_event_text *ep;
 	unsigned int stamp;
 	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->type = ev_type;
-	ep->pipe = urb->pipe;
 	ep->id = (unsigned long) urb;
 	ep->id = (unsigned long) urb;
 	ep->busnum = urb->dev->bus->busnum;
 	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->tstamp = stamp;
 	ep->length = (ev_type == 'S') ?
 	ep->length = (ev_type == 'S') ?
 	    urb->transfer_buffer_length : urb->actual_length;
 	    urb->transfer_buffer_length : urb->actual_length;
 	/* Collecting status makes debugging sense for submits, too */
 	/* 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;
 		ep->interval = urb->interval;
-	} else if (usb_pipeisoc(urb->pipe)) {
+	} else if (ep->xfertype == USB_ENDPOINT_XFER_ISOC) {
 		ep->interval = urb->interval;
 		ep->interval = urb->interval;
 		ep->start_frame = urb->start_frame;
 		ep->start_frame = urb->start_frame;
 		ep->error_count = urb->error_count;
 		ep->error_count = urb->error_count;
 	}
 	}
 	ep->numdesc = urb->number_of_packets;
 	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)
 		if ((ndesc = urb->number_of_packets) > ISODESC_MAX)
 			ndesc = ISODESC_MAX;
 			ndesc = ISODESC_MAX;
 		fp = urb->iso_frame_desc;
 		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)
 static void mon_text_submit(void *data, struct urb *urb)
 {
 {
 	struct mon_reader_text *rp = data;
 	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;
 	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)
 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->type = 'E';
-	ep->pipe = urb->pipe;
 	ep->id = (unsigned long) urb;
 	ep->id = (unsigned long) urb;
 	ep->busnum = 0;
 	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->tstamp = 0;
 	ep->length = 0;
 	ep->length = 0;
 	ep->status = error;
 	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);
 	mon_text_read_head_u(rp, &ptr, ep);
 	if (ep->type == 'E') {
 	if (ep->type == 'E') {
 		mon_text_read_statset(rp, &ptr, ep);
 		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_isostat(rp, &ptr, ep);
 		mon_text_read_isodesc(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);
 		mon_text_read_intstat(rp, &ptr, ep);
 	} else {
 	} else {
 		mon_text_read_statset(rp, &ptr, ep);
 		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;
 	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';
 	default: /* PIPE_BULK */  utype = 'B';
 	}
 	}
 	p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
 	p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
 	    "%lx %u %c %c%c:%03u:%02u",
 	    "%lx %u %c %c%c:%03u:%02u",
 	    ep->id, ep->tstamp, ep->type,
 	    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,
 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;
 	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';
 	default: /* PIPE_BULK */  utype = 'B';
 	}
 	}
 	p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
 	p->cnt += snprintf(p->pbuf + p->cnt, p->limit - p->cnt,
 	    "%lx %u %c %c%c:%d:%03u:%u",
 	    "%lx %u %c %c%c:%d:%03u:%u",
 	    ep->id, ep->tstamp, ep->type,
 	    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,
 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_submit)(void *data, struct urb *urb);
 	void (*rnf_error)(void *data, struct urb *urb, int error);
 	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);
 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
 	  To compile this driver as a module, choose M here: the
 	  module will be called belkin_sa.
 	  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
 config USB_SERIAL_WHITEHEAT
 	tristate "USB ConnectTech WhiteHEAT Serial Driver"
 	tristate "USB ConnectTech WhiteHEAT Serial Driver"
 	depends on USB_SERIAL
 	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_AIRPRIME)		+= airprime.o
 obj-$(CONFIG_USB_SERIAL_ARK3116)		+= ark3116.o
 obj-$(CONFIG_USB_SERIAL_ARK3116)		+= ark3116.o
 obj-$(CONFIG_USB_SERIAL_BELKIN)			+= belkin_sa.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_CP2101)			+= cp2101.o
 obj-$(CONFIG_USB_SERIAL_CYBERJACK)		+= cyberjack.o
 obj-$(CONFIG_USB_SERIAL_CYBERJACK)		+= cyberjack.o
 obj-$(CONFIG_USB_SERIAL_CYPRESS_M8)		+= cypress_m8.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);
 	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);
 	spin_lock_irqsave(&priv->lock, flags);
 	if (!priv->termios_initialized) {
 	if (!priv->termios_initialized) {
 		*(port->tty->termios) = tty_std_termios;
 		*(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;
 	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)
 static int usb_serial_device_probe (struct device *dev)
 {
 {
 	struct usb_serial_driver *driver;
 	struct usb_serial_driver *driver;
@@ -62,6 +72,10 @@ static int usb_serial_device_probe (struct device *dev)
 			goto exit;
 			goto exit;
 	}
 	}
 
 
+	retval = device_create_file(dev, &dev_attr_port_number);
+	if (retval)
+		goto exit;
+
 	minor = port->number;
 	minor = port->number;
 	tty_register_device (usb_serial_tty_driver, minor, dev);
 	tty_register_device (usb_serial_tty_driver, minor, dev);
 	dev_info(&port->serial->dev->dev, 
 	dev_info(&port->serial->dev->dev, 
@@ -84,6 +98,8 @@ static int usb_serial_device_remove (struct device *dev)
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
+	device_remove_file(&port->dev, &dev_attr_port_number);
+
 	driver = port->serial->type;
 	driver = port->serial->type;
 	if (driver->port_remove) {
 	if (driver->port_remove) {
 		if (!try_module_get(driver->driver.owner)) {
 		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 int debug;
 
 
 static struct usb_device_id id_table [] = {
 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(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
 	{ USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
 	{ USB_DEVICE(0x10A6, 0xAA26) }, /* Knock-off DCU-11 cable */
 	{ USB_DEVICE(0x10AB, 0x10C5) }, /* Siemens MC60 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);
 	dbg("%s - port %d", __FUNCTION__, port->number);
 
 
-	if ((!port->tty) || (!port->tty->termios)) {
+	if (!port->tty || !port->tty->termios) {
 		dbg("%s - no tty structures", __FUNCTION__);
 		dbg("%s - no tty structures", __FUNCTION__);
 		return;
 		return;
 	}
 	}

+ 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 */
 	/* XXX see create_sysfs_attrs */
 	if (priv->chip_type != SIO) {
 	if (priv->chip_type != SIO) {
 		device_remove_file(&port->dev, &dev_attr_event_char);
 		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);
 			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 FT8U232AM:
 	case FT232BM:
 	case FT232BM:
 	case FT2232C:
 	case FT2232C:
+	case FT232RL:
 		/* the 8U232AM returns a two byte value (the sio is a 1 byte value) - in the same
 		/* 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 */
 		   format as the data returned from the in point */
 		if ((ret = usb_control_msg(port->serial->dev,
 		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);
 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 = {
 static struct usb_driver funsoft_driver = {
 	.name =		"funsoft",
 	.name =		"funsoft",
 	.probe =	usb_serial_probe,
 	.probe =	usb_serial_probe,
@@ -63,7 +43,6 @@ static struct usb_serial_driver funsoft_device = {
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_in =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,
 	.num_bulk_out =		NUM_DONT_CARE,
 	.num_ports =		1,
 	.num_ports =		1,
-	.ioctl =		funsoft_ioctl,
 };
 };
 
 
 static int __init funsoft_init(void)
 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, 0x9121) }, /* SHARP WS004SH USB Modem */
 	{ USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */
 	{ USB_DEVICE(0x04DD, 0x9123) }, /* SHARP WS007SH USB Modem */
 	{ USB_DEVICE(0x04DD, 0x9151) }, /* SHARP S01SH 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, 0x5F00) }, /* Samsung NEXiO USB Sync */
 	{ USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */
 	{ USB_DEVICE(0x04E8, 0x5F01) }, /* Samsung NEXiO USB Sync */
 	{ USB_DEVICE(0x04E8, 0x5F02) }, /* 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);
 	kfree(port->bulk_out_buffer);
 	port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
 	port->bulk_in_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
 	if (port->bulk_in_buffer == NULL) {
 	if (port->bulk_in_buffer == NULL) {
+		port->bulk_out_buffer = NULL; /* prevent double free */
 		goto enomem;
 		goto enomem;
 	}
 	}
 	port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
 	port->bulk_out_buffer = kmalloc(URBDATA_SIZE, GFP_KERNEL);
 	if (port->bulk_out_buffer == NULL) {
 	if (port->bulk_out_buffer == NULL) {
 		kfree(port->bulk_in_buffer);
 		kfree(port->bulk_in_buffer);
+		port->bulk_in_buffer = NULL;
 		goto enomem;
 		goto enomem;
 	}
 	}
 	port->read_urb->transfer_buffer = port->bulk_in_buffer;
 	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
 #endif
 		}
 		}
 		
 		
-		switch(cflag & CBAUD) {
-		case B0: /* handled below */
+		switch(tty_get_baud_rate(port->tty)) {
+		case 0: /* handled below */
 			break;
 			break;
-		case B1200: priv->cfg.baudrate = kl5kusb105a_sio_b1200;
+		case 1200:
+			priv->cfg.baudrate = kl5kusb105a_sio_b1200;
 			break;
 			break;
-		case B2400: priv->cfg.baudrate = kl5kusb105a_sio_b2400;
+		case 2400:
+			priv->cfg.baudrate = kl5kusb105a_sio_b2400;
 			break;
 			break;
-		case B4800: priv->cfg.baudrate = kl5kusb105a_sio_b4800;
+		case 4800:
+			priv->cfg.baudrate = kl5kusb105a_sio_b4800;
 			break;
 			break;
-		case B9600: priv->cfg.baudrate = kl5kusb105a_sio_b9600;
+		case 9600:
+			priv->cfg.baudrate = kl5kusb105a_sio_b9600;
 			break;
 			break;
-		case B19200: priv->cfg.baudrate = kl5kusb105a_sio_b19200;
+		case 19200:
+			priv->cfg.baudrate = kl5kusb105a_sio_b19200;
 			break;
 			break;
-		case B38400: priv->cfg.baudrate = kl5kusb105a_sio_b38400;
+		case 38400:
+			priv->cfg.baudrate = kl5kusb105a_sio_b38400;
 			break;
 			break;
-		case B57600: priv->cfg.baudrate = kl5kusb105a_sio_b57600;
+		case 57600:
+			priv->cfg.baudrate = kl5kusb105a_sio_b57600;
 			break;
 			break;
-		case B115200: priv->cfg.baudrate = kl5kusb105a_sio_b115200;
+		case 115200:
+			priv->cfg.baudrate = kl5kusb105a_sio_b115200;
 			break;
 			break;
 		default:
 		default:
 			err("KLSI USB->Serial converter:"
 			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);
 			   unsigned int set, unsigned int clear);
 static void kobil_read_int_callback( struct urb *urb );
 static void kobil_read_int_callback( struct urb *urb );
 static void kobil_write_callback( struct urb *purb );
 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 [] = {
 static struct usb_device_id id_table [] = {
@@ -119,6 +120,7 @@ static struct usb_serial_driver kobil_device = {
 	.attach =		kobil_startup,
 	.attach =		kobil_startup,
 	.shutdown =		kobil_shutdown,
 	.shutdown =		kobil_shutdown,
 	.ioctl =		kobil_ioctl,
 	.ioctl =		kobil_ioctl,
+	.set_termios =		kobil_set_termios,
 	.tiocmget =		kobil_tiocmget,
 	.tiocmget =		kobil_tiocmget,
 	.tiocmset =		kobil_tiocmset,
 	.tiocmset =		kobil_tiocmset,
 	.open =			kobil_open,
 	.open =			kobil_open,
@@ -137,7 +139,6 @@ struct kobil_private {
 	int cur_pos; // index of the next char to send in buf
 	int cur_pos; // index of the next char to send in buf
 	__u16 device_type;
 	__u16 device_type;
 	int line_state;
 	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)
 static int kobil_open (struct usb_serial_port *port, struct file *filp)
 {
 {
-	int i, result = 0;
+	int result = 0;
 	struct kobil_private *priv;
 	struct kobil_private *priv;
 	unsigned char *transfer_buffer;
 	unsigned char *transfer_buffer;
 	int transfer_buffer_length = 8;
 	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_iflag = IGNBRK | IGNPAR | IXOFF;
 	port->tty->termios->c_oflag &= ~ONLCR; // do NOT translate CR to CR-NL (0x0A -> 0x0A 0x0D)
 	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
 	// allocate memory for transfer buffer
 	transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
 	transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
 	if (! transfer_buffer) {
 	if (! transfer_buffer) {
@@ -607,102 +598,79 @@ static int  kobil_tiocmset(struct usb_serial_port *port, struct file *file,
 	return (result < 0) ? result : 0;
 	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;
 	struct kobil_private * priv;
 	int result;
 	int result;
 	unsigned short urb_val = 0;
 	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);
 	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
 		// 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;
 			urb_val = SUSBCR_SBR_1200;
-			strcat(settings, "1200 ");
 			break;
 			break;
-		case B9600:
+		case 9600:
 		default:
 		default:
 			urb_val = SUSBCR_SBR_9600;
 			urb_val = SUSBCR_SBR_9600;
-			strcat(settings, "9600 ");
 			break;
 			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 {
 		} 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;
 		return 0;
 
 
+	switch (cmd) {
 	case TCFLSH:   // 0x540B
 	case TCFLSH:   // 0x540B
 		transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL);
 		transfer_buffer = kmalloc(transfer_buffer_length, GFP_KERNEL);
-		if (! transfer_buffer) {
+		if (! transfer_buffer)
 		 	return -ENOBUFS;
 		 	return -ENOBUFS;
-		}
 
 
 		result = usb_control_msg( port->serial->dev, 
 		result = usb_control_msg( port->serial->dev, 
 		 			  usb_rcvctrlpipe(port->serial->dev, 0 ), 
 		 			  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);
 		dbg("%s - port %d Send reset_all_queues (FLUSH) URB returns: %i", __FUNCTION__, port->number, result);
-
 		kfree(transfer_buffer);
 		kfree(transfer_buffer);
-		return ((result < 0) ? -EFAULT : 0);
-
+		return (result < 0) ? -EFAULT : 0;
+	default:
+		return -ENOIOCTLCMD;
 	}
 	}
-	return -ENOIOCTLCMD;
 }
 }
 
 
-
 static int __init kobil_init (void)
 static int __init kobil_init (void)
 {
 {
 	int retval;
 	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 {
 	} else {
 		switch (value) {
 		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;
 		return 115200/value;
 	}
 	}

部分文件因文件數量過多而無法顯示