Browse Source

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

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (220 commits)
  USB: backlight, appledisplay: fix incomplete registration failure handling
  USB: pl2303: remove unnecessary reset of usb_device in urbs
  USB: ftdi_sio: remove obsolete check in unthrottle
  USB: ftdi_sio: remove unused tx_bytes counter
  USB: qcaux: driver for auxiliary serial ports on Qualcomm devices
  USB: pl2303: initial TIOCGSERIAL support
  USB: option: add Longcheer/Longsung vendor ID
  USB: fix I2C API usage in ohci-pnx4008.
  USB: usbmon: mask seconds properly in text API
  USB: sisusbvga: no unnecessary GFP_ATOMIC
  USB: storage: onetouch: unnecessary GFP_ATOMIC
  USB: serial: ftdi: add CONTEC vendor and product id
  USB: remove references to port->port.count from the serial drivers
  USB: tty: Prune uses of tty_request_room in the USB layer
  USB: tty: Add a function to insert a string of characters with the same flag
  USB: don't read past config->interface[] if usb_control_msg() fails in usb_reset_configuration()
  USB: tty: kill request_room for USB ACM class
  USB: tty: sort out the request_room handling for whiteheat
  USB: storage: fix misplaced parenthesis
  USB: vstusb.c: removal of driver for Vernier Software & Technology, Inc., devices and spectrometers
  ...
Linus Torvalds 15 years ago
parent
commit
7f5b09c15a
100 changed files with 5357 additions and 1436 deletions
  1. 11 0
      Documentation/ABI/testing/sysfs-bus-usb
  2. 0 1
      Documentation/ioctl/ioctl-number.txt
  3. 2 0
      Documentation/networking/00-INDEX
  4. 48 0
      Documentation/networking/cxacru-cf.py
  5. 16 0
      Documentation/networking/cxacru.txt
  6. 4 2
      Documentation/usb/error-codes.txt
  7. 95 140
      Documentation/usb/power-management.txt
  8. 10 1
      arch/arm/configs/rx51_defconfig
  9. 54 26
      arch/arm/mach-mx2/devices.c
  10. 1 0
      arch/arm/mach-mx2/devices.h
  11. 38 0
      arch/arm/plat-mxc/include/mach/mx21-usbhost.h
  12. 5 2
      arch/avr32/mach-at32ap/at32ap700x.c
  13. 6 5
      drivers/char/tty_buffer.c
  14. 5 2
      drivers/hid/usbhid/hiddev.c
  15. 7 1
      drivers/media/video/dabusb.c
  16. 1 1
      drivers/staging/usbip/vhci_sysfs.c
  17. 2 0
      drivers/usb/Kconfig
  18. 1 0
      drivers/usb/Makefile
  19. 137 55
      drivers/usb/atm/cxacru.c
  20. 2 1
      drivers/usb/atm/usbatm.c
  21. 15 0
      drivers/usb/atm/usbatm.h
  22. 4 4
      drivers/usb/c67x00/c67x00-drv.c
  23. 53 29
      drivers/usb/class/cdc-acm.c
  24. 1 1
      drivers/usb/class/cdc-acm.h
  25. 1 1
      drivers/usb/class/cdc-wdm.c
  26. 4 18
      drivers/usb/class/usblp.c
  27. 1 1
      drivers/usb/class/usbtmc.c
  28. 2 2
      drivers/usb/core/Kconfig
  29. 11 21
      drivers/usb/core/devices.c
  30. 80 47
      drivers/usb/core/devio.c
  31. 424 494
      drivers/usb/core/driver.c
  32. 0 2
      drivers/usb/core/file.c
  33. 18 9
      drivers/usb/core/hcd.c
  34. 9 4
      drivers/usb/core/hcd.h
  35. 53 67
      drivers/usb/core/hub.c
  36. 2 3
      drivers/usb/core/message.c
  37. 14 4
      drivers/usb/core/quirks.c
  38. 61 24
      drivers/usb/core/sysfs.c
  39. 10 3
      drivers/usb/core/urb.c
  40. 3 35
      drivers/usb/core/usb.c
  41. 6 37
      drivers/usb/core/usb.h
  42. 28 40
      drivers/usb/early/ehci-dbgp.c
  43. 10 0
      drivers/usb/gadget/Kconfig
  44. 2 0
      drivers/usb/gadget/Makefile
  45. 4 6
      drivers/usb/gadget/at91_udc.c
  46. 5 4
      drivers/usb/gadget/atmel_usba_udc.c
  47. 1 0
      drivers/usb/gadget/atmel_usba_udc.h
  48. 16 8
      drivers/usb/gadget/epautoconf.c
  49. 1 1
      drivers/usb/gadget/ether.c
  50. 0 8
      drivers/usb/gadget/f_acm.c
  51. 2 5
      drivers/usb/gadget/f_ecm.c
  52. 29 21
      drivers/usb/gadget/f_mass_storage.c
  53. 0 4
      drivers/usb/gadget/f_rndis.c
  54. 2 6
      drivers/usb/gadget/file_storage.c
  55. 1 1
      drivers/usb/gadget/fsl_qe_udc.c
  56. 0 59
      drivers/usb/gadget/gadget_chips.h
  57. 0 5
      drivers/usb/gadget/gmidi.c
  58. 1 1
      drivers/usb/gadget/goku_udc.c
  59. 21 18
      drivers/usb/gadget/inode.c
  60. 7 1
      drivers/usb/gadget/mass_storage.c
  61. 259 0
      drivers/usb/gadget/nokia.c
  62. 0 18
      drivers/usb/gadget/printer.c
  63. 93 42
      drivers/usb/gadget/pxa27x_udc.c
  64. 6 0
      drivers/usb/gadget/pxa27x_udc.h
  65. 6 5
      drivers/usb/gadget/s3c-hsotg.c
  66. 5 0
      drivers/usb/gadget/u_ether.c
  67. 0 7
      drivers/usb/gadget/u_ether.h
  68. 2 4
      drivers/usb/gadget/zero.c
  69. 11 0
      drivers/usb/host/Kconfig
  70. 2 0
      drivers/usb/host/Makefile
  71. 1 1
      drivers/usb/host/ehci-atmel.c
  72. 4 2
      drivers/usb/host/ehci-au1xxx.c
  73. 87 10
      drivers/usb/host/ehci-fsl.c
  74. 11 12
      drivers/usb/host/ehci-mxc.c
  75. 41 6
      drivers/usb/host/ehci-omap.c
  76. 4 4
      drivers/usb/host/ehci-orion.c
  77. 7 7
      drivers/usb/host/ehci-ppc-of.c
  78. 9 3
      drivers/usb/host/ehci-sched.c
  79. 4 4
      drivers/usb/host/ehci-xilinx-of.c
  80. 2 2
      drivers/usb/host/fhci-hcd.c
  81. 527 0
      drivers/usb/host/imx21-dbg.c
  82. 1789 0
      drivers/usb/host/imx21-hcd.c
  83. 436 0
      drivers/usb/host/imx21-hcd.h
  84. 1 14
      drivers/usb/host/isp1362-hcd.c
  85. 10 0
      drivers/usb/host/isp1760-hcd.c
  86. 1 1
      drivers/usb/host/isp1760-if.c
  87. 456 0
      drivers/usb/host/ohci-da8xx.c
  88. 2 2
      drivers/usb/host/ohci-dbg.c
  89. 5 0
      drivers/usb/host/ohci-hcd.c
  90. 5 6
      drivers/usb/host/ohci-lh7a404.c
  91. 3 3
      drivers/usb/host/ohci-pnx4008.c
  92. 5 5
      drivers/usb/host/ohci-ppc-of.c
  93. 4 4
      drivers/usb/host/ohci-ppc-soc.c
  94. 4 4
      drivers/usb/host/ohci-sa1111.c
  95. 3 2
      drivers/usb/host/sl811-hcd.c
  96. 1 0
      drivers/usb/host/uhci-hcd.c
  97. 19 0
      drivers/usb/host/xhci-dbg.c
  98. 5 2
      drivers/usb/host/xhci-ext-caps.h
  99. 130 20
      drivers/usb/host/xhci-hcd.c
  100. 50 15
      drivers/usb/host/xhci-hub.c

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

@@ -159,3 +159,14 @@ Description:
 		device.  This is useful to ensure auto probing won't
 		device.  This is useful to ensure auto probing won't
 		match the driver to the device.  For example:
 		match the driver to the device.  For example:
 		# echo "046d c315" > /sys/bus/usb/drivers/foo/remove_id
 		# echo "046d c315" > /sys/bus/usb/drivers/foo/remove_id
+
+What:		/sys/bus/usb/device/.../avoid_reset
+Date:		December 2009
+Contact:	Oliver Neukum <oliver@neukum.org>
+Description:
+		Writing 1 to this file tells the kernel that this
+		device will morph into another mode when it is reset.
+		Drivers will not use reset for error handling for
+		such devices.
+Users:
+		usb_modeswitch

+ 0 - 1
Documentation/ioctl/ioctl-number.txt

@@ -139,7 +139,6 @@ Code  Seq#(hex)	Include File		Comments
 'K'	all	linux/kd.h
 'K'	all	linux/kd.h
 'L'	00-1F	linux/loop.h		conflict!
 'L'	00-1F	linux/loop.h		conflict!
 'L'	10-1F	drivers/scsi/mpt2sas/mpt2sas_ctl.h	conflict!
 'L'	10-1F	drivers/scsi/mpt2sas/mpt2sas_ctl.h	conflict!
-'L'	20-2F	linux/usb/vstusb.h
 'L'	E0-FF	linux/ppdd.h		encrypted disk device driver
 'L'	E0-FF	linux/ppdd.h		encrypted disk device driver
 					<http://linux01.gwdg.de/~alatham/ppdd.html>
 					<http://linux01.gwdg.de/~alatham/ppdd.html>
 'M'	all	linux/soundcard.h	conflict!
 'M'	all	linux/soundcard.h	conflict!

+ 2 - 0
Documentation/networking/00-INDEX

@@ -32,6 +32,8 @@ cs89x0.txt
 	- the Crystal LAN (CS8900/20-based) Ethernet ISA adapter driver
 	- the Crystal LAN (CS8900/20-based) Ethernet ISA adapter driver
 cxacru.txt
 cxacru.txt
 	- Conexant AccessRunner USB ADSL Modem
 	- Conexant AccessRunner USB ADSL Modem
+cxacru-cf.py
+	- Conexant AccessRunner USB ADSL Modem configuration file parser
 de4x5.txt
 de4x5.txt
 	- the Digital EtherWORKS DE4?? and DE5?? PCI Ethernet driver
 	- the Digital EtherWORKS DE4?? and DE5?? PCI Ethernet driver
 decnet.txt
 decnet.txt

+ 48 - 0
Documentation/networking/cxacru-cf.py

@@ -0,0 +1,48 @@
+#!/usr/bin/env python
+# Copyright 2009 Simon Arlott
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; either version 2 of the License, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+# more details.
+#
+# You should have received a copy of the GNU General Public License along with
+# this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+#
+# Usage: cxacru-cf.py < cxacru-cf.bin
+# Output: values string suitable for the sysfs adsl_config attribute
+#
+# Warning: cxacru-cf.bin with MD5 hash cdbac2689969d5ed5d4850f117702110
+# contains mis-aligned values which will stop the modem from being able
+# to make a connection. If the first and last two bytes are removed then
+# the values become valid, but the modulation will be forced to ANSI
+# T1.413 only which may not be appropriate.
+#
+# The original binary format is a packed list of le32 values.
+
+import sys
+import struct
+
+i = 0
+while True:
+	buf = sys.stdin.read(4)
+
+	if len(buf) == 0:
+		break
+	elif len(buf) != 4:
+		sys.stdout.write("\n")
+		sys.stderr.write("Error: read {0} not 4 bytes\n".format(len(buf)))
+		sys.exit(1)
+
+	if i > 0:
+		sys.stdout.write(" ")
+	sys.stdout.write("{0:x}={1}".format(i, struct.unpack("<I", buf)[0]))
+	i += 1
+
+sys.stdout.write("\n")

+ 16 - 0
Documentation/networking/cxacru.txt

@@ -4,6 +4,12 @@ While it is capable of managing/maintaining the ADSL connection without the
 module loaded, the device will sometimes stop responding after unloading the
 module loaded, the device will sometimes stop responding after unloading the
 driver and it is necessary to unplug/remove power to the device to fix this.
 driver and it is necessary to unplug/remove power to the device to fix this.
 
 
+Note: support for cxacru-cf.bin has been removed. It was not loaded correctly
+so it had no effect on the device configuration. Fixing it could have stopped
+existing devices working when an invalid configuration is supplied.
+
+There is a script cxacru-cf.py to convert an existing file to the sysfs form.
+
 Detected devices will appear as ATM devices named "cxacru". In /sys/class/atm/
 Detected devices will appear as ATM devices named "cxacru". In /sys/class/atm/
 these are directories named cxacruN where N is the device number. A symlink
 these are directories named cxacruN where N is the device number. A symlink
 named device points to the USB interface device's directory which contains
 named device points to the USB interface device's directory which contains
@@ -15,6 +21,15 @@ several sysfs attribute files for retrieving device statistics:
 * adsl_headend_environment
 * adsl_headend_environment
 	Information about the remote headend.
 	Information about the remote headend.
 
 
+* adsl_config
+	Configuration writing interface.
+	Write parameters in hexadecimal format <index>=<value>,
+	separated by whitespace, e.g.:
+		"1=0 a=5"
+	Up to 7 parameters at a time will be sent and the modem will restart
+	the ADSL connection when any value is set. These are logged for future
+	reference.
+
 * downstream_attenuation (dB)
 * downstream_attenuation (dB)
 * downstream_bits_per_frame
 * downstream_bits_per_frame
 * downstream_rate (kbps)
 * downstream_rate (kbps)
@@ -61,6 +76,7 @@ several sysfs attribute files for retrieving device statistics:
 * mac_address
 * mac_address
 
 
 * modulation
 * modulation
+	"" (when not connected)
 	"ANSI T1.413"
 	"ANSI T1.413"
 	"ITU-T G.992.1 (G.DMT)"
 	"ITU-T G.992.1 (G.DMT)"
 	"ITU-T G.992.2 (G.LITE)"
 	"ITU-T G.992.2 (G.LITE)"

+ 4 - 2
Documentation/usb/error-codes.txt

@@ -41,8 +41,8 @@ USB-specific:
 
 
 -EFBIG		Host controller driver can't schedule that many ISO frames.
 -EFBIG		Host controller driver can't schedule that many ISO frames.
 
 
--EPIPE		Specified endpoint is stalled.  For non-control endpoints,
-		reset this status with usb_clear_halt().
+-EPIPE		The pipe type specified in the URB doesn't match the
+		endpoint's actual type.
 
 
 -EMSGSIZE	(a) endpoint maxpacket size is zero; it is not usable
 -EMSGSIZE	(a) endpoint maxpacket size is zero; it is not usable
 		    in the current interface altsetting.
 		    in the current interface altsetting.
@@ -60,6 +60,8 @@ USB-specific:
 
 
 -EHOSTUNREACH	URB was rejected because the device is suspended.
 -EHOSTUNREACH	URB was rejected because the device is suspended.
 
 
+-ENOEXEC	A control URB doesn't contain a Setup packet.
+
 
 
 **************************************************************************
 **************************************************************************
 *                   Error codes returned by in urb->status               *
 *                   Error codes returned by in urb->status               *

+ 95 - 140
Documentation/usb/power-management.txt

@@ -2,7 +2,7 @@
 
 
 		 Alan Stern <stern@rowland.harvard.edu>
 		 Alan Stern <stern@rowland.harvard.edu>
 
 
-			    November 10, 2009
+			    December 11, 2009
 
 
 
 
 
 
@@ -29,9 +29,9 @@ covered to some extent (see Documentation/power/*.txt for more
 information about system PM).
 information about system PM).
 
 
 Note: Dynamic PM support for USB is present only if the kernel was
 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.
+built with CONFIG_USB_SUSPEND enabled (which depends on
+CONFIG_PM_RUNTIME).  System PM support is present only if the kernel
+was built with CONFIG_SUSPEND or CONFIG_HIBERNATION enabled.
 
 
 
 
 	What is Remote Wakeup?
 	What is Remote Wakeup?
@@ -229,6 +229,11 @@ 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
 also change the idle-delay time; 2 seconds is not the best choice for
 every device.
 every device.
 
 
+If a driver knows that its device has proper suspend/resume support,
+it can enable autosuspend all by itself.  For example, the video
+driver for a laptop's webcam might do this, since these devices are
+rarely used and so should normally be autosuspended.
+
 Sometimes it turns out that even when a device does work okay with
 Sometimes it turns out that even when a device does work okay with
 autosuspend there are still problems.  For example, there are
 autosuspend there are still problems.  For example, there are
 experimental patches adding autosuspend support to the usbhid driver,
 experimental patches adding autosuspend support to the usbhid driver,
@@ -321,69 +326,81 @@ driver does so by calling these six functions:
 	void usb_autopm_get_interface_no_resume(struct usb_interface *intf);
 	void usb_autopm_get_interface_no_resume(struct usb_interface *intf);
 	void usb_autopm_put_interface_no_suspend(struct usb_interface *intf);
 	void usb_autopm_put_interface_no_suspend(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.
+The functions work by maintaining a usage counter in the
+usb_interface's embedded device structure.  When the counter is > 0
+then the interface is deemed to be busy, and the kernel will not
+autosuspend the interface's device.  When the usage counter 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,
+(There is a similar usage counter field in struct usb_device,
 associated with the device itself rather than any of its interfaces.
 associated with the device itself rather than any of its interfaces.
-This field is used only by the USB core.)
-
-Drivers must not modify intf->pm_usage_count directly; its value
-should be changed only be using the functions listed above.  Drivers
-are responsible for insuring that the overall change to pm_usage_count
-during their lifetime balances out to 0 (it may be necessary for the
-disconnect method to call usb_autopm_put_interface() one or more times
-to fulfill this requirement).  The first two routines use the PM mutex
-in struct usb_device for mutual exclusion; drivers using the async
-routines are responsible for their own synchronization and mutual
-exclusion.
-
-	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.
+This counter is used only by the USB core.)
+
+Drivers need not be concerned about balancing changes to the usage
+counter; the USB core will undo any remaining "get"s when a driver
+is unbound from its interface.  As a corollary, drivers must not call
+any of the usb_autopm_* functions after their diconnect() routine has
+returned.
+
+Drivers using the async routines are responsible for their own
+synchronization and mutual exclusion.
+
+	usb_autopm_get_interface() increments the usage counter and
+	does an autoresume if the device is suspended.  If the
+	autoresume fails, the counter is decremented back.
+
+	usb_autopm_put_interface() decrements the usage counter and
+	attempts an autosuspend if the new value is = 0.
 
 
 	usb_autopm_get_interface_async() and
 	usb_autopm_get_interface_async() and
 	usb_autopm_put_interface_async() do almost the same things as
 	usb_autopm_put_interface_async() do almost the same things as
-	their non-async counterparts.  The differences are: they do
-	not acquire the PM mutex, and they use a workqueue to do their
+	their non-async counterparts.  The big difference is that they
+	use a workqueue to do the resume or suspend part of their
 	jobs.  As a result they can be called in an atomic context,
 	jobs.  As a result they can be called in an atomic context,
 	such as an URB's completion handler, but when they return the
 	such as an URB's completion handler, but when they return the
-	device will not generally not yet be in the desired state.
+	device will generally not yet be in the desired state.
 
 
 	usb_autopm_get_interface_no_resume() and
 	usb_autopm_get_interface_no_resume() and
 	usb_autopm_put_interface_no_suspend() merely increment or
 	usb_autopm_put_interface_no_suspend() merely increment or
-	decrement the pm_usage_count value; they do not attempt to
-	carry out an autoresume or an autosuspend.  Hence they can be
-	called in an atomic context.
+	decrement the usage counter; they do not attempt to carry out
+	an autoresume or an autosuspend.  Hence they can be called in
+	an atomic context.
 
 
-The conventional usage pattern is that a driver calls
+The simplest usage pattern is that a driver calls
 usb_autopm_get_interface() in its open routine and
 usb_autopm_get_interface() in its open routine and
-usb_autopm_put_interface() in its close or release routine.  But
-other patterns are possible.
+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
 The autosuspend attempts mentioned above will often fail for one
 reason or another.  For example, the power/level attribute might be
 reason or another.  For example, the power/level attribute might be
 set to "on", or another interface in the same device might not 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
 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.
+the device hasn't been idle for long enough, a timer is scheduled to
+carry out the operation automatically when the autosuspend idle-delay
+has expired.
 
 
 Autoresume attempts also can fail, although failure would mean that
 Autoresume attempts also can fail, although failure would mean that
 the device is no longer present or operating properly.  Unlike
 the device is no longer present or operating properly.  Unlike
-autosuspend, there's no delay for an autoresume.
+autosuspend, there's no idle-delay for an autoresume.
 
 
 
 
 	Other parts of the driver interface
 	Other parts of the driver interface
 	-----------------------------------
 	-----------------------------------
 
 
+Drivers can enable autosuspend for their devices by calling
+
+	usb_enable_autosuspend(struct usb_device *udev);
+
+in their probe() routine, if they know that the device is capable of
+suspending and resuming correctly.  This is exactly equivalent to
+writing "auto" to the device's power/level attribute.  Likewise,
+drivers can disable autosuspend by calling
+
+	usb_disable_autosuspend(struct usb_device *udev);
+
+This is exactly the same as writing "on" to the power/level attribute.
+
 Sometimes a driver needs to make sure that remote wakeup is enabled
 Sometimes a driver needs to make sure that remote wakeup is enabled
 during autosuspend.  For example, there's not much point
 during autosuspend.  For example, there's not much point
 autosuspending a keyboard if the user can't cause the keyboard to do a
 autosuspending a keyboard if the user can't cause the keyboard to do a
@@ -395,26 +412,27 @@ 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
 Normally a driver would set this flag in its probe method, at which
 time the device is guaranteed not to be autosuspended.)
 time the device is guaranteed not to be autosuspended.)
 
 
-The synchronous 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:
+If a driver does its I/O asynchronously in interrupt context, it
+should call usb_autopm_get_interface_async() before starting output and
+usb_autopm_put_interface_async() when the output queue drains.  When
+it receives an input event, it should call
 
 
 	usb_mark_last_busy(struct usb_device *udev);
 	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.
+in the event handler.  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.  Most
+of the usb_autopm_* routines will also set the last_busy field to the
+current time.
+
+Asynchronous operation is always subject to races.  For example, a
+driver may call one of the usb_autopm_*_interface_async() routines at
+a time when the core has just finished deciding the device has been
+idle for long enough but not yet gotten around to calling the driver's
+suspend method.  The suspend method must be responsible for
+synchronizing with the output request routine and the URB completion
+handler; it should cause autosuspends to fail with -EBUSY if the
+driver needs to use the device.
 
 
 External suspend calls should never be allowed to fail in this way,
 External suspend calls should never be allowed to fail in this way,
 only autosuspend calls.  The driver can tell them apart by checking
 only autosuspend calls.  The driver can tell them apart by checking
@@ -422,75 +440,23 @@ the PM_EVENT_AUTO bit in the message.event argument to the suspend
 method; this bit will be set for internal PM events (autosuspend) and
 method; this bit will be set for internal PM events (autosuspend) and
 clear for external PM events.
 clear 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 (i.e., usb_mark_last_busy()) 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
-	--------------------
+	Mutual exclusion
+	----------------
 
 
-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.
+For external events -- but not necessarily for autosuspend or
+autoresume -- the device semaphore (udev->dev.sem) will be held when a
+suspend or resume method is called.  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 autosuspend/autoresume events as well.
 
 
 If a driver wants to block all suspend/resume calls during some
 If a driver wants to block all suspend/resume calls during some
-critical section, it can simply acquire udev->pm_mutex. Note that
-calls to resume may be triggered indirectly. Block IO due to memory
-allocations can make the vm subsystem resume a device. Thus while
-holding this lock you must not allocate memory with GFP_KERNEL or
-GFP_NOFS.
-
-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.
+critical section, the best way is to lock the device and call
+usb_autopm_get_interface() (and do the reverse at the end of the
+critical section).  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?)
 
 
 
 
 	Interaction between dynamic PM and system PM
 	Interaction between dynamic PM and system PM
@@ -499,22 +465,11 @@ synchronize with the driver's I/O activities in some other way.
 Dynamic power management and system power management can interact in
 Dynamic power management and system power management can interact in
 a couple of ways.
 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.)
+Firstly, a device may already be 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.  But this theory may not work out well in practice; over time
+the kernel's behavior in this regard has changed.
 
 
 Secondly, a dynamic power-management event may occur as a system
 Secondly, a dynamic power-management event may occur as a system
 suspend is underway.  The window for this is short, since system
 suspend is underway.  The window for this is short, since system

+ 10 - 1
arch/arm/configs/rx51_defconfig

@@ -445,6 +445,8 @@ CONFIG_IP_NF_FILTER=m
 # CONFIG_LAPB is not set
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_WAN_ROUTER is not set
+CONFIG_PHONET=y
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED is not set
 # CONFIG_NET_SCHED is not set
 # CONFIG_DCB is not set
 # CONFIG_DCB is not set
 
 
@@ -1325,27 +1327,34 @@ CONFIG_USB_GADGET_SELECTED=y
 # CONFIG_USB_GADGET_LH7A40X is not set
 # CONFIG_USB_GADGET_LH7A40X is not set
 # CONFIG_USB_GADGET_OMAP is not set
 # CONFIG_USB_GADGET_OMAP is not set
 # CONFIG_USB_GADGET_PXA25X is not set
 # CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_R8A66597 is not set
 # CONFIG_USB_GADGET_PXA27X is not set
 # CONFIG_USB_GADGET_PXA27X is not set
-# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_S3C_HSOTG is not set
 # CONFIG_USB_GADGET_IMX is not set
 # CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
 # CONFIG_USB_GADGET_M66592 is not set
 # CONFIG_USB_GADGET_M66592 is not set
 # CONFIG_USB_GADGET_AMD5536UDC is not set
 # CONFIG_USB_GADGET_AMD5536UDC is not set
 # CONFIG_USB_GADGET_FSL_QE is not set
 # CONFIG_USB_GADGET_FSL_QE is not set
 # CONFIG_USB_GADGET_CI13XXX is not set
 # CONFIG_USB_GADGET_CI13XXX is not set
 # CONFIG_USB_GADGET_NET2280 is not set
 # CONFIG_USB_GADGET_NET2280 is not set
 # CONFIG_USB_GADGET_GOKU is not set
 # CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LANGWELL is not set
 # CONFIG_USB_GADGET_DUMMY_HCD is not set
 # CONFIG_USB_GADGET_DUMMY_HCD is not set
 CONFIG_USB_GADGET_DUALSPEED=y
 CONFIG_USB_GADGET_DUALSPEED=y
 CONFIG_USB_ZERO=m
 CONFIG_USB_ZERO=m
 # CONFIG_USB_ZERO_HNPTEST is not set
 # CONFIG_USB_ZERO_HNPTEST is not set
+# CONFIG_USB_AUDIO is not set
 # CONFIG_USB_ETH is not set
 # CONFIG_USB_ETH is not set
 # CONFIG_USB_GADGETFS is not set
 # CONFIG_USB_GADGETFS is not set
 CONFIG_USB_FILE_STORAGE=m
 CONFIG_USB_FILE_STORAGE=m
 # CONFIG_USB_FILE_STORAGE_TEST is not set
 # CONFIG_USB_FILE_STORAGE_TEST is not set
+# CONFIG_USB_MASS_STORAGE is not set
 # CONFIG_USB_G_SERIAL is not set
 # CONFIG_USB_G_SERIAL is not set
 # CONFIG_USB_MIDI_GADGET is not set
 # CONFIG_USB_MIDI_GADGET is not set
 # CONFIG_USB_G_PRINTER is not set
 # CONFIG_USB_G_PRINTER is not set
 # CONFIG_USB_CDC_COMPOSITE is not set
 # CONFIG_USB_CDC_COMPOSITE is not set
+CONFIG_USB_G_NOKIA=m
+# CONFIG_USB_G_MULTI is not set
 
 
 #
 #
 # OTG and related infrastructure
 # OTG and related infrastructure

+ 54 - 26
arch/arm/mach-mx2/devices.c

@@ -31,6 +31,7 @@
 #include <linux/init.h>
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
+#include <linux/dma-mapping.h>
 
 
 #include <mach/irqs.h>
 #include <mach/irqs.h>
 #include <mach/hardware.h>
 #include <mach/hardware.h>
@@ -292,7 +293,7 @@ struct platform_device mxc_fb_device = {
 	.num_resources = ARRAY_SIZE(mxc_fb),
 	.num_resources = ARRAY_SIZE(mxc_fb),
 	.resource = mxc_fb,
 	.resource = mxc_fb,
 	.dev = {
 	.dev = {
-		.coherent_dma_mask = 0xFFFFFFFF,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
 	},
 	},
 };
 };
 
 
@@ -395,17 +396,17 @@ static struct resource mxc_sdhc1_resources[] = {
 	},
 	},
 };
 };
 
 
-static u64 mxc_sdhc1_dmamask = 0xffffffffUL;
+static u64 mxc_sdhc1_dmamask = DMA_BIT_MASK(32);
 
 
 struct platform_device mxc_sdhc_device0 = {
 struct platform_device mxc_sdhc_device0 = {
-       .name           = "mxc-mmc",
-       .id             = 0,
-       .dev            = {
-               .dma_mask = &mxc_sdhc1_dmamask,
-               .coherent_dma_mask = 0xffffffff,
-       },
-       .num_resources  = ARRAY_SIZE(mxc_sdhc1_resources),
-       .resource       = mxc_sdhc1_resources,
+	.name           = "mxc-mmc",
+	.id             = 0,
+	.dev            = {
+		.dma_mask = &mxc_sdhc1_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+	.num_resources  = ARRAY_SIZE(mxc_sdhc1_resources),
+	.resource       = mxc_sdhc1_resources,
 };
 };
 
 
 static struct resource mxc_sdhc2_resources[] = {
 static struct resource mxc_sdhc2_resources[] = {
@@ -424,17 +425,17 @@ static struct resource mxc_sdhc2_resources[] = {
 	},
 	},
 };
 };
 
 
-static u64 mxc_sdhc2_dmamask = 0xffffffffUL;
+static u64 mxc_sdhc2_dmamask = DMA_BIT_MASK(32);
 
 
 struct platform_device mxc_sdhc_device1 = {
 struct platform_device mxc_sdhc_device1 = {
-       .name           = "mxc-mmc",
-       .id             = 1,
-       .dev            = {
-               .dma_mask = &mxc_sdhc2_dmamask,
-               .coherent_dma_mask = 0xffffffff,
-       },
-       .num_resources  = ARRAY_SIZE(mxc_sdhc2_resources),
-       .resource       = mxc_sdhc2_resources,
+	.name           = "mxc-mmc",
+	.id             = 1,
+	.dev            = {
+		.dma_mask = &mxc_sdhc2_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+	.num_resources  = ARRAY_SIZE(mxc_sdhc2_resources),
+	.resource       = mxc_sdhc2_resources,
 };
 };
 
 
 #ifdef CONFIG_MACH_MX27
 #ifdef CONFIG_MACH_MX27
@@ -450,7 +451,7 @@ static struct resource otg_resources[] = {
 	},
 	},
 };
 };
 
 
-static u64 otg_dmamask = 0xffffffffUL;
+static u64 otg_dmamask = DMA_BIT_MASK(32);
 
 
 /* OTG gadget device */
 /* OTG gadget device */
 struct platform_device mxc_otg_udc_device = {
 struct platform_device mxc_otg_udc_device = {
@@ -458,7 +459,7 @@ struct platform_device mxc_otg_udc_device = {
 	.id		= -1,
 	.id		= -1,
 	.dev		= {
 	.dev		= {
 		.dma_mask		= &otg_dmamask,
 		.dma_mask		= &otg_dmamask,
-		.coherent_dma_mask	= 0xffffffffUL,
+		.coherent_dma_mask	= DMA_BIT_MASK(32),
 	},
 	},
 	.resource	= otg_resources,
 	.resource	= otg_resources,
 	.num_resources	= ARRAY_SIZE(otg_resources),
 	.num_resources	= ARRAY_SIZE(otg_resources),
@@ -469,7 +470,7 @@ struct platform_device mxc_otg_host = {
 	.name = "mxc-ehci",
 	.name = "mxc-ehci",
 	.id = 0,
 	.id = 0,
 	.dev = {
 	.dev = {
-		.coherent_dma_mask = 0xffffffff,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
 		.dma_mask = &otg_dmamask,
 		.dma_mask = &otg_dmamask,
 	},
 	},
 	.resource = otg_resources,
 	.resource = otg_resources,
@@ -478,7 +479,7 @@ struct platform_device mxc_otg_host = {
 
 
 /* USB host 1 */
 /* USB host 1 */
 
 
-static u64 usbh1_dmamask = 0xffffffffUL;
+static u64 usbh1_dmamask = DMA_BIT_MASK(32);
 
 
 static struct resource mxc_usbh1_resources[] = {
 static struct resource mxc_usbh1_resources[] = {
 	{
 	{
@@ -496,7 +497,7 @@ struct platform_device mxc_usbh1 = {
 	.name = "mxc-ehci",
 	.name = "mxc-ehci",
 	.id = 1,
 	.id = 1,
 	.dev = {
 	.dev = {
-		.coherent_dma_mask = 0xffffffff,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
 		.dma_mask = &usbh1_dmamask,
 		.dma_mask = &usbh1_dmamask,
 	},
 	},
 	.resource = mxc_usbh1_resources,
 	.resource = mxc_usbh1_resources,
@@ -504,7 +505,7 @@ struct platform_device mxc_usbh1 = {
 };
 };
 
 
 /* USB host 2 */
 /* USB host 2 */
-static u64 usbh2_dmamask = 0xffffffffUL;
+static u64 usbh2_dmamask = DMA_BIT_MASK(32);
 
 
 static struct resource mxc_usbh2_resources[] = {
 static struct resource mxc_usbh2_resources[] = {
 	{
 	{
@@ -522,7 +523,7 @@ struct platform_device mxc_usbh2 = {
 	.name = "mxc-ehci",
 	.name = "mxc-ehci",
 	.id = 2,
 	.id = 2,
 	.dev = {
 	.dev = {
-		.coherent_dma_mask = 0xffffffff,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
 		.dma_mask = &usbh2_dmamask,
 		.dma_mask = &usbh2_dmamask,
 	},
 	},
 	.resource = mxc_usbh2_resources,
 	.resource = mxc_usbh2_resources,
@@ -642,3 +643,30 @@ int __init mxc_register_gpios(void)
 {
 {
 	return mxc_gpio_init(imx_gpio_ports, ARRAY_SIZE(imx_gpio_ports));
 	return mxc_gpio_init(imx_gpio_ports, ARRAY_SIZE(imx_gpio_ports));
 }
 }
+
+#ifdef CONFIG_MACH_MX21
+static struct resource mx21_usbhc_resources[] = {
+	{
+		.start	= USBOTG_BASE_ADDR,
+		.end	= USBOTG_BASE_ADDR + 0x1FFF,
+		.flags	= IORESOURCE_MEM,
+	},
+	{
+		.start		= MXC_INT_USBHOST,
+		.end		= MXC_INT_USBHOST,
+		.flags		= IORESOURCE_IRQ,
+	},
+};
+
+struct platform_device mx21_usbhc_device = {
+	.name		= "imx21-hcd",
+	.id		= 0,
+	.dev		= {
+		.dma_mask = &mx21_usbhc_device.dev.coherent_dma_mask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+	.num_resources	= ARRAY_SIZE(mx21_usbhc_resources),
+	.resource	= mx21_usbhc_resources,
+};
+#endif
+

+ 1 - 0
arch/arm/mach-mx2/devices.h

@@ -26,5 +26,6 @@ extern struct platform_device mxc_usbh2;
 extern struct platform_device mxc_spi_device0;
 extern struct platform_device mxc_spi_device0;
 extern struct platform_device mxc_spi_device1;
 extern struct platform_device mxc_spi_device1;
 extern struct platform_device mxc_spi_device2;
 extern struct platform_device mxc_spi_device2;
+extern struct platform_device mx21_usbhc_device;
 extern struct platform_device imx_ssi_device0;
 extern struct platform_device imx_ssi_device0;
 extern struct platform_device imx_ssi_device1;
 extern struct platform_device imx_ssi_device1;

+ 38 - 0
arch/arm/plat-mxc/include/mach/mx21-usbhost.h

@@ -0,0 +1,38 @@
+/*
+ *	Copyright (C) 2009 Martin Fuzzey <mfuzzey@gmail.com>
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ *	This program is distributed in the hope that it will be useful,
+ *	but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *	GNU General Public License for more details.
+ */
+
+#ifndef __ASM_ARCH_MX21_USBH
+#define __ASM_ARCH_MX21_USBH
+
+enum mx21_usbh_xcvr {
+	/* Values below as used by hardware (HWMODE register) */
+	MX21_USBXCVR_TXDIF_RXDIF = 0,
+	MX21_USBXCVR_TXDIF_RXSE = 1,
+	MX21_USBXCVR_TXSE_RXDIF = 2,
+	MX21_USBXCVR_TXSE_RXSE = 3,
+};
+
+struct mx21_usbh_platform_data {
+	enum mx21_usbh_xcvr host_xcvr; /* tranceiver mode host 1,2 ports */
+	enum mx21_usbh_xcvr otg_xcvr; /* tranceiver mode otg (as host) port */
+	u16 	enable_host1:1,
+		enable_host2:1,
+		enable_otg_host:1, /* enable "OTG" port (as host) */
+		host1_xcverless:1, /* traceiverless host1 port */
+		host1_txenoe:1, /* output enable host1 transmit enable */
+		otg_ext_xcvr:1, /* external tranceiver for OTG port */
+		unused:10;
+};
+
+#endif /* __ASM_ARCH_MX21_USBH */

+ 5 - 2
arch/avr32/mach-at32ap/at32ap700x.c

@@ -1770,10 +1770,13 @@ at32_add_device_usba(unsigned int id, struct usba_platform_data *data)
 					  ARRAY_SIZE(usba0_resource)))
 					  ARRAY_SIZE(usba0_resource)))
 		goto out_free_pdev;
 		goto out_free_pdev;
 
 
-	if (data)
+	if (data) {
 		usba_data.pdata.vbus_pin = data->vbus_pin;
 		usba_data.pdata.vbus_pin = data->vbus_pin;
-	else
+		usba_data.pdata.vbus_pin_inverted = data->vbus_pin_inverted;
+	} else {
 		usba_data.pdata.vbus_pin = -EINVAL;
 		usba_data.pdata.vbus_pin = -EINVAL;
+		usba_data.pdata.vbus_pin_inverted = -EINVAL;
+	}
 
 
 	data = &usba_data.pdata;
 	data = &usba_data.pdata;
 	data->num_ep = ARRAY_SIZE(at32_usba_ep);
 	data->num_ep = ARRAY_SIZE(at32_usba_ep);

+ 6 - 5
drivers/char/tty_buffer.c

@@ -231,9 +231,10 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
 EXPORT_SYMBOL_GPL(tty_buffer_request_room);
 EXPORT_SYMBOL_GPL(tty_buffer_request_room);
 
 
 /**
 /**
- *	tty_insert_flip_string	-	Add characters to the tty buffer
+ *	tty_insert_flip_string_fixed_flag - Add characters to the tty buffer
  *	@tty: tty structure
  *	@tty: tty structure
  *	@chars: characters
  *	@chars: characters
+ *	@flag: flag value for each character
  *	@size: size
  *	@size: size
  *
  *
  *	Queue a series of bytes to the tty buffering. All the characters
  *	Queue a series of bytes to the tty buffering. All the characters
@@ -242,8 +243,8 @@ EXPORT_SYMBOL_GPL(tty_buffer_request_room);
  *	Locking: Called functions may take tty->buf.lock
  *	Locking: Called functions may take tty->buf.lock
  */
  */
 
 
-int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
-				size_t size)
+int tty_insert_flip_string_fixed_flag(struct tty_struct *tty,
+		const unsigned char *chars, char flag, size_t size)
 {
 {
 	int copied = 0;
 	int copied = 0;
 	do {
 	do {
@@ -254,7 +255,7 @@ int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
 		if (unlikely(space == 0))
 		if (unlikely(space == 0))
 			break;
 			break;
 		memcpy(tb->char_buf_ptr + tb->used, chars, space);
 		memcpy(tb->char_buf_ptr + tb->used, chars, space);
-		memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
+		memset(tb->flag_buf_ptr + tb->used, flag, space);
 		tb->used += space;
 		tb->used += space;
 		copied += space;
 		copied += space;
 		chars += space;
 		chars += space;
@@ -263,7 +264,7 @@ int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
 	} while (unlikely(size > copied));
 	} while (unlikely(size > copied));
 	return copied;
 	return copied;
 }
 }
-EXPORT_SYMBOL(tty_insert_flip_string);
+EXPORT_SYMBOL(tty_insert_flip_string_fixed_flag);
 
 
 /**
 /**
  *	tty_insert_flip_string_flags	-	Add characters to the tty buffer
  *	tty_insert_flip_string_flags	-	Add characters to the tty buffer

+ 5 - 2
drivers/hid/usbhid/hiddev.c

@@ -265,9 +265,10 @@ static int hiddev_release(struct inode * inode, struct file * file)
 static int hiddev_open(struct inode *inode, struct file *file)
 static int hiddev_open(struct inode *inode, struct file *file)
 {
 {
 	struct hiddev_list *list;
 	struct hiddev_list *list;
-	int res;
+	int res, i;
 
 
-	int i = iminor(inode) - HIDDEV_MINOR_BASE;
+	lock_kernel();
+	i = iminor(inode) - HIDDEV_MINOR_BASE;
 
 
 	if (i >= HIDDEV_MINORS || i < 0 || !hiddev_table[i])
 	if (i >= HIDDEV_MINORS || i < 0 || !hiddev_table[i])
 		return -ENODEV;
 		return -ENODEV;
@@ -313,10 +314,12 @@ static int hiddev_open(struct inode *inode, struct file *file)
 			usbhid_open(hid);
 			usbhid_open(hid);
 		}
 		}
 
 
+	unlock_kernel();
 	return 0;
 	return 0;
 bail:
 bail:
 	file->private_data = NULL;
 	file->private_data = NULL;
 	kfree(list);
 	kfree(list);
+	unlock_kernel();
 	return res;
 	return res;
 }
 }
 
 

+ 7 - 1
drivers/media/video/dabusb.c

@@ -616,10 +616,12 @@ static int dabusb_open (struct inode *inode, struct file *file)
 {
 {
 	int devnum = iminor(inode);
 	int devnum = iminor(inode);
 	pdabusb_t s;
 	pdabusb_t s;
+	int r;
 
 
 	if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB))
 	if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB))
 		return -EIO;
 		return -EIO;
 
 
+	lock_kernel();
 	s = &dabusb[devnum - DABUSB_MINOR];
 	s = &dabusb[devnum - DABUSB_MINOR];
 
 
 	dbg("dabusb_open");
 	dbg("dabusb_open");
@@ -634,6 +636,7 @@ static int dabusb_open (struct inode *inode, struct file *file)
 		msleep_interruptible(500);
 		msleep_interruptible(500);
 
 
 		if (signal_pending (current)) {
 		if (signal_pending (current)) {
+			unlock_kernel();
 			return -EAGAIN;
 			return -EAGAIN;
 		}
 		}
 		mutex_lock(&s->mutex);
 		mutex_lock(&s->mutex);
@@ -641,6 +644,7 @@ static int dabusb_open (struct inode *inode, struct file *file)
 	if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
 	if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
 		mutex_unlock(&s->mutex);
 		mutex_unlock(&s->mutex);
 		dev_err(&s->usbdev->dev, "set_interface failed\n");
 		dev_err(&s->usbdev->dev, "set_interface failed\n");
+		unlock_kernel();
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
 	s->opened = 1;
 	s->opened = 1;
@@ -649,7 +653,9 @@ static int dabusb_open (struct inode *inode, struct file *file)
 	file->f_pos = 0;
 	file->f_pos = 0;
 	file->private_data = s;
 	file->private_data = s;
 
 
-	return nonseekable_open(inode, file);
+	r = nonseekable_open(inode, file);
+	unlock_kernel();
+	return r;
 }
 }
 
 
 static int dabusb_release (struct inode *inode, struct file *file)
 static int dabusb_release (struct inode *inode, struct file *file)

+ 1 - 1
drivers/staging/usbip/vhci_sysfs.c

@@ -144,7 +144,7 @@ static int valid_args(__u32 rhport, enum usb_device_speed speed)
 	case USB_SPEED_LOW:
 	case USB_SPEED_LOW:
 	case USB_SPEED_FULL:
 	case USB_SPEED_FULL:
 	case USB_SPEED_HIGH:
 	case USB_SPEED_HIGH:
-	case USB_SPEED_VARIABLE:
+	case USB_SPEED_WIRELESS:
 		break;
 		break;
 	default:
 	default:
 		usbip_uerr("speed %d\n", speed);
 		usbip_uerr("speed %d\n", speed);

+ 2 - 0
drivers/usb/Kconfig

@@ -21,6 +21,7 @@ config USB_ARCH_HAS_HCD
 	default y if USB_ARCH_HAS_EHCI
 	default y if USB_ARCH_HAS_EHCI
 	default y if PCMCIA && !M32R			# sl811_cs
 	default y if PCMCIA && !M32R			# sl811_cs
 	default y if ARM				# SL-811
 	default y if ARM				# SL-811
+	default y if BLACKFIN				# SL-811
 	default y if SUPERH				# r8a66597-hcd
 	default y if SUPERH				# r8a66597-hcd
 	default PCI
 	default PCI
 
 
@@ -39,6 +40,7 @@ config USB_ARCH_HAS_OHCI
 	default y if ARCH_PNX4008 && I2C
 	default y if ARCH_PNX4008 && I2C
 	default y if MFD_TC6393XB
 	default y if MFD_TC6393XB
 	default y if ARCH_W90X900
 	default y if ARCH_W90X900
+	default y if ARCH_DAVINCI_DA8XX
 	# PPC:
 	# PPC:
 	default y if STB03xxx
 	default y if STB03xxx
 	default y if PPC_MPC52xx
 	default y if PPC_MPC52xx

+ 1 - 0
drivers/usb/Makefile

@@ -21,6 +21,7 @@ obj-$(CONFIG_USB_U132_HCD)	+= host/
 obj-$(CONFIG_USB_R8A66597_HCD)	+= host/
 obj-$(CONFIG_USB_R8A66597_HCD)	+= host/
 obj-$(CONFIG_USB_HWA_HCD)	+= host/
 obj-$(CONFIG_USB_HWA_HCD)	+= host/
 obj-$(CONFIG_USB_ISP1760_HCD)	+= host/
 obj-$(CONFIG_USB_ISP1760_HCD)	+= host/
+obj-$(CONFIG_USB_IMX21_HCD)	+= host/
 
 
 obj-$(CONFIG_USB_C67X00_HCD)	+= c67x00/
 obj-$(CONFIG_USB_C67X00_HCD)	+= c67x00/
 
 

+ 137 - 55
drivers/usb/atm/cxacru.c

@@ -5,6 +5,7 @@
  *  Copyright (C) 2004 David Woodhouse, Duncan Sands, Roman Kagan
  *  Copyright (C) 2004 David Woodhouse, Duncan Sands, Roman Kagan
  *  Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru)
  *  Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru)
  *  Copyright (C) 2007 Simon Arlott
  *  Copyright (C) 2007 Simon Arlott
+ *  Copyright (C) 2009 Simon Arlott
  *
  *
  *  This program is free software; you can redistribute it and/or modify it
  *  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
  *  under the terms of the GNU General Public License as published by the Free
@@ -43,7 +44,7 @@
 #include "usbatm.h"
 #include "usbatm.h"
 
 
 #define DRIVER_AUTHOR	"Roman Kagan, David Woodhouse, Duncan Sands, Simon Arlott"
 #define DRIVER_AUTHOR	"Roman Kagan, David Woodhouse, Duncan Sands, Simon Arlott"
-#define DRIVER_VERSION	"0.3"
+#define DRIVER_VERSION	"0.4"
 #define DRIVER_DESC	"Conexant AccessRunner ADSL USB modem driver"
 #define DRIVER_DESC	"Conexant AccessRunner ADSL USB modem driver"
 
 
 static const char cxacru_driver_name[] = "cxacru";
 static const char cxacru_driver_name[] = "cxacru";
@@ -52,6 +53,7 @@ static const char cxacru_driver_name[] = "cxacru";
 #define CXACRU_EP_DATA		0x02	/* Bulk in/out */
 #define CXACRU_EP_DATA		0x02	/* Bulk in/out */
 
 
 #define CMD_PACKET_SIZE		64	/* Should be maxpacket(ep)? */
 #define CMD_PACKET_SIZE		64	/* Should be maxpacket(ep)? */
+#define CMD_MAX_CONFIG		((CMD_PACKET_SIZE / 4 - 1) / 2)
 
 
 /* Addresses */
 /* Addresses */
 #define PLLFCLK_ADDR	0x00350068
 #define PLLFCLK_ADDR	0x00350068
@@ -105,6 +107,26 @@ enum cxacru_cm_request {
 	CM_REQUEST_MAX,
 	CM_REQUEST_MAX,
 };
 };
 
 
+/* commands for interaction with the flash memory
+ *
+ * read:  response is the contents of the first 60 bytes of flash memory
+ * write: request contains the 60 bytes of data to write to flash memory
+ *        response is the contents of the first 60 bytes of flash memory
+ *
+ * layout: PP PP VV VV  MM MM MM MM  MM MM ?? ??  SS SS SS SS  SS SS SS SS
+ *         SS SS SS SS  SS SS SS SS  00 00 00 00  00 00 00 00  00 00 00 00
+ *         00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00  00 00 00 00
+ *
+ *   P: le16  USB Product ID
+ *   V: le16  USB Vendor ID
+ *   M: be48  MAC Address
+ *   S: le16  ASCII Serial Number
+ */
+enum cxacru_cm_flash {
+	CM_FLASH_READ = 0xa1,
+	CM_FLASH_WRITE = 0xa2
+};
+
 /* reply codes to the commands above */
 /* reply codes to the commands above */
 enum cxacru_cm_status {
 enum cxacru_cm_status {
 	CM_STATUS_UNDEFINED,
 	CM_STATUS_UNDEFINED,
@@ -196,23 +218,32 @@ static DEVICE_ATTR(_name, S_IRUGO, cxacru_sysfs_show_##_name, NULL)
 static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, \
 static DEVICE_ATTR(_name, S_IWUSR | S_IRUGO, \
 	cxacru_sysfs_show_##_name, cxacru_sysfs_store_##_name)
 	cxacru_sysfs_show_##_name, cxacru_sysfs_store_##_name)
 
 
+#define CXACRU_SET_INIT(_name) \
+static DEVICE_ATTR(_name, S_IWUSR, \
+	NULL, cxacru_sysfs_store_##_name)
+
 #define CXACRU_ATTR_INIT(_value, _type, _name) \
 #define CXACRU_ATTR_INIT(_value, _type, _name) \
 static ssize_t cxacru_sysfs_show_##_name(struct device *dev, \
 static ssize_t cxacru_sysfs_show_##_name(struct device *dev, \
 	struct device_attribute *attr, char *buf) \
 	struct device_attribute *attr, char *buf) \
 { \
 { \
-	struct usb_interface *intf = to_usb_interface(dev); \
-	struct usbatm_data *usbatm_instance = usb_get_intfdata(intf); \
-	struct cxacru_data *instance = usbatm_instance->driver_data; \
+	struct cxacru_data *instance = to_usbatm_driver_data(\
+		to_usb_interface(dev)); \
+\
+	if (instance == NULL) \
+		return -ENODEV; \
+\
 	return cxacru_sysfs_showattr_##_type(instance->card_info[_value], buf); \
 	return cxacru_sysfs_showattr_##_type(instance->card_info[_value], buf); \
 } \
 } \
 CXACRU__ATTR_INIT(_name)
 CXACRU__ATTR_INIT(_name)
 
 
 #define CXACRU_ATTR_CREATE(_v, _t, _name) CXACRU_DEVICE_CREATE_FILE(_name)
 #define CXACRU_ATTR_CREATE(_v, _t, _name) CXACRU_DEVICE_CREATE_FILE(_name)
 #define CXACRU_CMD_CREATE(_name)          CXACRU_DEVICE_CREATE_FILE(_name)
 #define CXACRU_CMD_CREATE(_name)          CXACRU_DEVICE_CREATE_FILE(_name)
+#define CXACRU_SET_CREATE(_name)          CXACRU_DEVICE_CREATE_FILE(_name)
 #define CXACRU__ATTR_CREATE(_name)        CXACRU_DEVICE_CREATE_FILE(_name)
 #define CXACRU__ATTR_CREATE(_name)        CXACRU_DEVICE_CREATE_FILE(_name)
 
 
 #define CXACRU_ATTR_REMOVE(_v, _t, _name) CXACRU_DEVICE_REMOVE_FILE(_name)
 #define CXACRU_ATTR_REMOVE(_v, _t, _name) CXACRU_DEVICE_REMOVE_FILE(_name)
 #define CXACRU_CMD_REMOVE(_name)          CXACRU_DEVICE_REMOVE_FILE(_name)
 #define CXACRU_CMD_REMOVE(_name)          CXACRU_DEVICE_REMOVE_FILE(_name)
+#define CXACRU_SET_REMOVE(_name)          CXACRU_DEVICE_REMOVE_FILE(_name)
 #define CXACRU__ATTR_REMOVE(_name)        CXACRU_DEVICE_REMOVE_FILE(_name)
 #define CXACRU__ATTR_REMOVE(_name)        CXACRU_DEVICE_REMOVE_FILE(_name)
 
 
 static ssize_t cxacru_sysfs_showattr_u32(u32 value, char *buf)
 static ssize_t cxacru_sysfs_showattr_u32(u32 value, char *buf)
@@ -267,12 +298,12 @@ static ssize_t cxacru_sysfs_showattr_LINE(u32 value, char *buf)
 static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf)
 static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf)
 {
 {
 	static char *str[] = {
 	static char *str[] = {
-			NULL,
+			"",
 			"ANSI T1.413",
 			"ANSI T1.413",
 			"ITU-T G.992.1 (G.DMT)",
 			"ITU-T G.992.1 (G.DMT)",
 			"ITU-T G.992.2 (G.LITE)"
 			"ITU-T G.992.2 (G.LITE)"
 	};
 	};
-	if (unlikely(value >= ARRAY_SIZE(str) || str[value] == NULL))
+	if (unlikely(value >= ARRAY_SIZE(str)))
 		return snprintf(buf, PAGE_SIZE, "%u\n", value);
 		return snprintf(buf, PAGE_SIZE, "%u\n", value);
 	return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
 	return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
 }
 }
@@ -288,22 +319,28 @@ static ssize_t cxacru_sysfs_showattr_MODU(u32 value, char *buf)
 static ssize_t cxacru_sysfs_show_mac_address(struct device *dev,
 static ssize_t cxacru_sysfs_show_mac_address(struct device *dev,
 	struct device_attribute *attr, char *buf)
 	struct device_attribute *attr, char *buf)
 {
 {
-	struct usb_interface *intf = to_usb_interface(dev);
-	struct usbatm_data *usbatm_instance = usb_get_intfdata(intf);
-	struct atm_dev *atm_dev = usbatm_instance->atm_dev;
+	struct cxacru_data *instance = to_usbatm_driver_data(
+			to_usb_interface(dev));
 
 
-	return snprintf(buf, PAGE_SIZE, "%pM\n", atm_dev->esi);
+	if (instance == NULL || instance->usbatm->atm_dev == NULL)
+		return -ENODEV;
+
+	return snprintf(buf, PAGE_SIZE, "%pM\n",
+		instance->usbatm->atm_dev->esi);
 }
 }
 
 
 static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev,
 static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev,
 	struct device_attribute *attr, char *buf)
 	struct device_attribute *attr, char *buf)
 {
 {
-	struct usb_interface *intf = to_usb_interface(dev);
-	struct usbatm_data *usbatm_instance = usb_get_intfdata(intf);
-	struct cxacru_data *instance = usbatm_instance->driver_data;
-	u32 value = instance->card_info[CXINF_LINE_STARTABLE];
-
 	static char *str[] = { "running", "stopped" };
 	static char *str[] = { "running", "stopped" };
+	struct cxacru_data *instance = to_usbatm_driver_data(
+			to_usb_interface(dev));
+	u32 value;
+
+	if (instance == NULL)
+		return -ENODEV;
+
+	value = instance->card_info[CXINF_LINE_STARTABLE];
 	if (unlikely(value >= ARRAY_SIZE(str)))
 	if (unlikely(value >= ARRAY_SIZE(str)))
 		return snprintf(buf, PAGE_SIZE, "%u\n", value);
 		return snprintf(buf, PAGE_SIZE, "%u\n", value);
 	return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
 	return snprintf(buf, PAGE_SIZE, "%s\n", str[value]);
@@ -312,9 +349,8 @@ static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev,
 static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
 static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
 	struct device_attribute *attr, const char *buf, size_t count)
 	struct device_attribute *attr, const char *buf, size_t count)
 {
 {
-	struct usb_interface *intf = to_usb_interface(dev);
-	struct usbatm_data *usbatm_instance = usb_get_intfdata(intf);
-	struct cxacru_data *instance = usbatm_instance->driver_data;
+	struct cxacru_data *instance = to_usbatm_driver_data(
+			to_usb_interface(dev));
 	int ret;
 	int ret;
 	int poll = -1;
 	int poll = -1;
 	char str_cmd[8];
 	char str_cmd[8];
@@ -328,13 +364,16 @@ static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
 		return -EINVAL;
 		return -EINVAL;
 	ret = 0;
 	ret = 0;
 
 
+	if (instance == NULL)
+		return -ENODEV;
+
 	if (mutex_lock_interruptible(&instance->adsl_state_serialize))
 	if (mutex_lock_interruptible(&instance->adsl_state_serialize))
 		return -ERESTARTSYS;
 		return -ERESTARTSYS;
 
 
 	if (!strcmp(str_cmd, "stop") || !strcmp(str_cmd, "restart")) {
 	if (!strcmp(str_cmd, "stop") || !strcmp(str_cmd, "restart")) {
 		ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_STOP, NULL, 0, NULL, 0);
 		ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_STOP, NULL, 0, NULL, 0);
 		if (ret < 0) {
 		if (ret < 0) {
-			atm_err(usbatm_instance, "change adsl state:"
+			atm_err(instance->usbatm, "change adsl state:"
 				" CHIP_ADSL_LINE_STOP returned %d\n", ret);
 				" CHIP_ADSL_LINE_STOP returned %d\n", ret);
 
 
 			ret = -EIO;
 			ret = -EIO;
@@ -354,7 +393,7 @@ static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
 	if (!strcmp(str_cmd, "start") || !strcmp(str_cmd, "restart")) {
 	if (!strcmp(str_cmd, "start") || !strcmp(str_cmd, "restart")) {
 		ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0);
 		ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 0);
 		if (ret < 0) {
 		if (ret < 0) {
-			atm_err(usbatm_instance, "change adsl state:"
+			atm_err(instance->usbatm, "change adsl state:"
 				" CHIP_ADSL_LINE_START returned %d\n", ret);
 				" CHIP_ADSL_LINE_START returned %d\n", ret);
 
 
 			ret = -EIO;
 			ret = -EIO;
@@ -407,6 +446,72 @@ static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
 	return ret;
 	return ret;
 }
 }
 
 
+/* CM_REQUEST_CARD_DATA_GET times out, so no show attribute */
+
+static ssize_t cxacru_sysfs_store_adsl_config(struct device *dev,
+	struct device_attribute *attr, const char *buf, size_t count)
+{
+	struct cxacru_data *instance = to_usbatm_driver_data(
+			to_usb_interface(dev));
+	int len = strlen(buf);
+	int ret, pos, num;
+	__le32 data[CMD_PACKET_SIZE / 4];
+
+	if (!capable(CAP_NET_ADMIN))
+		return -EACCES;
+
+	if (instance == NULL)
+		return -ENODEV;
+
+	pos = 0;
+	num = 0;
+	while (pos < len) {
+		int tmp;
+		u32 index;
+		u32 value;
+
+		ret = sscanf(buf + pos, "%x=%x%n", &index, &value, &tmp);
+		if (ret < 2)
+			return -EINVAL;
+		if (index < 0 || index > 0x7f)
+			return -EINVAL;
+		pos += tmp;
+
+		/* skip trailing newline */
+		if (buf[pos] == '\n' && pos == len-1)
+			pos++;
+
+		data[num * 2 + 1] = cpu_to_le32(index);
+		data[num * 2 + 2] = cpu_to_le32(value);
+		num++;
+
+		/* send config values when data buffer is full
+		 * or no more data
+		 */
+		if (pos >= len || num >= CMD_MAX_CONFIG) {
+			char log[CMD_MAX_CONFIG * 12 + 1]; /* %02x=%08x */
+
+			data[0] = cpu_to_le32(num);
+			ret = cxacru_cm(instance, CM_REQUEST_CARD_DATA_SET,
+				(u8 *) data, 4 + num * 8, NULL, 0);
+			if (ret < 0) {
+				atm_err(instance->usbatm,
+					"set card data returned %d\n", ret);
+				return -EIO;
+			}
+
+			for (tmp = 0; tmp < num; tmp++)
+				snprintf(log + tmp*12, 13, " %02x=%08x",
+					le32_to_cpu(data[tmp * 2 + 1]),
+					le32_to_cpu(data[tmp * 2 + 2]));
+			atm_info(instance->usbatm, "config%s\n", log);
+			num = 0;
+		}
+	}
+
+	return len;
+}
+
 /*
 /*
  * All device attributes are included in CXACRU_ALL_FILES
  * All device attributes are included in CXACRU_ALL_FILES
  * so that the same list can be used multiple times:
  * so that the same list can be used multiple times:
@@ -442,7 +547,8 @@ CXACRU_ATTR_##_action(CXINF_MODULATION,                MODU, modulation); \
 CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND,              u32,  adsl_headend); \
 CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND,              u32,  adsl_headend); \
 CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND_ENVIRONMENT,  u32,  adsl_headend_environment); \
 CXACRU_ATTR_##_action(CXINF_ADSL_HEADEND_ENVIRONMENT,  u32,  adsl_headend_environment); \
 CXACRU_ATTR_##_action(CXINF_CONTROLLER_VERSION,        u32,  adsl_controller_version); \
 CXACRU_ATTR_##_action(CXINF_CONTROLLER_VERSION,        u32,  adsl_controller_version); \
-CXACRU_CMD_##_action(                                        adsl_state);
+CXACRU_CMD_##_action(                                        adsl_state); \
+CXACRU_SET_##_action(                                        adsl_config);
 
 
 CXACRU_ALL_FILES(INIT);
 CXACRU_ALL_FILES(INIT);
 
 
@@ -596,7 +702,7 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ
 	len = ret / 4;
 	len = ret / 4;
 	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 < 0 || l > stride || l > (len - offb) / 2) {
 			if (printk_ratelimit())
 			if (printk_ratelimit())
 				usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n",
 				usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n",
 					cm, l);
 					cm, l);
@@ -649,9 +755,6 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
 {
 {
 	struct cxacru_data *instance = usbatm_instance->driver_data;
 	struct cxacru_data *instance = usbatm_instance->driver_data;
 	struct usb_interface *intf = usbatm_instance->usb_intf;
 	struct usb_interface *intf = usbatm_instance->usb_intf;
-	/*
-	struct atm_dev *atm_dev = usbatm_instance->atm_dev;
-	*/
 	int ret;
 	int ret;
 	int start_polling = 1;
 	int start_polling = 1;
 
 
@@ -697,6 +800,9 @@ static int cxacru_atm_start(struct usbatm_data *usbatm_instance,
 	mutex_unlock(&instance->poll_state_serialize);
 	mutex_unlock(&instance->poll_state_serialize);
 	mutex_unlock(&instance->adsl_state_serialize);
 	mutex_unlock(&instance->adsl_state_serialize);
 
 
+	printk(KERN_INFO "%s%d: %s %pM\n", atm_dev->type, atm_dev->number,
+			usbatm_instance->description, atm_dev->esi);
+
 	if (start_polling)
 	if (start_polling)
 		cxacru_poll_status(&instance->poll_work.work);
 		cxacru_poll_status(&instance->poll_work.work);
 	return 0;
 	return 0;
@@ -873,11 +979,9 @@ cleanup:
 
 
 static void cxacru_upload_firmware(struct cxacru_data *instance,
 static void cxacru_upload_firmware(struct cxacru_data *instance,
 				   const struct firmware *fw,
 				   const struct firmware *fw,
-				   const struct firmware *bp,
-				   const struct firmware *cf)
+				   const struct firmware *bp)
 {
 {
 	int ret;
 	int ret;
-	int off;
 	struct usbatm_data *usbatm = instance->usbatm;
 	struct usbatm_data *usbatm = instance->usbatm;
 	struct usb_device *usb_dev = usbatm->usb_dev;
 	struct usb_device *usb_dev = usbatm->usb_dev;
 	__le16 signature[] = { usb_dev->descriptor.idVendor,
 	__le16 signature[] = { usb_dev->descriptor.idVendor,
@@ -911,6 +1015,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
 	}
 	}
 
 
 	/* Firmware */
 	/* Firmware */
+	usb_info(usbatm, "loading firmware\n");
 	ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, FW_ADDR, fw->data, fw->size);
 	ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, FW_ADDR, fw->data, fw->size);
 	if (ret) {
 	if (ret) {
 		usb_err(usbatm, "Firmware upload failed: %d\n", ret);
 		usb_err(usbatm, "Firmware upload failed: %d\n", ret);
@@ -919,6 +1024,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
 
 
 	/* Boot ROM patch */
 	/* Boot ROM patch */
 	if (instance->modem_type->boot_rom_patch) {
 	if (instance->modem_type->boot_rom_patch) {
+		usb_info(usbatm, "loading boot ROM patch\n");
 		ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_ADDR, bp->data, bp->size);
 		ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_ADDR, bp->data, bp->size);
 		if (ret) {
 		if (ret) {
 			usb_err(usbatm, "Boot ROM patching failed: %d\n", ret);
 			usb_err(usbatm, "Boot ROM patching failed: %d\n", ret);
@@ -933,6 +1039,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
 		return;
 		return;
 	}
 	}
 
 
+	usb_info(usbatm, "starting device\n");
 	if (instance->modem_type->boot_rom_patch) {
 	if (instance->modem_type->boot_rom_patch) {
 		val = cpu_to_le32(BR_ADDR);
 		val = cpu_to_le32(BR_ADDR);
 		ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_STACK_ADDR, (u8 *) &val, 4);
 		ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, BR_STACK_ADDR, (u8 *) &val, 4);
@@ -958,26 +1065,6 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
 		usb_err(usbatm, "modem failed to initialize: %d\n", ret);
 		usb_err(usbatm, "modem failed to initialize: %d\n", ret);
 		return;
 		return;
 	}
 	}
-
-	/* Load config data (le32), doing one packet at a time */
-	if (cf)
-		for (off = 0; off < cf->size / 4; ) {
-			__le32 buf[CMD_PACKET_SIZE / 4 - 1];
-			int i, len = min_t(int, cf->size / 4 - off, CMD_PACKET_SIZE / 4 / 2 - 1);
-			buf[0] = cpu_to_le32(len);
-			for (i = 0; i < len; i++, off++) {
-				buf[i * 2 + 1] = cpu_to_le32(off);
-				memcpy(buf + i * 2 + 2, cf->data + off * 4, 4);
-			}
-			ret = cxacru_cm(instance, CM_REQUEST_CARD_DATA_SET,
-					(u8 *) buf, len, NULL, 0);
-			if (ret < 0) {
-				usb_err(usbatm, "load config data failed: %d\n", ret);
-				return;
-			}
-		}
-
-	msleep_interruptible(4000);
 }
 }
 
 
 static int cxacru_find_firmware(struct cxacru_data *instance,
 static int cxacru_find_firmware(struct cxacru_data *instance,
@@ -1003,7 +1090,7 @@ static int cxacru_find_firmware(struct cxacru_data *instance,
 static int cxacru_heavy_init(struct usbatm_data *usbatm_instance,
 static int cxacru_heavy_init(struct usbatm_data *usbatm_instance,
 			     struct usb_interface *usb_intf)
 			     struct usb_interface *usb_intf)
 {
 {
-	const struct firmware *fw, *bp, *cf;
+	const struct firmware *fw, *bp;
 	struct cxacru_data *instance = usbatm_instance->driver_data;
 	struct cxacru_data *instance = usbatm_instance->driver_data;
 
 
 	int ret = cxacru_find_firmware(instance, "fw", &fw);
 	int ret = cxacru_find_firmware(instance, "fw", &fw);
@@ -1021,13 +1108,8 @@ static int cxacru_heavy_init(struct usbatm_data *usbatm_instance,
 		}
 		}
 	}
 	}
 
 
-	if (cxacru_find_firmware(instance, "cf", &cf))		/* optional */
-		cf = NULL;
-
-	cxacru_upload_firmware(instance, fw, bp, cf);
+	cxacru_upload_firmware(instance, fw, bp);
 
 
-	if (cf)
-		release_firmware(cf);
 	if (instance->modem_type->boot_rom_patch)
 	if (instance->modem_type->boot_rom_patch)
 		release_firmware(bp);
 		release_firmware(bp);
 	release_firmware(fw);
 	release_firmware(fw);

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

@@ -1333,6 +1333,7 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
 	if (instance->atm_dev) {
 	if (instance->atm_dev) {
 		sysfs_remove_link(&instance->atm_dev->class_dev.kobj, "device");
 		sysfs_remove_link(&instance->atm_dev->class_dev.kobj, "device");
 		atm_dev_deregister(instance->atm_dev);
 		atm_dev_deregister(instance->atm_dev);
+		instance->atm_dev = NULL;
 	}
 	}
 
 
 	usbatm_put_instance(instance);	/* taken in usbatm_usb_probe */
 	usbatm_put_instance(instance);	/* taken in usbatm_usb_probe */
@@ -1348,7 +1349,7 @@ static int __init usbatm_usb_init(void)
 {
 {
 	dbg("%s: driver version %s", __func__, DRIVER_VERSION);
 	dbg("%s: driver version %s", __func__, DRIVER_VERSION);
 
 
-	if (sizeof(struct usbatm_control) > sizeof(((struct sk_buff *) 0)->cb)) {
+	if (sizeof(struct usbatm_control) > FIELD_SIZEOF(struct sk_buff, cb)) {
 		printk(KERN_ERR "%s unusable with this kernel!\n", usbatm_driver_name);
 		printk(KERN_ERR "%s unusable with this kernel!\n", usbatm_driver_name);
 		return -EIO;
 		return -EIO;
 	}
 	}

+ 15 - 0
drivers/usb/atm/usbatm.h

@@ -204,4 +204,19 @@ struct usbatm_data {
 	struct urb *urbs[0];
 	struct urb *urbs[0];
 };
 };
 
 
+static inline void *to_usbatm_driver_data(struct usb_interface *intf)
+{
+	struct usbatm_data *usbatm_instance;
+
+	if (intf == NULL)
+		return NULL;
+
+	usbatm_instance = usb_get_intfdata(intf);
+
+	if (usbatm_instance == NULL) /* set NULL before unbind() */
+		return NULL;
+
+	return usbatm_instance->driver_data; /* set NULL after unbind() */
+}
+
 #endif	/* _USBATM_H_ */
 #endif	/* _USBATM_H_ */

+ 4 - 4
drivers/usb/c67x00/c67x00-drv.c

@@ -137,13 +137,13 @@ static int __devinit c67x00_drv_probe(struct platform_device *pdev)
 	if (!c67x00)
 	if (!c67x00)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	if (!request_mem_region(res->start, res->end - res->start + 1,
+	if (!request_mem_region(res->start, resource_size(res),
 				pdev->name)) {
 				pdev->name)) {
 		dev_err(&pdev->dev, "Memory region busy\n");
 		dev_err(&pdev->dev, "Memory region busy\n");
 		ret = -EBUSY;
 		ret = -EBUSY;
 		goto request_mem_failed;
 		goto request_mem_failed;
 	}
 	}
-	c67x00->hpi.base = ioremap(res->start, res->end - res->start + 1);
+	c67x00->hpi.base = ioremap(res->start, resource_size(res));
 	if (!c67x00->hpi.base) {
 	if (!c67x00->hpi.base) {
 		dev_err(&pdev->dev, "Unable to map HPI registers\n");
 		dev_err(&pdev->dev, "Unable to map HPI registers\n");
 		ret = -EIO;
 		ret = -EIO;
@@ -182,7 +182,7 @@ static int __devinit c67x00_drv_probe(struct platform_device *pdev)
  request_irq_failed:
  request_irq_failed:
 	iounmap(c67x00->hpi.base);
 	iounmap(c67x00->hpi.base);
  map_failed:
  map_failed:
-	release_mem_region(res->start, res->end - res->start + 1);
+	release_mem_region(res->start, resource_size(res));
  request_mem_failed:
  request_mem_failed:
 	kfree(c67x00);
 	kfree(c67x00);
 
 
@@ -208,7 +208,7 @@ static int __devexit c67x00_drv_remove(struct platform_device *pdev)
 
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (res)
 	if (res)
-		release_mem_region(res->start, res->end - res->start + 1);
+		release_mem_region(res->start, resource_size(res));
 
 
 	kfree(c67x00);
 	kfree(c67x00);
 
 

+ 53 - 29
drivers/usb/class/cdc-acm.c

@@ -170,6 +170,7 @@ static void acm_write_done(struct acm *acm, struct acm_wb *wb)
 {
 {
 	wb->use = 0;
 	wb->use = 0;
 	acm->transmitting--;
 	acm->transmitting--;
+	usb_autopm_put_interface_async(acm->control);
 }
 }
 
 
 /*
 /*
@@ -211,9 +212,12 @@ static int acm_write_start(struct acm *acm, int wbn)
 	}
 	}
 
 
 	dbg("%s susp_count: %d", __func__, acm->susp_count);
 	dbg("%s susp_count: %d", __func__, acm->susp_count);
+	usb_autopm_get_interface_async(acm->control);
 	if (acm->susp_count) {
 	if (acm->susp_count) {
-		acm->delayed_wb = wb;
-		schedule_work(&acm->waker);
+		if (!acm->delayed_wb)
+			acm->delayed_wb = wb;
+		else
+			usb_autopm_put_interface_async(acm->control);
 		spin_unlock_irqrestore(&acm->write_lock, flags);
 		spin_unlock_irqrestore(&acm->write_lock, flags);
 		return 0;	/* A white lie */
 		return 0;	/* A white lie */
 	}
 	}
@@ -424,7 +428,6 @@ next_buffer:
 		throttled = acm->throttle;
 		throttled = acm->throttle;
 		spin_unlock_irqrestore(&acm->throttle_lock, flags);
 		spin_unlock_irqrestore(&acm->throttle_lock, flags);
 		if (!throttled) {
 		if (!throttled) {
-			tty_buffer_request_room(tty, buf->size);
 			tty_insert_flip_string(tty, buf->base, buf->size);
 			tty_insert_flip_string(tty, buf->base, buf->size);
 			tty_flip_buffer_push(tty);
 			tty_flip_buffer_push(tty);
 		} else {
 		} else {
@@ -534,23 +537,6 @@ static void acm_softint(struct work_struct *work)
 	tty_kref_put(tty);
 	tty_kref_put(tty);
 }
 }
 
 
-static void acm_waker(struct work_struct *waker)
-{
-	struct acm *acm = container_of(waker, struct acm, waker);
-	int rv;
-
-	rv = usb_autopm_get_interface(acm->control);
-	if (rv < 0) {
-		dev_err(&acm->dev->dev, "Autopm failure in %s\n", __func__);
-		return;
-	}
-	if (acm->delayed_wb) {
-		acm_start_wb(acm, acm->delayed_wb);
-		acm->delayed_wb = NULL;
-	}
-	usb_autopm_put_interface(acm->control);
-}
-
 /*
 /*
  * TTY handlers
  * TTY handlers
  */
  */
@@ -566,7 +552,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
 
 
 	acm = acm_table[tty->index];
 	acm = acm_table[tty->index];
 	if (!acm || !acm->dev)
 	if (!acm || !acm->dev)
-		goto err_out;
+		goto out;
 	else
 	else
 		rv = 0;
 		rv = 0;
 
 
@@ -582,8 +568,9 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
 
 
 	mutex_lock(&acm->mutex);
 	mutex_lock(&acm->mutex);
 	if (acm->port.count++) {
 	if (acm->port.count++) {
+		mutex_unlock(&acm->mutex);
 		usb_autopm_put_interface(acm->control);
 		usb_autopm_put_interface(acm->control);
-		goto done;
+		goto out;
 	}
 	}
 
 
 	acm->ctrlurb->dev = acm->dev;
 	acm->ctrlurb->dev = acm->dev;
@@ -612,18 +599,18 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
 	set_bit(ASYNCB_INITIALIZED, &acm->port.flags);
 	set_bit(ASYNCB_INITIALIZED, &acm->port.flags);
 	rv = tty_port_block_til_ready(&acm->port, tty, filp);
 	rv = tty_port_block_til_ready(&acm->port, tty, filp);
 	tasklet_schedule(&acm->urb_task);
 	tasklet_schedule(&acm->urb_task);
-done:
+
 	mutex_unlock(&acm->mutex);
 	mutex_unlock(&acm->mutex);
-err_out:
+out:
 	mutex_unlock(&open_mutex);
 	mutex_unlock(&open_mutex);
 	return rv;
 	return rv;
 
 
 full_bailout:
 full_bailout:
 	usb_kill_urb(acm->ctrlurb);
 	usb_kill_urb(acm->ctrlurb);
 bail_out:
 bail_out:
-	usb_autopm_put_interface(acm->control);
 	acm->port.count--;
 	acm->port.count--;
 	mutex_unlock(&acm->mutex);
 	mutex_unlock(&acm->mutex);
+	usb_autopm_put_interface(acm->control);
 early_bail:
 early_bail:
 	mutex_unlock(&open_mutex);
 	mutex_unlock(&open_mutex);
 	tty_port_tty_set(&acm->port, NULL);
 	tty_port_tty_set(&acm->port, NULL);
@@ -1023,7 +1010,7 @@ static int acm_probe(struct usb_interface *intf,
 		case USB_CDC_CALL_MANAGEMENT_TYPE:
 		case USB_CDC_CALL_MANAGEMENT_TYPE:
 			call_management_function = buffer[3];
 			call_management_function = buffer[3];
 			call_interface_num = buffer[4];
 			call_interface_num = buffer[4];
-			if ((call_management_function & 3) != 3)
+			if ( (quirks & NOT_A_MODEM) == 0 && (call_management_function & 3) != 3)
 				dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
 				dev_err(&intf->dev, "This device cannot do calls on its own. It is not a modem.\n");
 			break;
 			break;
 		default:
 		default:
@@ -1178,7 +1165,6 @@ made_compressed_probe:
 	acm->urb_task.func = acm_rx_tasklet;
 	acm->urb_task.func = acm_rx_tasklet;
 	acm->urb_task.data = (unsigned long) acm;
 	acm->urb_task.data = (unsigned long) acm;
 	INIT_WORK(&acm->work, acm_softint);
 	INIT_WORK(&acm->work, acm_softint);
-	INIT_WORK(&acm->waker, acm_waker);
 	init_waitqueue_head(&acm->drain_wait);
 	init_waitqueue_head(&acm->drain_wait);
 	spin_lock_init(&acm->throttle_lock);
 	spin_lock_init(&acm->throttle_lock);
 	spin_lock_init(&acm->write_lock);
 	spin_lock_init(&acm->write_lock);
@@ -1343,7 +1329,6 @@ static void stop_data_traffic(struct acm *acm)
 	tasklet_enable(&acm->urb_task);
 	tasklet_enable(&acm->urb_task);
 
 
 	cancel_work_sync(&acm->work);
 	cancel_work_sync(&acm->work);
-	cancel_work_sync(&acm->waker);
 }
 }
 
 
 static void acm_disconnect(struct usb_interface *intf)
 static void acm_disconnect(struct usb_interface *intf)
@@ -1435,6 +1420,7 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
 static int acm_resume(struct usb_interface *intf)
 static int acm_resume(struct usb_interface *intf)
 {
 {
 	struct acm *acm = usb_get_intfdata(intf);
 	struct acm *acm = usb_get_intfdata(intf);
+	struct acm_wb *wb;
 	int rv = 0;
 	int rv = 0;
 	int cnt;
 	int cnt;
 
 
@@ -1449,6 +1435,21 @@ static int acm_resume(struct usb_interface *intf)
 	mutex_lock(&acm->mutex);
 	mutex_lock(&acm->mutex);
 	if (acm->port.count) {
 	if (acm->port.count) {
 		rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
 		rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
+
+		spin_lock_irq(&acm->write_lock);
+		if (acm->delayed_wb) {
+			wb = acm->delayed_wb;
+			acm->delayed_wb = NULL;
+			spin_unlock_irq(&acm->write_lock);
+			acm_start_wb(acm, acm->delayed_wb);
+		} else {
+			spin_unlock_irq(&acm->write_lock);
+		}
+
+		/*
+		 * delayed error checking because we must
+		 * do the write path at all cost
+		 */
 		if (rv < 0)
 		if (rv < 0)
 			goto err_out;
 			goto err_out;
 
 
@@ -1460,6 +1461,23 @@ err_out:
 	return rv;
 	return rv;
 }
 }
 
 
+static int acm_reset_resume(struct usb_interface *intf)
+{
+	struct acm *acm = usb_get_intfdata(intf);
+	struct tty_struct *tty;
+
+	mutex_lock(&acm->mutex);
+	if (acm->port.count) {
+		tty = tty_port_tty_get(&acm->port);
+		if (tty) {
+			tty_hangup(tty);
+			tty_kref_put(tty);
+		}
+	}
+	mutex_unlock(&acm->mutex);
+	return acm_resume(intf);
+}
+
 #endif /* CONFIG_PM */
 #endif /* CONFIG_PM */
 
 
 #define NOKIA_PCSUITE_ACM_INFO(x) \
 #define NOKIA_PCSUITE_ACM_INFO(x) \
@@ -1471,7 +1489,7 @@ err_out:
  * USB driver structure.
  * USB driver structure.
  */
  */
 
 
-static struct usb_device_id acm_ids[] = {
+static const struct usb_device_id acm_ids[] = {
 	/* quirky and broken devices */
 	/* quirky and broken devices */
 	{ USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
 	{ USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
 	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
 	.driver_info = NO_UNION_NORMAL, /* has no union descriptor */
@@ -1576,6 +1594,11 @@ static struct usb_device_id acm_ids[] = {
 
 
 	/* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
 	/* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
 
 
+	/* Support Lego NXT using pbLua firmware */
+	{ USB_DEVICE(0x0694, 0xff00),
+	.driver_info = NOT_A_MODEM,
+       	},
+
 	/* control interfaces with various AT-command sets */
 	/* control interfaces with various AT-command sets */
 	{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
 	{ USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
 		USB_CDC_ACM_PROTO_AT_V25TER) },
 		USB_CDC_ACM_PROTO_AT_V25TER) },
@@ -1602,6 +1625,7 @@ static struct usb_driver acm_driver = {
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
 	.suspend =	acm_suspend,
 	.suspend =	acm_suspend,
 	.resume =	acm_resume,
 	.resume =	acm_resume,
+	.reset_resume =	acm_reset_resume,
 #endif
 #endif
 	.id_table =	acm_ids,
 	.id_table =	acm_ids,
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM

+ 1 - 1
drivers/usb/class/cdc-acm.h

@@ -112,7 +112,6 @@ struct acm {
 	struct mutex mutex;
 	struct mutex mutex;
 	struct usb_cdc_line_coding line;		/* bits, stop, parity */
 	struct usb_cdc_line_coding line;		/* bits, stop, parity */
 	struct work_struct work;			/* work queue entry for line discipline waking up */
 	struct work_struct work;			/* work queue entry for line discipline waking up */
-	struct work_struct waker;
 	wait_queue_head_t drain_wait;			/* close processing */
 	wait_queue_head_t drain_wait;			/* close processing */
 	struct tasklet_struct urb_task;                 /* rx processing */
 	struct tasklet_struct urb_task;                 /* rx processing */
 	spinlock_t throttle_lock;			/* synchronize throtteling and read callback */
 	spinlock_t throttle_lock;			/* synchronize throtteling and read callback */
@@ -137,3 +136,4 @@ struct acm {
 #define NO_UNION_NORMAL			1
 #define NO_UNION_NORMAL			1
 #define SINGLE_RX_URB			2
 #define SINGLE_RX_URB			2
 #define NO_CAP_LINE			4
 #define NO_CAP_LINE			4
+#define NOT_A_MODEM			8

+ 1 - 1
drivers/usb/class/cdc-wdm.c

@@ -31,7 +31,7 @@
 #define DRIVER_AUTHOR "Oliver Neukum"
 #define DRIVER_AUTHOR "Oliver Neukum"
 #define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management"
 #define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management"
 
 
-static struct usb_device_id wdm_ids[] = {
+static const struct usb_device_id wdm_ids[] = {
 	{
 	{
 		.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
 		.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
 				 USB_DEVICE_ID_MATCH_INT_SUBCLASS,
 				 USB_DEVICE_ID_MATCH_INT_SUBCLASS,

+ 4 - 18
drivers/usb/class/usblp.c

@@ -163,7 +163,6 @@ struct usblp {
 	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		no_paper;		/* Paper Out happened */
 	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 */
@@ -191,7 +190,6 @@ static void usblp_dump(struct usblp *usblp) {
 	dbg("quirks=%d", usblp->quirks);
 	dbg("quirks=%d", usblp->quirks);
 	dbg("used=%d", usblp->used);
 	dbg("used=%d", usblp->used);
 	dbg("bidir=%d", usblp->bidir);
 	dbg("bidir=%d", usblp->bidir);
-	dbg("sleeping=%d", usblp->sleeping);
 	dbg("device_id_string=\"%s\"",
 	dbg("device_id_string=\"%s\"",
 		usblp->device_id_string ?
 		usblp->device_id_string ?
 			usblp->device_id_string + 2 :
 			usblp->device_id_string + 2 :
@@ -376,7 +374,7 @@ static int usblp_check_status(struct usblp *usblp, int err)
 
 
 static int handle_bidir (struct usblp *usblp)
 static int handle_bidir (struct usblp *usblp)
 {
 {
-	if (usblp->bidir && usblp->used && !usblp->sleeping) {
+	if (usblp->bidir && usblp->used) {
 		if (usblp_submit_read(usblp) < 0)
 		if (usblp_submit_read(usblp) < 0)
 			return -EIO;
 			return -EIO;
 	}
 	}
@@ -503,11 +501,6 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 		goto done;
 		goto done;
 	}
 	}
 
 
-	if (usblp->sleeping) {
-		retval = -ENODEV;
-		goto done;
-	}
-
 	dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd),
 	dbg("usblp_ioctl: cmd=0x%x (%c nr=%d len=%d dir=%d)", cmd, _IOC_TYPE(cmd),
 		_IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) );
 		_IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) );
 
 
@@ -914,8 +907,6 @@ static int usblp_wtest(struct usblp *usblp, int nonblock)
 		return 0;
 		return 0;
 	}
 	}
 	spin_unlock_irqrestore(&usblp->lock, flags);
 	spin_unlock_irqrestore(&usblp->lock, flags);
-	if (usblp->sleeping)
-		return -ENODEV;
 	if (nonblock)
 	if (nonblock)
 		return -EAGAIN;
 		return -EAGAIN;
 	return 1;
 	return 1;
@@ -968,8 +959,6 @@ static int usblp_rtest(struct usblp *usblp, int nonblock)
 		return 0;
 		return 0;
 	}
 	}
 	spin_unlock_irqrestore(&usblp->lock, flags);
 	spin_unlock_irqrestore(&usblp->lock, flags);
-	if (usblp->sleeping)
-		return -ENODEV;
 	if (nonblock)
 	if (nonblock)
 		return -EAGAIN;
 		return -EAGAIN;
 	return 1;
 	return 1;
@@ -1377,12 +1366,10 @@ static void usblp_disconnect(struct usb_interface *intf)
 	mutex_unlock (&usblp_mutex);
 	mutex_unlock (&usblp_mutex);
 }
 }
 
 
-static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
+static int usblp_suspend(struct usb_interface *intf, pm_message_t message)
 {
 {
 	struct usblp *usblp = usb_get_intfdata (intf);
 	struct usblp *usblp = usb_get_intfdata (intf);
 
 
-	/* we take no more IO */
-	usblp->sleeping = 1;
 	usblp_unlink_urbs(usblp);
 	usblp_unlink_urbs(usblp);
 #if 0 /* XXX Do we want this? What if someone is reading, should we fail? */
 #if 0 /* XXX Do we want this? What if someone is reading, should we fail? */
 	/* not strictly necessary, but just in case */
 	/* not strictly necessary, but just in case */
@@ -1393,18 +1380,17 @@ static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
 	return 0;
 	return 0;
 }
 }
 
 
-static int usblp_resume (struct usb_interface *intf)
+static int usblp_resume(struct usb_interface *intf)
 {
 {
 	struct usblp *usblp = usb_get_intfdata (intf);
 	struct usblp *usblp = usb_get_intfdata (intf);
 	int r;
 	int r;
 
 
-	usblp->sleeping = 0;
 	r = handle_bidir (usblp);
 	r = handle_bidir (usblp);
 
 
 	return r;
 	return r;
 }
 }
 
 
-static struct usb_device_id usblp_ids [] = {
+static const struct usb_device_id usblp_ids[] = {
 	{ USB_DEVICE_INFO(7, 1, 1) },
 	{ USB_DEVICE_INFO(7, 1, 1) },
 	{ USB_DEVICE_INFO(7, 1, 2) },
 	{ USB_DEVICE_INFO(7, 1, 2) },
 	{ USB_DEVICE_INFO(7, 1, 3) },
 	{ USB_DEVICE_INFO(7, 1, 3) },

+ 1 - 1
drivers/usb/class/usbtmc.c

@@ -48,7 +48,7 @@
  */
  */
 #define USBTMC_MAX_READS_TO_CLEAR_BULK_IN	100
 #define USBTMC_MAX_READS_TO_CLEAR_BULK_IN	100
 
 
-static struct usb_device_id usbtmc_devices[] = {
+static const struct usb_device_id usbtmc_devices[] = {
 	{ USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 0), },
 	{ USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 0), },
 	{ USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 1), },
 	{ USB_INTERFACE_INFO(USB_CLASS_APP_SPEC, 3, 1), },
 	{ 0, } /* terminating entry */
 	{ 0, } /* terminating entry */

+ 2 - 2
drivers/usb/core/Kconfig

@@ -91,8 +91,8 @@ config USB_DYNAMIC_MINORS
 	  If you are unsure about this, say N here.
 	  If you are unsure about this, say N here.
 
 
 config USB_SUSPEND
 config USB_SUSPEND
-	bool "USB selective suspend/resume and wakeup"
-	depends on USB && PM
+	bool "USB runtime power management (suspend/resume and wakeup)"
+	depends on USB && PM_RUNTIME
 	help
 	help
 	  If you say Y here, you can use driver calls or the sysfs
 	  If you say Y here, you can use driver calls or the sysfs
 	  "power/level" file to suspend or resume individual USB
 	  "power/level" file to suspend or resume individual USB

+ 11 - 21
drivers/usb/core/devices.c

@@ -118,6 +118,7 @@ static const char *format_endpt =
  */
  */
 
 
 static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq);
 static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq);
+/* guarded by usbfs_mutex */
 static unsigned int conndiscevcnt;
 static unsigned int conndiscevcnt;
 
 
 /* this struct stores the poll state for <mountpoint>/devices pollers */
 /* this struct stores the poll state for <mountpoint>/devices pollers */
@@ -156,7 +157,9 @@ static const struct class_info clas_info[] =
 
 
 void usbfs_conn_disc_event(void)
 void usbfs_conn_disc_event(void)
 {
 {
+	mutex_lock(&usbfs_mutex);
 	conndiscevcnt++;
 	conndiscevcnt++;
+	mutex_unlock(&usbfs_mutex);
 	wake_up(&deviceconndiscwq);
 	wake_up(&deviceconndiscwq);
 }
 }
 
 
@@ -629,42 +632,29 @@ static ssize_t usb_device_read(struct file *file, char __user *buf,
 static unsigned int usb_device_poll(struct file *file,
 static unsigned int usb_device_poll(struct file *file,
 				    struct poll_table_struct *wait)
 				    struct poll_table_struct *wait)
 {
 {
-	struct usb_device_status *st = file->private_data;
+	struct usb_device_status *st;
 	unsigned int mask = 0;
 	unsigned int mask = 0;
 
 
-	lock_kernel();
+	mutex_lock(&usbfs_mutex);
+	st = file->private_data;
 	if (!st) {
 	if (!st) {
 		st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL);
 		st = kmalloc(sizeof(struct usb_device_status), GFP_KERNEL);
-
-		/* we may have dropped BKL -
-		 * need to check for having lost the race */
-		if (file->private_data) {
-			kfree(st);
-			st = file->private_data;
-			goto lost_race;
-		}
-		/* we haven't lost - check for allocation failure now */
 		if (!st) {
 		if (!st) {
-			unlock_kernel();
+			mutex_unlock(&usbfs_mutex);
 			return POLLIN;
 			return POLLIN;
 		}
 		}
 
 
-		/*
-		 * need to prevent the module from being unloaded, since
-		 * proc_unregister does not call the release method and
-		 * we would have a memory leak
-		 */
 		st->lastev = conndiscevcnt;
 		st->lastev = conndiscevcnt;
 		file->private_data = st;
 		file->private_data = st;
 		mask = POLLIN;
 		mask = POLLIN;
 	}
 	}
-lost_race:
+
 	if (file->f_mode & FMODE_READ)
 	if (file->f_mode & FMODE_READ)
 		poll_wait(file, &deviceconndiscwq, wait);
 		poll_wait(file, &deviceconndiscwq, wait);
 	if (st->lastev != conndiscevcnt)
 	if (st->lastev != conndiscevcnt)
 		mask |= POLLIN;
 		mask |= POLLIN;
 	st->lastev = conndiscevcnt;
 	st->lastev = conndiscevcnt;
-	unlock_kernel();
+	mutex_unlock(&usbfs_mutex);
 	return mask;
 	return mask;
 }
 }
 
 
@@ -685,7 +675,7 @@ static loff_t usb_device_lseek(struct file *file, loff_t offset, int orig)
 {
 {
 	loff_t ret;
 	loff_t ret;
 
 
-	lock_kernel();
+	mutex_lock(&file->f_dentry->d_inode->i_mutex);
 
 
 	switch (orig) {
 	switch (orig) {
 	case 0:
 	case 0:
@@ -701,7 +691,7 @@ static loff_t usb_device_lseek(struct file *file, loff_t offset, int orig)
 		ret = -EINVAL;
 		ret = -EINVAL;
 	}
 	}
 
 
-	unlock_kernel();
+	mutex_unlock(&file->f_dentry->d_inode->i_mutex);
 	return ret;
 	return ret;
 }
 }
 
 

+ 80 - 47
drivers/usb/core/devio.c

@@ -122,7 +122,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
 {
 {
 	loff_t ret;
 	loff_t ret;
 
 
-	lock_kernel();
+	mutex_lock(&file->f_dentry->d_inode->i_mutex);
 
 
 	switch (orig) {
 	switch (orig) {
 	case 0:
 	case 0:
@@ -138,7 +138,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
 		ret = -EINVAL;
 		ret = -EINVAL;
 	}
 	}
 
 
-	unlock_kernel();
+	mutex_unlock(&file->f_dentry->d_inode->i_mutex);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -310,7 +310,8 @@ static struct async *async_getpending(struct dev_state *ps,
 
 
 static void snoop_urb(struct usb_device *udev,
 static void snoop_urb(struct usb_device *udev,
 		void __user *userurb, int pipe, unsigned length,
 		void __user *userurb, int pipe, unsigned length,
-		int timeout_or_status, enum snoop_when when)
+		int timeout_or_status, enum snoop_when when,
+		unsigned char *data, unsigned data_len)
 {
 {
 	static const char *types[] = {"isoc", "int", "ctrl", "bulk"};
 	static const char *types[] = {"isoc", "int", "ctrl", "bulk"};
 	static const char *dirs[] = {"out", "in"};
 	static const char *dirs[] = {"out", "in"};
@@ -344,6 +345,11 @@ static void snoop_urb(struct usb_device *udev,
 					"status %d\n",
 					"status %d\n",
 					ep, t, d, length, timeout_or_status);
 					ep, t, d, length, timeout_or_status);
 	}
 	}
+
+	if (data && data_len > 0) {
+		print_hex_dump(KERN_DEBUG, "data: ", DUMP_PREFIX_NONE, 32, 1,
+			data, data_len, 1);
+	}
 }
 }
 
 
 #define AS_CONTINUATION	1
 #define AS_CONTINUATION	1
@@ -410,7 +416,9 @@ static void async_completed(struct urb *urb)
 	}
 	}
 	snoop(&urb->dev->dev, "urb complete\n");
 	snoop(&urb->dev->dev, "urb complete\n");
 	snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
 	snoop_urb(urb->dev, as->userurb, urb->pipe, urb->actual_length,
-			as->status, COMPLETE);
+			as->status, COMPLETE,
+			((urb->transfer_flags & URB_DIR_MASK) == USB_DIR_OUT) ?
+				NULL : urb->transfer_buffer, urb->actual_length);
 	if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
 	if (as->status < 0 && as->bulk_addr && as->status != -ECONNRESET &&
 			as->status != -ENOENT)
 			as->status != -ENOENT)
 		cancel_bulk_urbs(ps, as->bulk_addr);
 		cancel_bulk_urbs(ps, as->bulk_addr);
@@ -653,20 +661,20 @@ static int usbdev_open(struct inode *inode, struct file *file)
 	const struct cred *cred = current_cred();
 	const struct cred *cred = current_cred();
 	int ret;
 	int ret;
 
 
-	lock_kernel();
-	/* Protect against simultaneous removal or release */
-	mutex_lock(&usbfs_mutex);
-
 	ret = -ENOMEM;
 	ret = -ENOMEM;
 	ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL);
 	ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL);
 	if (!ps)
 	if (!ps)
-		goto out;
+		goto out_free_ps;
 
 
 	ret = -ENODEV;
 	ret = -ENODEV;
 
 
+	/* Protect against simultaneous removal or release */
+	mutex_lock(&usbfs_mutex);
+
 	/* usbdev device-node */
 	/* usbdev device-node */
 	if (imajor(inode) == USB_DEVICE_MAJOR)
 	if (imajor(inode) == USB_DEVICE_MAJOR)
 		dev = usbdev_lookup_by_devt(inode->i_rdev);
 		dev = usbdev_lookup_by_devt(inode->i_rdev);
+
 #ifdef CONFIG_USB_DEVICEFS
 #ifdef CONFIG_USB_DEVICEFS
 	/* procfs file */
 	/* procfs file */
 	if (!dev) {
 	if (!dev) {
@@ -678,13 +686,19 @@ static int usbdev_open(struct inode *inode, struct file *file)
 			dev = NULL;
 			dev = NULL;
 	}
 	}
 #endif
 #endif
-	if (!dev || dev->state == USB_STATE_NOTATTACHED)
-		goto out;
+	mutex_unlock(&usbfs_mutex);
+
+	if (!dev)
+		goto out_free_ps;
+
+	usb_lock_device(dev);
+	if (dev->state == USB_STATE_NOTATTACHED)
+		goto out_unlock_device;
+
 	ret = usb_autoresume_device(dev);
 	ret = usb_autoresume_device(dev);
 	if (ret)
 	if (ret)
-		goto out;
+		goto out_unlock_device;
 
 
-	ret = 0;
 	ps->dev = dev;
 	ps->dev = dev;
 	ps->file = file;
 	ps->file = file;
 	spin_lock_init(&ps->lock);
 	spin_lock_init(&ps->lock);
@@ -702,15 +716,16 @@ static int usbdev_open(struct inode *inode, struct file *file)
 	smp_wmb();
 	smp_wmb();
 	list_add_tail(&ps->list, &dev->filelist);
 	list_add_tail(&ps->list, &dev->filelist);
 	file->private_data = ps;
 	file->private_data = ps;
+	usb_unlock_device(dev);
 	snoop(&dev->dev, "opened by process %d: %s\n", task_pid_nr(current),
 	snoop(&dev->dev, "opened by process %d: %s\n", task_pid_nr(current),
 			current->comm);
 			current->comm);
- out:
-	if (ret) {
-		kfree(ps);
-		usb_put_dev(dev);
-	}
-	mutex_unlock(&usbfs_mutex);
-	unlock_kernel();
+	return ret;
+
+ out_unlock_device:
+	usb_unlock_device(dev);
+	usb_put_dev(dev);
+ out_free_ps:
+	kfree(ps);
 	return ret;
 	return ret;
 }
 }
 
 
@@ -724,10 +739,7 @@ static int usbdev_release(struct inode *inode, struct file *file)
 	usb_lock_device(dev);
 	usb_lock_device(dev);
 	usb_hub_release_all_ports(dev, ps);
 	usb_hub_release_all_ports(dev, ps);
 
 
-	/* Protect against simultaneous open */
-	mutex_lock(&usbfs_mutex);
 	list_del_init(&ps->list);
 	list_del_init(&ps->list);
-	mutex_unlock(&usbfs_mutex);
 
 
 	for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed);
 	for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed);
 			ifnum++) {
 			ifnum++) {
@@ -770,6 +782,13 @@ static int proc_control(struct dev_state *ps, void __user *arg)
 	if (!tbuf)
 	if (!tbuf)
 		return -ENOMEM;
 		return -ENOMEM;
 	tmo = ctrl.timeout;
 	tmo = ctrl.timeout;
+	snoop(&dev->dev, "control urb: bRequestType=%02x "
+		"bRequest=%02x wValue=%04x "
+		"wIndex=%04x wLength=%04x\n",
+		ctrl.bRequestType, ctrl.bRequest,
+		__le16_to_cpup(&ctrl.wValue),
+		__le16_to_cpup(&ctrl.wIndex),
+		__le16_to_cpup(&ctrl.wLength));
 	if (ctrl.bRequestType & 0x80) {
 	if (ctrl.bRequestType & 0x80) {
 		if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data,
 		if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data,
 					       ctrl.wLength)) {
 					       ctrl.wLength)) {
@@ -777,15 +796,15 @@ static int proc_control(struct dev_state *ps, void __user *arg)
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
 		pipe = usb_rcvctrlpipe(dev, 0);
 		pipe = usb_rcvctrlpipe(dev, 0);
-		snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT);
+		snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, NULL, 0);
 
 
 		usb_unlock_device(dev);
 		usb_unlock_device(dev);
 		i = usb_control_msg(dev, pipe, ctrl.bRequest,
 		i = usb_control_msg(dev, pipe, ctrl.bRequest,
 				    ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
 				    ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
 				    tbuf, ctrl.wLength, tmo);
 				    tbuf, ctrl.wLength, tmo);
 		usb_lock_device(dev);
 		usb_lock_device(dev);
-		snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE);
-
+		snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE,
+			tbuf, i);
 		if ((i > 0) && ctrl.wLength) {
 		if ((i > 0) && ctrl.wLength) {
 			if (copy_to_user(ctrl.data, tbuf, i)) {
 			if (copy_to_user(ctrl.data, tbuf, i)) {
 				free_page((unsigned long)tbuf);
 				free_page((unsigned long)tbuf);
@@ -800,14 +819,15 @@ static int proc_control(struct dev_state *ps, void __user *arg)
 			}
 			}
 		}
 		}
 		pipe = usb_sndctrlpipe(dev, 0);
 		pipe = usb_sndctrlpipe(dev, 0);
-		snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT);
+		snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT,
+			tbuf, ctrl.wLength);
 
 
 		usb_unlock_device(dev);
 		usb_unlock_device(dev);
 		i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest,
 		i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest,
 				    ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
 				    ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
 				    tbuf, ctrl.wLength, tmo);
 				    tbuf, ctrl.wLength, tmo);
 		usb_lock_device(dev);
 		usb_lock_device(dev);
-		snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE);
+		snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, NULL, 0);
 	}
 	}
 	free_page((unsigned long)tbuf);
 	free_page((unsigned long)tbuf);
 	if (i < 0 && i != -EPIPE) {
 	if (i < 0 && i != -EPIPE) {
@@ -853,12 +873,12 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
 			kfree(tbuf);
 			kfree(tbuf);
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
-		snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT);
+		snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0);
 
 
 		usb_unlock_device(dev);
 		usb_unlock_device(dev);
 		i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
 		i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
 		usb_lock_device(dev);
 		usb_lock_device(dev);
-		snoop_urb(dev, NULL, pipe, len2, i, COMPLETE);
+		snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, tbuf, len2);
 
 
 		if (!i && len2) {
 		if (!i && len2) {
 			if (copy_to_user(bulk.data, tbuf, len2)) {
 			if (copy_to_user(bulk.data, tbuf, len2)) {
@@ -873,12 +893,12 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
 				return -EFAULT;
 				return -EFAULT;
 			}
 			}
 		}
 		}
-		snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT);
+		snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, tbuf, len1);
 
 
 		usb_unlock_device(dev);
 		usb_unlock_device(dev);
 		i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
 		i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
 		usb_lock_device(dev);
 		usb_lock_device(dev);
-		snoop_urb(dev, NULL, pipe, len2, i, COMPLETE);
+		snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, NULL, 0);
 	}
 	}
 	kfree(tbuf);
 	kfree(tbuf);
 	if (i < 0)
 	if (i < 0)
@@ -1097,6 +1117,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 			is_in = 0;
 			is_in = 0;
 			uurb->endpoint &= ~USB_DIR_IN;
 			uurb->endpoint &= ~USB_DIR_IN;
 		}
 		}
+		snoop(&ps->dev->dev, "control urb: bRequestType=%02x "
+			"bRequest=%02x wValue=%04x "
+			"wIndex=%04x wLength=%04x\n",
+			dr->bRequestType, dr->bRequest,
+			__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:
@@ -1104,13 +1131,25 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 		case USB_ENDPOINT_XFER_CONTROL:
 		case USB_ENDPOINT_XFER_CONTROL:
 		case USB_ENDPOINT_XFER_ISOC:
 		case USB_ENDPOINT_XFER_ISOC:
 			return -EINVAL;
 			return -EINVAL;
-		/* allow single-shot interrupt transfers, at bogus rates */
+		case USB_ENDPOINT_XFER_INT:
+			/* allow single-shot interrupt transfers */
+			uurb->type = USBDEVFS_URB_TYPE_INTERRUPT;
+			goto interrupt_urb;
 		}
 		}
 		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;
 		break;
 		break;
 
 
+	case USBDEVFS_URB_TYPE_INTERRUPT:
+		if (!usb_endpoint_xfer_int(&ep->desc))
+			return -EINVAL;
+ interrupt_urb:
+		uurb->number_of_packets = 0;
+		if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
+			return -EINVAL;
+		break;
+
 	case USBDEVFS_URB_TYPE_ISO:
 	case USBDEVFS_URB_TYPE_ISO:
 		/* arbitrary limit */
 		/* arbitrary limit */
 		if (uurb->number_of_packets < 1 ||
 		if (uurb->number_of_packets < 1 ||
@@ -1143,14 +1182,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 		uurb->buffer_length = totlen;
 		uurb->buffer_length = totlen;
 		break;
 		break;
 
 
-	case USBDEVFS_URB_TYPE_INTERRUPT:
-		uurb->number_of_packets = 0;
-		if (!usb_endpoint_xfer_int(&ep->desc))
-			return -EINVAL;
-		if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
-			return -EINVAL;
-		break;
-
 	default:
 	default:
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
@@ -1236,7 +1267,9 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 		}
 		}
 	}
 	}
 	snoop_urb(ps->dev, as->userurb, as->urb->pipe,
 	snoop_urb(ps->dev, as->userurb, as->urb->pipe,
-			as->urb->transfer_buffer_length, 0, SUBMIT);
+			as->urb->transfer_buffer_length, 0, SUBMIT,
+			is_in ? NULL : as->urb->transfer_buffer,
+				uurb->buffer_length);
 	async_newpending(as);
 	async_newpending(as);
 
 
 	if (usb_endpoint_xfer_bulk(&ep->desc)) {
 	if (usb_endpoint_xfer_bulk(&ep->desc)) {
@@ -1274,7 +1307,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 		dev_printk(KERN_DEBUG, &ps->dev->dev,
 		dev_printk(KERN_DEBUG, &ps->dev->dev,
 			   "usbfs: usb_submit_urb returned %d\n", ret);
 			   "usbfs: usb_submit_urb returned %d\n", ret);
 		snoop_urb(ps->dev, as->userurb, as->urb->pipe,
 		snoop_urb(ps->dev, as->userurb, as->urb->pipe,
-				0, ret, COMPLETE);
+				0, ret, COMPLETE, NULL, 0);
 		async_removepending(as);
 		async_removepending(as);
 		free_async(as);
 		free_async(as);
 		return ret;
 		return ret;
@@ -1628,7 +1661,10 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
 		if (driver == NULL || driver->ioctl == NULL) {
 		if (driver == NULL || driver->ioctl == NULL) {
 			retval = -ENOTTY;
 			retval = -ENOTTY;
 		} else {
 		} else {
+			/* keep API that guarantees BKL */
+			lock_kernel();
 			retval = driver->ioctl(intf, ctl->ioctl_code, buf);
 			retval = driver->ioctl(intf, ctl->ioctl_code, buf);
+			unlock_kernel();
 			if (retval == -ENOIOCTLCMD)
 			if (retval == -ENOIOCTLCMD)
 				retval = -ENOTTY;
 				retval = -ENOTTY;
 		}
 		}
@@ -1711,6 +1747,7 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
 
 
 	if (!(file->f_mode & FMODE_WRITE))
 	if (!(file->f_mode & FMODE_WRITE))
 		return -EPERM;
 		return -EPERM;
+
 	usb_lock_device(dev);
 	usb_lock_device(dev);
 	if (!connected(ps)) {
 	if (!connected(ps)) {
 		usb_unlock_device(dev);
 		usb_unlock_device(dev);
@@ -1877,9 +1914,7 @@ static long usbdev_ioctl(struct file *file, unsigned int cmd,
 {
 {
 	int ret;
 	int ret;
 
 
-	lock_kernel();
 	ret = usbdev_do_ioctl(file, cmd, (void __user *)arg);
 	ret = usbdev_do_ioctl(file, cmd, (void __user *)arg);
-	unlock_kernel();
 
 
 	return ret;
 	return ret;
 }
 }
@@ -1890,9 +1925,7 @@ static long usbdev_compat_ioctl(struct file *file, unsigned int cmd,
 {
 {
 	int ret;
 	int ret;
 
 
-	lock_kernel();
 	ret = usbdev_do_ioctl(file, cmd, compat_ptr(arg));
 	ret = usbdev_do_ioctl(file, cmd, compat_ptr(arg));
-	unlock_kernel();
 
 
 	return ret;
 	return ret;
 }
 }

+ 424 - 494
drivers/usb/core/driver.c

@@ -25,7 +25,7 @@
 #include <linux/device.h>
 #include <linux/device.h>
 #include <linux/usb.h>
 #include <linux/usb.h>
 #include <linux/usb/quirks.h>
 #include <linux/usb/quirks.h>
-#include <linux/workqueue.h>
+#include <linux/pm_runtime.h>
 #include "hcd.h"
 #include "hcd.h"
 #include "usb.h"
 #include "usb.h"
 
 
@@ -221,7 +221,7 @@ static int usb_probe_device(struct device *dev)
 {
 {
 	struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
 	struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
 	struct usb_device *udev = to_usb_device(dev);
 	struct usb_device *udev = to_usb_device(dev);
-	int error = -ENODEV;
+	int error = 0;
 
 
 	dev_dbg(dev, "%s\n", __func__);
 	dev_dbg(dev, "%s\n", __func__);
 
 
@@ -230,18 +230,23 @@ static int usb_probe_device(struct device *dev)
 	/* The device should always appear to be in use
 	/* The device should always appear to be in use
 	 * unless the driver suports autosuspend.
 	 * unless the driver suports autosuspend.
 	 */
 	 */
-	udev->pm_usage_cnt = !(udriver->supports_autosuspend);
+	if (!udriver->supports_autosuspend)
+		error = usb_autoresume_device(udev);
 
 
-	error = udriver->probe(udev);
+	if (!error)
+		error = udriver->probe(udev);
 	return error;
 	return error;
 }
 }
 
 
 /* called from driver core with dev locked */
 /* called from driver core with dev locked */
 static int usb_unbind_device(struct device *dev)
 static int usb_unbind_device(struct device *dev)
 {
 {
+	struct usb_device *udev = to_usb_device(dev);
 	struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
 	struct usb_device_driver *udriver = to_usb_device_driver(dev->driver);
 
 
-	udriver->disconnect(to_usb_device(dev));
+	udriver->disconnect(udev);
+	if (!udriver->supports_autosuspend)
+		usb_autosuspend_device(udev);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -274,60 +279,62 @@ static int usb_probe_interface(struct device *dev)
 	intf->needs_binding = 0;
 	intf->needs_binding = 0;
 
 
 	if (usb_device_is_owned(udev))
 	if (usb_device_is_owned(udev))
-		return -ENODEV;
+		return error;
 
 
 	if (udev->authorized == 0) {
 	if (udev->authorized == 0) {
 		dev_err(&intf->dev, "Device is not authorized for usage\n");
 		dev_err(&intf->dev, "Device is not authorized for usage\n");
-		return -ENODEV;
+		return error;
 	}
 	}
 
 
 	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);
-	if (id) {
-		dev_dbg(dev, "%s - got id\n", __func__);
-
-		error = usb_autoresume_device(udev);
-		if (error)
-			return error;
+	if (!id)
+		return error;
 
 
-		/* Interface "power state" doesn't correspond to any hardware
-		 * state whatsoever.  We use it to record when it's bound to
-		 * a driver that may start I/0:  it's not frozen/quiesced.
-		 */
-		mark_active(intf);
-		intf->condition = USB_INTERFACE_BINDING;
+	dev_dbg(dev, "%s - got id\n", __func__);
 
 
-		/* The interface should always appear to be in use
-		 * unless the driver suports autosuspend.
-		 */
-		atomic_set(&intf->pm_usage_cnt, !driver->supports_autosuspend);
-
-		/* Carry out a deferred switch to altsetting 0 */
-		if (intf->needs_altsetting0) {
-			error = usb_set_interface(udev, intf->altsetting[0].
-					desc.bInterfaceNumber, 0);
-			if (error < 0)
-				goto err;
+	error = usb_autoresume_device(udev);
+	if (error)
+		return error;
 
 
-			intf->needs_altsetting0 = 0;
-		}
+	intf->condition = USB_INTERFACE_BINDING;
 
 
-		error = driver->probe(intf, id);
-		if (error)
+	/* Bound interfaces are initially active.  They are
+	 * runtime-PM-enabled only if the driver has autosuspend support.
+	 * They are sensitive to their children's power states.
+	 */
+	pm_runtime_set_active(dev);
+	pm_suspend_ignore_children(dev, false);
+	if (driver->supports_autosuspend)
+		pm_runtime_enable(dev);
+
+	/* Carry out a deferred switch to altsetting 0 */
+	if (intf->needs_altsetting0) {
+		error = usb_set_interface(udev, intf->altsetting[0].
+				desc.bInterfaceNumber, 0);
+		if (error < 0)
 			goto err;
 			goto err;
-
-		intf->condition = USB_INTERFACE_BOUND;
-		usb_autosuspend_device(udev);
+		intf->needs_altsetting0 = 0;
 	}
 	}
 
 
+	error = driver->probe(intf, id);
+	if (error)
+		goto err;
+
+	intf->condition = USB_INTERFACE_BOUND;
+	usb_autosuspend_device(udev);
 	return error;
 	return error;
 
 
-err:
-	mark_quiesced(intf);
+ err:
 	intf->needs_remote_wakeup = 0;
 	intf->needs_remote_wakeup = 0;
 	intf->condition = USB_INTERFACE_UNBOUND;
 	intf->condition = USB_INTERFACE_UNBOUND;
 	usb_cancel_queued_reset(intf);
 	usb_cancel_queued_reset(intf);
+
+	/* Unbound interfaces are always runtime-PM-disabled and -suspended */
+	pm_runtime_disable(dev);
+	pm_runtime_set_suspended(dev);
+
 	usb_autosuspend_device(udev);
 	usb_autosuspend_device(udev);
 	return error;
 	return error;
 }
 }
@@ -377,9 +384,17 @@ static int usb_unbind_interface(struct device *dev)
 	usb_set_intfdata(intf, NULL);
 	usb_set_intfdata(intf, NULL);
 
 
 	intf->condition = USB_INTERFACE_UNBOUND;
 	intf->condition = USB_INTERFACE_UNBOUND;
-	mark_quiesced(intf);
 	intf->needs_remote_wakeup = 0;
 	intf->needs_remote_wakeup = 0;
 
 
+	/* Unbound interfaces are always runtime-PM-disabled and -suspended */
+	pm_runtime_disable(dev);
+	pm_runtime_set_suspended(dev);
+
+	/* Undo any residual pm_autopm_get_interface_* calls */
+	for (r = atomic_read(&intf->pm_usage_cnt); r > 0; --r)
+		usb_autopm_put_interface_no_suspend(intf);
+	atomic_set(&intf->pm_usage_cnt, 0);
+
 	if (!error)
 	if (!error)
 		usb_autosuspend_device(udev);
 		usb_autosuspend_device(udev);
 
 
@@ -410,7 +425,6 @@ int usb_driver_claim_interface(struct usb_driver *driver,
 				struct usb_interface *iface, void *priv)
 				struct usb_interface *iface, void *priv)
 {
 {
 	struct device *dev = &iface->dev;
 	struct device *dev = &iface->dev;
-	struct usb_device *udev = interface_to_usbdev(iface);
 	int retval = 0;
 	int retval = 0;
 
 
 	if (dev->driver)
 	if (dev->driver)
@@ -420,11 +434,16 @@ int usb_driver_claim_interface(struct usb_driver *driver,
 	usb_set_intfdata(iface, priv);
 	usb_set_intfdata(iface, priv);
 	iface->needs_binding = 0;
 	iface->needs_binding = 0;
 
 
-	usb_pm_lock(udev);
 	iface->condition = USB_INTERFACE_BOUND;
 	iface->condition = USB_INTERFACE_BOUND;
-	mark_active(iface);
-	atomic_set(&iface->pm_usage_cnt, !driver->supports_autosuspend);
-	usb_pm_unlock(udev);
+
+	/* Bound interfaces are initially active.  They are
+	 * runtime-PM-enabled only if the driver has autosuspend support.
+	 * They are sensitive to their children's power states.
+	 */
+	pm_runtime_set_active(dev);
+	pm_suspend_ignore_children(dev, false);
+	if (driver->supports_autosuspend)
+		pm_runtime_enable(dev);
 
 
 	/* if interface was already added, bind now; else let
 	/* if interface was already added, bind now; else let
 	 * the future device_add() bind it, bypassing probe()
 	 * the future device_add() bind it, bypassing probe()
@@ -691,9 +710,6 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
 {
 {
 	struct usb_device *usb_dev;
 	struct usb_device *usb_dev;
 
 
-	/* driver is often null here; dev_dbg() would oops */
-	pr_debug("usb %s: uevent\n", dev_name(dev));
-
 	if (is_usb_device(dev)) {
 	if (is_usb_device(dev)) {
 		usb_dev = to_usb_device(dev);
 		usb_dev = to_usb_device(dev);
 	} else if (is_usb_interface(dev)) {
 	} else if (is_usb_interface(dev)) {
@@ -705,6 +721,7 @@ static int usb_uevent(struct device *dev, struct kobj_uevent_env *env)
 	}
 	}
 
 
 	if (usb_dev->devnum < 0) {
 	if (usb_dev->devnum < 0) {
+		/* driver is often null here; dev_dbg() would oops */
 		pr_debug("usb %s: already deleted?\n", dev_name(dev));
 		pr_debug("usb %s: already deleted?\n", dev_name(dev));
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
@@ -983,7 +1000,6 @@ static void do_unbind_rebind(struct usb_device *udev, int action)
 	}
 	}
 }
 }
 
 
-/* Caller has locked udev's pm_mutex */
 static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
 static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
 {
 {
 	struct usb_device_driver	*udriver;
 	struct usb_device_driver	*udriver;
@@ -1007,7 +1023,6 @@ static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
 	return status;
 	return status;
 }
 }
 
 
-/* Caller has locked udev's pm_mutex */
 static int usb_resume_device(struct usb_device *udev, pm_message_t msg)
 static int usb_resume_device(struct usb_device *udev, pm_message_t msg)
 {
 {
 	struct usb_device_driver	*udriver;
 	struct usb_device_driver	*udriver;
@@ -1041,27 +1056,20 @@ static int usb_resume_device(struct usb_device *udev, pm_message_t msg)
 	return status;
 	return status;
 }
 }
 
 
-/* Caller has locked intf's usb_device's pm mutex */
 static int usb_suspend_interface(struct usb_device *udev,
 static int usb_suspend_interface(struct usb_device *udev,
 		struct usb_interface *intf, pm_message_t msg)
 		struct usb_interface *intf, pm_message_t msg)
 {
 {
 	struct usb_driver	*driver;
 	struct usb_driver	*driver;
 	int			status = 0;
 	int			status = 0;
 
 
-	/* with no hardware, USB interfaces only use FREEZE and ON states */
-	if (udev->state == USB_STATE_NOTATTACHED || !is_active(intf))
-		goto done;
-
-	/* This can happen; see usb_driver_release_interface() */
-	if (intf->condition == USB_INTERFACE_UNBOUND)
+	if (udev->state == USB_STATE_NOTATTACHED ||
+			intf->condition == USB_INTERFACE_UNBOUND)
 		goto done;
 		goto done;
 	driver = to_usb_driver(intf->dev.driver);
 	driver = to_usb_driver(intf->dev.driver);
 
 
 	if (driver->suspend) {
 	if (driver->suspend) {
 		status = driver->suspend(intf, msg);
 		status = driver->suspend(intf, msg);
-		if (status == 0)
-			mark_quiesced(intf);
-		else if (!(msg.event & PM_EVENT_AUTO))
+		if (status && !(msg.event & PM_EVENT_AUTO))
 			dev_err(&intf->dev, "%s error %d\n",
 			dev_err(&intf->dev, "%s error %d\n",
 					"suspend", status);
 					"suspend", status);
 	} else {
 	} else {
@@ -1069,7 +1077,6 @@ static int usb_suspend_interface(struct usb_device *udev,
 		intf->needs_binding = 1;
 		intf->needs_binding = 1;
 		dev_warn(&intf->dev, "no %s for driver %s?\n",
 		dev_warn(&intf->dev, "no %s for driver %s?\n",
 				"suspend", driver->name);
 				"suspend", driver->name);
-		mark_quiesced(intf);
 	}
 	}
 
 
  done:
  done:
@@ -1077,14 +1084,13 @@ static int usb_suspend_interface(struct usb_device *udev,
 	return status;
 	return status;
 }
 }
 
 
-/* Caller has locked intf's usb_device's pm_mutex */
 static int usb_resume_interface(struct usb_device *udev,
 static int usb_resume_interface(struct usb_device *udev,
 		struct usb_interface *intf, pm_message_t msg, int reset_resume)
 		struct usb_interface *intf, pm_message_t msg, int reset_resume)
 {
 {
 	struct usb_driver	*driver;
 	struct usb_driver	*driver;
 	int			status = 0;
 	int			status = 0;
 
 
-	if (udev->state == USB_STATE_NOTATTACHED || is_active(intf))
+	if (udev->state == USB_STATE_NOTATTACHED)
 		goto done;
 		goto done;
 
 
 	/* Don't let autoresume interfere with unbinding */
 	/* Don't let autoresume interfere with unbinding */
@@ -1135,90 +1141,11 @@ static int usb_resume_interface(struct usb_device *udev,
 
 
 done:
 done:
 	dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status);
 	dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status);
-	if (status == 0 && intf->condition == USB_INTERFACE_BOUND)
-		mark_active(intf);
 
 
 	/* Later we will unbind the driver and/or reprobe, if necessary */
 	/* Later we will unbind the driver and/or reprobe, if necessary */
 	return status;
 	return status;
 }
 }
 
 
-#ifdef	CONFIG_USB_SUSPEND
-
-/* Internal routine to check whether we may autosuspend a device. */
-static int autosuspend_check(struct usb_device *udev, int reschedule)
-{
-	int			i;
-	struct usb_interface	*intf;
-	unsigned long		suspend_time, j;
-
-	/* For autosuspend, fail fast if anything is in use or autosuspend
-	 * is disabled.  Also fail if any interfaces require remote wakeup
-	 * but it isn't available.
-	 */
-	if (udev->pm_usage_cnt > 0)
-		return -EBUSY;
-	if (udev->autosuspend_delay < 0 || udev->autosuspend_disabled)
-		return -EPERM;
-
-	suspend_time = udev->last_busy + udev->autosuspend_delay;
-	if (udev->actconfig) {
-		for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
-			intf = udev->actconfig->interface[i];
-			if (!is_active(intf))
-				continue;
-			if (atomic_read(&intf->pm_usage_cnt) > 0)
-				return -EBUSY;
-			if (intf->needs_remote_wakeup &&
-					!udev->do_remote_wakeup) {
-				dev_dbg(&udev->dev, "remote wakeup needed "
-						"for autosuspend\n");
-				return -EOPNOTSUPP;
-			}
-
-			/* Don't allow autosuspend if the device will need
-			 * a reset-resume and any of its interface drivers
-			 * doesn't include support.
-			 */
-			if (udev->quirks & USB_QUIRK_RESET_RESUME) {
-				struct usb_driver *driver;
-
-				driver = to_usb_driver(intf->dev.driver);
-				if (!driver->reset_resume ||
-				    intf->needs_remote_wakeup)
-					return -EOPNOTSUPP;
-			}
-		}
-	}
-
-	/* If everything is okay but the device hasn't been idle for long
-	 * 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.
-	 */
-	j = jiffies;
-	if (time_before(j, suspend_time))
-		reschedule = 1;
-	else
-		suspend_time = j + HZ;
-	if (reschedule) {
-		if (!timer_pending(&udev->autosuspend.timer)) {
-			queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
-				round_jiffies_up_relative(suspend_time - j));
-		}
-		return -EAGAIN;
-	}
-	return 0;
-}
-
-#else
-
-static inline int autosuspend_check(struct usb_device *udev, int reschedule)
-{
-	return 0;
-}
-
-#endif	/* CONFIG_USB_SUSPEND */
-
 /**
 /**
  * usb_suspend_both - suspend a USB device and its interfaces
  * usb_suspend_both - suspend a USB device and its interfaces
  * @udev: the usb_device to suspend
  * @udev: the usb_device to suspend
@@ -1230,27 +1157,12 @@ static inline int autosuspend_check(struct usb_device *udev, int reschedule)
  * all the interfaces which were suspended are resumed so that they remain
  * all the interfaces which were suspended are resumed so that they remain
  * in the same state as the device.
  * in the same state as the device.
  *
  *
- * If an autosuspend is in progress the routine checks first to make sure
- * that neither the device itself or any of its active interfaces is in use
- * (pm_usage_cnt is greater than 0).  If they are, the autosuspend fails.
- *
- * If the suspend succeeds, the routine recursively queues an autosuspend
- * request for @udev's parent device, thereby propagating the change up
- * the device tree.  If all of the parent's children are now suspended,
- * the parent will autosuspend in turn.
- *
- * The suspend method calls are subject to mutual exclusion under control
- * of @udev's pm_mutex.  Many of these calls are also under the protection
- * of @udev's device lock (including all requests originating outside the
- * USB subsystem), but autosuspend requests generated by a child device or
- * interface driver may not be.  Usbcore will insure that the method calls
- * do not arrive during bind, unbind, or reset operations.  However, drivers
- * must be prepared to handle suspend calls arriving at unpredictable times.
- * The only way to block such calls is to do an autoresume (preventing
- * autosuspends) while holding @udev's device lock (preventing outside
- * suspends).
- *
- * The caller must hold @udev->pm_mutex.
+ * Autosuspend requests originating from a child device or an interface
+ * driver may be made without the protection of @udev's device lock, but
+ * all other suspend calls will hold the lock.  Usbcore will insure that
+ * method calls do not arrive during bind, unbind, or reset operations.
+ * However drivers must be prepared to handle suspend calls arriving at
+ * unpredictable times.
  *
  *
  * This routine can run only in process context.
  * This routine can run only in process context.
  */
  */
@@ -1259,20 +1171,11 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
 	int			status = 0;
 	int			status = 0;
 	int			i = 0;
 	int			i = 0;
 	struct usb_interface	*intf;
 	struct usb_interface	*intf;
-	struct usb_device	*parent = udev->parent;
 
 
 	if (udev->state == USB_STATE_NOTATTACHED ||
 	if (udev->state == USB_STATE_NOTATTACHED ||
 			udev->state == USB_STATE_SUSPENDED)
 			udev->state == USB_STATE_SUSPENDED)
 		goto done;
 		goto done;
 
 
-	udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
-
-	if (msg.event & PM_EVENT_AUTO) {
-		status = autosuspend_check(udev, 0);
-		if (status < 0)
-			goto done;
-	}
-
 	/* Suspend all the interfaces and then udev itself */
 	/* Suspend all the interfaces and then udev itself */
 	if (udev->actconfig) {
 	if (udev->actconfig) {
 		for (; i < udev->actconfig->desc.bNumInterfaces; i++) {
 		for (; i < udev->actconfig->desc.bNumInterfaces; i++) {
@@ -1287,35 +1190,21 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t 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) {
-		pm_message_t msg2;
-
-		msg2.event = msg.event ^ (PM_EVENT_SUSPEND | PM_EVENT_RESUME);
+		msg.event ^= (PM_EVENT_SUSPEND | PM_EVENT_RESUME);
 		while (--i >= 0) {
 		while (--i >= 0) {
 			intf = udev->actconfig->interface[i];
 			intf = udev->actconfig->interface[i];
-			usb_resume_interface(udev, intf, msg2, 0);
+			usb_resume_interface(udev, intf, msg, 0);
 		}
 		}
 
 
-		/* Try another autosuspend when the interfaces aren't busy */
-		if (msg.event & PM_EVENT_AUTO)
-			autosuspend_check(udev, status == -EBUSY);
-
-	/* If the suspend succeeded then prevent any more URB submissions,
-	 * flush any outstanding URBs, and propagate the suspend up the tree.
+	/* If the suspend succeeded then prevent any more URB submissions
+	 * and flush any outstanding URBs.
 	 */
 	 */
 	} else {
 	} else {
-		cancel_delayed_work(&udev->autosuspend);
 		udev->can_submit = 0;
 		udev->can_submit = 0;
 		for (i = 0; i < 16; ++i) {
 		for (i = 0; i < 16; ++i) {
 			usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
 			usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
 			usb_hcd_flush_endpoint(udev, udev->ep_in[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);
 	}
 	}
 
 
  done:
  done:
@@ -1332,23 +1221,12 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
  * the resume method for @udev and then calls the resume methods for all
  * the resume method for @udev and then calls the resume methods for all
  * the interface drivers in @udev.
  * the interface drivers in @udev.
  *
  *
- * Before starting the resume, the routine calls itself recursively for
- * the parent device of @udev, thereby propagating the change up the device
- * tree and assuring that @udev will be able to resume.  If the parent is
- * unable to resume successfully, the routine fails.
- *
- * The resume method calls are subject to mutual exclusion under control
- * of @udev's pm_mutex.  Many of these calls are also under the protection
- * of @udev's device lock (including all requests originating outside the
- * USB subsystem), but autoresume requests generated by a child device or
- * interface driver may not be.  Usbcore will insure that the method calls
- * do not arrive during bind, unbind, or reset operations.  However, drivers
- * must be prepared to handle resume calls arriving at unpredictable times.
- * The only way to block such calls is to do an autoresume (preventing
- * other autoresumes) while holding @udev's device lock (preventing outside
- * resumes).
- *
- * The caller must hold @udev->pm_mutex.
+ * Autoresume requests originating from a child device or an interface
+ * driver may be made without the protection of @udev's device lock, but
+ * all other resume calls will hold the lock.  Usbcore will insure that
+ * method calls do not arrive during bind, unbind, or reset operations.
+ * However drivers must be prepared to handle resume calls arriving at
+ * unpredictable times.
  *
  *
  * This routine can run only in process context.
  * This routine can run only in process context.
  */
  */
@@ -1357,48 +1235,18 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
 	int			status = 0;
 	int			status = 0;
 	int			i;
 	int			i;
 	struct usb_interface	*intf;
 	struct usb_interface	*intf;
-	struct usb_device	*parent = udev->parent;
 
 
-	cancel_delayed_work(&udev->autosuspend);
 	if (udev->state == USB_STATE_NOTATTACHED) {
 	if (udev->state == USB_STATE_NOTATTACHED) {
 		status = -ENODEV;
 		status = -ENODEV;
 		goto done;
 		goto done;
 	}
 	}
 	udev->can_submit = 1;
 	udev->can_submit = 1;
 
 
-	/* Propagate the resume up the tree, if necessary */
-	if (udev->state == USB_STATE_SUSPENDED) {
-		if (parent) {
-			status = usb_autoresume_device(parent);
-			if (status == 0) {
-				status = usb_resume_device(udev, msg);
-				if (status || udev->state ==
-						USB_STATE_NOTATTACHED) {
-					usb_autosuspend_device(parent);
-
-					/* It's possible usb_resume_device()
-					 * failed after the port was
-					 * unsuspended, causing udev to be
-					 * logically disconnected.  We don't
-					 * want usb_disconnect() to autosuspend
-					 * the parent again, so tell it that
-					 * udev disconnected while still
-					 * suspended. */
-					if (udev->state ==
-							USB_STATE_NOTATTACHED)
-						udev->discon_suspended = 1;
-				}
-			}
-		} else {
-
-			/* We can't progagate beyond the USB subsystem,
-			 * so if a root hub's controller is suspended
-			 * then we're stuck. */
-			status = usb_resume_device(udev, msg);
-		}
-	} else if (udev->reset_resume)
+	/* Resume the device */
+	if (udev->state == USB_STATE_SUSPENDED || udev->reset_resume)
 		status = usb_resume_device(udev, msg);
 		status = usb_resume_device(udev, msg);
 
 
+	/* Resume the interfaces */
 	if (status == 0 && udev->actconfig) {
 	if (status == 0 && udev->actconfig) {
 		for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
 		for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
 			intf = udev->actconfig->interface[i];
 			intf = udev->actconfig->interface[i];
@@ -1414,55 +1262,94 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
 	return status;
 	return status;
 }
 }
 
 
-#ifdef CONFIG_USB_SUSPEND
+/* The device lock is held by the PM core */
+int usb_suspend(struct device *dev, pm_message_t msg)
+{
+	struct usb_device	*udev = to_usb_device(dev);
 
 
-/* Internal routine to adjust a device's usage counter and change
- * its autosuspend state.
- */
-static int usb_autopm_do_device(struct usb_device *udev, int inc_usage_cnt)
+	do_unbind_rebind(udev, DO_UNBIND);
+	udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
+	return usb_suspend_both(udev, msg);
+}
+
+/* The device lock is held by the PM core */
+int usb_resume(struct device *dev, pm_message_t msg)
 {
 {
-	int	status = 0;
+	struct usb_device	*udev = to_usb_device(dev);
+	int			status;
 
 
-	usb_pm_lock(udev);
-	udev->pm_usage_cnt += inc_usage_cnt;
-	WARN_ON(udev->pm_usage_cnt < 0);
-	if (inc_usage_cnt)
-		udev->last_busy = jiffies;
-	if (inc_usage_cnt >= 0 && udev->pm_usage_cnt > 0) {
-		if (udev->state == USB_STATE_SUSPENDED)
-			status = usb_resume_both(udev, PMSG_AUTO_RESUME);
-		if (status != 0)
-			udev->pm_usage_cnt -= inc_usage_cnt;
-		else if (inc_usage_cnt)
+	/* For PM complete calls, all we do is rebind interfaces */
+	if (msg.event == PM_EVENT_ON) {
+		if (udev->state != USB_STATE_NOTATTACHED)
+			do_unbind_rebind(udev, DO_REBIND);
+		status = 0;
+
+	/* For all other calls, take the device back to full power and
+	 * tell the PM core in case it was autosuspended previously.
+	 */
+	} else {
+		status = usb_resume_both(udev, msg);
+		if (status == 0) {
+			pm_runtime_disable(dev);
+			pm_runtime_set_active(dev);
+			pm_runtime_enable(dev);
 			udev->last_busy = jiffies;
 			udev->last_busy = jiffies;
-	} else if (inc_usage_cnt <= 0 && udev->pm_usage_cnt <= 0) {
-		status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
+		}
 	}
 	}
-	usb_pm_unlock(udev);
+
+	/* Avoid PM error messages for devices disconnected while suspended
+	 * as we'll display regular disconnect messages just a bit later.
+	 */
+	if (status == -ENODEV)
+		status = 0;
 	return status;
 	return status;
 }
 }
 
 
-/* usb_autosuspend_work - callback routine to autosuspend a USB device */
-void usb_autosuspend_work(struct work_struct *work)
-{
-	struct usb_device *udev =
-		container_of(work, struct usb_device, autosuspend.work);
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_USB_SUSPEND
 
 
-	usb_autopm_do_device(udev, 0);
+/**
+ * usb_enable_autosuspend - allow a USB device to be autosuspended
+ * @udev: the USB device which may be autosuspended
+ *
+ * This routine allows @udev to be autosuspended.  An autosuspend won't
+ * take place until the autosuspend_delay has elapsed and all the other
+ * necessary conditions are satisfied.
+ *
+ * The caller must hold @udev's device lock.
+ */
+int usb_enable_autosuspend(struct usb_device *udev)
+{
+	if (udev->autosuspend_disabled) {
+		udev->autosuspend_disabled = 0;
+		usb_autosuspend_device(udev);
+	}
+	return 0;
 }
 }
+EXPORT_SYMBOL_GPL(usb_enable_autosuspend);
 
 
-/* usb_autoresume_work - callback routine to autoresume a USB device */
-void usb_autoresume_work(struct work_struct *work)
+/**
+ * usb_disable_autosuspend - prevent a USB device from being autosuspended
+ * @udev: the USB device which may not be autosuspended
+ *
+ * This routine prevents @udev from being autosuspended and wakes it up
+ * if it is already autosuspended.
+ *
+ * The caller must hold @udev's device lock.
+ */
+int usb_disable_autosuspend(struct usb_device *udev)
 {
 {
-	struct usb_device *udev =
-		container_of(work, struct usb_device, autoresume);
+	int rc = 0;
 
 
-	/* Wake it up, let the drivers do their thing, and then put it
-	 * back to sleep.
-	 */
-	if (usb_autopm_do_device(udev, 1) == 0)
-		usb_autopm_do_device(udev, -1);
+	if (!udev->autosuspend_disabled) {
+		rc = usb_autoresume_device(udev);
+		if (rc == 0)
+			udev->autosuspend_disabled = 1;
+	}
+	return rc;
 }
 }
+EXPORT_SYMBOL_GPL(usb_disable_autosuspend);
 
 
 /**
 /**
  * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces
  * usb_autosuspend_device - delayed autosuspend of a USB device and its interfaces
@@ -1472,15 +1359,11 @@ void usb_autoresume_work(struct work_struct *work)
  * @udev and wants to allow it to autosuspend.  Examples would be when
  * @udev and wants to allow it to autosuspend.  Examples would be when
  * @udev's device file in usbfs is closed or after a configuration change.
  * @udev's device file in usbfs is closed or after a configuration change.
  *
  *
- * @udev's usage counter is decremented.  If it or any of the usage counters
- * for an active interface is greater than 0, no autosuspend request will be
- * queued.  (If an interface driver does not support autosuspend then its
- * usage counter is permanently positive.)  Furthermore, if an interface
- * driver requires remote-wakeup capability during autosuspend but remote
- * wakeup is disabled, the autosuspend will fail.
+ * @udev's usage counter is decremented; if it drops to 0 and all the
+ * interfaces are inactive then a delayed autosuspend will be attempted.
+ * The attempt may fail (see autosuspend_check()).
  *
  *
- * Often the caller will hold @udev's device lock, but this is not
- * necessary.
+ * The caller must hold @udev's device lock.
  *
  *
  * This routine can run only in process context.
  * This routine can run only in process context.
  */
  */
@@ -1488,9 +1371,11 @@ void usb_autosuspend_device(struct usb_device *udev)
 {
 {
 	int	status;
 	int	status;
 
 
-	status = usb_autopm_do_device(udev, -1);
-	dev_vdbg(&udev->dev, "%s: cnt %d\n",
-			__func__, udev->pm_usage_cnt);
+	udev->last_busy = jiffies;
+	status = pm_runtime_put_sync(&udev->dev);
+	dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n",
+			__func__, atomic_read(&udev->dev.power.usage_count),
+			status);
 }
 }
 
 
 /**
 /**
@@ -1500,17 +1385,22 @@ void usb_autosuspend_device(struct usb_device *udev)
  * This routine should be called when a core subsystem thinks @udev may
  * This routine should be called when a core subsystem thinks @udev may
  * be ready to autosuspend.
  * be ready to autosuspend.
  *
  *
- * @udev's usage counter left unchanged.  If it or any of the usage counters
- * for an active interface is greater than 0, or autosuspend is not allowed
- * for any other reason, no autosuspend request will be queued.
+ * @udev's usage counter left unchanged.  If it is 0 and all the interfaces
+ * are inactive then an autosuspend will be attempted.  The attempt may
+ * fail or be delayed.
+ *
+ * The caller must hold @udev's device lock.
  *
  *
  * This routine can run only in process context.
  * This routine can run only in process context.
  */
  */
 void usb_try_autosuspend_device(struct usb_device *udev)
 void usb_try_autosuspend_device(struct usb_device *udev)
 {
 {
-	usb_autopm_do_device(udev, 0);
-	dev_vdbg(&udev->dev, "%s: cnt %d\n",
-			__func__, udev->pm_usage_cnt);
+	int	status;
+
+	status = pm_runtime_idle(&udev->dev);
+	dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n",
+			__func__, atomic_read(&udev->dev.power.usage_count),
+			status);
 }
 }
 
 
 /**
 /**
@@ -1519,16 +1409,15 @@ void usb_try_autosuspend_device(struct usb_device *udev)
  *
  *
  * This routine should be called when a core subsystem wants to use @udev
  * This routine should be called when a core subsystem wants to use @udev
  * and needs to guarantee that it is not suspended.  No autosuspend will
  * and needs to guarantee that it is not suspended.  No autosuspend will
- * occur until usb_autosuspend_device is called.  (Note that this will not
- * prevent suspend events originating in the PM core.)  Examples would be
- * when @udev's device file in usbfs is opened or when a remote-wakeup
+ * occur until usb_autosuspend_device() is called.  (Note that this will
+ * not prevent suspend events originating in the PM core.)  Examples would
+ * be when @udev's device file in usbfs is opened or when a remote-wakeup
  * request is received.
  * request is received.
  *
  *
  * @udev's usage counter is incremented to prevent subsequent autosuspends.
  * @udev's usage counter is incremented to prevent subsequent autosuspends.
  * However if the autoresume fails then the usage counter is re-decremented.
  * However if the autoresume fails then the usage counter is re-decremented.
  *
  *
- * Often the caller will hold @udev's device lock, but this is not
- * necessary (and attempting it might cause deadlock).
+ * The caller must hold @udev's device lock.
  *
  *
  * This routine can run only in process context.
  * This routine can run only in process context.
  */
  */
@@ -1536,42 +1425,14 @@ int usb_autoresume_device(struct usb_device *udev)
 {
 {
 	int	status;
 	int	status;
 
 
-	status = usb_autopm_do_device(udev, 1);
-	dev_vdbg(&udev->dev, "%s: status %d cnt %d\n",
-			__func__, status, udev->pm_usage_cnt);
-	return status;
-}
-
-/* Internal routine to adjust an interface's usage counter and change
- * its device's autosuspend state.
- */
-static int usb_autopm_do_interface(struct usb_interface *intf,
-		int inc_usage_cnt)
-{
-	struct usb_device	*udev = interface_to_usbdev(intf);
-	int			status = 0;
-
-	usb_pm_lock(udev);
-	if (intf->condition == USB_INTERFACE_UNBOUND)
-		status = -ENODEV;
-	else {
-		atomic_add(inc_usage_cnt, &intf->pm_usage_cnt);
-		udev->last_busy = jiffies;
-		if (inc_usage_cnt >= 0 &&
-				atomic_read(&intf->pm_usage_cnt) > 0) {
-			if (udev->state == USB_STATE_SUSPENDED)
-				status = usb_resume_both(udev,
-						PMSG_AUTO_RESUME);
-			if (status != 0)
-				atomic_sub(inc_usage_cnt, &intf->pm_usage_cnt);
-			else
-				udev->last_busy = jiffies;
-		} else if (inc_usage_cnt <= 0 &&
-				atomic_read(&intf->pm_usage_cnt) <= 0) {
-			status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
-		}
-	}
-	usb_pm_unlock(udev);
+	status = pm_runtime_get_sync(&udev->dev);
+	if (status < 0)
+		pm_runtime_put_sync(&udev->dev);
+	dev_vdbg(&udev->dev, "%s: cnt %d -> %d\n",
+			__func__, atomic_read(&udev->dev.power.usage_count),
+			status);
+	if (status > 0)
+		status = 0;
 	return status;
 	return status;
 }
 }
 
 
@@ -1585,34 +1446,25 @@ static int usb_autopm_do_interface(struct usb_interface *intf,
  * closed.
  * closed.
  *
  *
  * The routine decrements @intf's usage counter.  When the counter reaches
  * The routine decrements @intf's usage counter.  When the counter reaches
- * 0, a delayed autosuspend request for @intf's device is queued.  When
- * the delay expires, if @intf->pm_usage_cnt is still <= 0 along with all
- * the other usage counters for the sibling interfaces and @intf's
- * usb_device, the device and all its interfaces will be autosuspended.
- *
- * Note that @intf->pm_usage_cnt is owned by the interface driver.  The
- * core will not change its value other than the increment and decrement
- * in usb_autopm_get_interface and usb_autopm_put_interface.  The driver
- * may use this simple counter-oriented discipline or may set the value
- * any way it likes.
+ * 0, a delayed autosuspend request for @intf's device is attempted.  The
+ * attempt may fail (see autosuspend_check()).
  *
  *
  * If the driver has set @intf->needs_remote_wakeup then autosuspend will
  * If the driver has set @intf->needs_remote_wakeup then autosuspend will
  * take place only if the device's remote-wakeup facility is enabled.
  * take place only if the device's remote-wakeup facility is enabled.
  *
  *
- * Suspend method calls queued by this routine can arrive at any time
- * while @intf is resumed and its usage counter is equal to 0.  They are
- * not protected by the usb_device's lock but only by its pm_mutex.
- * Drivers must provide their own synchronization.
- *
  * This routine can run only in process context.
  * This routine can run only in process context.
  */
  */
 void usb_autopm_put_interface(struct usb_interface *intf)
 void usb_autopm_put_interface(struct usb_interface *intf)
 {
 {
-	int	status;
+	struct usb_device	*udev = interface_to_usbdev(intf);
+	int			status;
 
 
-	status = usb_autopm_do_interface(intf, -1);
-	dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
-			__func__, status, atomic_read(&intf->pm_usage_cnt));
+	udev->last_busy = jiffies;
+	atomic_dec(&intf->pm_usage_cnt);
+	status = pm_runtime_put_sync(&intf->dev);
+	dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
+			__func__, atomic_read(&intf->dev.power.usage_count),
+			status);
 }
 }
 EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
 EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
 
 
@@ -1620,11 +1472,11 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
  * usb_autopm_put_interface_async - decrement a USB interface's PM-usage counter
  * usb_autopm_put_interface_async - decrement a USB interface's PM-usage counter
  * @intf: the usb_interface whose counter should be decremented
  * @intf: the usb_interface whose counter should be decremented
  *
  *
- * This routine does essentially the same thing as
- * usb_autopm_put_interface(): it decrements @intf's usage counter and
- * queues a delayed autosuspend request if the counter is <= 0.  The
- * difference is that it does not acquire the device's pm_mutex;
- * callers must handle all synchronization issues themselves.
+ * This routine does much the same thing as usb_autopm_put_interface():
+ * It decrements @intf's usage counter and schedules a delayed
+ * autosuspend request if the counter is <= 0.  The difference is that it
+ * does not perform any synchronization; callers should hold a private
+ * lock and handle all synchronization issues themselves.
  *
  *
  * Typically a driver would call this routine during an URB's completion
  * Typically a driver would call this routine during an URB's completion
  * handler, if no more URBs were pending.
  * handler, if no more URBs were pending.
@@ -1634,27 +1486,57 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
 void usb_autopm_put_interface_async(struct usb_interface *intf)
 void usb_autopm_put_interface_async(struct usb_interface *intf)
 {
 {
 	struct usb_device	*udev = interface_to_usbdev(intf);
 	struct usb_device	*udev = interface_to_usbdev(intf);
+	unsigned long		last_busy;
 	int			status = 0;
 	int			status = 0;
 
 
-	if (intf->condition == USB_INTERFACE_UNBOUND) {
-		status = -ENODEV;
-	} else {
-		udev->last_busy = jiffies;
-		atomic_dec(&intf->pm_usage_cnt);
-		if (udev->autosuspend_disabled || udev->autosuspend_delay < 0)
-			status = -EPERM;
-		else if (atomic_read(&intf->pm_usage_cnt) <= 0 &&
-				!timer_pending(&udev->autosuspend.timer)) {
-			queue_delayed_work(ksuspend_usb_wq, &udev->autosuspend,
+	last_busy = udev->last_busy;
+	udev->last_busy = jiffies;
+	atomic_dec(&intf->pm_usage_cnt);
+	pm_runtime_put_noidle(&intf->dev);
+
+	if (!udev->autosuspend_disabled) {
+		/* Optimization: Don't schedule a delayed autosuspend if
+		 * the timer is already running and the expiration time
+		 * wouldn't change.
+		 *
+		 * We have to use the interface's timer.  Attempts to
+		 * schedule a suspend for the device would fail because
+		 * the interface is still active.
+		 */
+		if (intf->dev.power.timer_expires == 0 ||
+				round_jiffies_up(last_busy) !=
+				round_jiffies_up(jiffies)) {
+			status = pm_schedule_suspend(&intf->dev,
+					jiffies_to_msecs(
 					round_jiffies_up_relative(
 					round_jiffies_up_relative(
-						udev->autosuspend_delay));
+						udev->autosuspend_delay)));
 		}
 		}
 	}
 	}
-	dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
-			__func__, status, atomic_read(&intf->pm_usage_cnt));
+	dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
+			__func__, atomic_read(&intf->dev.power.usage_count),
+			status);
 }
 }
 EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async);
 EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async);
 
 
+/**
+ * usb_autopm_put_interface_no_suspend - decrement a USB interface's PM-usage counter
+ * @intf: the usb_interface whose counter should be decremented
+ *
+ * This routine decrements @intf's usage counter but does not carry out an
+ * autosuspend.
+ *
+ * This routine can run in atomic context.
+ */
+void usb_autopm_put_interface_no_suspend(struct usb_interface *intf)
+{
+	struct usb_device	*udev = interface_to_usbdev(intf);
+
+	udev->last_busy = jiffies;
+	atomic_dec(&intf->pm_usage_cnt);
+	pm_runtime_put_noidle(&intf->dev);
+}
+EXPORT_SYMBOL_GPL(usb_autopm_put_interface_no_suspend);
+
 /**
 /**
  * usb_autopm_get_interface - increment a USB interface's PM-usage counter
  * usb_autopm_get_interface - increment a USB interface's PM-usage counter
  * @intf: the usb_interface whose counter should be incremented
  * @intf: the usb_interface whose counter should be incremented
@@ -1667,25 +1549,8 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface_async);
  * or @intf is unbound.  A typical example would be a character-device
  * or @intf is unbound.  A typical example would be a character-device
  * driver when its device file is opened.
  * driver when its device file is opened.
  *
  *
- *
- * The routine increments @intf's usage counter.  (However if the
- * autoresume fails then the counter is re-decremented.)  So long as the
- * counter is greater than 0, autosuspend will not be allowed for @intf
- * or its usb_device.  When the driver is finished using @intf it should
- * call usb_autopm_put_interface() to decrement the usage counter and
- * queue a delayed autosuspend request (if the counter is <= 0).
- *
- *
- * Note that @intf->pm_usage_cnt is owned by the interface driver.  The
- * core will not change its value other than the increment and decrement
- * in usb_autopm_get_interface and usb_autopm_put_interface.  The driver
- * may use this simple counter-oriented discipline or may set the value
- * any way it likes.
- *
- * Resume method calls generated by this routine can arrive at any time
- * while @intf is suspended.  They are not protected by the usb_device's
- * lock but only by its pm_mutex.  Drivers must provide their own
- * synchronization.
+ * @intf's usage counter is incremented to prevent subsequent autosuspends.
+ * However if the autoresume fails then the counter is re-decremented.
  *
  *
  * This routine can run only in process context.
  * This routine can run only in process context.
  */
  */
@@ -1693,9 +1558,16 @@ int usb_autopm_get_interface(struct usb_interface *intf)
 {
 {
 	int	status;
 	int	status;
 
 
-	status = usb_autopm_do_interface(intf, 1);
-	dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
-			__func__, status, atomic_read(&intf->pm_usage_cnt));
+	status = pm_runtime_get_sync(&intf->dev);
+	if (status < 0)
+		pm_runtime_put_sync(&intf->dev);
+	else
+		atomic_inc(&intf->pm_usage_cnt);
+	dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
+			__func__, atomic_read(&intf->dev.power.usage_count),
+			status);
+	if (status > 0)
+		status = 0;
 	return status;
 	return status;
 }
 }
 EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
 EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
@@ -1705,149 +1577,207 @@ EXPORT_SYMBOL_GPL(usb_autopm_get_interface);
  * @intf: the usb_interface whose counter should be incremented
  * @intf: the usb_interface whose counter should be incremented
  *
  *
  * This routine does much the same thing as
  * This routine does much the same thing as
- * usb_autopm_get_interface(): it increments @intf's usage counter and
- * queues an autoresume request if the result is > 0.  The differences
- * are that it does not acquire the device's pm_mutex (callers must
- * handle all synchronization issues themselves), and it does not
- * autoresume the device directly (it only queues a request).  After a
- * successful call, the device will generally not yet be resumed.
+ * usb_autopm_get_interface(): It increments @intf's usage counter and
+ * queues an autoresume request if the device is suspended.  The
+ * differences are that it does not perform any synchronization (callers
+ * should hold a private lock and handle all synchronization issues
+ * themselves), and it does not autoresume the device directly (it only
+ * queues a request).  After a successful call, the device may not yet be
+ * resumed.
  *
  *
  * This routine can run in atomic context.
  * This routine can run in atomic context.
  */
  */
 int usb_autopm_get_interface_async(struct usb_interface *intf)
 int usb_autopm_get_interface_async(struct usb_interface *intf)
 {
 {
-	struct usb_device	*udev = interface_to_usbdev(intf);
-	int			status = 0;
+	int		status = 0;
+	enum rpm_status	s;
 
 
-	if (intf->condition == USB_INTERFACE_UNBOUND)
-		status = -ENODEV;
-	else {
+	/* Don't request a resume unless the interface is already suspending
+	 * or suspended.  Doing so would force a running suspend timer to be
+	 * cancelled.
+	 */
+	pm_runtime_get_noresume(&intf->dev);
+	s = ACCESS_ONCE(intf->dev.power.runtime_status);
+	if (s == RPM_SUSPENDING || s == RPM_SUSPENDED)
+		status = pm_request_resume(&intf->dev);
+
+	if (status < 0 && status != -EINPROGRESS)
+		pm_runtime_put_noidle(&intf->dev);
+	else
 		atomic_inc(&intf->pm_usage_cnt);
 		atomic_inc(&intf->pm_usage_cnt);
-		if (atomic_read(&intf->pm_usage_cnt) > 0 &&
-				udev->state == USB_STATE_SUSPENDED)
-			queue_work(ksuspend_usb_wq, &udev->autoresume);
-	}
-	dev_vdbg(&intf->dev, "%s: status %d cnt %d\n",
-			__func__, status, atomic_read(&intf->pm_usage_cnt));
+	dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
+			__func__, atomic_read(&intf->dev.power.usage_count),
+			status);
+	if (status > 0)
+		status = 0;
 	return status;
 	return status;
 }
 }
 EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async);
 EXPORT_SYMBOL_GPL(usb_autopm_get_interface_async);
 
 
-#else
-
-void usb_autosuspend_work(struct work_struct *work)
-{}
-
-void usb_autoresume_work(struct work_struct *work)
-{}
-
-#endif /* CONFIG_USB_SUSPEND */
-
 /**
 /**
- * usb_external_suspend_device - external suspend of a USB device and its interfaces
- * @udev: the usb_device to suspend
- * @msg: Power Management message describing this state transition
+ * usb_autopm_get_interface_no_resume - increment a USB interface's PM-usage counter
+ * @intf: the usb_interface whose counter should be incremented
  *
  *
- * This routine handles external suspend requests: ones not generated
- * internally by a USB driver (autosuspend) but rather coming from the user
- * (via sysfs) or the PM core (system sleep).  The suspend will be carried
- * out regardless of @udev's usage counter or those of its interfaces,
- * and regardless of whether or not remote wakeup is enabled.  Of course,
- * interface drivers still have the option of failing the suspend (if
- * there are unsuspended children, for example).
+ * This routine increments @intf's usage counter but does not carry out an
+ * autoresume.
  *
  *
- * The caller must hold @udev's device lock.
+ * This routine can run in atomic context.
  */
  */
-int usb_external_suspend_device(struct usb_device *udev, pm_message_t msg)
+void usb_autopm_get_interface_no_resume(struct usb_interface *intf)
 {
 {
-	int	status;
+	struct usb_device	*udev = interface_to_usbdev(intf);
 
 
-	do_unbind_rebind(udev, DO_UNBIND);
-	usb_pm_lock(udev);
-	status = usb_suspend_both(udev, msg);
-	usb_pm_unlock(udev);
-	return status;
+	udev->last_busy = jiffies;
+	atomic_inc(&intf->pm_usage_cnt);
+	pm_runtime_get_noresume(&intf->dev);
 }
 }
+EXPORT_SYMBOL_GPL(usb_autopm_get_interface_no_resume);
 
 
-/**
- * usb_external_resume_device - external resume of a USB device and its interfaces
- * @udev: the usb_device to resume
- * @msg: Power Management message describing this state transition
- *
- * This routine handles external resume requests: ones not generated
- * internally by a USB driver (autoresume) but rather coming from the user
- * (via sysfs), the PM core (system resume), or the device itself (remote
- * wakeup).  @udev's usage counter is unaffected.
- *
- * The caller must hold @udev's device lock.
- */
-int usb_external_resume_device(struct usb_device *udev, pm_message_t msg)
+/* Internal routine to check whether we may autosuspend a device. */
+static int autosuspend_check(struct usb_device *udev)
 {
 {
-	int	status;
+	int			i;
+	struct usb_interface	*intf;
+	unsigned long		suspend_time, j;
 
 
-	usb_pm_lock(udev);
-	status = usb_resume_both(udev, msg);
-	udev->last_busy = jiffies;
-	usb_pm_unlock(udev);
-	if (status == 0)
-		do_unbind_rebind(udev, DO_REBIND);
+	/* Fail if autosuspend is disabled, or any interfaces are in use, or
+	 * any interface drivers require remote wakeup but it isn't available.
+	 */
+	udev->do_remote_wakeup = device_may_wakeup(&udev->dev);
+	if (udev->actconfig) {
+		for (i = 0; i < udev->actconfig->desc.bNumInterfaces; i++) {
+			intf = udev->actconfig->interface[i];
 
 
-	/* Now that the device is awake, we can start trying to autosuspend
-	 * it again. */
-	if (status == 0)
-		usb_try_autosuspend_device(udev);
-	return status;
+			/* We don't need to check interfaces that are
+			 * disabled for runtime PM.  Either they are unbound
+			 * or else their drivers don't support autosuspend
+			 * and so they are permanently active.
+			 */
+			if (intf->dev.power.disable_depth)
+				continue;
+			if (atomic_read(&intf->dev.power.usage_count) > 0)
+				return -EBUSY;
+			if (intf->needs_remote_wakeup &&
+					!udev->do_remote_wakeup) {
+				dev_dbg(&udev->dev, "remote wakeup needed "
+						"for autosuspend\n");
+				return -EOPNOTSUPP;
+			}
+
+			/* Don't allow autosuspend if the device will need
+			 * a reset-resume and any of its interface drivers
+			 * doesn't include support or needs remote wakeup.
+			 */
+			if (udev->quirks & USB_QUIRK_RESET_RESUME) {
+				struct usb_driver *driver;
+
+				driver = to_usb_driver(intf->dev.driver);
+				if (!driver->reset_resume ||
+						intf->needs_remote_wakeup)
+					return -EOPNOTSUPP;
+			}
+		}
+	}
+
+	/* If everything is okay but the device hasn't been idle for long
+	 * enough, queue a delayed autosuspend request.
+	 */
+	j = ACCESS_ONCE(jiffies);
+	suspend_time = udev->last_busy + udev->autosuspend_delay;
+	if (time_before(j, suspend_time)) {
+		pm_schedule_suspend(&udev->dev, jiffies_to_msecs(
+				round_jiffies_up_relative(suspend_time - j)));
+		return -EAGAIN;
+	}
+	return 0;
 }
 }
 
 
-int usb_suspend(struct device *dev, pm_message_t msg)
+static int usb_runtime_suspend(struct device *dev)
 {
 {
-	struct usb_device	*udev;
-
-	udev = to_usb_device(dev);
+	int	status = 0;
 
 
-	/* If udev is already suspended, we can skip this suspend and
-	 * we should also skip the upcoming system resume.  High-speed
-	 * root hubs are an exception; they need to resume whenever the
-	 * system wakes up in order for USB-PERSIST port handover to work
-	 * properly.
+	/* A USB device can be suspended if it passes the various autosuspend
+	 * checks.  Runtime suspend for a USB device means suspending all the
+	 * interfaces and then the device itself.
 	 */
 	 */
-	if (udev->state == USB_STATE_SUSPENDED) {
-		if (udev->parent || udev->speed != USB_SPEED_HIGH)
-			udev->skip_sys_resume = 1;
-		return 0;
+	if (is_usb_device(dev)) {
+		struct usb_device	*udev = to_usb_device(dev);
+
+		if (autosuspend_check(udev) != 0)
+			return -EAGAIN;
+
+		status = usb_suspend_both(udev, PMSG_AUTO_SUSPEND);
+
+		/* If an interface fails the suspend, adjust the last_busy
+		 * time so that we don't get another suspend attempt right
+		 * away.
+		 */
+		if (status) {
+			udev->last_busy = jiffies +
+					(udev->autosuspend_delay == 0 ?
+						HZ/2 : 0);
+		}
+
+		/* Prevent the parent from suspending immediately after */
+		else if (udev->parent) {
+			udev->parent->last_busy = jiffies;
+		}
 	}
 	}
 
 
-	udev->skip_sys_resume = 0;
-	return usb_external_suspend_device(udev, msg);
+	/* Runtime suspend for a USB interface doesn't mean anything. */
+	return status;
 }
 }
 
 
-int usb_resume(struct device *dev, pm_message_t msg)
+static int usb_runtime_resume(struct device *dev)
 {
 {
-	struct usb_device	*udev;
-	int			status;
+	/* Runtime resume for a USB device means resuming both the device
+	 * and all its interfaces.
+	 */
+	if (is_usb_device(dev)) {
+		struct usb_device	*udev = to_usb_device(dev);
+		int			status;
 
 
-	udev = to_usb_device(dev);
+		status = usb_resume_both(udev, PMSG_AUTO_RESUME);
+		udev->last_busy = jiffies;
+		return status;
+	}
 
 
-	/* If udev->skip_sys_resume is set then udev was already suspended
-	 * when the system sleep started, so we don't want to resume it
-	 * during this system wakeup.
-	 */
-	if (udev->skip_sys_resume)
-		return 0;
-	status = usb_external_resume_device(udev, msg);
+	/* Runtime resume for a USB interface doesn't mean anything. */
+	return 0;
+}
 
 
-	/* Avoid PM error messages for devices disconnected while suspended
-	 * as we'll display regular disconnect messages just a bit later.
+static int usb_runtime_idle(struct device *dev)
+{
+	/* An idle USB device can be suspended if it passes the various
+	 * autosuspend checks.  An idle interface can be suspended at
+	 * any time.
 	 */
 	 */
-	if (status == -ENODEV)
-		return 0;
-	return status;
+	if (is_usb_device(dev)) {
+		struct usb_device	*udev = to_usb_device(dev);
+
+		if (autosuspend_check(udev) != 0)
+			return 0;
+	}
+
+	pm_runtime_suspend(dev);
+	return 0;
 }
 }
 
 
-#endif /* CONFIG_PM */
+static struct dev_pm_ops usb_bus_pm_ops = {
+	.runtime_suspend =	usb_runtime_suspend,
+	.runtime_resume =	usb_runtime_resume,
+	.runtime_idle =		usb_runtime_idle,
+};
+
+#else
+
+#define usb_bus_pm_ops	(*(struct dev_pm_ops *) NULL)
+
+#endif /* CONFIG_USB_SUSPEND */
 
 
 struct bus_type usb_bus_type = {
 struct bus_type usb_bus_type = {
 	.name =		"usb",
 	.name =		"usb",
 	.match =	usb_device_match,
 	.match =	usb_device_match,
 	.uevent =	usb_uevent,
 	.uevent =	usb_uevent,
+	.pm =		&usb_bus_pm_ops,
 };
 };

+ 0 - 2
drivers/usb/core/file.c

@@ -34,7 +34,6 @@ static int usb_open(struct inode * inode, struct file * file)
 	int err = -ENODEV;
 	int err = -ENODEV;
 	const struct file_operations *old_fops, *new_fops = NULL;
 	const struct file_operations *old_fops, *new_fops = NULL;
 
 
-	lock_kernel();
 	down_read(&minor_rwsem);
 	down_read(&minor_rwsem);
 	c = usb_minors[minor];
 	c = usb_minors[minor];
 
 
@@ -53,7 +52,6 @@ static int usb_open(struct inode * inode, struct file * file)
 	fops_put(old_fops);
 	fops_put(old_fops);
  done:
  done:
 	up_read(&minor_rwsem);
 	up_read(&minor_rwsem);
-	unlock_kernel();
 	return err;
 	return err;
 }
 }
 
 

+ 18 - 9
drivers/usb/core/hcd.c

@@ -39,6 +39,7 @@
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/workqueue.h>
 #include <linux/workqueue.h>
 #include <linux/mutex.h>
 #include <linux/mutex.h>
+#include <linux/pm_runtime.h>
 
 
 #include <linux/usb.h>
 #include <linux/usb.h>
 
 
@@ -141,7 +142,7 @@ static const u8 usb3_rh_dev_descriptor[18] = {
 	0x09,       /*  __u8  bMaxPacketSize0; 2^9 = 512 Bytes */
 	0x09,       /*  __u8  bMaxPacketSize0; 2^9 = 512 Bytes */
 
 
 	0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation */
 	0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation */
-	0x02, 0x00, /*  __le16 idProduct; device 0x0002 */
+	0x03, 0x00, /*  __le16 idProduct; device 0x0003 */
 	KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */
 	KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */
 
 
 	0x03,       /*  __u8  iManufacturer; */
 	0x03,       /*  __u8  iManufacturer; */
@@ -1670,11 +1671,16 @@ int usb_hcd_alloc_bandwidth(struct usb_device *udev,
 			}
 			}
 		}
 		}
 		for (i = 0; i < num_intfs; ++i) {
 		for (i = 0; i < num_intfs; ++i) {
+			struct usb_host_interface *first_alt;
+			int iface_num;
+
+			first_alt = &new_config->intf_cache[i]->altsetting[0];
+			iface_num = first_alt->desc.bInterfaceNumber;
 			/* Set up endpoints for alternate interface setting 0 */
 			/* Set up endpoints for alternate interface setting 0 */
-			alt = usb_find_alt_setting(new_config, i, 0);
+			alt = usb_find_alt_setting(new_config, iface_num, 0);
 			if (!alt)
 			if (!alt)
 				/* No alt setting 0? Pick the first setting. */
 				/* No alt setting 0? Pick the first setting. */
-				alt = &new_config->intf_cache[i]->altsetting[0];
+				alt = first_alt;
 
 
 			for (j = 0; j < alt->desc.bNumEndpoints; j++) {
 			for (j = 0; j < alt->desc.bNumEndpoints; j++) {
 				ret = hcd->driver->add_endpoint(hcd, udev, &alt->endpoint[j]);
 				ret = hcd->driver->add_endpoint(hcd, udev, &alt->endpoint[j]);
@@ -1853,6 +1859,10 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
 	return status;
 	return status;
 }
 }
 
 
+#endif	/* CONFIG_PM */
+
+#ifdef	CONFIG_USB_SUSPEND
+
 /* Workqueue routine for root-hub remote wakeup */
 /* Workqueue routine for root-hub remote wakeup */
 static void hcd_resume_work(struct work_struct *work)
 static void hcd_resume_work(struct work_struct *work)
 {
 {
@@ -1860,8 +1870,7 @@ static void hcd_resume_work(struct work_struct *work)
 	struct usb_device *udev = hcd->self.root_hub;
 	struct usb_device *udev = hcd->self.root_hub;
 
 
 	usb_lock_device(udev);
 	usb_lock_device(udev);
-	usb_mark_last_busy(udev);
-	usb_external_resume_device(udev, PMSG_REMOTE_RESUME);
+	usb_remote_wakeup(udev);
 	usb_unlock_device(udev);
 	usb_unlock_device(udev);
 }
 }
 
 
@@ -1880,12 +1889,12 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
 
 
 	spin_lock_irqsave (&hcd_root_hub_lock, flags);
 	spin_lock_irqsave (&hcd_root_hub_lock, flags);
 	if (hcd->rh_registered)
 	if (hcd->rh_registered)
-		queue_work(ksuspend_usb_wq, &hcd->wakeup_work);
+		queue_work(pm_wq, &hcd->wakeup_work);
 	spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
 	spin_unlock_irqrestore (&hcd_root_hub_lock, flags);
 }
 }
 EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
 EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
 
 
-#endif
+#endif	/* CONFIG_USB_SUSPEND */
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
@@ -2030,7 +2039,7 @@ struct usb_hcd *usb_create_hcd (const struct hc_driver *driver,
 	init_timer(&hcd->rh_timer);
 	init_timer(&hcd->rh_timer);
 	hcd->rh_timer.function = rh_timer_func;
 	hcd->rh_timer.function = rh_timer_func;
 	hcd->rh_timer.data = (unsigned long) hcd;
 	hcd->rh_timer.data = (unsigned long) hcd;
-#ifdef CONFIG_PM
+#ifdef CONFIG_USB_SUSPEND
 	INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
 	INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
 #endif
 #endif
 	mutex_init(&hcd->bandwidth_mutex);
 	mutex_init(&hcd->bandwidth_mutex);
@@ -2230,7 +2239,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
 	hcd->rh_registered = 0;
 	hcd->rh_registered = 0;
 	spin_unlock_irq (&hcd_root_hub_lock);
 	spin_unlock_irq (&hcd_root_hub_lock);
 
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_USB_SUSPEND
 	cancel_work_sync(&hcd->wakeup_work);
 	cancel_work_sync(&hcd->wakeup_work);
 #endif
 #endif
 
 

+ 9 - 4
drivers/usb/core/hcd.h

@@ -80,7 +80,7 @@ struct usb_hcd {
 
 
 	struct timer_list	rh_timer;	/* drives root-hub polling */
 	struct timer_list	rh_timer;	/* drives root-hub polling */
 	struct urb		*status_urb;	/* the current status urb */
 	struct urb		*status_urb;	/* the current status urb */
-#ifdef CONFIG_PM
+#ifdef CONFIG_USB_SUSPEND
 	struct work_struct	wakeup_work;	/* for remote wakeup */
 	struct work_struct	wakeup_work;	/* for remote wakeup */
 #endif
 #endif
 
 
@@ -248,7 +248,7 @@ struct hc_driver {
 	/* xHCI specific functions */
 	/* xHCI specific functions */
 		/* Called by usb_alloc_dev to alloc HC device structures */
 		/* Called by usb_alloc_dev to alloc HC device structures */
 	int	(*alloc_dev)(struct usb_hcd *, struct usb_device *);
 	int	(*alloc_dev)(struct usb_hcd *, struct usb_device *);
-		/* Called by usb_release_dev to free HC device structures */
+		/* Called by usb_disconnect to free HC device structures */
 	void	(*free_dev)(struct usb_hcd *, struct usb_device *);
 	void	(*free_dev)(struct usb_hcd *, struct usb_device *);
 
 
 	/* Bandwidth computation functions */
 	/* Bandwidth computation functions */
@@ -286,6 +286,7 @@ struct hc_driver {
 		 */
 		 */
 	int	(*update_hub_device)(struct usb_hcd *, struct usb_device *hdev,
 	int	(*update_hub_device)(struct usb_hcd *, struct usb_device *hdev,
 			struct usb_tt *tt, gfp_t mem_flags);
 			struct usb_tt *tt, gfp_t mem_flags);
+	int	(*reset_device)(struct usb_hcd *, struct usb_device *);
 };
 };
 
 
 extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
 extern int usb_hcd_link_urb_to_ep(struct usb_hcd *hcd, struct urb *urb);
@@ -463,16 +464,20 @@ extern int usb_find_interface_driver(struct usb_device *dev,
 #define usb_endpoint_out(ep_dir)	(!((ep_dir) & USB_DIR_IN))
 #define usb_endpoint_out(ep_dir)	(!((ep_dir) & USB_DIR_IN))
 
 
 #ifdef CONFIG_PM
 #ifdef CONFIG_PM
-extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);
 extern void usb_root_hub_lost_power(struct usb_device *rhdev);
 extern void usb_root_hub_lost_power(struct usb_device *rhdev);
 extern int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg);
 extern int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg);
 extern int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg);
 extern int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg);
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_USB_SUSPEND
+extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);
 #else
 #else
 static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
 static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
 {
 {
 	return;
 	return;
 }
 }
-#endif /* CONFIG_PM */
+#endif /* CONFIG_USB_SUSPEND */
+
 
 
 /*
 /*
  * USB device fs stuff
  * USB device fs stuff

+ 53 - 67
drivers/usb/core/hub.c

@@ -22,6 +22,7 @@
 #include <linux/kthread.h>
 #include <linux/kthread.h>
 #include <linux/mutex.h>
 #include <linux/mutex.h>
 #include <linux/freezer.h>
 #include <linux/freezer.h>
+#include <linux/pm_runtime.h>
 
 
 #include <asm/uaccess.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 #include <asm/byteorder.h>
@@ -71,7 +72,6 @@ struct usb_hub {
 
 
 	unsigned		mA_per_port;	/* current for each child */
 	unsigned		mA_per_port;	/* current for each child */
 
 
-	unsigned		init_done:1;
 	unsigned		limited_power:1;
 	unsigned		limited_power:1;
 	unsigned		quiescing:1;
 	unsigned		quiescing:1;
 	unsigned		disconnected:1;
 	unsigned		disconnected:1;
@@ -820,7 +820,6 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
 	}
 	}
  init3:
  init3:
 	hub->quiescing = 0;
 	hub->quiescing = 0;
-	hub->init_done = 1;
 
 
 	status = usb_submit_urb(hub->urb, GFP_NOIO);
 	status = usb_submit_urb(hub->urb, GFP_NOIO);
 	if (status < 0)
 	if (status < 0)
@@ -861,11 +860,6 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
 	int i;
 	int i;
 
 
 	cancel_delayed_work_sync(&hub->init_work);
 	cancel_delayed_work_sync(&hub->init_work);
-	if (!hub->init_done) {
-		hub->init_done = 1;
-		usb_autopm_put_interface_no_suspend(
-				to_usb_interface(hub->intfdev));
-	}
 
 
 	/* khubd and related activity won't re-trigger */
 	/* khubd and related activity won't re-trigger */
 	hub->quiescing = 1;
 	hub->quiescing = 1;
@@ -1224,6 +1218,9 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
 	desc = intf->cur_altsetting;
 	desc = intf->cur_altsetting;
 	hdev = interface_to_usbdev(intf);
 	hdev = interface_to_usbdev(intf);
 
 
+	/* Hubs have proper suspend/resume support */
+	usb_enable_autosuspend(hdev);
+
 	if (hdev->level == MAX_TOPO_LEVEL) {
 	if (hdev->level == MAX_TOPO_LEVEL) {
 		dev_err(&intf->dev,
 		dev_err(&intf->dev,
 			"Unsupported bus topology: hub nested too deep\n");
 			"Unsupported bus topology: hub nested too deep\n");
@@ -1402,10 +1399,8 @@ static void recursively_mark_NOTATTACHED(struct usb_device *udev)
 		if (udev->children[i])
 		if (udev->children[i])
 			recursively_mark_NOTATTACHED(udev->children[i]);
 			recursively_mark_NOTATTACHED(udev->children[i]);
 	}
 	}
-	if (udev->state == USB_STATE_SUSPENDED) {
-		udev->discon_suspended = 1;
+	if (udev->state == USB_STATE_SUSPENDED)
 		udev->active_duration -= jiffies;
 		udev->active_duration -= jiffies;
-	}
 	udev->state = USB_STATE_NOTATTACHED;
 	udev->state = USB_STATE_NOTATTACHED;
 }
 }
 
 
@@ -1448,11 +1443,11 @@ void usb_set_device_state(struct usb_device *udev,
 					|| new_state == USB_STATE_SUSPENDED)
 					|| new_state == USB_STATE_SUSPENDED)
 				;	/* No change to wakeup settings */
 				;	/* No change to wakeup settings */
 			else if (new_state == USB_STATE_CONFIGURED)
 			else if (new_state == USB_STATE_CONFIGURED)
-				device_init_wakeup(&udev->dev,
+				device_set_wakeup_capable(&udev->dev,
 					(udev->actconfig->desc.bmAttributes
 					(udev->actconfig->desc.bmAttributes
 					 & USB_CONFIG_ATT_WAKEUP));
 					 & USB_CONFIG_ATT_WAKEUP));
 			else
 			else
-				device_init_wakeup(&udev->dev, 0);
+				device_set_wakeup_capable(&udev->dev, 0);
 		}
 		}
 		if (udev->state == USB_STATE_SUSPENDED &&
 		if (udev->state == USB_STATE_SUSPENDED &&
 			new_state != USB_STATE_SUSPENDED)
 			new_state != USB_STATE_SUSPENDED)
@@ -1529,31 +1524,15 @@ static void update_address(struct usb_device *udev, int devnum)
 		udev->devnum = devnum;
 		udev->devnum = devnum;
 }
 }
 
 
-#ifdef	CONFIG_USB_SUSPEND
-
-static void usb_stop_pm(struct usb_device *udev)
+static void hub_free_dev(struct usb_device *udev)
 {
 {
-	/* Synchronize with the ksuspend thread to prevent any more
-	 * autosuspend requests from being submitted, and decrement
-	 * the parent's count of unsuspended children.
-	 */
-	usb_pm_lock(udev);
-	if (udev->parent && !udev->discon_suspended)
-		usb_autosuspend_device(udev->parent);
-	usb_pm_unlock(udev);
+	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
 
 
-	/* Stop any autosuspend or autoresume requests already submitted */
-	cancel_delayed_work_sync(&udev->autosuspend);
-	cancel_work_sync(&udev->autoresume);
+	/* Root hubs aren't real devices, so don't free HCD resources */
+	if (hcd->driver->free_dev && udev->parent)
+		hcd->driver->free_dev(hcd, udev);
 }
 }
 
 
-#else
-
-static inline void usb_stop_pm(struct usb_device *udev)
-{ }
-
-#endif
-
 /**
 /**
  * usb_disconnect - disconnect a device (usbcore-internal)
  * usb_disconnect - disconnect a device (usbcore-internal)
  * @pdev: pointer to device being disconnected
  * @pdev: pointer to device being disconnected
@@ -1622,7 +1601,7 @@ void usb_disconnect(struct usb_device **pdev)
 	*pdev = NULL;
 	*pdev = NULL;
 	spin_unlock_irq(&device_state_lock);
 	spin_unlock_irq(&device_state_lock);
 
 
-	usb_stop_pm(udev);
+	hub_free_dev(udev);
 
 
 	put_device(&udev->dev);
 	put_device(&udev->dev);
 }
 }
@@ -1799,9 +1778,18 @@ int usb_new_device(struct usb_device *udev)
 {
 {
 	int err;
 	int err;
 
 
-	/* Increment the parent's count of unsuspended children */
-	if (udev->parent)
-		usb_autoresume_device(udev->parent);
+	if (udev->parent) {
+		/* Initialize non-root-hub device wakeup to disabled;
+		 * device (un)configuration controls wakeup capable
+		 * sysfs power/wakeup controls wakeup enabled/disabled
+		 */
+		device_init_wakeup(&udev->dev, 0);
+		device_set_wakeup_enable(&udev->dev, 1);
+	}
+
+	/* Tell the runtime-PM framework the device is active */
+	pm_runtime_set_active(&udev->dev);
+	pm_runtime_enable(&udev->dev);
 
 
 	usb_detect_quirks(udev);
 	usb_detect_quirks(udev);
 	err = usb_enumerate_device(udev);	/* Read descriptors */
 	err = usb_enumerate_device(udev);	/* Read descriptors */
@@ -1833,7 +1821,8 @@ int usb_new_device(struct usb_device *udev)
 
 
 fail:
 fail:
 	usb_set_device_state(udev, USB_STATE_NOTATTACHED);
 	usb_set_device_state(udev, USB_STATE_NOTATTACHED);
-	usb_stop_pm(udev);
+	pm_runtime_disable(&udev->dev);
+	pm_runtime_set_suspended(&udev->dev);
 	return err;
 	return err;
 }
 }
 
 
@@ -1982,7 +1971,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
 		if (!(portstatus & USB_PORT_STAT_RESET) &&
 		if (!(portstatus & USB_PORT_STAT_RESET) &&
 		    (portstatus & USB_PORT_STAT_ENABLE)) {
 		    (portstatus & USB_PORT_STAT_ENABLE)) {
 			if (hub_is_wusb(hub))
 			if (hub_is_wusb(hub))
-				udev->speed = USB_SPEED_VARIABLE;
+				udev->speed = USB_SPEED_WIRELESS;
 			else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
 			else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
 				udev->speed = USB_SPEED_HIGH;
 				udev->speed = USB_SPEED_HIGH;
 			else if (portstatus & USB_PORT_STAT_LOW_SPEED)
 			else if (portstatus & USB_PORT_STAT_LOW_SPEED)
@@ -2008,7 +1997,9 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 				struct usb_device *udev, unsigned int delay)
 				struct usb_device *udev, unsigned int delay)
 {
 {
 	int i, status;
 	int i, status;
+	struct usb_hcd *hcd;
 
 
+	hcd = bus_to_hcd(udev->bus);
 	/* Block EHCI CF initialization during the port reset.
 	/* Block EHCI CF initialization during the port reset.
 	 * Some companion controllers don't like it when they mix.
 	 * Some companion controllers don't like it when they mix.
 	 */
 	 */
@@ -2036,6 +2027,14 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 			/* TRSTRCY = 10 ms; plus some extra */
 			/* TRSTRCY = 10 ms; plus some extra */
 			msleep(10 + 40);
 			msleep(10 + 40);
 			update_address(udev, 0);
 			update_address(udev, 0);
+			if (hcd->driver->reset_device) {
+				status = hcd->driver->reset_device(hcd, udev);
+				if (status < 0) {
+					dev_err(&udev->dev, "Cannot reset "
+							"HCD device state\n");
+					break;
+				}
+			}
 			/* FALL THROUGH */
 			/* FALL THROUGH */
 		case -ENOTCONN:
 		case -ENOTCONN:
 		case -ENODEV:
 		case -ENODEV:
@@ -2381,14 +2380,17 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
 }
 }
 
 
 /* caller has locked udev */
 /* caller has locked udev */
-static int remote_wakeup(struct usb_device *udev)
+int usb_remote_wakeup(struct usb_device *udev)
 {
 {
 	int	status = 0;
 	int	status = 0;
 
 
 	if (udev->state == USB_STATE_SUSPENDED) {
 	if (udev->state == USB_STATE_SUSPENDED) {
 		dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-");
 		dev_dbg(&udev->dev, "usb %sresume\n", "wakeup-");
-		usb_mark_last_busy(udev);
-		status = usb_external_resume_device(udev, PMSG_REMOTE_RESUME);
+		status = usb_autoresume_device(udev);
+		if (status == 0) {
+			/* Let the drivers do their thing, then... */
+			usb_autosuspend_device(udev);
+		}
 	}
 	}
 	return status;
 	return status;
 }
 }
@@ -2425,11 +2427,6 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
 	return status;
 	return status;
 }
 }
 
 
-static inline int remote_wakeup(struct usb_device *udev)
-{
-	return 0;
-}
-
 #endif
 #endif
 
 
 static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
 static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
@@ -2496,11 +2493,6 @@ EXPORT_SYMBOL_GPL(usb_root_hub_lost_power);
 
 
 #else	/* CONFIG_PM */
 #else	/* CONFIG_PM */
 
 
-static inline int remote_wakeup(struct usb_device *udev)
-{
-	return 0;
-}
-
 #define hub_suspend		NULL
 #define hub_suspend		NULL
 #define hub_resume		NULL
 #define hub_resume		NULL
 #define hub_reset_resume	NULL
 #define hub_reset_resume	NULL
@@ -2645,14 +2637,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 
 
 	mutex_lock(&usb_address0_mutex);
 	mutex_lock(&usb_address0_mutex);
 
 
-	if ((hcd->driver->flags & HCD_USB3) && udev->config) {
-		/* FIXME this will need special handling by the xHCI driver. */
-		dev_dbg(&udev->dev,
-				"xHCI reset of configured device "
-				"not supported yet.\n");
-		retval = -EINVAL;
-		goto fail;
-	} else if (!udev->config && oldspeed == USB_SPEED_SUPER) {
+	if (!udev->config && oldspeed == USB_SPEED_SUPER) {
 		/* Don't reset USB 3.0 devices during an initial setup */
 		/* Don't reset USB 3.0 devices during an initial setup */
 		usb_set_device_state(udev, USB_STATE_DEFAULT);
 		usb_set_device_state(udev, USB_STATE_DEFAULT);
 	} else {
 	} else {
@@ -2678,7 +2663,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 	 */
 	 */
 	switch (udev->speed) {
 	switch (udev->speed) {
 	case USB_SPEED_SUPER:
 	case USB_SPEED_SUPER:
-	case USB_SPEED_VARIABLE:	/* fixed at 512 */
+	case USB_SPEED_WIRELESS:	/* fixed at 512 */
 		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
 		udev->ep0.desc.wMaxPacketSize = cpu_to_le16(512);
 		break;
 		break;
 	case USB_SPEED_HIGH:		/* fixed at 64 */
 	case USB_SPEED_HIGH:		/* fixed at 64 */
@@ -2706,7 +2691,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 	case USB_SPEED_SUPER:
 	case USB_SPEED_SUPER:
 				speed = "super";
 				speed = "super";
 				break;
 				break;
-	case USB_SPEED_VARIABLE:
+	case USB_SPEED_WIRELESS:
 				speed = "variable";
 				speed = "variable";
 				type = "Wireless ";
 				type = "Wireless ";
 				break;
 				break;
@@ -3006,7 +2991,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
 			/* For a suspended device, treat this as a
 			/* For a suspended device, treat this as a
 			 * remote wakeup event.
 			 * remote wakeup event.
 			 */
 			 */
-			status = remote_wakeup(udev);
+			status = usb_remote_wakeup(udev);
 #endif
 #endif
 
 
 		} else {
 		} else {
@@ -3192,6 +3177,7 @@ loop_disable:
 loop:
 loop:
 		usb_ep0_reinit(udev);
 		usb_ep0_reinit(udev);
 		release_address(udev);
 		release_address(udev);
+		hub_free_dev(udev);
 		usb_put_dev(udev);
 		usb_put_dev(udev);
 		if ((status == -ENOTCONN) || (status == -ENOTSUPP))
 		if ((status == -ENOTCONN) || (status == -ENOTSUPP))
 			break;
 			break;
@@ -3259,7 +3245,7 @@ static void hub_events(void)
 		 * disconnected while waiting for the lock to succeed. */
 		 * disconnected while waiting for the lock to succeed. */
 		usb_lock_device(hdev);
 		usb_lock_device(hdev);
 		if (unlikely(hub->disconnected))
 		if (unlikely(hub->disconnected))
-			goto loop2;
+			goto loop_disconnected;
 
 
 		/* If the hub has died, clean up after it */
 		/* If the hub has died, clean up after it */
 		if (hdev->state == USB_STATE_NOTATTACHED) {
 		if (hdev->state == USB_STATE_NOTATTACHED) {
@@ -3352,7 +3338,7 @@ static void hub_events(void)
 					msleep(10);
 					msleep(10);
 
 
 					usb_lock_device(udev);
 					usb_lock_device(udev);
-					ret = remote_wakeup(hdev->
+					ret = usb_remote_wakeup(hdev->
 							children[i-1]);
 							children[i-1]);
 					usb_unlock_device(udev);
 					usb_unlock_device(udev);
 					if (ret < 0)
 					if (ret < 0)
@@ -3419,7 +3405,7 @@ static void hub_events(void)
 		 * kick_khubd() and allow autosuspend.
 		 * kick_khubd() and allow autosuspend.
 		 */
 		 */
 		usb_autopm_put_interface(intf);
 		usb_autopm_put_interface(intf);
- loop2:
+ loop_disconnected:
 		usb_unlock_device(hdev);
 		usb_unlock_device(hdev);
 		kref_put(&hub->kref, hub_release);
 		kref_put(&hub->kref, hub_release);
 
 
@@ -3446,7 +3432,7 @@ static int hub_thread(void *__unused)
 	return 0;
 	return 0;
 }
 }
 
 
-static struct usb_device_id hub_id_table [] = {
+static const struct usb_device_id hub_id_table[] = {
     { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
     { .match_flags = USB_DEVICE_ID_MATCH_DEV_CLASS,
       .bDeviceClass = USB_CLASS_HUB},
       .bDeviceClass = USB_CLASS_HUB},
     { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
     { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,

+ 2 - 3
drivers/usb/core/message.c

@@ -1316,7 +1316,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
 
 
 	alt = usb_altnum_to_altsetting(iface, alternate);
 	alt = usb_altnum_to_altsetting(iface, alternate);
 	if (!alt) {
 	if (!alt) {
-		dev_warn(&dev->dev, "selecting invalid altsetting %d",
+		dev_warn(&dev->dev, "selecting invalid altsetting %d\n",
 			 alternate);
 			 alternate);
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
@@ -1471,7 +1471,7 @@ int usb_reset_configuration(struct usb_device *dev)
 	/* If not, reinstate the old alternate settings */
 	/* If not, reinstate the old alternate settings */
 	if (retval < 0) {
 	if (retval < 0) {
 reset_old_alts:
 reset_old_alts:
-		for (; i >= 0; i--) {
+		for (i--; i >= 0; i--) {
 			struct usb_interface *intf = config->interface[i];
 			struct usb_interface *intf = config->interface[i];
 			struct usb_host_interface *alt;
 			struct usb_host_interface *alt;
 
 
@@ -1843,7 +1843,6 @@ free_interfaces:
 		intf->dev.dma_mask = dev->dev.dma_mask;
 		intf->dev.dma_mask = dev->dev.dma_mask;
 		INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
 		INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
 		device_initialize(&intf->dev);
 		device_initialize(&intf->dev);
-		mark_quiesced(intf);
 		dev_set_name(&intf->dev, "%d-%s:%d.%d",
 		dev_set_name(&intf->dev, "%d-%s:%d.%d",
 			dev->bus->busnum, dev->devpath,
 			dev->bus->busnum, dev->devpath,
 			configuration, alt->desc.bInterfaceNumber);
 			configuration, alt->desc.bInterfaceNumber);

+ 14 - 4
drivers/usb/core/quirks.c

@@ -103,10 +103,19 @@ 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);
 
 
-	/* By default, disable autosuspend for all non-hubs */
 #ifdef	CONFIG_USB_SUSPEND
 #ifdef	CONFIG_USB_SUSPEND
-	if (udev->descriptor.bDeviceClass != USB_CLASS_HUB)
-		udev->autosuspend_disabled = 1;
+
+	/* By default, disable autosuspend for all devices.  The hub driver
+	 * will enable it for hubs.
+	 */
+	usb_disable_autosuspend(udev);
+
+	/* Autosuspend can also be disabled if the initial autosuspend_delay
+	 * is negative.
+	 */
+	if (udev->autosuspend_delay < 0)
+		usb_autoresume_device(udev);
+
 #endif
 #endif
 
 
 	/* For the present, all devices default to USB-PERSIST enabled */
 	/* For the present, all devices default to USB-PERSIST enabled */
@@ -120,6 +129,7 @@ void usb_detect_quirks(struct usb_device *udev)
 	 * for all devices.  It will affect things like hub resets
 	 * for all devices.  It will affect things like hub resets
 	 * and EMF-related port disables.
 	 * and EMF-related port disables.
 	 */
 	 */
-	udev->persist_enabled = 1;
+	if (!(udev->quirks & USB_QUIRK_RESET_MORPHS))
+		udev->persist_enabled = 1;
 #endif	/* CONFIG_PM */
 #endif	/* CONFIG_PM */
 }
 }

+ 61 - 24
drivers/usb/core/sysfs.c

@@ -115,7 +115,7 @@ show_speed(struct device *dev, struct device_attribute *attr, char *buf)
 	case USB_SPEED_HIGH:
 	case USB_SPEED_HIGH:
 		speed = "480";
 		speed = "480";
 		break;
 		break;
-	case USB_SPEED_VARIABLE:
+	case USB_SPEED_WIRELESS:
 		speed = "480";
 		speed = "480";
 		break;
 		break;
 	case USB_SPEED_SUPER:
 	case USB_SPEED_SUPER:
@@ -190,6 +190,36 @@ 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_avoid_reset_quirk(struct device *dev, struct device_attribute *attr, char *buf)
+{
+	struct usb_device *udev;
+
+	udev = to_usb_device(dev);
+	return sprintf(buf, "%d\n", !!(udev->quirks & USB_QUIRK_RESET_MORPHS));
+}
+
+static ssize_t
+set_avoid_reset_quirk(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct usb_device	*udev = to_usb_device(dev);
+	int			config;
+
+	if (sscanf(buf, "%d", &config) != 1 || config < 0 || config > 1)
+		return -EINVAL;
+	usb_lock_device(udev);
+	if (config)
+		udev->quirks |= USB_QUIRK_RESET_MORPHS;
+	else
+		udev->quirks &= ~USB_QUIRK_RESET_MORPHS;
+	usb_unlock_device(udev);
+	return count;
+}
+
+static DEVICE_ATTR(avoid_reset_quirk, S_IRUGO | S_IWUSR,
+		show_avoid_reset_quirk, set_avoid_reset_quirk);
+
 static ssize_t
 static ssize_t
 show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
 show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
@@ -226,9 +256,10 @@ set_persist(struct device *dev, struct device_attribute *attr,
 
 
 	if (sscanf(buf, "%d", &value) != 1)
 	if (sscanf(buf, "%d", &value) != 1)
 		return -EINVAL;
 		return -EINVAL;
-	usb_pm_lock(udev);
+
+	usb_lock_device(udev);
 	udev->persist_enabled = !!value;
 	udev->persist_enabled = !!value;
-	usb_pm_unlock(udev);
+	usb_unlock_device(udev);
 	return count;
 	return count;
 }
 }
 
 
@@ -315,20 +346,34 @@ set_autosuspend(struct device *dev, struct device_attribute *attr,
 		const char *buf, size_t count)
 		const char *buf, size_t count)
 {
 {
 	struct usb_device *udev = to_usb_device(dev);
 	struct usb_device *udev = to_usb_device(dev);
-	int value;
+	int value, old_delay;
+	int rc;
 
 
 	if (sscanf(buf, "%d", &value) != 1 || value >= INT_MAX/HZ ||
 	if (sscanf(buf, "%d", &value) != 1 || value >= INT_MAX/HZ ||
 			value <= - INT_MAX/HZ)
 			value <= - INT_MAX/HZ)
 		return -EINVAL;
 		return -EINVAL;
 	value *= HZ;
 	value *= HZ;
 
 
+	usb_lock_device(udev);
+	old_delay = udev->autosuspend_delay;
 	udev->autosuspend_delay = value;
 	udev->autosuspend_delay = value;
-	if (value >= 0)
-		usb_try_autosuspend_device(udev);
-	else {
-		if (usb_autoresume_device(udev) == 0)
+
+	if (old_delay < 0) {	/* Autosuspend wasn't allowed */
+		if (value >= 0)
 			usb_autosuspend_device(udev);
 			usb_autosuspend_device(udev);
+	} else {		/* Autosuspend was allowed */
+		if (value < 0) {
+			rc = usb_autoresume_device(udev);
+			if (rc < 0) {
+				count = rc;
+				udev->autosuspend_delay = old_delay;
+			}
+		} else {
+			usb_try_autosuspend_device(udev);
+		}
 	}
 	}
+
+	usb_unlock_device(udev);
 	return count;
 	return count;
 }
 }
 
 
@@ -356,34 +401,25 @@ set_level(struct device *dev, struct device_attribute *attr,
 	struct usb_device *udev = to_usb_device(dev);
 	struct usb_device *udev = to_usb_device(dev);
 	int len = count;
 	int len = count;
 	char *cp;
 	char *cp;
-	int rc = 0;
-	int old_autosuspend_disabled;
+	int rc;
 
 
 	cp = memchr(buf, '\n', count);
 	cp = memchr(buf, '\n', count);
 	if (cp)
 	if (cp)
 		len = cp - buf;
 		len = cp - buf;
 
 
 	usb_lock_device(udev);
 	usb_lock_device(udev);
-	old_autosuspend_disabled = udev->autosuspend_disabled;
 
 
-	/* Setting the flags without calling usb_pm_lock is a subject to
-	 * races, but who cares...
-	 */
 	if (len == sizeof on_string - 1 &&
 	if (len == sizeof on_string - 1 &&
-			strncmp(buf, on_string, len) == 0) {
-		udev->autosuspend_disabled = 1;
-		rc = usb_external_resume_device(udev, PMSG_USER_RESUME);
+			strncmp(buf, on_string, len) == 0)
+		rc = usb_disable_autosuspend(udev);
 
 
-	} else if (len == sizeof auto_string - 1 &&
-			strncmp(buf, auto_string, len) == 0) {
-		udev->autosuspend_disabled = 0;
-		rc = usb_external_resume_device(udev, PMSG_USER_RESUME);
+	else if (len == sizeof auto_string - 1 &&
+			strncmp(buf, auto_string, len) == 0)
+		rc = usb_enable_autosuspend(udev);
 
 
-	} else
+	else
 		rc = -EINVAL;
 		rc = -EINVAL;
 
 
-	if (rc)
-		udev->autosuspend_disabled = old_autosuspend_disabled;
 	usb_unlock_device(udev);
 	usb_unlock_device(udev);
 	return (rc < 0 ? rc : count);
 	return (rc < 0 ? rc : count);
 }
 }
@@ -558,6 +594,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_avoid_reset_quirk.attr,
 	&dev_attr_authorized.attr,
 	&dev_attr_authorized.attr,
 	&dev_attr_remove.attr,
 	&dev_attr_remove.attr,
 	NULL,
 	NULL,

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

@@ -387,6 +387,13 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 	{
 	{
 	unsigned int	orig_flags = urb->transfer_flags;
 	unsigned int	orig_flags = urb->transfer_flags;
 	unsigned int	allowed;
 	unsigned int	allowed;
+	static int pipetypes[4] = {
+		PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
+	};
+
+	/* Check that the pipe's type matches the endpoint's type */
+	if (usb_pipetype(urb->pipe) != pipetypes[xfertype])
+		return -EPIPE;		/* The most suitable error code :-) */
 
 
 	/* 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 |
@@ -430,7 +437,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 	case USB_ENDPOINT_XFER_INT:
 	case USB_ENDPOINT_XFER_INT:
 		/* too small? */
 		/* too small? */
 		switch (dev->speed) {
 		switch (dev->speed) {
-		case USB_SPEED_VARIABLE:
+		case USB_SPEED_WIRELESS:
 			if (urb->interval < 6)
 			if (urb->interval < 6)
 				return -EINVAL;
 				return -EINVAL;
 			break;
 			break;
@@ -446,7 +453,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 			if (urb->interval > (1 << 15))
 			if (urb->interval > (1 << 15))
 				return -EINVAL;
 				return -EINVAL;
 			max = 1 << 15;
 			max = 1 << 15;
-		case USB_SPEED_VARIABLE:
+		case USB_SPEED_WIRELESS:
 			if (urb->interval > 16)
 			if (urb->interval > 16)
 				return -EINVAL;
 				return -EINVAL;
 			break;
 			break;
@@ -473,7 +480,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 		default:
 		default:
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
-		if (dev->speed != USB_SPEED_VARIABLE) {
+		if (dev->speed != USB_SPEED_WIRELESS) {
 			/* Round down to a power of 2, no more than max */
 			/* Round down to a power of 2, no more than max */
 			urb->interval = min(max, 1 << ilog2(urb->interval));
 			urb->interval = min(max, 1 << ilog2(urb->interval));
 		}
 		}

+ 3 - 35
drivers/usb/core/usb.c

@@ -49,9 +49,6 @@ const char *usbcore_name = "usbcore";
 
 
 static int nousb;	/* Disable USB when built into kernel image */
 static int nousb;	/* Disable USB when built into kernel image */
 
 
-/* Workqueue for autosuspend and for remote wakeup of root hubs */
-struct workqueue_struct *ksuspend_usb_wq;
-
 #ifdef	CONFIG_USB_SUSPEND
 #ifdef	CONFIG_USB_SUSPEND
 static int usb_autosuspend_delay = 2;		/* Default delay value,
 static int usb_autosuspend_delay = 2;		/* Default delay value,
 						 * in seconds */
 						 * in seconds */
@@ -228,9 +225,6 @@ static void usb_release_dev(struct device *dev)
 	hcd = bus_to_hcd(udev->bus);
 	hcd = bus_to_hcd(udev->bus);
 
 
 	usb_destroy_configuration(udev);
 	usb_destroy_configuration(udev);
-	/* Root hubs aren't real devices, so don't free HCD resources */
-	if (hcd->driver->free_dev && udev->parent)
-		hcd->driver->free_dev(hcd, udev);
 	usb_put_hcd(hcd);
 	usb_put_hcd(hcd);
 	kfree(udev->product);
 	kfree(udev->product);
 	kfree(udev->manufacturer);
 	kfree(udev->manufacturer);
@@ -264,23 +258,6 @@ static int usb_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
 
 
 #ifdef	CONFIG_PM
 #ifdef	CONFIG_PM
 
 
-static int ksuspend_usb_init(void)
-{
-	/* This workqueue is supposed to be both freezable and
-	 * singlethreaded.  Its job doesn't justify running on more
-	 * than one CPU.
-	 */
-	ksuspend_usb_wq = create_freezeable_workqueue("ksuspend_usbd");
-	if (!ksuspend_usb_wq)
-		return -ENOMEM;
-	return 0;
-}
-
-static void ksuspend_usb_cleanup(void)
-{
-	destroy_workqueue(ksuspend_usb_wq);
-}
-
 /* USB device Power-Management thunks.
 /* USB device Power-Management thunks.
  * There's no need to distinguish here between quiescing a USB device
  * There's no need to distinguish here between quiescing a USB device
  * and powering it down; the generic_suspend() routine takes care of
  * and powering it down; the generic_suspend() routine takes care of
@@ -296,7 +273,7 @@ static int usb_dev_prepare(struct device *dev)
 static void usb_dev_complete(struct device *dev)
 static void usb_dev_complete(struct device *dev)
 {
 {
 	/* Currently used only for rebinding interfaces */
 	/* Currently used only for rebinding interfaces */
-	usb_resume(dev, PMSG_RESUME);	/* Message event is meaningless */
+	usb_resume(dev, PMSG_ON);	/* FIXME: change to PMSG_COMPLETE */
 }
 }
 
 
 static int usb_dev_suspend(struct device *dev)
 static int usb_dev_suspend(struct device *dev)
@@ -342,9 +319,7 @@ static const struct dev_pm_ops usb_device_pm_ops = {
 
 
 #else
 #else
 
 
-#define ksuspend_usb_init()	0
-#define ksuspend_usb_cleanup()	do {} while (0)
-#define usb_device_pm_ops	(*(struct dev_pm_ops *)0)
+#define usb_device_pm_ops	(*(struct dev_pm_ops *) NULL)
 
 
 #endif	/* CONFIG_PM */
 #endif	/* CONFIG_PM */
 
 
@@ -472,9 +447,6 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
 	INIT_LIST_HEAD(&dev->filelist);
 	INIT_LIST_HEAD(&dev->filelist);
 
 
 #ifdef	CONFIG_PM
 #ifdef	CONFIG_PM
-	mutex_init(&dev->pm_mutex);
-	INIT_DELAYED_WORK(&dev->autosuspend, usb_autosuspend_work);
-	INIT_WORK(&dev->autoresume, usb_autoresume_work);
 	dev->autosuspend_delay = usb_autosuspend_delay * HZ;
 	dev->autosuspend_delay = usb_autosuspend_delay * HZ;
 	dev->connect_time = jiffies;
 	dev->connect_time = jiffies;
 	dev->active_duration = -jiffies;
 	dev->active_duration = -jiffies;
@@ -1117,9 +1089,6 @@ static int __init usb_init(void)
 	if (retval)
 	if (retval)
 		goto out;
 		goto out;
 
 
-	retval = ksuspend_usb_init();
-	if (retval)
-		goto out;
 	retval = bus_register(&usb_bus_type);
 	retval = bus_register(&usb_bus_type);
 	if (retval)
 	if (retval)
 		goto bus_register_failed;
 		goto bus_register_failed;
@@ -1159,7 +1128,7 @@ major_init_failed:
 bus_notifier_failed:
 bus_notifier_failed:
 	bus_unregister(&usb_bus_type);
 	bus_unregister(&usb_bus_type);
 bus_register_failed:
 bus_register_failed:
-	ksuspend_usb_cleanup();
+	usb_debugfs_cleanup();
 out:
 out:
 	return retval;
 	return retval;
 }
 }
@@ -1181,7 +1150,6 @@ static void __exit usb_exit(void)
 	usb_hub_cleanup();
 	usb_hub_cleanup();
 	bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
 	bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
 	bus_unregister(&usb_bus_type);
 	bus_unregister(&usb_bus_type);
-	ksuspend_usb_cleanup();
 	usb_debugfs_cleanup();
 	usb_debugfs_cleanup();
 }
 }
 
 

+ 6 - 37
drivers/usb/core/usb.h

@@ -55,24 +55,8 @@ extern void usb_major_cleanup(void);
 extern int usb_suspend(struct device *dev, pm_message_t msg);
 extern int usb_suspend(struct device *dev, pm_message_t msg);
 extern int usb_resume(struct device *dev, pm_message_t msg);
 extern int usb_resume(struct device *dev, pm_message_t msg);
 
 
-extern void usb_autosuspend_work(struct work_struct *work);
-extern void usb_autoresume_work(struct work_struct *work);
 extern int usb_port_suspend(struct usb_device *dev, pm_message_t msg);
 extern int usb_port_suspend(struct usb_device *dev, pm_message_t msg);
 extern int usb_port_resume(struct usb_device *dev, pm_message_t msg);
 extern int usb_port_resume(struct usb_device *dev, pm_message_t msg);
-extern int usb_external_suspend_device(struct usb_device *udev,
-		pm_message_t msg);
-extern int usb_external_resume_device(struct usb_device *udev,
-		pm_message_t msg);
-
-static inline void usb_pm_lock(struct usb_device *udev)
-{
-	mutex_lock_nested(&udev->pm_mutex, udev->level);
-}
-
-static inline void usb_pm_unlock(struct usb_device *udev)
-{
-	mutex_unlock(&udev->pm_mutex);
-}
 
 
 #else
 #else
 
 
@@ -86,9 +70,6 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg)
 	return 0;
 	return 0;
 }
 }
 
 
-static inline void usb_pm_lock(struct usb_device *udev) {}
-static inline void usb_pm_unlock(struct usb_device *udev) {}
-
 #endif
 #endif
 
 
 #ifdef CONFIG_USB_SUSPEND
 #ifdef CONFIG_USB_SUSPEND
@@ -96,6 +77,7 @@ static inline void usb_pm_unlock(struct usb_device *udev) {}
 extern void usb_autosuspend_device(struct usb_device *udev);
 extern void usb_autosuspend_device(struct usb_device *udev);
 extern void usb_try_autosuspend_device(struct usb_device *udev);
 extern void usb_try_autosuspend_device(struct usb_device *udev);
 extern int usb_autoresume_device(struct usb_device *udev);
 extern int usb_autoresume_device(struct usb_device *udev);
+extern int usb_remote_wakeup(struct usb_device *dev);
 
 
 #else
 #else
 
 
@@ -106,9 +88,13 @@ static inline int usb_autoresume_device(struct usb_device *udev)
 	return 0;
 	return 0;
 }
 }
 
 
+static inline int usb_remote_wakeup(struct usb_device *udev)
+{
+	return 0;
+}
+
 #endif
 #endif
 
 
-extern struct workqueue_struct *ksuspend_usb_wq;
 extern struct bus_type usb_bus_type;
 extern struct bus_type usb_bus_type;
 extern struct device_type usb_device_type;
 extern struct device_type usb_device_type;
 extern struct device_type usb_if_device_type;
 extern struct device_type usb_if_device_type;
@@ -138,23 +124,6 @@ static inline int is_usb_device_driver(struct device_driver *drv)
 			for_devices;
 			for_devices;
 }
 }
 
 
-/* Interfaces and their "power state" are owned by usbcore */
-
-static inline void mark_active(struct usb_interface *f)
-{
-	f->is_active = 1;
-}
-
-static inline void mark_quiesced(struct usb_interface *f)
-{
-	f->is_active = 0;
-}
-
-static inline int is_active(const struct usb_interface *f)
-{
-	return f->is_active;
-}
-
 
 
 /* for labeling diagnostics */
 /* for labeling diagnostics */
 extern const char *usbcore_name;
 extern const char *usbcore_name;

+ 28 - 40
drivers/usb/early/ehci-dbgp.c

@@ -66,8 +66,6 @@ static struct ehci_dev ehci_dev;
 
 
 #define USB_DEBUG_DEVNUM 127
 #define USB_DEBUG_DEVNUM 127
 
 
-#define DBGP_DATA_TOGGLE	0x8800
-
 #ifdef DBGP_DEBUG
 #ifdef DBGP_DEBUG
 #define dbgp_printk printk
 #define dbgp_printk printk
 static void dbgp_ehci_status(char *str)
 static void dbgp_ehci_status(char *str)
@@ -88,11 +86,6 @@ static inline void dbgp_ehci_status(char *str) { }
 static inline void dbgp_printk(const char *fmt, ...) { }
 static inline void dbgp_printk(const char *fmt, ...) { }
 #endif
 #endif
 
 
-static inline u32 dbgp_pid_update(u32 x, u32 tok)
-{
-	return ((x ^ DBGP_DATA_TOGGLE) & 0xffff00) | (tok & 0xff);
-}
-
 static inline u32 dbgp_len_update(u32 x, u32 len)
 static inline u32 dbgp_len_update(u32 x, u32 len)
 {
 {
 	return (x & ~0x0f) | (len & 0x0f);
 	return (x & ~0x0f) | (len & 0x0f);
@@ -136,6 +129,19 @@ static inline u32 dbgp_len_update(u32 x, u32 len)
 
 
 #define DBGP_MAX_PACKET		8
 #define DBGP_MAX_PACKET		8
 #define DBGP_TIMEOUT		(250 * 1000)
 #define DBGP_TIMEOUT		(250 * 1000)
+#define DBGP_LOOPS		1000
+
+static inline u32 dbgp_pid_write_update(u32 x, u32 tok)
+{
+	static int data0 = USB_PID_DATA1;
+	data0 ^= USB_PID_DATA_TOGGLE;
+	return (x & 0xffff0000) | (data0 << 8) | (tok & 0xff);
+}
+
+static inline u32 dbgp_pid_read_update(u32 x, u32 tok)
+{
+	return (x & 0xffff0000) | (USB_PID_DATA0 << 8) | (tok & 0xff);
+}
 
 
 static int dbgp_wait_until_complete(void)
 static int dbgp_wait_until_complete(void)
 {
 {
@@ -180,7 +186,7 @@ static int dbgp_wait_until_done(unsigned ctrl)
 {
 {
 	u32 pids, lpid;
 	u32 pids, lpid;
 	int ret;
 	int ret;
-	int loop = 3;
+	int loop = DBGP_LOOPS;
 
 
 retry:
 retry:
 	writel(ctrl | DBGP_GO, &ehci_debug->control);
 	writel(ctrl | DBGP_GO, &ehci_debug->control);
@@ -197,6 +203,8 @@ retry:
 		 */
 		 */
 		if (ret == -DBGP_TIMEOUT && !dbgp_not_safe)
 		if (ret == -DBGP_TIMEOUT && !dbgp_not_safe)
 			dbgp_not_safe = 1;
 			dbgp_not_safe = 1;
+		if (ret == -DBGP_ERR_BAD && --loop > 0)
+			goto retry;
 		return ret;
 		return ret;
 	}
 	}
 
 
@@ -245,12 +253,20 @@ static inline void dbgp_get_data(void *buf, int size)
 		bytes[i] = (hi >> (8*(i - 4))) & 0xff;
 		bytes[i] = (hi >> (8*(i - 4))) & 0xff;
 }
 }
 
 
-static int dbgp_out(u32 addr, const char *bytes, int size)
+static int dbgp_bulk_write(unsigned devnum, unsigned endpoint,
+			 const char *bytes, int size)
 {
 {
+	int ret;
+	u32 addr;
 	u32 pids, ctrl;
 	u32 pids, ctrl;
 
 
+	if (size > DBGP_MAX_PACKET)
+		return -1;
+
+	addr = DBGP_EPADDR(devnum, endpoint);
+
 	pids = readl(&ehci_debug->pids);
 	pids = readl(&ehci_debug->pids);
-	pids = dbgp_pid_update(pids, USB_PID_OUT);
+	pids = dbgp_pid_write_update(pids, USB_PID_OUT);
 
 
 	ctrl = readl(&ehci_debug->control);
 	ctrl = readl(&ehci_debug->control);
 	ctrl = dbgp_len_update(ctrl, size);
 	ctrl = dbgp_len_update(ctrl, size);
@@ -260,34 +276,7 @@ static int dbgp_out(u32 addr, const char *bytes, int size)
 	dbgp_set_data(bytes, size);
 	dbgp_set_data(bytes, size);
 	writel(addr, &ehci_debug->address);
 	writel(addr, &ehci_debug->address);
 	writel(pids, &ehci_debug->pids);
 	writel(pids, &ehci_debug->pids);
-	return dbgp_wait_until_done(ctrl);
-}
-
-static int dbgp_bulk_write(unsigned devnum, unsigned endpoint,
-			 const char *bytes, int size)
-{
-	int ret;
-	int loops = 5;
-	u32 addr;
-	if (size > DBGP_MAX_PACKET)
-		return -1;
-
-	addr = DBGP_EPADDR(devnum, endpoint);
-try_again:
-	if (loops--) {
-		ret = dbgp_out(addr, bytes, size);
-		if (ret == -DBGP_ERR_BAD) {
-			int try_loops = 3;
-			do {
-				/* Emit a dummy packet to re-sync communication
-				 * with the debug device */
-				if (dbgp_out(addr, "12345678", 8) >= 0) {
-					udelay(2);
-					goto try_again;
-				}
-			} while (try_loops--);
-		}
-	}
+	ret = dbgp_wait_until_done(ctrl);
 
 
 	return ret;
 	return ret;
 }
 }
@@ -304,7 +293,7 @@ static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data,
 	addr = DBGP_EPADDR(devnum, endpoint);
 	addr = DBGP_EPADDR(devnum, endpoint);
 
 
 	pids = readl(&ehci_debug->pids);
 	pids = readl(&ehci_debug->pids);
-	pids = dbgp_pid_update(pids, USB_PID_IN);
+	pids = dbgp_pid_read_update(pids, USB_PID_IN);
 
 
 	ctrl = readl(&ehci_debug->control);
 	ctrl = readl(&ehci_debug->control);
 	ctrl = dbgp_len_update(ctrl, size);
 	ctrl = dbgp_len_update(ctrl, size);
@@ -362,7 +351,6 @@ static int dbgp_control_msg(unsigned devnum, int requesttype,
 	return dbgp_bulk_read(devnum, 0, data, size);
 	return dbgp_bulk_read(devnum, 0, data, size);
 }
 }
 
 
-
 /* Find a PCI capability */
 /* Find a PCI capability */
 static u32 __init find_cap(u32 num, u32 slot, u32 func, int cap)
 static u32 __init find_cap(u32 num, u32 slot, u32 func, int cap)
 {
 {

+ 10 - 0
drivers/usb/gadget/Kconfig

@@ -812,6 +812,16 @@ config USB_CDC_COMPOSITE
 	  Say "y" to link the driver statically, or "m" to build a
 	  Say "y" to link the driver statically, or "m" to build a
 	  dynamically linked module.
 	  dynamically linked module.
 
 
+config USB_G_NOKIA
+	tristate "Nokia composite gadget"
+	depends on PHONET
+	help
+	  The Nokia composite gadget provides support for acm, obex
+	  and phonet in only one composite gadget driver.
+
+	  It's only really useful for N900 hardware. If you're building
+	  a kernel for N900, say Y or M here. If unsure, say N.
+
 config USB_G_MULTI
 config USB_G_MULTI
 	tristate "Multifunction Composite Gadget (EXPERIMENTAL)"
 	tristate "Multifunction Composite Gadget (EXPERIMENTAL)"
 	depends on BLOCK && NET
 	depends on BLOCK && NET

+ 2 - 0
drivers/usb/gadget/Makefile

@@ -43,6 +43,7 @@ g_mass_storage-objs		:= mass_storage.o
 g_printer-objs			:= printer.o
 g_printer-objs			:= printer.o
 g_cdc-objs			:= cdc2.o
 g_cdc-objs			:= cdc2.o
 g_multi-objs			:= multi.o
 g_multi-objs			:= multi.o
+g_nokia-objs			:= nokia.o
 
 
 obj-$(CONFIG_USB_ZERO)		+= g_zero.o
 obj-$(CONFIG_USB_ZERO)		+= g_zero.o
 obj-$(CONFIG_USB_AUDIO)		+= g_audio.o
 obj-$(CONFIG_USB_AUDIO)		+= g_audio.o
@@ -55,4 +56,5 @@ obj-$(CONFIG_USB_G_PRINTER)	+= g_printer.o
 obj-$(CONFIG_USB_MIDI_GADGET)	+= g_midi.o
 obj-$(CONFIG_USB_MIDI_GADGET)	+= g_midi.o
 obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
 obj-$(CONFIG_USB_CDC_COMPOSITE) += g_cdc.o
 obj-$(CONFIG_USB_G_MULTI)	+= g_multi.o
 obj-$(CONFIG_USB_G_MULTI)	+= g_multi.o
+obj-$(CONFIG_USB_G_NOKIA)	+= g_nokia.o
 
 

+ 4 - 6
drivers/usb/gadget/at91_udc.c

@@ -1656,9 +1656,7 @@ static int __init at91udc_probe(struct platform_device *pdev)
 	if (!res)
 	if (!res)
 		return -ENXIO;
 		return -ENXIO;
 
 
-	if (!request_mem_region(res->start,
-			res->end - res->start + 1,
-			driver_name)) {
+	if (!request_mem_region(res->start, resource_size(res), driver_name)) {
 		DBG("someone's using UDC memory\n");
 		DBG("someone's using UDC memory\n");
 		return -EBUSY;
 		return -EBUSY;
 	}
 	}
@@ -1699,7 +1697,7 @@ static int __init at91udc_probe(struct platform_device *pdev)
 		udc->ep[3].maxpacket = 64;
 		udc->ep[3].maxpacket = 64;
 	}
 	}
 
 
-	udc->udp_baseaddr = ioremap(res->start, res->end - res->start + 1);
+	udc->udp_baseaddr = ioremap(res->start, resource_size(res));
 	if (!udc->udp_baseaddr) {
 	if (!udc->udp_baseaddr) {
 		retval = -ENOMEM;
 		retval = -ENOMEM;
 		goto fail0a;
 		goto fail0a;
@@ -1781,7 +1779,7 @@ fail0a:
 	if (cpu_is_at91rm9200())
 	if (cpu_is_at91rm9200())
 		gpio_free(udc->board.pullup_pin);
 		gpio_free(udc->board.pullup_pin);
 fail0:
 fail0:
-	release_mem_region(res->start, res->end - res->start + 1);
+	release_mem_region(res->start, resource_size(res));
 	DBG("%s probe failed, %d\n", driver_name, retval);
 	DBG("%s probe failed, %d\n", driver_name, retval);
 	return retval;
 	return retval;
 }
 }
@@ -1813,7 +1811,7 @@ static int __exit at91udc_remove(struct platform_device *pdev)
 		gpio_free(udc->board.pullup_pin);
 		gpio_free(udc->board.pullup_pin);
 
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-	release_mem_region(res->start, res->end - res->start + 1);
+	release_mem_region(res->start, resource_size(res));
 
 
 	clk_put(udc->iclk);
 	clk_put(udc->iclk);
 	clk_put(udc->fclk);
 	clk_put(udc->fclk);

+ 5 - 4
drivers/usb/gadget/atmel_usba_udc.c

@@ -320,7 +320,7 @@ static inline void usba_cleanup_debugfs(struct usba_udc *udc)
 static int vbus_is_present(struct usba_udc *udc)
 static int vbus_is_present(struct usba_udc *udc)
 {
 {
 	if (gpio_is_valid(udc->vbus_pin))
 	if (gpio_is_valid(udc->vbus_pin))
-		return gpio_get_value(udc->vbus_pin);
+		return gpio_get_value(udc->vbus_pin) ^ udc->vbus_pin_inverted;
 
 
 	/* No Vbus detection: Assume always present */
 	/* No Vbus detection: Assume always present */
 	return 1;
 	return 1;
@@ -1763,7 +1763,7 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
 	if (!udc->driver)
 	if (!udc->driver)
 		goto out;
 		goto out;
 
 
-	vbus = gpio_get_value(udc->vbus_pin);
+	vbus = vbus_is_present(udc);
 	if (vbus != udc->vbus_prev) {
 	if (vbus != udc->vbus_prev) {
 		if (vbus) {
 		if (vbus) {
 			toggle_bias(1);
 			toggle_bias(1);
@@ -1914,14 +1914,14 @@ static int __init usba_udc_probe(struct platform_device *pdev)
 	udc->vbus_pin = -ENODEV;
 	udc->vbus_pin = -ENODEV;
 
 
 	ret = -ENOMEM;
 	ret = -ENOMEM;
-	udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+	udc->regs = ioremap(regs->start, resource_size(regs));
 	if (!udc->regs) {
 	if (!udc->regs) {
 		dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n");
 		dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n");
 		goto err_map_regs;
 		goto err_map_regs;
 	}
 	}
 	dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n",
 	dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n",
 		 (unsigned long)regs->start, udc->regs);
 		 (unsigned long)regs->start, udc->regs);
-	udc->fifo = ioremap(fifo->start, fifo->end - fifo->start + 1);
+	udc->fifo = ioremap(fifo->start, resource_size(fifo));
 	if (!udc->fifo) {
 	if (!udc->fifo) {
 		dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n");
 		dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n");
 		goto err_map_fifo;
 		goto err_map_fifo;
@@ -2000,6 +2000,7 @@ static int __init usba_udc_probe(struct platform_device *pdev)
 	if (gpio_is_valid(pdata->vbus_pin)) {
 	if (gpio_is_valid(pdata->vbus_pin)) {
 		if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
 		if (!gpio_request(pdata->vbus_pin, "atmel_usba_udc")) {
 			udc->vbus_pin = pdata->vbus_pin;
 			udc->vbus_pin = pdata->vbus_pin;
+			udc->vbus_pin_inverted = pdata->vbus_pin_inverted;
 
 
 			ret = request_irq(gpio_to_irq(udc->vbus_pin),
 			ret = request_irq(gpio_to_irq(udc->vbus_pin),
 					usba_vbus_irq, 0,
 					usba_vbus_irq, 0,

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

@@ -323,6 +323,7 @@ struct usba_udc {
 	struct platform_device *pdev;
 	struct platform_device *pdev;
 	int irq;
 	int irq;
 	int vbus_pin;
 	int vbus_pin;
+	int vbus_pin_inverted;
 	struct clk *pclk;
 	struct clk *pclk;
 	struct clk *hclk;
 	struct clk *hclk;
 
 

+ 16 - 8
drivers/usb/gadget/epautoconf.c

@@ -265,16 +265,24 @@ struct usb_ep * __init usb_ep_autoconfig (
 				return ep;
 				return ep;
 		}
 		}
 
 
-	} else if (gadget_is_sh (gadget) && USB_ENDPOINT_XFER_INT == type) {
-		/* single buffering is enough; maybe 8 byte fifo is too */
-		ep = find_ep (gadget, "ep3in-bulk");
-		if (ep && ep_matches (gadget, ep, desc))
-			return ep;
-
-	} else if (gadget_is_mq11xx (gadget) && USB_ENDPOINT_XFER_INT == type) {
-		ep = find_ep (gadget, "ep1-bulk");
+#ifdef CONFIG_BLACKFIN
+	} else if (gadget_is_musbhsfc(gadget) || gadget_is_musbhdrc(gadget)) {
+		if ((USB_ENDPOINT_XFER_BULK == type) ||
+		    (USB_ENDPOINT_XFER_ISOC == type)) {
+			if (USB_DIR_IN & desc->bEndpointAddress)
+				ep = find_ep (gadget, "ep5in");
+			else
+				ep = find_ep (gadget, "ep6out");
+		} else if (USB_ENDPOINT_XFER_INT == type) {
+			if (USB_DIR_IN & desc->bEndpointAddress)
+				ep = find_ep(gadget, "ep1in");
+			else
+				ep = find_ep(gadget, "ep2out");
+		} else
+			ep = NULL;
 		if (ep && ep_matches (gadget, ep, desc))
 		if (ep && ep_matches (gadget, ep, desc))
 			return ep;
 			return ep;
+#endif
 	}
 	}
 
 
 	/* Second, look at endpoints until an unclaimed one looks usable */
 	/* Second, look at endpoints until an unclaimed one looks usable */

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

@@ -259,7 +259,7 @@ static struct usb_configuration rndis_config_driver = {
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-#ifdef USB_ETH_EEM
+#ifdef CONFIG_USB_ETH_EEM
 static int use_eem = 1;
 static int use_eem = 1;
 #else
 #else
 static int use_eem;
 static int use_eem;

+ 0 - 8
drivers/usb/gadget/f_acm.c

@@ -702,14 +702,6 @@ acm_unbind(struct usb_configuration *c, struct usb_function *f)
 /* Some controllers can't support CDC ACM ... */
 /* Some controllers can't support CDC ACM ... */
 static inline bool can_support_cdc(struct usb_configuration *c)
 static inline bool can_support_cdc(struct usb_configuration *c)
 {
 {
-	/* SH3 doesn't support multiple interfaces */
-	if (gadget_is_sh(c->cdev->gadget))
-		return false;
-
-	/* sa1100 doesn't have a third interrupt endpoint */
-	if (gadget_is_sa1100(c->cdev->gadget))
-		return false;
-
 	/* everything else is *probably* fine ... */
 	/* everything else is *probably* fine ... */
 	return true;
 	return true;
 }
 }

+ 2 - 5
drivers/usb/gadget/f_ecm.c

@@ -497,12 +497,9 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			struct net_device	*net;
 			struct net_device	*net;
 
 
 			/* Enable zlps by default for ECM conformance;
 			/* Enable zlps by default for ECM conformance;
-			 * override for musb_hdrc (avoids txdma ovhead)
-			 * and sa1100 (can't).
+			 * override for musb_hdrc (avoids txdma ovhead).
 			 */
 			 */
-			ecm->port.is_zlp_ok = !(
-				   gadget_is_sa1100(cdev->gadget)
-				|| gadget_is_musbhdrc(cdev->gadget)
+			ecm->port.is_zlp_ok = !(gadget_is_musbhdrc(cdev->gadget)
 				);
 				);
 			ecm->port.cdc_filter = DEFAULT_FILTER;
 			ecm->port.cdc_filter = DEFAULT_FILTER;
 			DBG(cdev, "activate ecm\n");
 			DBG(cdev, "activate ecm\n");

+ 29 - 21
drivers/usb/gadget/f_mass_storage.c

@@ -368,7 +368,7 @@ struct fsg_common {
 	struct task_struct	*thread_task;
 	struct task_struct	*thread_task;
 
 
 	/* Callback function to call when thread exits. */
 	/* Callback function to call when thread exits. */
-	void			(*thread_exits)(struct fsg_common *common);
+	int			(*thread_exits)(struct fsg_common *common);
 	/* Gadget's private data. */
 	/* Gadget's private data. */
 	void			*private_data;
 	void			*private_data;
 
 
@@ -392,8 +392,12 @@ struct fsg_config {
 	const char		*lun_name_format;
 	const char		*lun_name_format;
 	const char		*thread_name;
 	const char		*thread_name;
 
 
-	/* Callback function to call when thread exits. */
-	void			(*thread_exits)(struct fsg_common *common);
+	/* Callback function to call when thread exits.  If no
+	 * callback is set or it returns value lower then zero MSF
+	 * will force eject all LUNs it operates on (including those
+	 * marked as non-removable or with prevent_medium_removal flag
+	 * set). */
+	int			(*thread_exits)(struct fsg_common *common);
 	/* Gadget's private data. */
 	/* Gadget's private data. */
 	void			*private_data;
 	void			*private_data;
 
 
@@ -614,7 +618,12 @@ static int fsg_setup(struct usb_function *f,
 			return -EDOM;
 			return -EDOM;
 		VDBG(fsg, "get max LUN\n");
 		VDBG(fsg, "get max LUN\n");
 		*(u8 *) req->buf = fsg->common->nluns - 1;
 		*(u8 *) req->buf = fsg->common->nluns - 1;
-		return 1;
+
+		/* Respond with data/status */
+		req->length = min((u16)1, w_length);
+		fsg->common->ep0req_name =
+			ctrl->bRequestType & USB_DIR_IN ? "ep0-in" : "ep0-out";
+		return ep0_queue(fsg->common);
 	}
 	}
 
 
 	VDBG(fsg,
 	VDBG(fsg,
@@ -2524,14 +2533,6 @@ static void handle_exception(struct fsg_common *common)
 
 
 	case FSG_STATE_CONFIG_CHANGE:
 	case FSG_STATE_CONFIG_CHANGE:
 		rc = do_set_config(common, new_config);
 		rc = do_set_config(common, new_config);
-		if (common->ep0_req_tag != exception_req_tag)
-			break;
-		if (rc != 0) {			/* STALL on errors */
-			DBG(common, "ep0 set halt\n");
-			usb_ep_set_halt(common->ep0);
-		} else {			/* Complete the status stage */
-			ep0_queue(common);
-		}
 		break;
 		break;
 
 
 	case FSG_STATE_EXIT:
 	case FSG_STATE_EXIT:
@@ -2615,8 +2616,20 @@ static int fsg_main_thread(void *common_)
 	common->thread_task = NULL;
 	common->thread_task = NULL;
 	spin_unlock_irq(&common->lock);
 	spin_unlock_irq(&common->lock);
 
 
-	if (common->thread_exits)
-		common->thread_exits(common);
+	if (!common->thread_exits || common->thread_exits(common) < 0) {
+		struct fsg_lun *curlun = common->luns;
+		unsigned i = common->nluns;
+
+		down_write(&common->filesem);
+		for (; i--; ++curlun) {
+			if (!fsg_lun_is_open(curlun))
+				continue;
+
+			fsg_lun_close(curlun);
+			curlun->unit_attention_data = SS_MEDIUM_NOT_PRESENT;
+		}
+		up_write(&common->filesem);
+	}
 
 
 	/* Let the unbind and cleanup routines know the thread has exited */
 	/* Let the unbind and cleanup routines know the thread has exited */
 	complete_and_exit(&common->thread_notifier, 0);
 	complete_and_exit(&common->thread_notifier, 0);
@@ -2763,10 +2776,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
 	if (cfg->release != 0xffff) {
 	if (cfg->release != 0xffff) {
 		i = cfg->release;
 		i = cfg->release;
 	} else {
 	} else {
-		/* The sa1100 controller is not supported */
-		i = gadget_is_sa1100(gadget)
-			? -1
-			: usb_gadget_controller_number(gadget);
+		i = usb_gadget_controller_number(gadget);
 		if (i >= 0) {
 		if (i >= 0) {
 			i = 0x0300 + i;
 			i = 0x0300 + i;
 		} else {
 		} else {
@@ -2791,8 +2801,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
 	 * disable stalls.
 	 * disable stalls.
 	 */
 	 */
 	common->can_stall = cfg->can_stall &&
 	common->can_stall = cfg->can_stall &&
-		!(gadget_is_sh(common->gadget) ||
-		  gadget_is_at91(common->gadget));
+		!(gadget_is_at91(common->gadget));
 
 
 
 
 	spin_lock_init(&common->lock);
 	spin_lock_init(&common->lock);
@@ -2852,7 +2861,6 @@ error_release:
 	/* Call fsg_common_release() directly, ref might be not
 	/* Call fsg_common_release() directly, ref might be not
 	 * initialised */
 	 * initialised */
 	fsg_common_release(&common->ref);
 	fsg_common_release(&common->ref);
-	complete(&common->thread_notifier);
 	return ERR_PTR(rc);
 	return ERR_PTR(rc);
 }
 }
 
 

+ 0 - 4
drivers/usb/gadget/f_rndis.c

@@ -769,10 +769,6 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f)
 /* Some controllers can't support RNDIS ... */
 /* Some controllers can't support RNDIS ... */
 static inline bool can_support_rndis(struct usb_configuration *c)
 static inline bool can_support_rndis(struct usb_configuration *c)
 {
 {
-	/* only two endpoints on sa1100 */
-	if (gadget_is_sa1100(c->cdev->gadget))
-		return false;
-
 	/* everything else is *presumably* fine */
 	/* everything else is *presumably* fine */
 	return true;
 	return true;
 }
 }

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

@@ -3208,15 +3208,11 @@ static int __init check_parameters(struct fsg_dev *fsg)
 	 * halt bulk endpoints correctly.  If one of them is present,
 	 * halt bulk endpoints correctly.  If one of them is present,
 	 * disable stalls.
 	 * disable stalls.
 	 */
 	 */
-	if (gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget))
+	if (gadget_is_at91(fsg->gadget))
 		mod_data.can_stall = 0;
 		mod_data.can_stall = 0;
 
 
 	if (mod_data.release == 0xffff) {	// Parameter wasn't set
 	if (mod_data.release == 0xffff) {	// Parameter wasn't set
-		/* The sa1100 controller is not supported */
-		if (gadget_is_sa1100(fsg->gadget))
-			gcnum = -1;
-		else
-			gcnum = usb_gadget_controller_number(fsg->gadget);
+		gcnum = usb_gadget_controller_number(fsg->gadget);
 		if (gcnum >= 0)
 		if (gcnum >= 0)
 			mod_data.release = 0x0300 + gcnum;
 			mod_data.release = 0x0300 + gcnum;
 		else {
 		else {

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

@@ -2749,7 +2749,7 @@ static int __devexit qe_udc_remove(struct of_device *ofdev)
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
-static struct of_device_id __devinitdata qe_udc_match[] = {
+static const struct of_device_id qe_udc_match[] __devinitconst = {
 	{
 	{
 		.compatible = "fsl,mpc8323-qe-usb",
 		.compatible = "fsl,mpc8323-qe-usb",
 		.data = (void *)PORT_QE,
 		.data = (void *)PORT_QE,

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

@@ -45,46 +45,18 @@
 #define	gadget_is_goku(g)	0
 #define	gadget_is_goku(g)	0
 #endif
 #endif
 
 
-/* SH3 UDC -- not yet ported 2.4 --> 2.6 */
-#ifdef CONFIG_USB_GADGET_SUPERH
-#define	gadget_is_sh(g)		!strcmp("sh_udc", (g)->name)
-#else
-#define	gadget_is_sh(g)		0
-#endif
-
-/* not yet stable on 2.6 (would help "original Zaurus") */
-#ifdef CONFIG_USB_GADGET_SA1100
-#define	gadget_is_sa1100(g)	!strcmp("sa1100_udc", (g)->name)
-#else
-#define	gadget_is_sa1100(g)	0
-#endif
-
 #ifdef CONFIG_USB_GADGET_LH7A40X
 #ifdef CONFIG_USB_GADGET_LH7A40X
 #define	gadget_is_lh7a40x(g)	!strcmp("lh7a40x_udc", (g)->name)
 #define	gadget_is_lh7a40x(g)	!strcmp("lh7a40x_udc", (g)->name)
 #else
 #else
 #define	gadget_is_lh7a40x(g)	0
 #define	gadget_is_lh7a40x(g)	0
 #endif
 #endif
 
 
-/* handhelds.org tree (?) */
-#ifdef CONFIG_USB_GADGET_MQ11XX
-#define	gadget_is_mq11xx(g)	!strcmp("mq11xx_udc", (g)->name)
-#else
-#define	gadget_is_mq11xx(g)	0
-#endif
-
 #ifdef CONFIG_USB_GADGET_OMAP
 #ifdef CONFIG_USB_GADGET_OMAP
 #define	gadget_is_omap(g)	!strcmp("omap_udc", (g)->name)
 #define	gadget_is_omap(g)	!strcmp("omap_udc", (g)->name)
 #else
 #else
 #define	gadget_is_omap(g)	0
 #define	gadget_is_omap(g)	0
 #endif
 #endif
 
 
-/* not yet ported 2.4 --> 2.6 */
-#ifdef CONFIG_USB_GADGET_N9604
-#define	gadget_is_n9604(g)	!strcmp("n9604_udc", (g)->name)
-#else
-#define	gadget_is_n9604(g)	0
-#endif
-
 /* various unstable versions available */
 /* various unstable versions available */
 #ifdef CONFIG_USB_GADGET_PXA27X
 #ifdef CONFIG_USB_GADGET_PXA27X
 #define	gadget_is_pxa27x(g)	!strcmp("pxa27x_udc", (g)->name)
 #define	gadget_is_pxa27x(g)	!strcmp("pxa27x_udc", (g)->name)
@@ -122,14 +94,6 @@
 #define gadget_is_fsl_usb2(g)	0
 #define gadget_is_fsl_usb2(g)	0
 #endif
 #endif
 
 
-/* Mentor high speed function controller */
-/* from Montavista kernel (?) */
-#ifdef CONFIG_USB_GADGET_MUSBHSFC
-#define gadget_is_musbhsfc(g)	!strcmp("musbhsfc_udc", (g)->name)
-#else
-#define gadget_is_musbhsfc(g)	0
-#endif
-
 /* Mentor high speed "dual role" controller, in peripheral role */
 /* Mentor high speed "dual role" controller, in peripheral role */
 #ifdef CONFIG_USB_GADGET_MUSB_HDRC
 #ifdef CONFIG_USB_GADGET_MUSB_HDRC
 #define gadget_is_musbhdrc(g)	!strcmp("musb_hdrc", (g)->name)
 #define gadget_is_musbhdrc(g)	!strcmp("musb_hdrc", (g)->name)
@@ -143,13 +107,6 @@
 #define gadget_is_langwell(g)	0
 #define gadget_is_langwell(g)	0
 #endif
 #endif
 
 
-/* from Montavista kernel (?) */
-#ifdef CONFIG_USB_GADGET_MPC8272
-#define gadget_is_mpc8272(g)	!strcmp("mpc8272_udc", (g)->name)
-#else
-#define gadget_is_mpc8272(g)	0
-#endif
-
 #ifdef CONFIG_USB_GADGET_M66592
 #ifdef CONFIG_USB_GADGET_M66592
 #define	gadget_is_m66592(g)	!strcmp("m66592_udc", (g)->name)
 #define	gadget_is_m66592(g)	!strcmp("m66592_udc", (g)->name)
 #else
 #else
@@ -203,20 +160,12 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x02;
 		return 0x02;
 	else if (gadget_is_pxa(gadget))
 	else if (gadget_is_pxa(gadget))
 		return 0x03;
 		return 0x03;
-	else if (gadget_is_sh(gadget))
-		return 0x04;
-	else if (gadget_is_sa1100(gadget))
-		return 0x05;
 	else if (gadget_is_goku(gadget))
 	else if (gadget_is_goku(gadget))
 		return 0x06;
 		return 0x06;
-	else if (gadget_is_mq11xx(gadget))
-		return 0x07;
 	else if (gadget_is_omap(gadget))
 	else if (gadget_is_omap(gadget))
 		return 0x08;
 		return 0x08;
 	else if (gadget_is_lh7a40x(gadget))
 	else if (gadget_is_lh7a40x(gadget))
 		return 0x09;
 		return 0x09;
-	else if (gadget_is_n9604(gadget))
-		return 0x10;
 	else if (gadget_is_pxa27x(gadget))
 	else if (gadget_is_pxa27x(gadget))
 		return 0x11;
 		return 0x11;
 	else if (gadget_is_s3c2410(gadget))
 	else if (gadget_is_s3c2410(gadget))
@@ -225,12 +174,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x13;
 		return 0x13;
 	else if (gadget_is_imx(gadget))
 	else if (gadget_is_imx(gadget))
 		return 0x14;
 		return 0x14;
-	else if (gadget_is_musbhsfc(gadget))
-		return 0x15;
 	else if (gadget_is_musbhdrc(gadget))
 	else if (gadget_is_musbhdrc(gadget))
 		return 0x16;
 		return 0x16;
-	else if (gadget_is_mpc8272(gadget))
-		return 0x17;
 	else if (gadget_is_atmel_usba(gadget))
 	else if (gadget_is_atmel_usba(gadget))
 		return 0x18;
 		return 0x18;
 	else if (gadget_is_fsl_usb2(gadget))
 	else if (gadget_is_fsl_usb2(gadget))
@@ -265,10 +210,6 @@ static inline bool gadget_supports_altsettings(struct usb_gadget *gadget)
 	if (gadget_is_pxa27x(gadget))
 	if (gadget_is_pxa27x(gadget))
 		return false;
 		return false;
 
 
-	/* SH3 hardware just doesn't do altsettings */
-	if (gadget_is_sh(gadget))
-		return false;
-
 	/* Everything else is *presumably* fine ... */
 	/* Everything else is *presumably* fine ... */
 	return true;
 	return true;
 }
 }

+ 0 - 5
drivers/usb/gadget/gmidi.c

@@ -618,11 +618,6 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags)
 	}
 	}
 #endif
 #endif
 
 
-	if (gadget_is_sa1100(gadget) && dev->config) {
-		/* tx fifo is full, but we can't clear it...*/
-		ERROR(dev, "can't change configurations\n");
-		return -ESPIPE;
-	}
 	gmidi_reset_config(dev);
 	gmidi_reset_config(dev);
 
 
 	switch (number) {
 	switch (number) {

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

@@ -1859,7 +1859,7 @@ done:
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-static struct pci_device_id pci_ids [] = { {
+static const struct pci_device_id pci_ids[] = { {
 	.class =	((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
 	.class =	((PCI_CLASS_SERIAL_USB << 8) | 0xfe),
 	.class_mask =	~0,
 	.class_mask =	~0,
 	.vendor =	0x102f,		/* Toshiba */
 	.vendor =	0x102f,		/* Toshiba */

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

@@ -194,7 +194,7 @@ enum ep_state {
 };
 };
 
 
 struct ep_data {
 struct ep_data {
-	struct semaphore		lock;
+	struct mutex			lock;
 	enum ep_state			state;
 	enum ep_state			state;
 	atomic_t			count;
 	atomic_t			count;
 	struct dev_data			*dev;
 	struct dev_data			*dev;
@@ -298,10 +298,10 @@ get_ready_ep (unsigned f_flags, struct ep_data *epdata)
 	int	val;
 	int	val;
 
 
 	if (f_flags & O_NONBLOCK) {
 	if (f_flags & O_NONBLOCK) {
-		if (down_trylock (&epdata->lock) != 0)
+		if (!mutex_trylock(&epdata->lock))
 			goto nonblock;
 			goto nonblock;
 		if (epdata->state != STATE_EP_ENABLED) {
 		if (epdata->state != STATE_EP_ENABLED) {
-			up (&epdata->lock);
+			mutex_unlock(&epdata->lock);
 nonblock:
 nonblock:
 			val = -EAGAIN;
 			val = -EAGAIN;
 		} else
 		} else
@@ -309,7 +309,8 @@ nonblock:
 		return val;
 		return val;
 	}
 	}
 
 
-	if ((val = down_interruptible (&epdata->lock)) < 0)
+	val = mutex_lock_interruptible(&epdata->lock);
+	if (val < 0)
 		return val;
 		return val;
 
 
 	switch (epdata->state) {
 	switch (epdata->state) {
@@ -323,7 +324,7 @@ nonblock:
 		// FALLTHROUGH
 		// FALLTHROUGH
 	case STATE_EP_UNBOUND:			/* clean disconnect */
 	case STATE_EP_UNBOUND:			/* clean disconnect */
 		val = -ENODEV;
 		val = -ENODEV;
-		up (&epdata->lock);
+		mutex_unlock(&epdata->lock);
 	}
 	}
 	return val;
 	return val;
 }
 }
@@ -393,7 +394,7 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
 		if (likely (data->ep != NULL))
 		if (likely (data->ep != NULL))
 			usb_ep_set_halt (data->ep);
 			usb_ep_set_halt (data->ep);
 		spin_unlock_irq (&data->dev->lock);
 		spin_unlock_irq (&data->dev->lock);
-		up (&data->lock);
+		mutex_unlock(&data->lock);
 		return -EBADMSG;
 		return -EBADMSG;
 	}
 	}
 
 
@@ -411,7 +412,7 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
 		value = -EFAULT;
 		value = -EFAULT;
 
 
 free1:
 free1:
-	up (&data->lock);
+	mutex_unlock(&data->lock);
 	kfree (kbuf);
 	kfree (kbuf);
 	return value;
 	return value;
 }
 }
@@ -436,7 +437,7 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
 		if (likely (data->ep != NULL))
 		if (likely (data->ep != NULL))
 			usb_ep_set_halt (data->ep);
 			usb_ep_set_halt (data->ep);
 		spin_unlock_irq (&data->dev->lock);
 		spin_unlock_irq (&data->dev->lock);
-		up (&data->lock);
+		mutex_unlock(&data->lock);
 		return -EBADMSG;
 		return -EBADMSG;
 	}
 	}
 
 
@@ -455,7 +456,7 @@ ep_write (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
 	VDEBUG (data->dev, "%s write %zu IN, status %d\n",
 	VDEBUG (data->dev, "%s write %zu IN, status %d\n",
 		data->name, len, (int) value);
 		data->name, len, (int) value);
 free1:
 free1:
-	up (&data->lock);
+	mutex_unlock(&data->lock);
 	kfree (kbuf);
 	kfree (kbuf);
 	return value;
 	return value;
 }
 }
@@ -466,7 +467,8 @@ ep_release (struct inode *inode, struct file *fd)
 	struct ep_data		*data = fd->private_data;
 	struct ep_data		*data = fd->private_data;
 	int value;
 	int value;
 
 
-	if ((value = down_interruptible(&data->lock)) < 0)
+	value = mutex_lock_interruptible(&data->lock);
+	if (value < 0)
 		return value;
 		return value;
 
 
 	/* clean up if this can be reopened */
 	/* clean up if this can be reopened */
@@ -476,7 +478,7 @@ ep_release (struct inode *inode, struct file *fd)
 		data->hs_desc.bDescriptorType = 0;
 		data->hs_desc.bDescriptorType = 0;
 		usb_ep_disable(data->ep);
 		usb_ep_disable(data->ep);
 	}
 	}
-	up (&data->lock);
+	mutex_unlock(&data->lock);
 	put_ep (data);
 	put_ep (data);
 	return 0;
 	return 0;
 }
 }
@@ -507,7 +509,7 @@ static long ep_ioctl(struct file *fd, unsigned code, unsigned long value)
 	} else
 	} else
 		status = -ENODEV;
 		status = -ENODEV;
 	spin_unlock_irq (&data->dev->lock);
 	spin_unlock_irq (&data->dev->lock);
-	up (&data->lock);
+	mutex_unlock(&data->lock);
 	return status;
 	return status;
 }
 }
 
 
@@ -673,7 +675,7 @@ fail:
 		value = -ENODEV;
 		value = -ENODEV;
 	spin_unlock_irq(&epdata->dev->lock);
 	spin_unlock_irq(&epdata->dev->lock);
 
 
-	up(&epdata->lock);
+	mutex_unlock(&epdata->lock);
 
 
 	if (unlikely(value)) {
 	if (unlikely(value)) {
 		kfree(priv);
 		kfree(priv);
@@ -765,7 +767,8 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
 	u32			tag;
 	u32			tag;
 	int			value, length = len;
 	int			value, length = len;
 
 
-	if ((value = down_interruptible (&data->lock)) < 0)
+	value = mutex_lock_interruptible(&data->lock);
+	if (value < 0)
 		return value;
 		return value;
 
 
 	if (data->state != STATE_EP_READY) {
 	if (data->state != STATE_EP_READY) {
@@ -854,7 +857,7 @@ fail:
 		data->desc.bDescriptorType = 0;
 		data->desc.bDescriptorType = 0;
 		data->hs_desc.bDescriptorType = 0;
 		data->hs_desc.bDescriptorType = 0;
 	}
 	}
-	up (&data->lock);
+	mutex_unlock(&data->lock);
 	return value;
 	return value;
 fail0:
 fail0:
 	value = -EINVAL;
 	value = -EINVAL;
@@ -870,7 +873,7 @@ ep_open (struct inode *inode, struct file *fd)
 	struct ep_data		*data = inode->i_private;
 	struct ep_data		*data = inode->i_private;
 	int			value = -EBUSY;
 	int			value = -EBUSY;
 
 
-	if (down_interruptible (&data->lock) != 0)
+	if (mutex_lock_interruptible(&data->lock) != 0)
 		return -EINTR;
 		return -EINTR;
 	spin_lock_irq (&data->dev->lock);
 	spin_lock_irq (&data->dev->lock);
 	if (data->dev->state == STATE_DEV_UNBOUND)
 	if (data->dev->state == STATE_DEV_UNBOUND)
@@ -885,7 +888,7 @@ ep_open (struct inode *inode, struct file *fd)
 		DBG (data->dev, "%s state %d\n",
 		DBG (data->dev, "%s state %d\n",
 			data->name, data->state);
 			data->name, data->state);
 	spin_unlock_irq (&data->dev->lock);
 	spin_unlock_irq (&data->dev->lock);
-	up (&data->lock);
+	mutex_unlock(&data->lock);
 	return value;
 	return value;
 }
 }
 
 
@@ -1631,7 +1634,7 @@ static int activate_ep_files (struct dev_data *dev)
 		if (!data)
 		if (!data)
 			goto enomem0;
 			goto enomem0;
 		data->state = STATE_EP_DISABLED;
 		data->state = STATE_EP_DISABLED;
-		init_MUTEX (&data->lock);
+		mutex_init(&data->lock);
 		init_waitqueue_head (&data->wait);
 		init_waitqueue_head (&data->wait);
 
 
 		strncpy (data->name, ep->name, sizeof (data->name) - 1);
 		strncpy (data->name, ep->name, sizeof (data->name) - 1);

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

@@ -135,6 +135,12 @@ FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
 static unsigned long msg_registered = 0;
 static unsigned long msg_registered = 0;
 static void msg_cleanup(void);
 static void msg_cleanup(void);
 
 
+static int msg_thread_exits(struct fsg_common *common)
+{
+	msg_cleanup();
+	return 0;
+}
+
 static int __init msg_do_config(struct usb_configuration *c)
 static int __init msg_do_config(struct usb_configuration *c)
 {
 {
 	struct fsg_common *common;
 	struct fsg_common *common;
@@ -147,7 +153,7 @@ static int __init msg_do_config(struct usb_configuration *c)
 	}
 	}
 
 
 	fsg_config_from_params(&config, &mod_data);
 	fsg_config_from_params(&config, &mod_data);
-	config.thread_exits = (void(*)(struct fsg_common*))&msg_cleanup;
+	config.thread_exits = msg_thread_exits;
 	common = fsg_common_init(0, c->cdev, &config);
 	common = fsg_common_init(0, c->cdev, &config);
 	if (IS_ERR(common))
 	if (IS_ERR(common))
 		return PTR_ERR(common);
 		return PTR_ERR(common);

+ 259 - 0
drivers/usb/gadget/nokia.c

@@ -0,0 +1,259 @@
+/*
+ * nokia.c -- Nokia Composite Gadget Driver
+ *
+ * Copyright (C) 2008-2010 Nokia Corporation
+ * Contact: Felipe Balbi <felipe.balbi@nokia.com>
+ *
+ * This gadget driver borrows from serial.c which is:
+ *
+ * Copyright (C) 2003 Al Borchers (alborchers@steinerpoint.com)
+ * Copyright (C) 2008 by David Brownell
+ * Copyright (C) 2008 by Nokia Corporation
+ *
+ * This software is distributed under the terms of the GNU General
+ * Public License ("GPL") as published by the Free Software Foundation,
+ * version 2 of that License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/utsname.h>
+#include <linux/device.h>
+
+#include "u_serial.h"
+#include "u_ether.h"
+#include "u_phonet.h"
+#include "gadget_chips.h"
+
+/* Defines */
+
+#define NOKIA_VERSION_NUM		0x0211
+#define NOKIA_LONG_NAME			"N900 (PC-Suite Mode)"
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Kbuild is not very cooperative with respect to linking separately
+ * compiled library objects into one module.  So for now we won't use
+ * separate compilation ... ensuring init/exit sections work to shrink
+ * the runtime footprint, and giving us at least some parts of what
+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
+ */
+#include "composite.c"
+#include "usbstring.c"
+#include "config.c"
+#include "epautoconf.c"
+
+#include "u_serial.c"
+#include "f_acm.c"
+#include "f_ecm.c"
+#include "f_obex.c"
+#include "f_serial.c"
+#include "f_phonet.c"
+#include "u_ether.c"
+
+/*-------------------------------------------------------------------------*/
+
+#define NOKIA_VENDOR_ID			0x0421	/* Nokia */
+#define NOKIA_PRODUCT_ID		0x01c8	/* Nokia Gadget */
+
+/* string IDs are assigned dynamically */
+
+#define STRING_MANUFACTURER_IDX		0
+#define STRING_PRODUCT_IDX		1
+#define STRING_DESCRIPTION_IDX		2
+
+static char manufacturer_nokia[] = "Nokia";
+static const char product_nokia[] = NOKIA_LONG_NAME;
+static const char description_nokia[] = "PC-Suite Configuration";
+
+static struct usb_string strings_dev[] = {
+	[STRING_MANUFACTURER_IDX].s = manufacturer_nokia,
+	[STRING_PRODUCT_IDX].s = NOKIA_LONG_NAME,
+	[STRING_DESCRIPTION_IDX].s = description_nokia,
+	{  } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+	.language	= 0x0409,	/* en-us */
+	.strings	= strings_dev,
+};
+
+static struct usb_gadget_strings *dev_strings[] = {
+	&stringtab_dev,
+	NULL,
+};
+
+static struct usb_device_descriptor device_desc = {
+	.bLength		= USB_DT_DEVICE_SIZE,
+	.bDescriptorType	= USB_DT_DEVICE,
+	.bcdUSB			= __constant_cpu_to_le16(0x0200),
+	.bDeviceClass		= USB_CLASS_COMM,
+	.idVendor		= __constant_cpu_to_le16(NOKIA_VENDOR_ID),
+	.idProduct		= __constant_cpu_to_le16(NOKIA_PRODUCT_ID),
+	/* .iManufacturer = DYNAMIC */
+	/* .iProduct = DYNAMIC */
+	.bNumConfigurations =	1,
+};
+
+/*-------------------------------------------------------------------------*/
+
+/* Module */
+MODULE_DESCRIPTION("Nokia composite gadget driver for N900");
+MODULE_AUTHOR("Felipe Balbi");
+MODULE_LICENSE("GPL");
+
+/*-------------------------------------------------------------------------*/
+
+static u8 hostaddr[ETH_ALEN];
+
+static int __init nokia_bind_config(struct usb_configuration *c)
+{
+	int status = 0;
+
+	status = phonet_bind_config(c);
+	if (status)
+		printk(KERN_DEBUG "could not bind phonet config\n");
+
+	status = obex_bind_config(c, 0);
+	if (status)
+		printk(KERN_DEBUG "could not bind obex config %d\n", 0);
+
+	status = obex_bind_config(c, 1);
+	if (status)
+		printk(KERN_DEBUG "could not bind obex config %d\n", 0);
+
+	status = acm_bind_config(c, 2);
+	if (status)
+		printk(KERN_DEBUG "could not bind acm config\n");
+
+	status = ecm_bind_config(c, hostaddr);
+	if (status)
+		printk(KERN_DEBUG "could not bind ecm config\n");
+
+	return status;
+}
+
+static struct usb_configuration nokia_config_500ma_driver = {
+	.label		= "Bus Powered",
+	.bind		= nokia_bind_config,
+	.bConfigurationValue = 1,
+	/* .iConfiguration = DYNAMIC */
+	.bmAttributes	= USB_CONFIG_ATT_ONE,
+	.bMaxPower	= 250, /* 500mA */
+};
+
+static struct usb_configuration nokia_config_100ma_driver = {
+	.label		= "Self Powered",
+	.bind		= nokia_bind_config,
+	.bConfigurationValue = 2,
+	/* .iConfiguration = DYNAMIC */
+	.bmAttributes	= USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
+	.bMaxPower	= 50, /* 100 mA */
+};
+
+static int __init nokia_bind(struct usb_composite_dev *cdev)
+{
+	int			gcnum;
+	struct usb_gadget	*gadget = cdev->gadget;
+	int			status;
+
+	status = gphonet_setup(cdev->gadget);
+	if (status < 0)
+		goto err_phonet;
+
+	status = gserial_setup(cdev->gadget, 3);
+	if (status < 0)
+		goto err_serial;
+
+	status = gether_setup(cdev->gadget, hostaddr);
+	if (status < 0)
+		goto err_ether;
+
+	status = usb_string_id(cdev);
+	if (status < 0)
+		goto err_usb;
+	strings_dev[STRING_MANUFACTURER_IDX].id = status;
+
+	device_desc.iManufacturer = status;
+
+	status = usb_string_id(cdev);
+	if (status < 0)
+		goto err_usb;
+	strings_dev[STRING_PRODUCT_IDX].id = status;
+
+	device_desc.iProduct = status;
+
+	/* config description */
+	status = usb_string_id(cdev);
+	if (status < 0)
+		goto err_usb;
+	strings_dev[STRING_DESCRIPTION_IDX].id = status;
+
+	nokia_config_500ma_driver.iConfiguration = status;
+	nokia_config_100ma_driver.iConfiguration = status;
+
+	/* set up other descriptors */
+	gcnum = usb_gadget_controller_number(gadget);
+	if (gcnum >= 0)
+		device_desc.bcdDevice = cpu_to_le16(NOKIA_VERSION_NUM);
+	else {
+		/* this should only work with hw that supports altsettings
+		 * and several endpoints, anything else, panic.
+		 */
+		pr_err("nokia_bind: controller '%s' not recognized\n",
+			gadget->name);
+		goto err_usb;
+	}
+
+	/* finaly register the configuration */
+	status = usb_add_config(cdev, &nokia_config_500ma_driver);
+	if (status < 0)
+		goto err_usb;
+
+	status = usb_add_config(cdev, &nokia_config_100ma_driver);
+	if (status < 0)
+		goto err_usb;
+
+	dev_info(&gadget->dev, "%s\n", NOKIA_LONG_NAME);
+
+	return 0;
+
+err_usb:
+	gether_cleanup();
+err_ether:
+	gserial_cleanup();
+err_serial:
+	gphonet_cleanup();
+err_phonet:
+	return status;
+}
+
+static int __exit nokia_unbind(struct usb_composite_dev *cdev)
+{
+	gphonet_cleanup();
+	gserial_cleanup();
+	gether_cleanup();
+
+	return 0;
+}
+
+static struct usb_composite_driver nokia_driver = {
+	.name		= "g_nokia",
+	.dev		= &device_desc,
+	.strings	= dev_strings,
+	.bind		= nokia_bind,
+	.unbind		= __exit_p(nokia_unbind),
+};
+
+static int __init nokia_init(void)
+{
+	return usb_composite_register(&nokia_driver);
+}
+module_init(nokia_init);
+
+static void __exit nokia_cleanup(void)
+{
+	usb_composite_unregister(&nokia_driver);
+}
+module_exit(nokia_cleanup);
+

+ 0 - 18
drivers/usb/gadget/printer.c

@@ -949,12 +949,6 @@ printer_set_config(struct printer_dev *dev, unsigned number)
 	int			result = 0;
 	int			result = 0;
 	struct usb_gadget	*gadget = dev->gadget;
 	struct usb_gadget	*gadget = dev->gadget;
 
 
-	if (gadget_is_sa1100(gadget) && dev->config) {
-		/* tx fifo is full, but we can't clear it...*/
-		INFO(dev, "can't change configurations\n");
-		return -ESPIPE;
-	}
-
 	switch (number) {
 	switch (number) {
 	case DEV_CONFIG_VALUE:
 	case DEV_CONFIG_VALUE:
 		result = 0;
 		result = 0;
@@ -1033,12 +1027,6 @@ set_interface(struct printer_dev *dev, unsigned number)
 {
 {
 	int			result = 0;
 	int			result = 0;
 
 
-	if (gadget_is_sa1100(dev->gadget) && dev->interface < 0) {
-		/* tx fifo is full, but we can't clear it...*/
-		INFO(dev, "can't change interfaces\n");
-		return -ESPIPE;
-	}
-
 	/* Free the current interface */
 	/* Free the current interface */
 	switch (dev->interface) {
 	switch (dev->interface) {
 	case PRINTER_INTERFACE:
 	case PRINTER_INTERFACE:
@@ -1392,12 +1380,6 @@ printer_bind(struct usb_gadget *gadget)
 		goto fail;
 		goto fail;
 	}
 	}
 
 
-	if (gadget_is_sa1100(gadget)) {
-		/* hardware can't write zero length packets. */
-		ERROR(dev, "SA1100 controller is unsupport by this driver\n");
-		goto fail;
-	}
-
 	gcnum = usb_gadget_controller_number(gadget);
 	gcnum = usb_gadget_controller_number(gadget);
 	if (gcnum >= 0) {
 	if (gcnum >= 0) {
 		device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
 		device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);

+ 93 - 42
drivers/usb/gadget/pxa27x_udc.c

@@ -742,13 +742,17 @@ static void ep_del_request(struct pxa_ep *ep, struct pxa27x_request *req)
  * @ep: pxa physical endpoint
  * @ep: pxa physical endpoint
  * @req: pxa request
  * @req: pxa request
  * @status: usb request status sent to gadget API
  * @status: usb request status sent to gadget API
+ * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held
  *
  *
- * Context: ep->lock held
+ * Context: ep->lock held if flags not NULL, else ep->lock released
  *
  *
  * Retire a pxa27x usb request. Endpoint must be locked.
  * Retire a pxa27x usb request. Endpoint must be locked.
  */
  */
-static void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status)
+static void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status,
+	unsigned long *pflags)
 {
 {
+	unsigned long	flags;
+
 	ep_del_request(ep, req);
 	ep_del_request(ep, req);
 	if (likely(req->req.status == -EINPROGRESS))
 	if (likely(req->req.status == -EINPROGRESS))
 		req->req.status = status;
 		req->req.status = status;
@@ -760,38 +764,48 @@ static void req_done(struct pxa_ep *ep, struct pxa27x_request *req, int status)
 			&req->req, status,
 			&req->req, status,
 			req->req.actual, req->req.length);
 			req->req.actual, req->req.length);
 
 
+	if (pflags)
+		spin_unlock_irqrestore(&ep->lock, *pflags);
+	local_irq_save(flags);
 	req->req.complete(&req->udc_usb_ep->usb_ep, &req->req);
 	req->req.complete(&req->udc_usb_ep->usb_ep, &req->req);
+	local_irq_restore(flags);
+	if (pflags)
+		spin_lock_irqsave(&ep->lock, *pflags);
 }
 }
 
 
 /**
 /**
  * ep_end_out_req - Ends endpoint OUT request
  * ep_end_out_req - Ends endpoint OUT request
  * @ep: physical endpoint
  * @ep: physical endpoint
  * @req: pxa request
  * @req: pxa request
+ * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held
  *
  *
- * Context: ep->lock held
+ * Context: ep->lock held or released (see req_done())
  *
  *
  * Ends endpoint OUT request (completes usb request).
  * Ends endpoint OUT request (completes usb request).
  */
  */
-static void ep_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
+static void ep_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req,
+	unsigned long *pflags)
 {
 {
 	inc_ep_stats_reqs(ep, !USB_DIR_IN);
 	inc_ep_stats_reqs(ep, !USB_DIR_IN);
-	req_done(ep, req, 0);
+	req_done(ep, req, 0, pflags);
 }
 }
 
 
 /**
 /**
  * ep0_end_out_req - Ends control endpoint OUT request (ends data stage)
  * ep0_end_out_req - Ends control endpoint OUT request (ends data stage)
  * @ep: physical endpoint
  * @ep: physical endpoint
  * @req: pxa request
  * @req: pxa request
+ * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held
  *
  *
- * Context: ep->lock held
+ * Context: ep->lock held or released (see req_done())
  *
  *
  * Ends control endpoint OUT request (completes usb request), and puts
  * Ends control endpoint OUT request (completes usb request), and puts
  * control endpoint into idle state
  * control endpoint into idle state
  */
  */
-static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
+static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req,
+	unsigned long *pflags)
 {
 {
 	set_ep0state(ep->dev, OUT_STATUS_STAGE);
 	set_ep0state(ep->dev, OUT_STATUS_STAGE);
-	ep_end_out_req(ep, req);
+	ep_end_out_req(ep, req, pflags);
 	ep0_idle(ep->dev);
 	ep0_idle(ep->dev);
 }
 }
 
 
@@ -799,31 +813,35 @@ static void ep0_end_out_req(struct pxa_ep *ep, struct pxa27x_request *req)
  * ep_end_in_req - Ends endpoint IN request
  * ep_end_in_req - Ends endpoint IN request
  * @ep: physical endpoint
  * @ep: physical endpoint
  * @req: pxa request
  * @req: pxa request
+ * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held
  *
  *
- * Context: ep->lock held
+ * Context: ep->lock held or released (see req_done())
  *
  *
  * Ends endpoint IN request (completes usb request).
  * Ends endpoint IN request (completes usb request).
  */
  */
-static void ep_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req)
+static void ep_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req,
+	unsigned long *pflags)
 {
 {
 	inc_ep_stats_reqs(ep, USB_DIR_IN);
 	inc_ep_stats_reqs(ep, USB_DIR_IN);
-	req_done(ep, req, 0);
+	req_done(ep, req, 0, pflags);
 }
 }
 
 
 /**
 /**
  * ep0_end_in_req - Ends control endpoint IN request (ends data stage)
  * ep0_end_in_req - Ends control endpoint IN request (ends data stage)
  * @ep: physical endpoint
  * @ep: physical endpoint
  * @req: pxa request
  * @req: pxa request
+ * @pflags: flags of previous spinlock_irq_save() or NULL if no lock held
  *
  *
- * Context: ep->lock held
+ * Context: ep->lock held or released (see req_done())
  *
  *
  * Ends control endpoint IN request (completes usb request), and puts
  * Ends control endpoint IN request (completes usb request), and puts
  * control endpoint into status state
  * control endpoint into status state
  */
  */
-static void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req)
+static void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req,
+	unsigned long *pflags)
 {
 {
 	set_ep0state(ep->dev, IN_STATUS_STAGE);
 	set_ep0state(ep->dev, IN_STATUS_STAGE);
-	ep_end_in_req(ep, req);
+	ep_end_in_req(ep, req, pflags);
 }
 }
 
 
 /**
 /**
@@ -831,19 +849,22 @@ static void ep0_end_in_req(struct pxa_ep *ep, struct pxa27x_request *req)
  * @ep: pxa endpoint
  * @ep: pxa endpoint
  * @status: usb request status
  * @status: usb request status
  *
  *
- * Context: ep->lock held
+ * Context: ep->lock released
  *
  *
  * Dequeues all requests on an endpoint. As a side effect, interrupts will be
  * Dequeues all requests on an endpoint. As a side effect, interrupts will be
  * disabled on that endpoint (because no more requests).
  * disabled on that endpoint (because no more requests).
  */
  */
 static void nuke(struct pxa_ep *ep, int status)
 static void nuke(struct pxa_ep *ep, int status)
 {
 {
-	struct pxa27x_request *req;
+	struct pxa27x_request	*req;
+	unsigned long		flags;
 
 
+	spin_lock_irqsave(&ep->lock, flags);
 	while (!list_empty(&ep->queue)) {
 	while (!list_empty(&ep->queue)) {
 		req = list_entry(ep->queue.next, struct pxa27x_request, queue);
 		req = list_entry(ep->queue.next, struct pxa27x_request, queue);
-		req_done(ep, req, status);
+		req_done(ep, req, status, &flags);
 	}
 	}
+	spin_unlock_irqrestore(&ep->lock, flags);
 }
 }
 
 
 /**
 /**
@@ -1123,6 +1144,7 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
 	int			rc = 0;
 	int			rc = 0;
 	int			is_first_req;
 	int			is_first_req;
 	unsigned		length;
 	unsigned		length;
+	int			recursion_detected;
 
 
 	req = container_of(_req, struct pxa27x_request, req);
 	req = container_of(_req, struct pxa27x_request, req);
 	udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
 	udc_usb_ep = container_of(_ep, struct udc_usb_ep, usb_ep);
@@ -1152,6 +1174,7 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
 		return -EMSGSIZE;
 		return -EMSGSIZE;
 
 
 	spin_lock_irqsave(&ep->lock, flags);
 	spin_lock_irqsave(&ep->lock, flags);
+	recursion_detected = ep->in_handle_ep;
 
 
 	is_first_req = list_empty(&ep->queue);
 	is_first_req = list_empty(&ep->queue);
 	ep_dbg(ep, "queue req %p(first=%s), len %d buf %p\n",
 	ep_dbg(ep, "queue req %p(first=%s), len %d buf %p\n",
@@ -1161,12 +1184,12 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
 	if (!ep->enabled) {
 	if (!ep->enabled) {
 		_req->status = -ESHUTDOWN;
 		_req->status = -ESHUTDOWN;
 		rc = -ESHUTDOWN;
 		rc = -ESHUTDOWN;
-		goto out;
+		goto out_locked;
 	}
 	}
 
 
 	if (req->in_use) {
 	if (req->in_use) {
 		ep_err(ep, "refusing to queue req %p (already queued)\n", req);
 		ep_err(ep, "refusing to queue req %p (already queued)\n", req);
-		goto out;
+		goto out_locked;
 	}
 	}
 
 
 	length = _req->length;
 	length = _req->length;
@@ -1174,12 +1197,13 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
 	_req->actual = 0;
 	_req->actual = 0;
 
 
 	ep_add_request(ep, req);
 	ep_add_request(ep, req);
+	spin_unlock_irqrestore(&ep->lock, flags);
 
 
 	if (is_ep0(ep)) {
 	if (is_ep0(ep)) {
 		switch (dev->ep0state) {
 		switch (dev->ep0state) {
 		case WAIT_ACK_SET_CONF_INTERF:
 		case WAIT_ACK_SET_CONF_INTERF:
 			if (length == 0) {
 			if (length == 0) {
-				ep_end_in_req(ep, req);
+				ep_end_in_req(ep, req, NULL);
 			} else {
 			} else {
 				ep_err(ep, "got a request of %d bytes while"
 				ep_err(ep, "got a request of %d bytes while"
 					"in state WAIT_ACK_SET_CONF_INTERF\n",
 					"in state WAIT_ACK_SET_CONF_INTERF\n",
@@ -1192,12 +1216,12 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
 		case IN_DATA_STAGE:
 		case IN_DATA_STAGE:
 			if (!ep_is_full(ep))
 			if (!ep_is_full(ep))
 				if (write_ep0_fifo(ep, req))
 				if (write_ep0_fifo(ep, req))
-					ep0_end_in_req(ep, req);
+					ep0_end_in_req(ep, req, NULL);
 			break;
 			break;
 		case OUT_DATA_STAGE:
 		case OUT_DATA_STAGE:
 			if ((length == 0) || !epout_has_pkt(ep))
 			if ((length == 0) || !epout_has_pkt(ep))
 				if (read_ep0_fifo(ep, req))
 				if (read_ep0_fifo(ep, req))
-					ep0_end_out_req(ep, req);
+					ep0_end_out_req(ep, req, NULL);
 			break;
 			break;
 		default:
 		default:
 			ep_err(ep, "odd state %s to send me a request\n",
 			ep_err(ep, "odd state %s to send me a request\n",
@@ -1207,12 +1231,15 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
 			break;
 			break;
 		}
 		}
 	} else {
 	} else {
-		handle_ep(ep);
+		if (!recursion_detected)
+			handle_ep(ep);
 	}
 	}
 
 
 out:
 out:
-	spin_unlock_irqrestore(&ep->lock, flags);
 	return rc;
 	return rc;
+out_locked:
+	spin_unlock_irqrestore(&ep->lock, flags);
+	goto out;
 }
 }
 
 
 /**
 /**
@@ -1242,13 +1269,14 @@ static int pxa_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
 	/* make sure it's actually queued on this endpoint */
 	/* make sure it's actually queued on this endpoint */
 	list_for_each_entry(req, &ep->queue, queue) {
 	list_for_each_entry(req, &ep->queue, queue) {
 		if (&req->req == _req) {
 		if (&req->req == _req) {
-			req_done(ep, req, -ECONNRESET);
 			rc = 0;
 			rc = 0;
 			break;
 			break;
 		}
 		}
 	}
 	}
 
 
 	spin_unlock_irqrestore(&ep->lock, flags);
 	spin_unlock_irqrestore(&ep->lock, flags);
+	if (!rc)
+		req_done(ep, req, -ECONNRESET, NULL);
 	return rc;
 	return rc;
 }
 }
 
 
@@ -1445,7 +1473,6 @@ static int pxa_ep_disable(struct usb_ep *_ep)
 {
 {
 	struct pxa_ep		*ep;
 	struct pxa_ep		*ep;
 	struct udc_usb_ep	*udc_usb_ep;
 	struct udc_usb_ep	*udc_usb_ep;
-	unsigned long		flags;
 
 
 	if (!_ep)
 	if (!_ep)
 		return -EINVAL;
 		return -EINVAL;
@@ -1455,10 +1482,8 @@ static int pxa_ep_disable(struct usb_ep *_ep)
 	if (!ep || is_ep0(ep) || !list_empty(&ep->queue))
 	if (!ep || is_ep0(ep) || !list_empty(&ep->queue))
 		return -EINVAL;
 		return -EINVAL;
 
 
-	spin_lock_irqsave(&ep->lock, flags);
 	ep->enabled = 0;
 	ep->enabled = 0;
 	nuke(ep, -ESHUTDOWN);
 	nuke(ep, -ESHUTDOWN);
-	spin_unlock_irqrestore(&ep->lock, flags);
 
 
 	pxa_ep_fifo_flush(_ep);
 	pxa_ep_fifo_flush(_ep);
 	udc_usb_ep->pxa_ep = NULL;
 	udc_usb_ep->pxa_ep = NULL;
@@ -1907,8 +1932,10 @@ static void handle_ep0_ctrl_req(struct pxa_udc *udc,
 	} u;
 	} u;
 	int i;
 	int i;
 	int have_extrabytes = 0;
 	int have_extrabytes = 0;
+	unsigned long flags;
 
 
 	nuke(ep, -EPROTO);
 	nuke(ep, -EPROTO);
+	spin_lock_irqsave(&ep->lock, flags);
 
 
 	/*
 	/*
 	 * In the PXA320 manual, in the section about Back-to-Back setup
 	 * In the PXA320 manual, in the section about Back-to-Back setup
@@ -1947,10 +1974,13 @@ static void handle_ep0_ctrl_req(struct pxa_udc *udc,
 	/* Tell UDC to enter Data Stage */
 	/* Tell UDC to enter Data Stage */
 	ep_write_UDCCSR(ep, UDCCSR0_SA | UDCCSR0_OPC);
 	ep_write_UDCCSR(ep, UDCCSR0_SA | UDCCSR0_OPC);
 
 
+	spin_unlock_irqrestore(&ep->lock, flags);
 	i = udc->driver->setup(&udc->gadget, &u.r);
 	i = udc->driver->setup(&udc->gadget, &u.r);
+	spin_lock_irqsave(&ep->lock, flags);
 	if (i < 0)
 	if (i < 0)
 		goto stall;
 		goto stall;
 out:
 out:
+	spin_unlock_irqrestore(&ep->lock, flags);
 	return;
 	return;
 stall:
 stall:
 	ep_dbg(ep, "protocol STALL, udccsr0=%03x err %d\n",
 	ep_dbg(ep, "protocol STALL, udccsr0=%03x err %d\n",
@@ -2055,13 +2085,13 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq)
 		if (req && !ep_is_full(ep))
 		if (req && !ep_is_full(ep))
 			completed = write_ep0_fifo(ep, req);
 			completed = write_ep0_fifo(ep, req);
 		if (completed)
 		if (completed)
-			ep0_end_in_req(ep, req);
+			ep0_end_in_req(ep, req, NULL);
 		break;
 		break;
 	case OUT_DATA_STAGE:			/* SET_DESCRIPTOR */
 	case OUT_DATA_STAGE:			/* SET_DESCRIPTOR */
 		if (epout_has_pkt(ep) && req)
 		if (epout_has_pkt(ep) && req)
 			completed = read_ep0_fifo(ep, req);
 			completed = read_ep0_fifo(ep, req);
 		if (completed)
 		if (completed)
-			ep0_end_out_req(ep, req);
+			ep0_end_out_req(ep, req, NULL);
 		break;
 		break;
 	case STALL:
 	case STALL:
 		ep_write_UDCCSR(ep, UDCCSR0_FST);
 		ep_write_UDCCSR(ep, UDCCSR0_FST);
@@ -2091,7 +2121,7 @@ static void handle_ep0(struct pxa_udc *udc, int fifo_irq, int opc_irq)
  * Tries to transfer all pending request data into the endpoint and/or
  * Tries to transfer all pending request data into the endpoint and/or
  * transfer all pending data in the endpoint into usb requests.
  * transfer all pending data in the endpoint into usb requests.
  *
  *
- * Is always called when in_interrupt() or with ep->lock held.
+ * Is always called when in_interrupt() and with ep->lock released.
  */
  */
 static void handle_ep(struct pxa_ep *ep)
 static void handle_ep(struct pxa_ep *ep)
 {
 {
@@ -2100,10 +2130,17 @@ static void handle_ep(struct pxa_ep *ep)
 	u32 udccsr;
 	u32 udccsr;
 	int is_in = ep->dir_in;
 	int is_in = ep->dir_in;
 	int loop = 0;
 	int loop = 0;
+	unsigned long		flags;
+
+	spin_lock_irqsave(&ep->lock, flags);
+	if (ep->in_handle_ep)
+		goto recursion_detected;
+	ep->in_handle_ep = 1;
 
 
 	do {
 	do {
 		completed = 0;
 		completed = 0;
 		udccsr = udc_ep_readl(ep, UDCCSR);
 		udccsr = udc_ep_readl(ep, UDCCSR);
+
 		if (likely(!list_empty(&ep->queue)))
 		if (likely(!list_empty(&ep->queue)))
 			req = list_entry(ep->queue.next,
 			req = list_entry(ep->queue.next,
 					struct pxa27x_request, queue);
 					struct pxa27x_request, queue);
@@ -2122,15 +2159,22 @@ static void handle_ep(struct pxa_ep *ep)
 		if (unlikely(is_in)) {
 		if (unlikely(is_in)) {
 			if (likely(!ep_is_full(ep)))
 			if (likely(!ep_is_full(ep)))
 				completed = write_fifo(ep, req);
 				completed = write_fifo(ep, req);
-			if (completed)
-				ep_end_in_req(ep, req);
 		} else {
 		} else {
 			if (likely(epout_has_pkt(ep)))
 			if (likely(epout_has_pkt(ep)))
 				completed = read_fifo(ep, req);
 				completed = read_fifo(ep, req);
-			if (completed)
-				ep_end_out_req(ep, req);
+		}
+
+		if (completed) {
+			if (is_in)
+				ep_end_in_req(ep, req, &flags);
+			else
+				ep_end_out_req(ep, req, &flags);
 		}
 		}
 	} while (completed);
 	} while (completed);
+
+	ep->in_handle_ep = 0;
+recursion_detected:
+	spin_unlock_irqrestore(&ep->lock, flags);
 }
 }
 
 
 /**
 /**
@@ -2218,9 +2262,13 @@ static void irq_handle_data(int irq, struct pxa_udc *udc)
 			continue;
 			continue;
 
 
 		udc_writel(udc, UDCISR0, UDCISR_INT(i, UDCISR_INT_MASK));
 		udc_writel(udc, UDCISR0, UDCISR_INT(i, UDCISR_INT_MASK));
-		ep = &udc->pxa_ep[i];
-		ep->stats.irqs++;
-		handle_ep(ep);
+
+		WARN_ON(i >= ARRAY_SIZE(udc->pxa_ep));
+		if (i < ARRAY_SIZE(udc->pxa_ep)) {
+			ep = &udc->pxa_ep[i];
+			ep->stats.irqs++;
+			handle_ep(ep);
+		}
 	}
 	}
 
 
 	for (i = 16; udcisr1 != 0 && i < 24; udcisr1 >>= 2, i++) {
 	for (i = 16; udcisr1 != 0 && i < 24; udcisr1 >>= 2, i++) {
@@ -2228,9 +2276,12 @@ static void irq_handle_data(int irq, struct pxa_udc *udc)
 		if (!(udcisr1 & UDCISR_INT_MASK))
 		if (!(udcisr1 & UDCISR_INT_MASK))
 			continue;
 			continue;
 
 
-		ep = &udc->pxa_ep[i];
-		ep->stats.irqs++;
-		handle_ep(ep);
+		WARN_ON(i >= ARRAY_SIZE(udc->pxa_ep));
+		if (i < ARRAY_SIZE(udc->pxa_ep)) {
+			ep = &udc->pxa_ep[i];
+			ep->stats.irqs++;
+			handle_ep(ep);
+		}
 	}
 	}
 
 
 }
 }
@@ -2439,7 +2490,7 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
 	}
 	}
 
 
 	retval = -ENOMEM;
 	retval = -ENOMEM;
-	udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+	udc->regs = ioremap(regs->start, resource_size(regs));
 	if (!udc->regs) {
 	if (!udc->regs) {
 		dev_err(&pdev->dev, "Unable to map UDC I/O memory\n");
 		dev_err(&pdev->dev, "Unable to map UDC I/O memory\n");
 		goto err_map;
 		goto err_map;

+ 6 - 0
drivers/usb/gadget/pxa27x_udc.h

@@ -318,6 +318,11 @@ struct udc_usb_ep {
  * @queue: requests queue
  * @queue: requests queue
  * @lock: lock to pxa_ep data (queues and stats)
  * @lock: lock to pxa_ep data (queues and stats)
  * @enabled: true when endpoint enabled (not stopped by gadget layer)
  * @enabled: true when endpoint enabled (not stopped by gadget layer)
+ * @in_handle_ep: number of recursions of handle_ep() function
+ * 	Prevents deadlocks or infinite recursions of types :
+ *	  irq->handle_ep()->req_done()->req.complete()->pxa_ep_queue()->handle_ep()
+ *      or
+ *        pxa_ep_queue()->handle_ep()->req_done()->req.complete()->pxa_ep_queue()
  * @idx: endpoint index (1 => epA, 2 => epB, ..., 24 => epX)
  * @idx: endpoint index (1 => epA, 2 => epB, ..., 24 => epX)
  * @name: endpoint name (for trace/debug purpose)
  * @name: endpoint name (for trace/debug purpose)
  * @dir_in: 1 if IN endpoint, 0 if OUT endpoint
  * @dir_in: 1 if IN endpoint, 0 if OUT endpoint
@@ -346,6 +351,7 @@ struct pxa_ep {
 	spinlock_t		lock;		/* Protects this structure */
 	spinlock_t		lock;		/* Protects this structure */
 						/* (queues, stats) */
 						/* (queues, stats) */
 	unsigned		enabled:1;
 	unsigned		enabled:1;
+	unsigned		in_handle_ep:1;
 
 
 	unsigned		idx:5;
 	unsigned		idx:5;
 	char			*name;
 	char			*name;

+ 6 - 5
drivers/usb/gadget/s3c-hsotg.c

@@ -317,7 +317,8 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)
  *
  *
  * Allocate a new USB request structure appropriate for the specified endpoint
  * Allocate a new USB request structure appropriate for the specified endpoint
  */
  */
-struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep, gfp_t flags)
+static struct usb_request *s3c_hsotg_ep_alloc_request(struct usb_ep *ep,
+						      gfp_t flags)
 {
 {
 	struct s3c_hsotg_req *req;
 	struct s3c_hsotg_req *req;
 
 
@@ -373,7 +374,7 @@ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg,
 		req->dma = DMA_ADDR_INVALID;
 		req->dma = DMA_ADDR_INVALID;
 		hs_req->mapped = 0;
 		hs_req->mapped = 0;
 	} else {
 	} else {
-		dma_sync_single(hsotg->dev, req->dma, req->length, dir);
+		dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir);
 	}
 	}
 }
 }
 
 
@@ -755,7 +756,7 @@ static int s3c_hsotg_map_dma(struct s3c_hsotg *hsotg,
 		hs_req->mapped = 1;
 		hs_req->mapped = 1;
 		req->dma = dma;
 		req->dma = dma;
 	} else {
 	} else {
-		dma_sync_single(hsotg->dev, req->dma, req->length, dir);
+		dma_sync_single_for_cpu(hsotg->dev, req->dma, req->length, dir);
 		hs_req->mapped = 0;
 		hs_req->mapped = 0;
 	}
 	}
 
 
@@ -1460,7 +1461,7 @@ static u32 s3c_hsotg_read_frameno(struct s3c_hsotg *hsotg)
  * as the actual data should be sent to the memory directly and we turn
  * as the actual data should be sent to the memory directly and we turn
  * on the completion interrupts to get notifications of transfer completion.
  * on the completion interrupts to get notifications of transfer completion.
  */
  */
-void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg)
+static void s3c_hsotg_handle_rx(struct s3c_hsotg *hsotg)
 {
 {
 	u32 grxstsr = readl(hsotg->regs + S3C_GRXSTSP);
 	u32 grxstsr = readl(hsotg->regs + S3C_GRXSTSP);
 	u32 epnum, status, size;
 	u32 epnum, status, size;
@@ -3094,7 +3095,7 @@ static void s3c_hsotg_gate(struct platform_device *pdev, bool on)
 	local_irq_restore(flags);
 	local_irq_restore(flags);
 }
 }
 
 
-struct s3c_hsotg_plat s3c_hsotg_default_pdata;
+static struct s3c_hsotg_plat s3c_hsotg_default_pdata;
 
 
 static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
 static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
 {
 {

+ 5 - 0
drivers/usb/gadget/u_ether.c

@@ -746,6 +746,10 @@ static const struct net_device_ops eth_netdev_ops = {
 	.ndo_validate_addr	= eth_validate_addr,
 	.ndo_validate_addr	= eth_validate_addr,
 };
 };
 
 
+static struct device_type gadget_type = {
+	.name	= "gadget",
+};
+
 /**
 /**
  * gether_setup - initialize one ethernet-over-usb link
  * gether_setup - initialize one ethernet-over-usb link
  * @g: gadget to associated with these links
  * @g: gadget to associated with these links
@@ -808,6 +812,7 @@ int __init gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN])
 
 
 	dev->gadget = g;
 	dev->gadget = g;
 	SET_NETDEV_DEV(net, &g->dev);
 	SET_NETDEV_DEV(net, &g->dev);
+	SET_NETDEV_DEVTYPE(net, &gadget_type);
 
 
 	status = register_netdev(net);
 	status = register_netdev(net);
 	if (status < 0) {
 	if (status < 0) {

+ 0 - 7
drivers/usb/gadget/u_ether.h

@@ -93,13 +93,6 @@ static inline bool can_support_ecm(struct usb_gadget *gadget)
 	if (!gadget_supports_altsettings(gadget))
 	if (!gadget_supports_altsettings(gadget))
 		return false;
 		return false;
 
 
-	/* SA1100 can do ECM, *without* status endpoint ... but we'll
-	 * only use it in non-ECM mode for backwards compatibility
-	 * (and since we currently require a status endpoint)
-	 */
-	if (gadget_is_sa1100(gadget))
-		return false;
-
 	/* Everything else is *presumably* fine ... but this is a bit
 	/* Everything else is *presumably* fine ... but this is a bit
 	 * chancy, so be **CERTAIN** there are no hardware issues with
 	 * chancy, so be **CERTAIN** there are no hardware issues with
 	 * your controller.  Add it above if it can't handle CDC.
 	 * your controller.  Add it above if it can't handle CDC.

+ 2 - 4
drivers/usb/gadget/zero.c

@@ -297,12 +297,10 @@ static int __init zero_bind(struct usb_composite_dev *cdev)
 	 */
 	 */
 	if (loopdefault) {
 	if (loopdefault) {
 		loopback_add(cdev, autoresume != 0);
 		loopback_add(cdev, autoresume != 0);
-		if (!gadget_is_sh(gadget))
-			sourcesink_add(cdev, autoresume != 0);
+		sourcesink_add(cdev, autoresume != 0);
 	} else {
 	} else {
 		sourcesink_add(cdev, autoresume != 0);
 		sourcesink_add(cdev, autoresume != 0);
-		if (!gadget_is_sh(gadget))
-			loopback_add(cdev, autoresume != 0);
+		loopback_add(cdev, autoresume != 0);
 	}
 	}
 
 
 	gcnum = usb_gadget_controller_number(gadget);
 	gcnum = usb_gadget_controller_number(gadget);

+ 11 - 0
drivers/usb/host/Kconfig

@@ -399,3 +399,14 @@ config USB_HWA_HCD
 
 
 	  To compile this driver a module, choose M here: the module
 	  To compile this driver a module, choose M here: the module
 	  will be called "hwa-hc".
 	  will be called "hwa-hc".
+
+config USB_IMX21_HCD
+       tristate "iMX21 HCD support"
+       depends on USB && ARM && MACH_MX21
+       help
+         This driver enables support for the on-chip USB host in the
+         iMX21 processor.
+
+         To compile this driver as a module, choose M here: the
+         module will be called "imx21-hcd".
+

+ 2 - 0
drivers/usb/host/Makefile

@@ -32,3 +32,5 @@ obj-$(CONFIG_USB_U132_HCD)	+= u132-hcd.o
 obj-$(CONFIG_USB_R8A66597_HCD)	+= r8a66597-hcd.o
 obj-$(CONFIG_USB_R8A66597_HCD)	+= r8a66597-hcd.o
 obj-$(CONFIG_USB_ISP1760_HCD)	+= isp1760.o
 obj-$(CONFIG_USB_ISP1760_HCD)	+= isp1760.o
 obj-$(CONFIG_USB_HWA_HCD)	+= hwa-hc.o
 obj-$(CONFIG_USB_HWA_HCD)	+= hwa-hc.o
+obj-$(CONFIG_USB_IMX21_HCD)	+= imx21-hcd.o
+

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

@@ -149,7 +149,7 @@ static int __init ehci_atmel_drv_probe(struct platform_device *pdev)
 		goto fail_request_resource;
 		goto fail_request_resource;
 	}
 	}
 	hcd->rsrc_start = res->start;
 	hcd->rsrc_start = res->start;
-	hcd->rsrc_len = res->end - res->start + 1;
+	hcd->rsrc_len = resource_size(res);
 
 
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
 				driver->description)) {
 				driver->description)) {

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

@@ -121,6 +121,7 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
 {
 {
 	struct usb_hcd *hcd;
 	struct usb_hcd *hcd;
 	struct ehci_hcd *ehci;
 	struct ehci_hcd *ehci;
+	struct resource *res;
 	int ret;
 	int ret;
 
 
 	if (usb_disabled())
 	if (usb_disabled())
@@ -144,8 +145,9 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
 	if (!hcd)
 	if (!hcd)
 		return -ENOMEM;
 		return -ENOMEM;
 
 
-	hcd->rsrc_start = pdev->resource[0].start;
-	hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	hcd->rsrc_start = res->start;
+	hcd->rsrc_len = resource_size(res);
 
 
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
 		pr_debug("request_mem_region failed");
 		pr_debug("request_mem_region failed");

+ 87 - 10
drivers/usb/host/ehci-fsl.c

@@ -1,5 +1,6 @@
 /*
 /*
- * Copyright (c) 2005 MontaVista Software
+ * Copyright 2005-2009 MontaVista Software, Inc.
+ * Copyright 2008      Freescale Semiconductor, Inc.
  *
  *
  * This program is free software; you can redistribute it and/or modify it
  * 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
  * under the terms of the GNU General Public License as published by the
@@ -17,17 +18,20 @@
  *
  *
  * Ported to 834x by Randy Vinson <rvinson@mvista.com> using code provided
  * Ported to 834x by Randy Vinson <rvinson@mvista.com> using code provided
  * by Hunter Wu.
  * by Hunter Wu.
+ * Power Management support by Dave Liu <daveliu@freescale.com>,
+ * Jerry Huang <Chang-Ming.Huang@freescale.com> and
+ * Anton Vorontsov <avorontsov@ru.mvista.com>.
  */
  */
 
 
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/fsl_devices.h>
 #include <linux/fsl_devices.h>
 
 
 #include "ehci-fsl.h"
 #include "ehci-fsl.h"
 
 
-/* FIXME: Power Management is un-ported so temporarily disable it */
-#undef CONFIG_PM
-
-
 /* configure so an HC device and id are always provided */
 /* configure so an HC device and id are always provided */
 /* always called with process context; sleeping is OK */
 /* always called with process context; sleeping is OK */
 
 
@@ -40,8 +44,8 @@
  * Allocates basic resources for this USB host controller.
  * Allocates basic resources for this USB host controller.
  *
  *
  */
  */
-int usb_hcd_fsl_probe(const struct hc_driver *driver,
-		      struct platform_device *pdev)
+static int usb_hcd_fsl_probe(const struct hc_driver *driver,
+			     struct platform_device *pdev)
 {
 {
 	struct fsl_usb2_platform_data *pdata;
 	struct fsl_usb2_platform_data *pdata;
 	struct usb_hcd *hcd;
 	struct usb_hcd *hcd;
@@ -147,7 +151,8 @@ int usb_hcd_fsl_probe(const struct hc_driver *driver,
  * Reverses the effect of usb_hcd_fsl_probe().
  * Reverses the effect of usb_hcd_fsl_probe().
  *
  *
  */
  */
-void usb_hcd_fsl_remove(struct usb_hcd *hcd, struct platform_device *pdev)
+static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
+			       struct platform_device *pdev)
 {
 {
 	usb_remove_hcd(hcd);
 	usb_remove_hcd(hcd);
 	iounmap(hcd->regs);
 	iounmap(hcd->regs);
@@ -284,10 +289,81 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
 	return retval;
 	return retval;
 }
 }
 
 
+struct ehci_fsl {
+	struct ehci_hcd	ehci;
+
+#ifdef CONFIG_PM
+	/* Saved USB PHY settings, need to restore after deep sleep. */
+	u32 usb_ctrl;
+#endif
+};
+
+#ifdef CONFIG_PM
+
+static struct ehci_fsl *hcd_to_ehci_fsl(struct usb_hcd *hcd)
+{
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+	return container_of(ehci, struct ehci_fsl, ehci);
+}
+
+static int ehci_fsl_drv_suspend(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
+	void __iomem *non_ehci = hcd->regs;
+
+	if (!fsl_deep_sleep())
+		return 0;
+
+	ehci_fsl->usb_ctrl = in_be32(non_ehci + FSL_SOC_USB_CTRL);
+	return 0;
+}
+
+static int ehci_fsl_drv_resume(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+	struct ehci_fsl *ehci_fsl = hcd_to_ehci_fsl(hcd);
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	void __iomem *non_ehci = hcd->regs;
+
+	if (!fsl_deep_sleep())
+		return 0;
+
+	usb_root_hub_lost_power(hcd->self.root_hub);
+
+	/* Restore USB PHY settings and enable the controller. */
+	out_be32(non_ehci + FSL_SOC_USB_CTRL, ehci_fsl->usb_ctrl);
+
+	ehci_reset(ehci);
+	ehci_fsl_reinit(ehci);
+
+	return 0;
+}
+
+static int ehci_fsl_drv_restore(struct device *dev)
+{
+	struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+	usb_root_hub_lost_power(hcd->self.root_hub);
+	return 0;
+}
+
+static struct dev_pm_ops ehci_fsl_pm_ops = {
+	.suspend = ehci_fsl_drv_suspend,
+	.resume = ehci_fsl_drv_resume,
+	.restore = ehci_fsl_drv_restore,
+};
+
+#define EHCI_FSL_PM_OPS		(&ehci_fsl_pm_ops)
+#else
+#define EHCI_FSL_PM_OPS		NULL
+#endif /* CONFIG_PM */
+
 static const struct hc_driver ehci_fsl_hc_driver = {
 static const struct hc_driver ehci_fsl_hc_driver = {
 	.description = hcd_name,
 	.description = hcd_name,
 	.product_desc = "Freescale On-Chip EHCI Host Controller",
 	.product_desc = "Freescale On-Chip EHCI Host Controller",
-	.hcd_priv_size = sizeof(struct ehci_hcd),
+	.hcd_priv_size = sizeof(struct ehci_fsl),
 
 
 	/*
 	/*
 	 * generic hardware linkage
 	 * generic hardware linkage
@@ -354,6 +430,7 @@ static struct platform_driver ehci_fsl_driver = {
 	.remove = ehci_fsl_drv_remove,
 	.remove = ehci_fsl_drv_remove,
 	.shutdown = usb_hcd_platform_shutdown,
 	.shutdown = usb_hcd_platform_shutdown,
 	.driver = {
 	.driver = {
-		   .name = "fsl-ehci",
+		.name = "fsl-ehci",
+		.pm = EHCI_FSL_PM_OPS,
 	},
 	},
 };
 };

+ 11 - 12
drivers/usb/host/ehci-mxc.c

@@ -162,6 +162,17 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
 		goto err_ioremap;
 		goto err_ioremap;
 	}
 	}
 
 
+	/* call platform specific init function */
+	if (pdata->init) {
+		ret = pdata->init(pdev);
+		if (ret) {
+			dev_err(dev, "platform init failed\n");
+			goto err_init;
+		}
+		/* platforms need some time to settle changed IO settings */
+		mdelay(10);
+	}
+
 	/* enable clocks */
 	/* enable clocks */
 	priv->usbclk = clk_get(dev, "usb");
 	priv->usbclk = clk_get(dev, "usb");
 	if (IS_ERR(priv->usbclk)) {
 	if (IS_ERR(priv->usbclk)) {
@@ -192,18 +203,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
 	if (ret < 0)
 	if (ret < 0)
 		goto err_init;
 		goto err_init;
 
 
-	/* call platform specific init function */
-	if (pdata->init) {
-		ret = pdata->init(pdev);
-		if (ret) {
-			dev_err(dev, "platform init failed\n");
-			goto err_init;
-		}
-	}
-
-	/* most platforms need some time to settle changed IO settings */
-	mdelay(10);
-
 	/* Initialize the transceiver */
 	/* Initialize the transceiver */
 	if (pdata->otg) {
 	if (pdata->otg) {
 		pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET;
 		pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET;

+ 41 - 6
drivers/usb/host/ehci-omap.c

@@ -26,10 +26,9 @@
  * along with this program; if not, write to the Free Software
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  *
  *
- * TODO (last updated Feb 23rd, 2009):
+ * TODO (last updated Feb 12, 2010):
  *	- add kernel-doc
  *	- add kernel-doc
  *	- enable AUTOIDLE
  *	- enable AUTOIDLE
- *	- move DPLL5 programming to clock fw
  *	- add suspend/resume
  *	- add suspend/resume
  *	- move workarounds to board-files
  *	- move workarounds to board-files
  */
  */
@@ -37,6 +36,7 @@
 #include <linux/platform_device.h>
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/clk.h>
 #include <linux/gpio.h>
 #include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
 #include <plat/usb.h>
 #include <plat/usb.h>
 
 
 /*
 /*
@@ -178,6 +178,11 @@ struct ehci_hcd_omap {
 	void __iomem		*uhh_base;
 	void __iomem		*uhh_base;
 	void __iomem		*tll_base;
 	void __iomem		*tll_base;
 	void __iomem		*ehci_base;
 	void __iomem		*ehci_base;
+
+	/* Regulators for USB PHYs.
+	 * Each PHY can have a seperate regulator.
+	 */
+	struct regulator        *regulator[OMAP3_HS_USB_PORTS];
 };
 };
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -546,6 +551,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
 
 
 	int irq = platform_get_irq(pdev, 0);
 	int irq = platform_get_irq(pdev, 0);
 	int ret = -ENODEV;
 	int ret = -ENODEV;
+	int i;
+	char supply[7];
 
 
 	if (!pdata) {
 	if (!pdata) {
 		dev_dbg(&pdev->dev, "missing platform_data\n");
 		dev_dbg(&pdev->dev, "missing platform_data\n");
@@ -613,6 +620,21 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
 		goto err_tll_ioremap;
 		goto err_tll_ioremap;
 	}
 	}
 
 
+	/* get ehci regulator and enable */
+	for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
+		if (omap->port_mode[i] != EHCI_HCD_OMAP_MODE_PHY) {
+			omap->regulator[i] = NULL;
+			continue;
+		}
+		snprintf(supply, sizeof(supply), "hsusb%d", i);
+		omap->regulator[i] = regulator_get(omap->dev, supply);
+		if (IS_ERR(omap->regulator[i]))
+			dev_dbg(&pdev->dev,
+			"failed to get ehci port%d regulator\n", i);
+		else
+			regulator_enable(omap->regulator[i]);
+	}
+
 	ret = omap_start_ehc(omap, hcd);
 	ret = omap_start_ehc(omap, hcd);
 	if (ret) {
 	if (ret) {
 		dev_dbg(&pdev->dev, "failed to start ehci\n");
 		dev_dbg(&pdev->dev, "failed to start ehci\n");
@@ -622,13 +644,12 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
 	omap->ehci->regs = hcd->regs
 	omap->ehci->regs = hcd->regs
 		+ HC_LENGTH(readl(&omap->ehci->caps->hc_capbase));
 		+ HC_LENGTH(readl(&omap->ehci->caps->hc_capbase));
 
 
+	dbg_hcs_params(omap->ehci, "reset");
+	dbg_hcc_params(omap->ehci, "reset");
+
 	/* cache this readonly data; minimize chip reads */
 	/* cache this readonly data; minimize chip reads */
 	omap->ehci->hcs_params = readl(&omap->ehci->caps->hcs_params);
 	omap->ehci->hcs_params = readl(&omap->ehci->caps->hcs_params);
 
 
-	/* SET 1 micro-frame Interrupt interval */
-	writel(readl(&omap->ehci->regs->command) | (1 << 16),
-			&omap->ehci->regs->command);
-
 	ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
 	ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
 	if (ret) {
 	if (ret) {
 		dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
 		dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
@@ -641,6 +662,12 @@ err_add_hcd:
 	omap_stop_ehc(omap, hcd);
 	omap_stop_ehc(omap, hcd);
 
 
 err_start:
 err_start:
+	for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
+		if (omap->regulator[i]) {
+			regulator_disable(omap->regulator[i]);
+			regulator_put(omap->regulator[i]);
+		}
+	}
 	iounmap(omap->tll_base);
 	iounmap(omap->tll_base);
 
 
 err_tll_ioremap:
 err_tll_ioremap:
@@ -674,13 +701,21 @@ static int ehci_hcd_omap_remove(struct platform_device *pdev)
 {
 {
 	struct ehci_hcd_omap *omap = platform_get_drvdata(pdev);
 	struct ehci_hcd_omap *omap = platform_get_drvdata(pdev);
 	struct usb_hcd *hcd = ehci_to_hcd(omap->ehci);
 	struct usb_hcd *hcd = ehci_to_hcd(omap->ehci);
+	int i;
 
 
 	usb_remove_hcd(hcd);
 	usb_remove_hcd(hcd);
 	omap_stop_ehc(omap, hcd);
 	omap_stop_ehc(omap, hcd);
 	iounmap(hcd->regs);
 	iounmap(hcd->regs);
+	for (i = 0 ; i < OMAP3_HS_USB_PORTS ; i++) {
+		if (omap->regulator[i]) {
+			regulator_disable(omap->regulator[i]);
+			regulator_put(omap->regulator[i]);
+		}
+	}
 	iounmap(omap->tll_base);
 	iounmap(omap->tll_base);
 	iounmap(omap->uhh_base);
 	iounmap(omap->uhh_base);
 	usb_put_hcd(hcd);
 	usb_put_hcd(hcd);
+	kfree(omap);
 
 
 	return 0;
 	return 0;
 }
 }

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

@@ -222,14 +222,14 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
 		goto err1;
 		goto err1;
 	}
 	}
 
 
-	if (!request_mem_region(res->start, res->end - res->start + 1,
+	if (!request_mem_region(res->start, resource_size(res),
 				ehci_orion_hc_driver.description)) {
 				ehci_orion_hc_driver.description)) {
 		dev_dbg(&pdev->dev, "controller already in use\n");
 		dev_dbg(&pdev->dev, "controller already in use\n");
 		err = -EBUSY;
 		err = -EBUSY;
 		goto err1;
 		goto err1;
 	}
 	}
 
 
-	regs = ioremap(res->start, res->end - res->start + 1);
+	regs = ioremap(res->start, resource_size(res));
 	if (regs == NULL) {
 	if (regs == NULL) {
 		dev_dbg(&pdev->dev, "error mapping memory\n");
 		dev_dbg(&pdev->dev, "error mapping memory\n");
 		err = -EFAULT;
 		err = -EFAULT;
@@ -244,7 +244,7 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
 	}
 	}
 
 
 	hcd->rsrc_start = res->start;
 	hcd->rsrc_start = res->start;
-	hcd->rsrc_len = res->end - res->start + 1;
+	hcd->rsrc_len = resource_size(res);
 	hcd->regs = regs;
 	hcd->regs = regs;
 
 
 	ehci = hcd_to_ehci(hcd);
 	ehci = hcd_to_ehci(hcd);
@@ -287,7 +287,7 @@ err4:
 err3:
 err3:
 	iounmap(regs);
 	iounmap(regs);
 err2:
 err2:
-	release_mem_region(res->start, res->end - res->start + 1);
+	release_mem_region(res->start, resource_size(res));
 err1:
 err1:
 	dev_err(&pdev->dev, "init %s fail, %d\n",
 	dev_err(&pdev->dev, "init %s fail, %d\n",
 		dev_name(&pdev->dev), err);
 		dev_name(&pdev->dev), err);

+ 7 - 7
drivers/usb/host/ehci-ppc-of.c

@@ -134,21 +134,21 @@ ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
 	hcd->rsrc_len = res.end - res.start + 1;
 	hcd->rsrc_len = res.end - res.start + 1;
 
 
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
+		printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
 		rv = -EBUSY;
 		rv = -EBUSY;
 		goto err_rmr;
 		goto err_rmr;
 	}
 	}
 
 
 	irq = irq_of_parse_and_map(dn, 0);
 	irq = irq_of_parse_and_map(dn, 0);
 	if (irq == NO_IRQ) {
 	if (irq == NO_IRQ) {
-		printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+		printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
 		rv = -EBUSY;
 		rv = -EBUSY;
 		goto err_irq;
 		goto err_irq;
 	}
 	}
 
 
 	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 	if (!hcd->regs) {
 	if (!hcd->regs) {
-		printk(KERN_ERR __FILE__ ": ioremap failed\n");
+		printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
 		rv = -ENOMEM;
 		rv = -ENOMEM;
 		goto err_ioremap;
 		goto err_ioremap;
 	}
 	}
@@ -161,9 +161,9 @@ ehci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
 			ehci->ohci_hcctrl_reg = ioremap(res.start +
 			ehci->ohci_hcctrl_reg = ioremap(res.start +
 					OHCI_HCCTRL_OFFSET, OHCI_HCCTRL_LEN);
 					OHCI_HCCTRL_OFFSET, OHCI_HCCTRL_LEN);
 		else
 		else
-			pr_debug(__FILE__ ": no ohci offset in fdt\n");
+			pr_debug("%s: no ohci offset in fdt\n", __FILE__);
 		if (!ehci->ohci_hcctrl_reg) {
 		if (!ehci->ohci_hcctrl_reg) {
-			pr_debug(__FILE__ ": ioremap for ohci hcctrl failed\n");
+			pr_debug("%s: ioremap for ohci hcctrl failed\n", __FILE__);
 		} else {
 		} else {
 			ehci->has_amcc_usb23 = 1;
 			ehci->has_amcc_usb23 = 1;
 		}
 		}
@@ -241,7 +241,7 @@ static int ehci_hcd_ppc_of_remove(struct of_device *op)
 				else
 				else
 					release_mem_region(res.start, 0x4);
 					release_mem_region(res.start, 0x4);
 			else
 			else
-				pr_debug(__FILE__ ": no ohci offset in fdt\n");
+				pr_debug("%s: no ohci offset in fdt\n", __FILE__);
 			of_node_put(np);
 			of_node_put(np);
 		}
 		}
 
 
@@ -264,7 +264,7 @@ static int ehci_hcd_ppc_of_shutdown(struct of_device *op)
 }
 }
 
 
 
 
-static struct of_device_id ehci_hcd_ppc_of_match[] = {
+static const struct of_device_id ehci_hcd_ppc_of_match[] = {
 	{
 	{
 		.compatible = "usb-ehci",
 		.compatible = "usb-ehci",
 	},
 	},

+ 9 - 3
drivers/usb/host/ehci-sched.c

@@ -510,6 +510,8 @@ static int disable_periodic (struct ehci_hcd *ehci)
 	ehci_writel(ehci, cmd, &ehci->regs->command);
 	ehci_writel(ehci, cmd, &ehci->regs->command);
 	/* posted write ... */
 	/* posted write ... */
 
 
+	free_cached_itd_list(ehci);
+
 	ehci->next_uframe = -1;
 	ehci->next_uframe = -1;
 	return 0;
 	return 0;
 }
 }
@@ -2322,9 +2324,13 @@ restart:
 				 * No need to check for activity unless the
 				 * No need to check for activity unless the
 				 * frame is current.
 				 * frame is current.
 				 */
 				 */
-				if (frame == clock_frame && live &&
-						(q.sitd->hw_results &
-							SITD_ACTIVE(ehci))) {
+				if (((frame == clock_frame) ||
+				     (((frame + 1) % ehci->periodic_size)
+				      == clock_frame))
+				    && live
+				    && (q.sitd->hw_results &
+					SITD_ACTIVE(ehci))) {
+
 					incomplete = true;
 					incomplete = true;
 					q_p = &q.sitd->sitd_next;
 					q_p = &q.sitd->sitd_next;
 					hw_p = &q.sitd->hw_next;
 					hw_p = &q.sitd->hw_next;

+ 4 - 4
drivers/usb/host/ehci-xilinx-of.c

@@ -177,21 +177,21 @@ ehci_hcd_xilinx_of_probe(struct of_device *op, const struct of_device_id *match)
 	hcd->rsrc_len = res.end - res.start + 1;
 	hcd->rsrc_len = res.end - res.start + 1;
 
 
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
+		printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
 		rv = -EBUSY;
 		rv = -EBUSY;
 		goto err_rmr;
 		goto err_rmr;
 	}
 	}
 
 
 	irq = irq_of_parse_and_map(dn, 0);
 	irq = irq_of_parse_and_map(dn, 0);
 	if (irq == NO_IRQ) {
 	if (irq == NO_IRQ) {
-		printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+		printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
 		rv = -EBUSY;
 		rv = -EBUSY;
 		goto err_irq;
 		goto err_irq;
 	}
 	}
 
 
 	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 	if (!hcd->regs) {
 	if (!hcd->regs) {
-		printk(KERN_ERR __FILE__ ": ioremap failed\n");
+		printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
 		rv = -ENOMEM;
 		rv = -ENOMEM;
 		goto err_ioremap;
 		goto err_ioremap;
 	}
 	}
@@ -281,7 +281,7 @@ static int ehci_hcd_xilinx_of_shutdown(struct of_device *op)
 }
 }
 
 
 
 
-static struct of_device_id ehci_hcd_xilinx_of_match[] = {
+static const struct of_device_id ehci_hcd_xilinx_of_match[] = {
 		{.compatible = "xlnx,xps-usb-host-1.00.a",},
 		{.compatible = "xlnx,xps-usb-host-1.00.a",},
 	{},
 	{},
 };
 };

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

@@ -433,7 +433,7 @@ static int fhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
 		return -ENOMEM;
 		return -ENOMEM;
 
 
 	/* allocate the private part of the URB */
 	/* allocate the private part of the URB */
-	urb_priv->tds = kzalloc(size * sizeof(struct td), mem_flags);
+	urb_priv->tds = kcalloc(size, sizeof(*urb_priv->tds), mem_flags);
 	if (!urb_priv->tds) {
 	if (!urb_priv->tds) {
 		kfree(urb_priv);
 		kfree(urb_priv);
 		return -ENOMEM;
 		return -ENOMEM;
@@ -805,7 +805,7 @@ static int __devexit of_fhci_remove(struct of_device *ofdev)
 	return fhci_remove(&ofdev->dev);
 	return fhci_remove(&ofdev->dev);
 }
 }
 
 
-static struct of_device_id of_fhci_match[] = {
+static const struct of_device_id of_fhci_match[] = {
 	{ .compatible = "fsl,mpc8323-qe-usb", },
 	{ .compatible = "fsl,mpc8323-qe-usb", },
 	{},
 	{},
 };
 };

+ 527 - 0
drivers/usb/host/imx21-dbg.c

@@ -0,0 +1,527 @@
+/*
+ * Copyright (c) 2009 by Martin Fuzzey
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of imx21-hcd.c */
+
+#ifndef DEBUG
+
+static inline void create_debug_files(struct imx21 *imx21) { }
+static inline void remove_debug_files(struct imx21 *imx21) { }
+static inline void debug_urb_submitted(struct imx21 *imx21, struct urb *urb) {}
+static inline void debug_urb_completed(struct imx21 *imx21, struct urb *urb,
+	int status) {}
+static inline void debug_urb_unlinked(struct imx21 *imx21, struct urb *urb) {}
+static inline void debug_urb_queued_for_etd(struct imx21 *imx21,
+	struct urb *urb) {}
+static inline void debug_urb_queued_for_dmem(struct imx21 *imx21,
+	struct urb *urb) {}
+static inline void debug_etd_allocated(struct imx21 *imx21) {}
+static inline void debug_etd_freed(struct imx21 *imx21) {}
+static inline void debug_dmem_allocated(struct imx21 *imx21, int size) {}
+static inline void debug_dmem_freed(struct imx21 *imx21, int size) {}
+static inline void debug_isoc_submitted(struct imx21 *imx21,
+	int frame, struct td *td) {}
+static inline void debug_isoc_completed(struct imx21 *imx21,
+	int frame, struct td *td, int cc, int len) {}
+
+#else
+
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+
+static const char *dir_labels[] = {
+	"TD 0",
+	"OUT",
+	"IN",
+	"TD 1"
+};
+
+static const char *speed_labels[] = {
+	"Full",
+	"Low"
+};
+
+static const char *format_labels[] = {
+	"Control",
+	"ISO",
+	"Bulk",
+	"Interrupt"
+};
+
+static inline struct debug_stats *stats_for_urb(struct imx21 *imx21,
+	struct urb *urb)
+{
+	return usb_pipeisoc(urb->pipe) ?
+		&imx21->isoc_stats : &imx21->nonisoc_stats;
+}
+
+static void debug_urb_submitted(struct imx21 *imx21, struct urb *urb)
+{
+	stats_for_urb(imx21, urb)->submitted++;
+}
+
+static void debug_urb_completed(struct imx21 *imx21, struct urb *urb, int st)
+{
+	if (st)
+		stats_for_urb(imx21, urb)->completed_failed++;
+	else
+		stats_for_urb(imx21, urb)->completed_ok++;
+}
+
+static void debug_urb_unlinked(struct imx21 *imx21, struct urb *urb)
+{
+	stats_for_urb(imx21, urb)->unlinked++;
+}
+
+static void debug_urb_queued_for_etd(struct imx21 *imx21, struct urb *urb)
+{
+	stats_for_urb(imx21, urb)->queue_etd++;
+}
+
+static void debug_urb_queued_for_dmem(struct imx21 *imx21, struct urb *urb)
+{
+	stats_for_urb(imx21, urb)->queue_dmem++;
+}
+
+static inline void debug_etd_allocated(struct imx21 *imx21)
+{
+	imx21->etd_usage.maximum = max(
+			++(imx21->etd_usage.value),
+			imx21->etd_usage.maximum);
+}
+
+static inline void debug_etd_freed(struct imx21 *imx21)
+{
+	imx21->etd_usage.value--;
+}
+
+static inline void debug_dmem_allocated(struct imx21 *imx21, int size)
+{
+	imx21->dmem_usage.value += size;
+	imx21->dmem_usage.maximum = max(
+			imx21->dmem_usage.value,
+			imx21->dmem_usage.maximum);
+}
+
+static inline void debug_dmem_freed(struct imx21 *imx21, int size)
+{
+	imx21->dmem_usage.value -= size;
+}
+
+
+static void debug_isoc_submitted(struct imx21 *imx21,
+	int frame, struct td *td)
+{
+	struct debug_isoc_trace *trace = &imx21->isoc_trace[
+		imx21->isoc_trace_index++];
+
+	imx21->isoc_trace_index %= ARRAY_SIZE(imx21->isoc_trace);
+	trace->schedule_frame = td->frame;
+	trace->submit_frame = frame;
+	trace->request_len = td->len;
+	trace->td = td;
+}
+
+static inline void debug_isoc_completed(struct imx21 *imx21,
+	int frame, struct td *td, int cc, int len)
+{
+	struct debug_isoc_trace *trace, *trace_failed;
+	int i;
+	int found = 0;
+
+	trace = imx21->isoc_trace;
+	for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace); i++, trace++) {
+		if (trace->td == td) {
+			trace->done_frame = frame;
+			trace->done_len = len;
+			trace->cc = cc;
+			trace->td = NULL;
+			found = 1;
+			break;
+		}
+	}
+
+	if (found && cc) {
+		trace_failed = &imx21->isoc_trace_failed[
+					imx21->isoc_trace_index_failed++];
+
+		imx21->isoc_trace_index_failed %= ARRAY_SIZE(
+						imx21->isoc_trace_failed);
+		*trace_failed = *trace;
+	}
+}
+
+
+static char *format_ep(struct usb_host_endpoint *ep, char *buf, int bufsize)
+{
+	if (ep)
+		snprintf(buf, bufsize, "ep_%02x (type:%02X kaddr:%p)",
+			ep->desc.bEndpointAddress,
+			usb_endpoint_type(&ep->desc),
+			ep);
+	else
+		snprintf(buf, bufsize, "none");
+	return buf;
+}
+
+static char *format_etd_dword0(u32 value, char *buf, int bufsize)
+{
+	snprintf(buf, bufsize,
+		"addr=%d ep=%d dir=%s speed=%s format=%s halted=%d",
+		value & 0x7F,
+		(value >> DW0_ENDPNT) & 0x0F,
+		dir_labels[(value >> DW0_DIRECT) & 0x03],
+		speed_labels[(value >> DW0_SPEED) & 0x01],
+		format_labels[(value >> DW0_FORMAT) & 0x03],
+		(value >> DW0_HALTED) & 0x01);
+	return buf;
+}
+
+static int debug_status_show(struct seq_file *s, void *v)
+{
+	struct imx21 *imx21 = s->private;
+	int etds_allocated = 0;
+	int etds_sw_busy = 0;
+	int etds_hw_busy = 0;
+	int dmem_blocks = 0;
+	int queued_for_etd = 0;
+	int queued_for_dmem = 0;
+	unsigned int dmem_bytes = 0;
+	int i;
+	struct etd_priv *etd;
+	u32 etd_enable_mask;
+	unsigned long flags;
+	struct imx21_dmem_area *dmem;
+	struct ep_priv *ep_priv;
+
+	spin_lock_irqsave(&imx21->lock, flags);
+
+	etd_enable_mask = readl(imx21->regs + USBH_ETDENSET);
+	for (i = 0, etd = imx21->etd; i < USB_NUM_ETD; i++, etd++) {
+		if (etd->alloc)
+			etds_allocated++;
+		if (etd->urb)
+			etds_sw_busy++;
+		if (etd_enable_mask & (1<<i))
+			etds_hw_busy++;
+	}
+
+	list_for_each_entry(dmem, &imx21->dmem_list, list) {
+		dmem_bytes += dmem->size;
+		dmem_blocks++;
+	}
+
+	list_for_each_entry(ep_priv, &imx21->queue_for_etd, queue)
+		queued_for_etd++;
+
+	list_for_each_entry(etd, &imx21->queue_for_dmem, queue)
+		queued_for_dmem++;
+
+	spin_unlock_irqrestore(&imx21->lock, flags);
+
+	seq_printf(s,
+		"Frame: %d\n"
+		"ETDs allocated: %d/%d (max=%d)\n"
+		"ETDs in use sw: %d\n"
+		"ETDs in use hw: %d\n"
+		"DMEM alocated: %d/%d (max=%d)\n"
+		"DMEM blocks: %d\n"
+		"Queued waiting for ETD: %d\n"
+		"Queued waiting for DMEM: %d\n",
+		readl(imx21->regs + USBH_FRMNUB) & 0xFFFF,
+		etds_allocated, USB_NUM_ETD, imx21->etd_usage.maximum,
+		etds_sw_busy,
+		etds_hw_busy,
+		dmem_bytes, DMEM_SIZE, imx21->dmem_usage.maximum,
+		dmem_blocks,
+		queued_for_etd,
+		queued_for_dmem);
+
+	return 0;
+}
+
+static int debug_dmem_show(struct seq_file *s, void *v)
+{
+	struct imx21 *imx21 = s->private;
+	struct imx21_dmem_area *dmem;
+	unsigned long flags;
+	char ep_text[40];
+
+	spin_lock_irqsave(&imx21->lock, flags);
+
+	list_for_each_entry(dmem, &imx21->dmem_list, list)
+		seq_printf(s,
+			"%04X: size=0x%X "
+			"ep=%s\n",
+			dmem->offset, dmem->size,
+			format_ep(dmem->ep, ep_text, sizeof(ep_text)));
+
+	spin_unlock_irqrestore(&imx21->lock, flags);
+
+	return 0;
+}
+
+static int debug_etd_show(struct seq_file *s, void *v)
+{
+	struct imx21 *imx21 = s->private;
+	struct etd_priv *etd;
+	char buf[60];
+	u32 dword;
+	int i, j;
+	unsigned long flags;
+
+	spin_lock_irqsave(&imx21->lock, flags);
+
+	for (i = 0, etd = imx21->etd; i < USB_NUM_ETD; i++, etd++) {
+		int state = -1;
+		struct urb_priv *urb_priv;
+		if (etd->urb) {
+			urb_priv = etd->urb->hcpriv;
+			if (urb_priv)
+				state = urb_priv->state;
+		}
+
+		seq_printf(s,
+			"etd_num: %d\n"
+			"ep: %s\n"
+			"alloc: %d\n"
+			"len: %d\n"
+			"busy sw: %d\n"
+			"busy hw: %d\n"
+			"urb state: %d\n"
+			"current urb: %p\n",
+
+			i,
+			format_ep(etd->ep, buf, sizeof(buf)),
+			etd->alloc,
+			etd->len,
+			etd->urb != NULL,
+			(readl(imx21->regs + USBH_ETDENSET) & (1 << i)) > 0,
+			state,
+			etd->urb);
+
+		for (j = 0; j < 4; j++) {
+			dword = etd_readl(imx21, i, j);
+			switch (j) {
+			case 0:
+				format_etd_dword0(dword, buf, sizeof(buf));
+				break;
+			case 2:
+				snprintf(buf, sizeof(buf),
+					"cc=0X%02X", dword >> DW2_COMPCODE);
+				break;
+			default:
+				*buf = 0;
+				break;
+			}
+			seq_printf(s,
+				"dword %d: submitted=%08X cur=%08X [%s]\n",
+				j,
+				etd->submitted_dwords[j],
+				dword,
+				buf);
+		}
+		seq_printf(s, "\n");
+	}
+
+	spin_unlock_irqrestore(&imx21->lock, flags);
+
+	return 0;
+}
+
+static void debug_statistics_show_one(struct seq_file *s,
+	const char *name, struct debug_stats *stats)
+{
+	seq_printf(s, "%s:\n"
+		"submitted URBs: %lu\n"
+		"completed OK: %lu\n"
+		"completed failed: %lu\n"
+		"unlinked: %lu\n"
+		"queued for ETD: %lu\n"
+		"queued for DMEM: %lu\n\n",
+		name,
+		stats->submitted,
+		stats->completed_ok,
+		stats->completed_failed,
+		stats->unlinked,
+		stats->queue_etd,
+		stats->queue_dmem);
+}
+
+static int debug_statistics_show(struct seq_file *s, void *v)
+{
+	struct imx21 *imx21 = s->private;
+	unsigned long flags;
+
+	spin_lock_irqsave(&imx21->lock, flags);
+
+	debug_statistics_show_one(s, "nonisoc", &imx21->nonisoc_stats);
+	debug_statistics_show_one(s, "isoc", &imx21->isoc_stats);
+	seq_printf(s, "unblock kludge triggers: %lu\n", imx21->debug_unblocks);
+	spin_unlock_irqrestore(&imx21->lock, flags);
+
+	return 0;
+}
+
+static void debug_isoc_show_one(struct seq_file *s,
+	const char *name, int index, 	struct debug_isoc_trace *trace)
+{
+	seq_printf(s, "%s %d:\n"
+		"cc=0X%02X\n"
+		"scheduled frame %d (%d)\n"
+		"submittted frame %d (%d)\n"
+		"completed frame %d (%d)\n"
+		"requested length=%d\n"
+		"completed length=%d\n\n",
+		name, index,
+		trace->cc,
+		trace->schedule_frame, trace->schedule_frame & 0xFFFF,
+		trace->submit_frame, trace->submit_frame & 0xFFFF,
+		trace->done_frame, trace->done_frame & 0xFFFF,
+		trace->request_len,
+		trace->done_len);
+}
+
+static int debug_isoc_show(struct seq_file *s, void *v)
+{
+	struct imx21 *imx21 = s->private;
+	struct debug_isoc_trace *trace;
+	unsigned long flags;
+	int i;
+
+	spin_lock_irqsave(&imx21->lock, flags);
+
+	trace = imx21->isoc_trace_failed;
+	for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace_failed); i++, trace++)
+		debug_isoc_show_one(s, "isoc failed", i, trace);
+
+	trace = imx21->isoc_trace;
+	for (i = 0; i < ARRAY_SIZE(imx21->isoc_trace); i++, trace++)
+		debug_isoc_show_one(s, "isoc", i, trace);
+
+	spin_unlock_irqrestore(&imx21->lock, flags);
+
+	return 0;
+}
+
+static int debug_status_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, debug_status_show, inode->i_private);
+}
+
+static int debug_dmem_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, debug_dmem_show, inode->i_private);
+}
+
+static int debug_etd_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, debug_etd_show, inode->i_private);
+}
+
+static int debug_statistics_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, debug_statistics_show, inode->i_private);
+}
+
+static int debug_isoc_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, debug_isoc_show, inode->i_private);
+}
+
+static const struct file_operations debug_status_fops = {
+	.open = debug_status_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations debug_dmem_fops = {
+	.open = debug_dmem_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations debug_etd_fops = {
+	.open = debug_etd_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations debug_statistics_fops = {
+	.open = debug_statistics_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static const struct file_operations debug_isoc_fops = {
+	.open = debug_isoc_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
+static void create_debug_files(struct imx21 *imx21)
+{
+	imx21->debug_root = debugfs_create_dir(dev_name(imx21->dev), NULL);
+	if (!imx21->debug_root)
+		goto failed_create_rootdir;
+
+	if (!debugfs_create_file("status", S_IRUGO,
+			imx21->debug_root, imx21, &debug_status_fops))
+		goto failed_create;
+
+	if (!debugfs_create_file("dmem", S_IRUGO,
+			imx21->debug_root, imx21, &debug_dmem_fops))
+		goto failed_create;
+
+	if (!debugfs_create_file("etd", S_IRUGO,
+			imx21->debug_root, imx21, &debug_etd_fops))
+		goto failed_create;
+
+	if (!debugfs_create_file("statistics", S_IRUGO,
+			imx21->debug_root, imx21, &debug_statistics_fops))
+		goto failed_create;
+
+	if (!debugfs_create_file("isoc", S_IRUGO,
+			imx21->debug_root, imx21, &debug_isoc_fops))
+		goto failed_create;
+
+	return;
+
+failed_create:
+	debugfs_remove_recursive(imx21->debug_root);
+
+failed_create_rootdir:
+	imx21->debug_root = NULL;
+}
+
+
+static void remove_debug_files(struct imx21 *imx21)
+{
+	if (imx21->debug_root) {
+		debugfs_remove_recursive(imx21->debug_root);
+		imx21->debug_root = NULL;
+	}
+}
+
+#endif
+

+ 1789 - 0
drivers/usb/host/imx21-hcd.c

@@ -0,0 +1,1789 @@
+/*
+ * USB Host Controller Driver for IMX21
+ *
+ * Copyright (C) 2006 Loping Dog Embedded Systems
+ * Copyright (C) 2009 Martin Fuzzey
+ * Originally written by Jay Monkman <jtm@lopingdog.com>
+ * Ported to 2.6.30, debugged and enhanced by Martin Fuzzey
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+ /*
+  * The i.MX21 USB hardware contains
+  *    * 32 transfer descriptors (called ETDs)
+  *    * 4Kb of Data memory
+  *
+  * The data memory is shared between the host and fuction controlers
+  * (but this driver only supports the host controler)
+  *
+  * So setting up a transfer involves:
+  *    * Allocating a ETD
+  *    * Fill in ETD with appropriate information
+  *    * Allocating data memory (and putting the offset in the ETD)
+  *    * Activate the ETD
+  *    * Get interrupt when done.
+  *
+  * An ETD is assigned to each active endpoint.
+  *
+  * Low resource (ETD and Data memory) situations are handled differently for
+  * isochronous and non insosynchronous transactions :
+  *
+  * Non ISOC transfers are queued if either ETDs or Data memory are unavailable
+  *
+  * ISOC transfers use 2 ETDs per endpoint to achieve double buffering.
+  * They allocate both ETDs and Data memory during URB submission
+  * (and fail if unavailable).
+  */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/usb.h>
+
+#include "../core/hcd.h"
+#include "imx21-hcd.h"
+
+#ifdef DEBUG
+#define DEBUG_LOG_FRAME(imx21, etd, event) \
+	(etd)->event##_frame = readl((imx21)->regs + USBH_FRMNUB)
+#else
+#define DEBUG_LOG_FRAME(imx21, etd, event) do { } while (0)
+#endif
+
+static const char hcd_name[] = "imx21-hcd";
+
+static inline struct imx21 *hcd_to_imx21(struct usb_hcd *hcd)
+{
+	return (struct imx21 *)hcd->hcd_priv;
+}
+
+
+/* =========================================== */
+/* Hardware access helpers			*/
+/* =========================================== */
+
+static inline void set_register_bits(struct imx21 *imx21, u32 offset, u32 mask)
+{
+	void __iomem *reg = imx21->regs + offset;
+	writel(readl(reg) | mask, reg);
+}
+
+static inline void clear_register_bits(struct imx21 *imx21,
+	u32 offset, u32 mask)
+{
+	void __iomem *reg = imx21->regs + offset;
+	writel(readl(reg) & ~mask, reg);
+}
+
+static inline void clear_toggle_bit(struct imx21 *imx21, u32 offset, u32 mask)
+{
+	void __iomem *reg = imx21->regs + offset;
+
+	if (readl(reg) & mask)
+		writel(mask, reg);
+}
+
+static inline void set_toggle_bit(struct imx21 *imx21, u32 offset, u32 mask)
+{
+	void __iomem *reg = imx21->regs + offset;
+
+	if (!(readl(reg) & mask))
+		writel(mask, reg);
+}
+
+static void etd_writel(struct imx21 *imx21, int etd_num, int dword, u32 value)
+{
+	writel(value, imx21->regs + USB_ETD_DWORD(etd_num, dword));
+}
+
+static u32 etd_readl(struct imx21 *imx21, int etd_num, int dword)
+{
+	return readl(imx21->regs + USB_ETD_DWORD(etd_num, dword));
+}
+
+static inline int wrap_frame(int counter)
+{
+	return counter & 0xFFFF;
+}
+
+static inline int frame_after(int frame, int after)
+{
+	/* handle wrapping like jiffies time_afer */
+	return (s16)((s16)after - (s16)frame) < 0;
+}
+
+static int imx21_hc_get_frame(struct usb_hcd *hcd)
+{
+	struct imx21 *imx21 = hcd_to_imx21(hcd);
+
+	return wrap_frame(readl(imx21->regs + USBH_FRMNUB));
+}
+
+
+#include "imx21-dbg.c"
+
+/* =========================================== */
+/* ETD management				*/
+/* ===========================================	*/
+
+static int alloc_etd(struct imx21 *imx21)
+{
+	int i;
+	struct etd_priv *etd = imx21->etd;
+
+	for (i = 0; i < USB_NUM_ETD; i++, etd++) {
+		if (etd->alloc == 0) {
+			memset(etd, 0, sizeof(imx21->etd[0]));
+			etd->alloc = 1;
+			debug_etd_allocated(imx21);
+			return i;
+		}
+	}
+	return -1;
+}
+
+static void disactivate_etd(struct imx21 *imx21, int num)
+{
+	int etd_mask = (1 << num);
+	struct etd_priv *etd = &imx21->etd[num];
+
+	writel(etd_mask, imx21->regs + USBH_ETDENCLR);
+	clear_register_bits(imx21, USBH_ETDDONEEN, etd_mask);
+	writel(etd_mask, imx21->regs + USB_ETDDMACHANLCLR);
+	clear_toggle_bit(imx21, USBH_ETDDONESTAT, etd_mask);
+
+	etd->active_count = 0;
+
+	DEBUG_LOG_FRAME(imx21, etd, disactivated);
+}
+
+static void reset_etd(struct imx21 *imx21, int num)
+{
+	struct etd_priv *etd = imx21->etd + num;
+	int i;
+
+	disactivate_etd(imx21, num);
+
+	for (i = 0; i < 4; i++)
+		etd_writel(imx21, num, i, 0);
+	etd->urb = NULL;
+	etd->ep = NULL;
+	etd->td = NULL;;
+}
+
+static void free_etd(struct imx21 *imx21, int num)
+{
+	if (num < 0)
+		return;
+
+	if (num >= USB_NUM_ETD) {
+		dev_err(imx21->dev, "BAD etd=%d!\n", num);
+		return;
+	}
+	if (imx21->etd[num].alloc == 0) {
+		dev_err(imx21->dev, "ETD %d already free!\n", num);
+		return;
+	}
+
+	debug_etd_freed(imx21);
+	reset_etd(imx21, num);
+	memset(&imx21->etd[num], 0, sizeof(imx21->etd[0]));
+}
+
+
+static void setup_etd_dword0(struct imx21 *imx21,
+	int etd_num, struct urb *urb,  u8 dir, u16 maxpacket)
+{
+	etd_writel(imx21, etd_num, 0,
+		((u32) usb_pipedevice(urb->pipe)) <<  DW0_ADDRESS |
+		((u32) usb_pipeendpoint(urb->pipe) << DW0_ENDPNT) |
+		((u32) dir << DW0_DIRECT) |
+		((u32) ((urb->dev->speed == USB_SPEED_LOW) ?
+			1 : 0) << DW0_SPEED) |
+		((u32) fmt_urb_to_etd[usb_pipetype(urb->pipe)] << DW0_FORMAT) |
+		((u32) maxpacket << DW0_MAXPKTSIZ));
+}
+
+static void activate_etd(struct imx21 *imx21,
+	int etd_num, dma_addr_t dma, u8 dir)
+{
+	u32 etd_mask = 1 << etd_num;
+	struct etd_priv *etd = &imx21->etd[etd_num];
+
+	clear_toggle_bit(imx21, USBH_ETDDONESTAT, etd_mask);
+	set_register_bits(imx21, USBH_ETDDONEEN, etd_mask);
+	clear_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask);
+	clear_toggle_bit(imx21, USBH_YFILLSTAT, etd_mask);
+
+	if (dma) {
+		set_register_bits(imx21, USB_ETDDMACHANLCLR, etd_mask);
+		clear_toggle_bit(imx21, USBH_XBUFSTAT, etd_mask);
+		clear_toggle_bit(imx21, USBH_YBUFSTAT, etd_mask);
+		writel(dma, imx21->regs + USB_ETDSMSA(etd_num));
+		set_register_bits(imx21, USB_ETDDMAEN, etd_mask);
+	} else {
+		if (dir != TD_DIR_IN) {
+			/* need to set for ZLP */
+			set_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask);
+			set_toggle_bit(imx21, USBH_YFILLSTAT, etd_mask);
+		}
+	}
+
+	DEBUG_LOG_FRAME(imx21, etd, activated);
+
+#ifdef DEBUG
+	if (!etd->active_count) {
+		int i;
+		etd->activated_frame = readl(imx21->regs + USBH_FRMNUB);
+		etd->disactivated_frame = -1;
+		etd->last_int_frame = -1;
+		etd->last_req_frame = -1;
+
+		for (i = 0; i < 4; i++)
+			etd->submitted_dwords[i] = etd_readl(imx21, etd_num, i);
+	}
+#endif
+
+	etd->active_count = 1;
+	writel(etd_mask, imx21->regs + USBH_ETDENSET);
+}
+
+/* ===========================================	*/
+/* Data memory management			*/
+/* ===========================================	*/
+
+static int alloc_dmem(struct imx21 *imx21, unsigned int size,
+		      struct usb_host_endpoint *ep)
+{
+	unsigned int offset = 0;
+	struct imx21_dmem_area *area;
+	struct imx21_dmem_area *tmp;
+
+	size += (~size + 1) & 0x3; /* Round to 4 byte multiple */
+
+	if (size > DMEM_SIZE) {
+		dev_err(imx21->dev, "size=%d > DMEM_SIZE(%d)\n",
+			size, DMEM_SIZE);
+		return -EINVAL;
+	}
+
+	list_for_each_entry(tmp, &imx21->dmem_list, list) {
+		if ((size + offset) < offset)
+			goto fail;
+		if ((size + offset) <= tmp->offset)
+			break;
+		offset = tmp->size + tmp->offset;
+		if ((offset + size) > DMEM_SIZE)
+			goto fail;
+	}
+
+	area = kmalloc(sizeof(struct imx21_dmem_area), GFP_ATOMIC);
+	if (area == NULL)
+		return -ENOMEM;
+
+	area->ep = ep;
+	area->offset = offset;
+	area->size = size;
+	list_add_tail(&area->list, &tmp->list);
+	debug_dmem_allocated(imx21, size);
+	return offset;
+
+fail:
+	return -ENOMEM;
+}
+
+/* Memory now available for a queued ETD - activate it */
+static void activate_queued_etd(struct imx21 *imx21,
+	struct etd_priv *etd, u32 dmem_offset)
+{
+	struct urb_priv *urb_priv = etd->urb->hcpriv;
+	int etd_num = etd - &imx21->etd[0];
+	u32 maxpacket = etd_readl(imx21, etd_num, 1) >> DW1_YBUFSRTAD;
+	u8 dir = (etd_readl(imx21, etd_num, 2) >> DW2_DIRPID) & 0x03;
+
+	dev_dbg(imx21->dev, "activating queued ETD %d now DMEM available\n",
+		etd_num);
+	etd_writel(imx21, etd_num, 1,
+	    ((dmem_offset + maxpacket) << DW1_YBUFSRTAD) | dmem_offset);
+
+	urb_priv->active = 1;
+	activate_etd(imx21, etd_num, etd->dma_handle, dir);
+}
+
+static void free_dmem(struct imx21 *imx21, int offset)
+{
+	struct imx21_dmem_area *area;
+	struct etd_priv *etd, *tmp;
+	int found = 0;
+
+	list_for_each_entry(area, &imx21->dmem_list, list) {
+		if (area->offset == offset) {
+			debug_dmem_freed(imx21, area->size);
+			list_del(&area->list);
+			kfree(area);
+			found = 1;
+			break;
+		}
+	}
+
+	if (!found)  {
+		dev_err(imx21->dev,
+			"Trying to free unallocated DMEM %d\n", offset);
+		return;
+	}
+
+	/* Try again to allocate memory for anything we've queued */
+	list_for_each_entry_safe(etd, tmp, &imx21->queue_for_dmem, queue) {
+		offset = alloc_dmem(imx21, etd->dmem_size, etd->ep);
+		if (offset >= 0) {
+			list_del(&etd->queue);
+			activate_queued_etd(imx21, etd, (u32)offset);
+		}
+	}
+}
+
+static void free_epdmem(struct imx21 *imx21, struct usb_host_endpoint *ep)
+{
+	struct imx21_dmem_area *area, *tmp;
+
+	list_for_each_entry_safe(area, tmp, &imx21->dmem_list, list) {
+		if (area->ep == ep) {
+			dev_err(imx21->dev,
+				"Active DMEM %d for disabled ep=%p\n",
+				area->offset, ep);
+			list_del(&area->list);
+			kfree(area);
+		}
+	}
+}
+
+
+/* ===========================================	*/
+/* End handling 				*/
+/* ===========================================	*/
+static void schedule_nonisoc_etd(struct imx21 *imx21, struct urb *urb);
+
+/* Endpoint now idle - release it's ETD(s) or asssign to queued request */
+static void ep_idle(struct imx21 *imx21, struct ep_priv *ep_priv)
+{
+	int etd_num;
+	int i;
+
+	for (i = 0; i < NUM_ISO_ETDS; i++) {
+		etd_num = ep_priv->etd[i];
+		if (etd_num < 0)
+			continue;
+
+		ep_priv->etd[i] = -1;
+		if (list_empty(&imx21->queue_for_etd)) {
+			free_etd(imx21, etd_num);
+			continue;
+		}
+
+		dev_dbg(imx21->dev,
+			"assigning idle etd %d for queued request\n", etd_num);
+		ep_priv = list_first_entry(&imx21->queue_for_etd,
+			struct ep_priv, queue);
+		list_del(&ep_priv->queue);
+		reset_etd(imx21, etd_num);
+		ep_priv->waiting_etd = 0;
+		ep_priv->etd[i] = etd_num;
+
+		if (list_empty(&ep_priv->ep->urb_list)) {
+			dev_err(imx21->dev, "No urb for queued ep!\n");
+			continue;
+		}
+		schedule_nonisoc_etd(imx21, list_first_entry(
+			&ep_priv->ep->urb_list, struct urb, urb_list));
+	}
+}
+
+static void urb_done(struct usb_hcd *hcd, struct urb *urb, int status)
+__releases(imx21->lock)
+__acquires(imx21->lock)
+{
+	struct imx21 *imx21 = hcd_to_imx21(hcd);
+	struct ep_priv *ep_priv = urb->ep->hcpriv;
+	struct urb_priv *urb_priv = urb->hcpriv;
+
+	debug_urb_completed(imx21, urb, status);
+	dev_vdbg(imx21->dev, "urb %p done %d\n", urb, status);
+
+	kfree(urb_priv->isoc_td);
+	kfree(urb->hcpriv);
+	urb->hcpriv = NULL;
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
+	spin_unlock(&imx21->lock);
+	usb_hcd_giveback_urb(hcd, urb, status);
+	spin_lock(&imx21->lock);
+	if (list_empty(&ep_priv->ep->urb_list))
+		ep_idle(imx21, ep_priv);
+}
+
+/* ===========================================	*/
+/* ISOC Handling ... 				*/
+/* ===========================================	*/
+
+static void schedule_isoc_etds(struct usb_hcd *hcd,
+	struct usb_host_endpoint *ep)
+{
+	struct imx21 *imx21 = hcd_to_imx21(hcd);
+	struct ep_priv *ep_priv = ep->hcpriv;
+	struct etd_priv *etd;
+	struct urb_priv *urb_priv;
+	struct td *td;
+	int etd_num;
+	int i;
+	int cur_frame;
+	u8 dir;
+
+	for (i = 0; i < NUM_ISO_ETDS; i++) {
+too_late:
+		if (list_empty(&ep_priv->td_list))
+			break;
+
+		etd_num = ep_priv->etd[i];
+		if (etd_num < 0)
+			break;
+
+		etd = &imx21->etd[etd_num];
+		if (etd->urb)
+			continue;
+
+		td = list_entry(ep_priv->td_list.next, struct td, list);
+		list_del(&td->list);
+		urb_priv = td->urb->hcpriv;
+
+		cur_frame = imx21_hc_get_frame(hcd);
+		if (frame_after(cur_frame, td->frame)) {
+			dev_dbg(imx21->dev, "isoc too late frame %d > %d\n",
+				cur_frame, td->frame);
+			urb_priv->isoc_status = -EXDEV;
+			td->urb->iso_frame_desc[
+				td->isoc_index].actual_length = 0;
+			td->urb->iso_frame_desc[td->isoc_index].status = -EXDEV;
+			if (--urb_priv->isoc_remaining == 0)
+				urb_done(hcd, td->urb, urb_priv->isoc_status);
+			goto too_late;
+		}
+
+		urb_priv->active = 1;
+		etd->td = td;
+		etd->ep = td->ep;
+		etd->urb = td->urb;
+		etd->len = td->len;
+
+		debug_isoc_submitted(imx21, cur_frame, td);
+
+		dir = usb_pipeout(td->urb->pipe) ? TD_DIR_OUT : TD_DIR_IN;
+		setup_etd_dword0(imx21, etd_num, td->urb, dir, etd->dmem_size);
+		etd_writel(imx21, etd_num, 1, etd->dmem_offset);
+		etd_writel(imx21, etd_num, 2,
+			(TD_NOTACCESSED << DW2_COMPCODE) |
+			((td->frame & 0xFFFF) << DW2_STARTFRM));
+		etd_writel(imx21, etd_num, 3,
+			(TD_NOTACCESSED << DW3_COMPCODE0) |
+			(td->len << DW3_PKTLEN0));
+
+		activate_etd(imx21, etd_num, td->data, dir);
+	}
+}
+
+static void isoc_etd_done(struct usb_hcd *hcd, struct urb *urb, int etd_num)
+{
+	struct imx21 *imx21 = hcd_to_imx21(hcd);
+	int etd_mask = 1 << etd_num;
+	struct urb_priv *urb_priv = urb->hcpriv;
+	struct etd_priv *etd = imx21->etd + etd_num;
+	struct td *td = etd->td;
+	struct usb_host_endpoint *ep = etd->ep;
+	int isoc_index = td->isoc_index;
+	unsigned int pipe = urb->pipe;
+	int dir_in = usb_pipein(pipe);
+	int cc;
+	int bytes_xfrd;
+
+	disactivate_etd(imx21, etd_num);
+
+	cc = (etd_readl(imx21, etd_num, 3) >> DW3_COMPCODE0) & 0xf;
+	bytes_xfrd = etd_readl(imx21, etd_num, 3) & 0x3ff;
+
+	/* Input doesn't always fill the buffer, don't generate an error
+	 * when this happens.
+	 */
+	if (dir_in && (cc == TD_DATAUNDERRUN))
+		cc = TD_CC_NOERROR;
+
+	if (cc == TD_NOTACCESSED)
+		bytes_xfrd = 0;
+
+	debug_isoc_completed(imx21,
+		imx21_hc_get_frame(hcd), td, cc, bytes_xfrd);
+	if (cc) {
+		urb_priv->isoc_status = -EXDEV;
+		dev_dbg(imx21->dev,
+			"bad iso cc=0x%X frame=%d sched frame=%d "
+			"cnt=%d len=%d urb=%p etd=%d index=%d\n",
+			cc,  imx21_hc_get_frame(hcd), td->frame,
+			bytes_xfrd, td->len, urb, etd_num, isoc_index);
+	}
+
+	if (dir_in)
+		clear_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask);
+
+	urb->actual_length += bytes_xfrd;
+	urb->iso_frame_desc[isoc_index].actual_length = bytes_xfrd;
+	urb->iso_frame_desc[isoc_index].status = cc_to_error[cc];
+
+	etd->td = NULL;
+	etd->urb = NULL;
+	etd->ep = NULL;
+
+	if (--urb_priv->isoc_remaining == 0)
+		urb_done(hcd, urb, urb_priv->isoc_status);
+
+	schedule_isoc_etds(hcd, ep);
+}
+
+static struct ep_priv *alloc_isoc_ep(
+	struct imx21 *imx21, struct usb_host_endpoint *ep)
+{
+	struct ep_priv *ep_priv;
+	int i;
+
+	ep_priv = kzalloc(sizeof(struct ep_priv), GFP_ATOMIC);
+	if (ep_priv == NULL)
+		return NULL;
+
+	/* Allocate the ETDs */
+	for (i = 0; i < NUM_ISO_ETDS; i++) {
+		ep_priv->etd[i] = alloc_etd(imx21);
+		if (ep_priv->etd[i] < 0) {
+			int j;
+			dev_err(imx21->dev, "isoc: Couldn't allocate etd\n");
+			for (j = 0; j < i; j++)
+				free_etd(imx21, ep_priv->etd[j]);
+			goto alloc_etd_failed;
+		}
+		imx21->etd[ep_priv->etd[i]].ep = ep;
+	}
+
+	INIT_LIST_HEAD(&ep_priv->td_list);
+	ep_priv->ep = ep;
+	ep->hcpriv = ep_priv;
+	return ep_priv;
+
+alloc_etd_failed:
+	kfree(ep_priv);
+	return NULL;
+}
+
+static int imx21_hc_urb_enqueue_isoc(struct usb_hcd *hcd,
+				     struct usb_host_endpoint *ep,
+				     struct urb *urb, gfp_t mem_flags)
+{
+	struct imx21 *imx21 = hcd_to_imx21(hcd);
+	struct urb_priv *urb_priv;
+	unsigned long flags;
+	struct ep_priv *ep_priv;
+	struct td *td = NULL;
+	int i;
+	int ret;
+	int cur_frame;
+	u16 maxpacket;
+
+	urb_priv = kzalloc(sizeof(struct urb_priv), mem_flags);
+	if (urb_priv == NULL)
+		return -ENOMEM;
+
+	urb_priv->isoc_td = kzalloc(
+		sizeof(struct td) * urb->number_of_packets, mem_flags);
+	if (urb_priv->isoc_td == NULL) {
+		ret = -ENOMEM;
+		goto alloc_td_failed;
+	}
+
+	spin_lock_irqsave(&imx21->lock, flags);
+
+	if (ep->hcpriv == NULL) {
+		ep_priv = alloc_isoc_ep(imx21, ep);
+		if (ep_priv == NULL) {
+			ret = -ENOMEM;
+			goto alloc_ep_failed;
+		}
+	} else {
+		ep_priv = ep->hcpriv;
+	}
+
+	ret = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (ret)
+		goto link_failed;
+
+	urb->status = -EINPROGRESS;
+	urb->actual_length = 0;
+	urb->error_count = 0;
+	urb->hcpriv = urb_priv;
+	urb_priv->ep = ep;
+
+	/* allocate data memory for largest packets if not already done */
+	maxpacket = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
+	for (i = 0; i < NUM_ISO_ETDS; i++) {
+		struct etd_priv *etd = &imx21->etd[ep_priv->etd[i]];
+
+		if (etd->dmem_size > 0 && etd->dmem_size < maxpacket) {
+			/* not sure if this can really occur.... */
+			dev_err(imx21->dev, "increasing isoc buffer %d->%d\n",
+				etd->dmem_size, maxpacket);
+			ret = -EMSGSIZE;
+			goto alloc_dmem_failed;
+		}
+
+		if (etd->dmem_size == 0) {
+			etd->dmem_offset = alloc_dmem(imx21, maxpacket, ep);
+			if (etd->dmem_offset < 0) {
+				dev_dbg(imx21->dev, "failed alloc isoc dmem\n");
+				ret = -EAGAIN;
+				goto alloc_dmem_failed;
+			}
+			etd->dmem_size = maxpacket;
+		}
+	}
+
+	/* calculate frame */
+	cur_frame = imx21_hc_get_frame(hcd);
+	if (urb->transfer_flags & URB_ISO_ASAP) {
+		if (list_empty(&ep_priv->td_list))
+			urb->start_frame = cur_frame + 5;
+		else
+			urb->start_frame = list_entry(
+				ep_priv->td_list.prev,
+				struct td, list)->frame + urb->interval;
+	}
+	urb->start_frame = wrap_frame(urb->start_frame);
+	if (frame_after(cur_frame, urb->start_frame)) {
+		dev_dbg(imx21->dev,
+			"enqueue: adjusting iso start %d (cur=%d) asap=%d\n",
+			urb->start_frame, cur_frame,
+			(urb->transfer_flags & URB_ISO_ASAP) != 0);
+		urb->start_frame = wrap_frame(cur_frame + 1);
+	}
+
+	/* set up transfers */
+	td = urb_priv->isoc_td;
+	for (i = 0; i < urb->number_of_packets; i++, td++) {
+		td->ep = ep;
+		td->urb = urb;
+		td->len = urb->iso_frame_desc[i].length;
+		td->isoc_index = i;
+		td->frame = wrap_frame(urb->start_frame + urb->interval * i);
+		td->data = urb->transfer_dma + urb->iso_frame_desc[i].offset;
+		list_add_tail(&td->list, &ep_priv->td_list);
+	}
+
+	urb_priv->isoc_remaining = urb->number_of_packets;
+	dev_vdbg(imx21->dev, "setup %d packets for iso frame %d->%d\n",
+		urb->number_of_packets, urb->start_frame, td->frame);
+
+	debug_urb_submitted(imx21, urb);
+	schedule_isoc_etds(hcd, ep);
+
+	spin_unlock_irqrestore(&imx21->lock, flags);
+	return 0;
+
+alloc_dmem_failed:
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
+
+link_failed:
+alloc_ep_failed:
+	spin_unlock_irqrestore(&imx21->lock, flags);
+	kfree(urb_priv->isoc_td);
+
+alloc_td_failed:
+	kfree(urb_priv);
+	return ret;
+}
+
+static void dequeue_isoc_urb(struct imx21 *imx21,
+	struct urb *urb, struct ep_priv *ep_priv)
+{
+	struct urb_priv *urb_priv = urb->hcpriv;
+	struct td *td, *tmp;
+	int i;
+
+	if (urb_priv->active) {
+		for (i = 0; i < NUM_ISO_ETDS; i++) {
+			int etd_num = ep_priv->etd[i];
+			if (etd_num != -1 && imx21->etd[etd_num].urb == urb) {
+				struct etd_priv *etd = imx21->etd + etd_num;
+
+				reset_etd(imx21, etd_num);
+				if (etd->dmem_size)
+					free_dmem(imx21, etd->dmem_offset);
+				etd->dmem_size = 0;
+			}
+		}
+	}
+
+	list_for_each_entry_safe(td, tmp, &ep_priv->td_list, list) {
+		if (td->urb == urb) {
+			dev_vdbg(imx21->dev, "removing td %p\n", td);
+			list_del(&td->list);
+		}
+	}
+}
+
+/* =========================================== */
+/* NON ISOC Handling ... 			*/
+/* =========================================== */
+
+static void schedule_nonisoc_etd(struct imx21 *imx21, struct urb *urb)
+{
+	unsigned int pipe = urb->pipe;
+	struct urb_priv *urb_priv = urb->hcpriv;
+	struct ep_priv *ep_priv = urb_priv->ep->hcpriv;
+	int state = urb_priv->state;
+	int etd_num = ep_priv->etd[0];
+	struct etd_priv *etd;
+	int dmem_offset;
+	u32 count;
+	u16 etd_buf_size;
+	u16 maxpacket;
+	u8 dir;
+	u8 bufround;
+	u8 datatoggle;
+	u8 interval = 0;
+	u8 relpolpos = 0;
+
+	if (etd_num < 0) {
+		dev_err(imx21->dev, "No valid ETD\n");
+		return;
+	}
+	if (readl(imx21->regs + USBH_ETDENSET) & (1 << etd_num))
+		dev_err(imx21->dev, "submitting to active ETD %d\n", etd_num);
+
+	etd = &imx21->etd[etd_num];
+	maxpacket = usb_maxpacket(urb->dev, pipe, usb_pipeout(pipe));
+	if (!maxpacket)
+		maxpacket = 8;
+
+	if (usb_pipecontrol(pipe) && (state != US_CTRL_DATA)) {
+		if (state == US_CTRL_SETUP) {
+			dir = TD_DIR_SETUP;
+			etd->dma_handle = urb->setup_dma;
+			bufround = 0;
+			count = 8;
+			datatoggle = TD_TOGGLE_DATA0;
+		} else {	/* US_CTRL_ACK */
+			dir = usb_pipeout(pipe) ? TD_DIR_IN : TD_DIR_OUT;
+			etd->dma_handle = urb->transfer_dma;
+			bufround = 0;
+			count = 0;
+			datatoggle = TD_TOGGLE_DATA1;
+		}
+	} else {
+		dir = usb_pipeout(pipe) ? TD_DIR_OUT : TD_DIR_IN;
+		bufround = (dir == TD_DIR_IN) ? 1 : 0;
+		etd->dma_handle = urb->transfer_dma;
+		if (usb_pipebulk(pipe) && (state == US_BULK0))
+			count = 0;
+		else
+			count = urb->transfer_buffer_length;
+
+		if (usb_pipecontrol(pipe)) {
+			datatoggle = TD_TOGGLE_DATA1;
+		} else {
+			if (usb_gettoggle(
+					urb->dev,
+					usb_pipeendpoint(urb->pipe),
+					usb_pipeout(urb->pipe)))
+				datatoggle = TD_TOGGLE_DATA1;
+			else
+				datatoggle = TD_TOGGLE_DATA0;
+		}
+	}
+
+	etd->urb = urb;
+	etd->ep = urb_priv->ep;
+	etd->len = count;
+
+	if (usb_pipeint(pipe)) {
+		interval = urb->interval;
+		relpolpos = (readl(imx21->regs + USBH_FRMNUB) + 1) & 0xff;
+	}
+
+	/* Write ETD to device memory */
+	setup_etd_dword0(imx21, etd_num, urb, dir, maxpacket);
+
+	etd_writel(imx21, etd_num, 2,
+		(u32) interval << DW2_POLINTERV |
+		((u32) relpolpos << DW2_RELPOLPOS) |
+		((u32) dir << DW2_DIRPID) |
+		((u32) bufround << DW2_BUFROUND) |
+		((u32) datatoggle << DW2_DATATOG) |
+		((u32) TD_NOTACCESSED << DW2_COMPCODE));
+
+	/* DMA will always transfer buffer size even if TOBYCNT in DWORD3
+	   is smaller. Make sure we don't overrun the buffer!
+	 */
+	if (count && count < maxpacket)
+		etd_buf_size = count;
+	else
+		etd_buf_size = maxpacket;
+
+	etd_writel(imx21, etd_num, 3,
+		((u32) (etd_buf_size - 1) << DW3_BUFSIZE) | (u32) count);
+
+	if (!count)
+		etd->dma_handle = 0;
+
+	/* allocate x and y buffer space at once */
+	etd->dmem_size = (count > maxpacket) ? maxpacket * 2 : maxpacket;
+	dmem_offset = alloc_dmem(imx21, etd->dmem_size, urb_priv->ep);
+	if (dmem_offset < 0) {
+		/* Setup everything we can in HW and update when we get DMEM */
+		etd_writel(imx21, etd_num, 1, (u32)maxpacket << 16);
+
+		dev_dbg(imx21->dev, "Queuing etd %d for DMEM\n", etd_num);
+		debug_urb_queued_for_dmem(imx21, urb);
+		list_add_tail(&etd->queue, &imx21->queue_for_dmem);
+		return;
+	}
+
+	etd_writel(imx21, etd_num, 1,
+		(((u32) dmem_offset + (u32) maxpacket) << DW1_YBUFSRTAD) |
+		(u32) dmem_offset);
+
+	urb_priv->active = 1;
+
+	/* enable the ETD to kick off transfer */
+	dev_vdbg(imx21->dev, "Activating etd %d for %d bytes %s\n",
+		etd_num, count, dir != TD_DIR_IN ? "out" : "in");
+	activate_etd(imx21, etd_num, etd->dma_handle, dir);
+
+}
+
+static void nonisoc_etd_done(struct usb_hcd *hcd, struct urb *urb, int etd_num)
+{
+	struct imx21 *imx21 = hcd_to_imx21(hcd);
+	struct etd_priv *etd = &imx21->etd[etd_num];
+	u32 etd_mask = 1 << etd_num;
+	struct urb_priv *urb_priv = urb->hcpriv;
+	int dir;
+	u16 xbufaddr;
+	int cc;
+	u32 bytes_xfrd;
+	int etd_done;
+
+	disactivate_etd(imx21, etd_num);
+
+	dir = (etd_readl(imx21, etd_num, 0) >> DW0_DIRECT) & 0x3;
+	xbufaddr = etd_readl(imx21, etd_num, 1) & 0xffff;
+	cc = (etd_readl(imx21, etd_num, 2) >> DW2_COMPCODE) & 0xf;
+	bytes_xfrd = etd->len - (etd_readl(imx21, etd_num, 3) & 0x1fffff);
+
+	/* save toggle carry */
+	usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
+		      usb_pipeout(urb->pipe),
+		      (etd_readl(imx21, etd_num, 0) >> DW0_TOGCRY) & 0x1);
+
+	if (dir == TD_DIR_IN) {
+		clear_toggle_bit(imx21, USBH_XFILLSTAT, etd_mask);
+		clear_toggle_bit(imx21, USBH_YFILLSTAT, etd_mask);
+	}
+	free_dmem(imx21, xbufaddr);
+
+	urb->error_count = 0;
+	if (!(urb->transfer_flags & URB_SHORT_NOT_OK)
+			&& (cc == TD_DATAUNDERRUN))
+		cc = TD_CC_NOERROR;
+
+	if (cc != 0)
+		dev_vdbg(imx21->dev, "cc is 0x%x\n", cc);
+
+	etd_done = (cc_to_error[cc] != 0);	/* stop if error */
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		switch (urb_priv->state) {
+		case US_CTRL_SETUP:
+			if (urb->transfer_buffer_length > 0)
+				urb_priv->state = US_CTRL_DATA;
+			else
+				urb_priv->state = US_CTRL_ACK;
+			break;
+		case US_CTRL_DATA:
+			urb->actual_length += bytes_xfrd;
+			urb_priv->state = US_CTRL_ACK;
+			break;
+		case US_CTRL_ACK:
+			etd_done = 1;
+			break;
+		default:
+			dev_err(imx21->dev,
+				"Invalid pipe state %d\n", urb_priv->state);
+			etd_done = 1;
+			break;
+		}
+		break;
+
+	case PIPE_BULK:
+		urb->actual_length += bytes_xfrd;
+		if ((urb_priv->state == US_BULK)
+		    && (urb->transfer_flags & URB_ZERO_PACKET)
+		    && urb->transfer_buffer_length > 0
+		    && ((urb->transfer_buffer_length %
+			 usb_maxpacket(urb->dev, urb->pipe,
+				       usb_pipeout(urb->pipe))) == 0)) {
+			/* need a 0-packet */
+			urb_priv->state = US_BULK0;
+		} else {
+			etd_done = 1;
+		}
+		break;
+
+	case PIPE_INTERRUPT:
+		urb->actual_length += bytes_xfrd;
+		etd_done = 1;
+		break;
+	}
+
+	if (!etd_done) {
+		dev_vdbg(imx21->dev, "next state=%d\n", urb_priv->state);
+		schedule_nonisoc_etd(imx21, urb);
+	} else {
+		struct usb_host_endpoint *ep = urb->ep;
+
+		urb_done(hcd, urb, cc_to_error[cc]);
+		etd->urb = NULL;
+
+		if (!list_empty(&ep->urb_list)) {
+			urb = list_first_entry(&ep->urb_list,
+				struct urb, urb_list);
+			dev_vdbg(imx21->dev, "next URB %p\n", urb);
+			schedule_nonisoc_etd(imx21, urb);
+		}
+	}
+}
+
+static struct ep_priv *alloc_ep(void)
+{
+	int i;
+	struct ep_priv *ep_priv;
+
+	ep_priv = kzalloc(sizeof(struct ep_priv), GFP_ATOMIC);
+	if (!ep_priv)
+		return NULL;
+
+	for (i = 0; i < NUM_ISO_ETDS; ++i)
+		ep_priv->etd[i] = -1;
+
+	return ep_priv;
+}
+
+static int imx21_hc_urb_enqueue(struct usb_hcd *hcd,
+				struct urb *urb, gfp_t mem_flags)
+{
+	struct imx21 *imx21 = hcd_to_imx21(hcd);
+	struct usb_host_endpoint *ep = urb->ep;
+	struct urb_priv *urb_priv;
+	struct ep_priv *ep_priv;
+	struct etd_priv *etd;
+	int ret;
+	unsigned long flags;
+	int new_ep = 0;
+
+	dev_vdbg(imx21->dev,
+		"enqueue urb=%p ep=%p len=%d "
+		"buffer=%p dma=%08X setupBuf=%p setupDma=%08X\n",
+		urb, ep,
+		urb->transfer_buffer_length,
+		urb->transfer_buffer, urb->transfer_dma,
+		urb->setup_packet, urb->setup_dma);
+
+	if (usb_pipeisoc(urb->pipe))
+		return imx21_hc_urb_enqueue_isoc(hcd, ep, urb, mem_flags);
+
+	urb_priv = kzalloc(sizeof(struct urb_priv), mem_flags);
+	if (!urb_priv)
+		return -ENOMEM;
+
+	spin_lock_irqsave(&imx21->lock, flags);
+
+	ep_priv = ep->hcpriv;
+	if (ep_priv == NULL) {
+		ep_priv = alloc_ep();
+		if (!ep_priv) {
+			ret = -ENOMEM;
+			goto failed_alloc_ep;
+		}
+		ep->hcpriv = ep_priv;
+		ep_priv->ep = ep;
+		new_ep = 1;
+	}
+
+	ret = usb_hcd_link_urb_to_ep(hcd, urb);
+	if (ret)
+		goto failed_link;
+
+	urb->status = -EINPROGRESS;
+	urb->actual_length = 0;
+	urb->error_count = 0;
+	urb->hcpriv = urb_priv;
+	urb_priv->ep = ep;
+
+	switch (usb_pipetype(urb->pipe)) {
+	case PIPE_CONTROL:
+		urb_priv->state = US_CTRL_SETUP;
+		break;
+	case PIPE_BULK:
+		urb_priv->state = US_BULK;
+		break;
+	}
+
+	debug_urb_submitted(imx21, urb);
+	if (ep_priv->etd[0] < 0) {
+		if (ep_priv->waiting_etd) {
+			dev_dbg(imx21->dev,
+				"no ETD available already queued %p\n",
+				ep_priv);
+			debug_urb_queued_for_etd(imx21, urb);
+			goto out;
+		}
+		ep_priv->etd[0] = alloc_etd(imx21);
+		if (ep_priv->etd[0] < 0) {
+			dev_dbg(imx21->dev,
+				"no ETD available queueing %p\n", ep_priv);
+			debug_urb_queued_for_etd(imx21, urb);
+			list_add_tail(&ep_priv->queue, &imx21->queue_for_etd);
+			ep_priv->waiting_etd = 1;
+			goto out;
+		}
+	}
+
+	/* Schedule if no URB already active for this endpoint */
+	etd = &imx21->etd[ep_priv->etd[0]];
+	if (etd->urb == NULL) {
+		DEBUG_LOG_FRAME(imx21, etd, last_req);
+		schedule_nonisoc_etd(imx21, urb);
+	}
+
+out:
+	spin_unlock_irqrestore(&imx21->lock, flags);
+	return 0;
+
+failed_link:
+failed_alloc_ep:
+	spin_unlock_irqrestore(&imx21->lock, flags);
+	kfree(urb_priv);
+	return ret;
+}
+
+static int imx21_hc_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+				int status)
+{
+	struct imx21 *imx21 = hcd_to_imx21(hcd);
+	unsigned long flags;
+	struct usb_host_endpoint *ep;
+	struct ep_priv *ep_priv;
+	struct urb_priv *urb_priv = urb->hcpriv;
+	int ret = -EINVAL;
+
+	dev_vdbg(imx21->dev, "dequeue urb=%p iso=%d status=%d\n",
+		urb, usb_pipeisoc(urb->pipe), status);
+
+	spin_lock_irqsave(&imx21->lock, flags);
+
+	ret = usb_hcd_check_unlink_urb(hcd, urb, status);
+	if (ret)
+		goto fail;
+	ep = urb_priv->ep;
+	ep_priv = ep->hcpriv;
+
+	debug_urb_unlinked(imx21, urb);
+
+	if (usb_pipeisoc(urb->pipe)) {
+		dequeue_isoc_urb(imx21, urb, ep_priv);
+		schedule_isoc_etds(hcd, ep);
+	} else if (urb_priv->active) {
+		int etd_num = ep_priv->etd[0];
+		if (etd_num != -1) {
+			disactivate_etd(imx21, etd_num);
+			free_dmem(imx21, etd_readl(imx21, etd_num, 1) & 0xffff);
+			imx21->etd[etd_num].urb = NULL;
+		}
+	}
+
+	urb_done(hcd, urb, status);
+
+	spin_unlock_irqrestore(&imx21->lock, flags);
+	return 0;
+
+fail:
+	spin_unlock_irqrestore(&imx21->lock, flags);
+	return ret;
+}
+
+/* =========================================== */
+/* Interrupt dispatch	 			*/
+/* =========================================== */
+
+static void process_etds(struct usb_hcd *hcd, struct imx21 *imx21, int sof)
+{
+	int etd_num;
+	int enable_sof_int = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&imx21->lock, flags);
+
+	for (etd_num = 0; etd_num < USB_NUM_ETD; etd_num++) {
+		u32 etd_mask = 1 << etd_num;
+		u32 enabled = readl(imx21->regs + USBH_ETDENSET) & etd_mask;
+		u32 done = readl(imx21->regs + USBH_ETDDONESTAT) & etd_mask;
+		struct etd_priv *etd = &imx21->etd[etd_num];
+
+
+		if (done) {
+			DEBUG_LOG_FRAME(imx21, etd, last_int);
+		} else {
+/*
+ * Kludge warning!
+ *
+ * When multiple transfers are using the bus we sometimes get into a state
+ * where the transfer has completed (the CC field of the ETD is != 0x0F),
+ * the ETD has self disabled but the ETDDONESTAT flag is not set
+ * (and hence no interrupt occurs).
+ * This causes the transfer in question to hang.
+ * The kludge below checks for this condition at each SOF and processes any
+ * blocked ETDs (after an arbitary 10 frame wait)
+ *
+ * With a single active transfer the usbtest test suite will run for days
+ * without the kludge.
+ * With other bus activity (eg mass storage) even just test1 will hang without
+ * the kludge.
+ */
+			u32 dword0;
+			int cc;
+
+			if (etd->active_count && !enabled) /* suspicious... */
+				enable_sof_int = 1;
+
+			if (!sof || enabled || !etd->active_count)
+				continue;
+
+			cc = etd_readl(imx21, etd_num, 2) >> DW2_COMPCODE;
+			if (cc == TD_NOTACCESSED)
+				continue;
+
+			if (++etd->active_count < 10)
+				continue;
+
+			dword0 = etd_readl(imx21, etd_num, 0);
+			dev_dbg(imx21->dev,
+				"unblock ETD %d dev=0x%X ep=0x%X cc=0x%02X!\n",
+				etd_num, dword0 & 0x7F,
+				(dword0 >> DW0_ENDPNT) & 0x0F,
+				cc);
+
+#ifdef DEBUG
+			dev_dbg(imx21->dev,
+				"frame: act=%d disact=%d"
+				" int=%d req=%d cur=%d\n",
+				etd->activated_frame,
+				etd->disactivated_frame,
+				etd->last_int_frame,
+				etd->last_req_frame,
+				readl(imx21->regs + USBH_FRMNUB));
+			imx21->debug_unblocks++;
+#endif
+			etd->active_count = 0;
+/* End of kludge */
+		}
+
+		if (etd->ep == NULL || etd->urb == NULL) {
+			dev_dbg(imx21->dev,
+				"Interrupt for unexpected etd %d"
+				" ep=%p urb=%p\n",
+				etd_num, etd->ep, etd->urb);
+			disactivate_etd(imx21, etd_num);
+			continue;
+		}
+
+		if (usb_pipeisoc(etd->urb->pipe))
+			isoc_etd_done(hcd, etd->urb, etd_num);
+		else
+			nonisoc_etd_done(hcd, etd->urb, etd_num);
+	}
+
+	/* only enable SOF interrupt if it may be needed for the kludge */
+	if (enable_sof_int)
+		set_register_bits(imx21, USBH_SYSIEN, USBH_SYSIEN_SOFINT);
+	else
+		clear_register_bits(imx21, USBH_SYSIEN, USBH_SYSIEN_SOFINT);
+
+
+	spin_unlock_irqrestore(&imx21->lock, flags);
+}
+
+static irqreturn_t imx21_irq(struct usb_hcd *hcd)
+{
+	struct imx21 *imx21 = hcd_to_imx21(hcd);
+	u32 ints = readl(imx21->regs + USBH_SYSISR);
+
+	if (ints & USBH_SYSIEN_HERRINT)
+		dev_dbg(imx21->dev, "Scheduling error\n");
+
+	if (ints & USBH_SYSIEN_SORINT)
+		dev_dbg(imx21->dev, "Scheduling overrun\n");
+
+	if (ints & (USBH_SYSISR_DONEINT | USBH_SYSISR_SOFINT))
+		process_etds(hcd, imx21, ints & USBH_SYSISR_SOFINT);
+
+	writel(ints, imx21->regs + USBH_SYSISR);
+	return IRQ_HANDLED;
+}
+
+static void imx21_hc_endpoint_disable(struct usb_hcd *hcd,
+				      struct usb_host_endpoint *ep)
+{
+	struct imx21 *imx21 = hcd_to_imx21(hcd);
+	unsigned long flags;
+	struct ep_priv *ep_priv;
+	int i;
+
+	if (ep == NULL)
+		return;
+
+	spin_lock_irqsave(&imx21->lock, flags);
+	ep_priv = ep->hcpriv;
+	dev_vdbg(imx21->dev, "disable ep=%p, ep->hcpriv=%p\n", ep, ep_priv);
+
+	if (!list_empty(&ep->urb_list))
+		dev_dbg(imx21->dev, "ep's URB list is not empty\n");
+
+	if (ep_priv != NULL) {
+		for (i = 0; i < NUM_ISO_ETDS; i++) {
+			if (ep_priv->etd[i] > -1)
+				dev_dbg(imx21->dev, "free etd %d for disable\n",
+					ep_priv->etd[i]);
+
+			free_etd(imx21, ep_priv->etd[i]);
+		}
+		kfree(ep_priv);
+		ep->hcpriv = NULL;
+	}
+
+	for (i = 0; i < USB_NUM_ETD; i++) {
+		if (imx21->etd[i].alloc && imx21->etd[i].ep == ep) {
+			dev_err(imx21->dev,
+				"Active etd %d for disabled ep=%p!\n", i, ep);
+			free_etd(imx21, i);
+		}
+	}
+	free_epdmem(imx21, ep);
+	spin_unlock_irqrestore(&imx21->lock, flags);
+}
+
+/* =========================================== */
+/* Hub handling		 			*/
+/* =========================================== */
+
+static int get_hub_descriptor(struct usb_hcd *hcd,
+			      struct usb_hub_descriptor *desc)
+{
+	struct imx21 *imx21 = hcd_to_imx21(hcd);
+	desc->bDescriptorType = 0x29;	/* HUB descriptor */
+	desc->bHubContrCurrent = 0;
+
+	desc->bNbrPorts = readl(imx21->regs + USBH_ROOTHUBA)
+		& USBH_ROOTHUBA_NDNSTMPRT_MASK;
+	desc->bDescLength = 9;
+	desc->bPwrOn2PwrGood = 0;
+	desc->wHubCharacteristics = (__force __u16) cpu_to_le16(
+		0x0002 |	/* No power switching */
+		0x0010 |	/* No over current protection */
+		0);
+
+	desc->bitmap[0] = 1 << 1;
+	desc->bitmap[1] = ~0;
+	return 0;
+}
+
+static int imx21_hc_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+	struct imx21 *imx21 = hcd_to_imx21(hcd);
+	int ports;
+	int changed = 0;
+	int i;
+	unsigned long flags;
+
+	spin_lock_irqsave(&imx21->lock, flags);
+	ports = readl(imx21->regs + USBH_ROOTHUBA)
+		& USBH_ROOTHUBA_NDNSTMPRT_MASK;
+	if (ports > 7) {
+		ports = 7;
+		dev_err(imx21->dev, "ports %d > 7\n", ports);
+	}
+	for (i = 0; i < ports; i++) {
+		if (readl(imx21->regs + USBH_PORTSTAT(i)) &
+			(USBH_PORTSTAT_CONNECTSC |
+			USBH_PORTSTAT_PRTENBLSC |
+			USBH_PORTSTAT_PRTSTATSC |
+			USBH_PORTSTAT_OVRCURIC |
+			USBH_PORTSTAT_PRTRSTSC)) {
+
+			changed = 1;
+			buf[0] |= 1 << (i + 1);
+		}
+	}
+	spin_unlock_irqrestore(&imx21->lock, flags);
+
+	if (changed)
+		dev_info(imx21->dev, "Hub status changed\n");
+	return changed;
+}
+
+static int imx21_hc_hub_control(struct usb_hcd *hcd,
+				u16 typeReq,
+				u16 wValue, u16 wIndex, char *buf, u16 wLength)
+{
+	struct imx21 *imx21 = hcd_to_imx21(hcd);
+	int rc = 0;
+	u32 status_write = 0;
+
+	switch (typeReq) {
+	case ClearHubFeature:
+		dev_dbg(imx21->dev, "ClearHubFeature\n");
+		switch (wValue) {
+		case C_HUB_OVER_CURRENT:
+			dev_dbg(imx21->dev, "    OVER_CURRENT\n");
+			break;
+		case C_HUB_LOCAL_POWER:
+			dev_dbg(imx21->dev, "    LOCAL_POWER\n");
+			break;
+		default:
+			dev_dbg(imx21->dev, "    unknown\n");
+			rc = -EINVAL;
+			break;
+		}
+		break;
+
+	case ClearPortFeature:
+		dev_dbg(imx21->dev, "ClearPortFeature\n");
+		switch (wValue) {
+		case USB_PORT_FEAT_ENABLE:
+			dev_dbg(imx21->dev, "    ENABLE\n");
+			status_write = USBH_PORTSTAT_CURCONST;
+			break;
+		case USB_PORT_FEAT_SUSPEND:
+			dev_dbg(imx21->dev, "    SUSPEND\n");
+			status_write = USBH_PORTSTAT_PRTOVRCURI;
+			break;
+		case USB_PORT_FEAT_POWER:
+			dev_dbg(imx21->dev, "    POWER\n");
+			status_write = USBH_PORTSTAT_LSDEVCON;
+			break;
+		case USB_PORT_FEAT_C_ENABLE:
+			dev_dbg(imx21->dev, "    C_ENABLE\n");
+			status_write = USBH_PORTSTAT_PRTENBLSC;
+			break;
+		case USB_PORT_FEAT_C_SUSPEND:
+			dev_dbg(imx21->dev, "    C_SUSPEND\n");
+			status_write = USBH_PORTSTAT_PRTSTATSC;
+			break;
+		case USB_PORT_FEAT_C_CONNECTION:
+			dev_dbg(imx21->dev, "    C_CONNECTION\n");
+			status_write = USBH_PORTSTAT_CONNECTSC;
+			break;
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+			dev_dbg(imx21->dev, "    C_OVER_CURRENT\n");
+			status_write = USBH_PORTSTAT_OVRCURIC;
+			break;
+		case USB_PORT_FEAT_C_RESET:
+			dev_dbg(imx21->dev, "    C_RESET\n");
+			status_write = USBH_PORTSTAT_PRTRSTSC;
+			break;
+		default:
+			dev_dbg(imx21->dev, "    unknown\n");
+			rc = -EINVAL;
+			break;
+		}
+
+		break;
+
+	case GetHubDescriptor:
+		dev_dbg(imx21->dev, "GetHubDescriptor\n");
+		rc = get_hub_descriptor(hcd, (void *)buf);
+		break;
+
+	case GetHubStatus:
+		dev_dbg(imx21->dev, "  GetHubStatus\n");
+		*(__le32 *) buf = 0;
+		break;
+
+	case GetPortStatus:
+		dev_dbg(imx21->dev, "GetPortStatus: port: %d, 0x%x\n",
+		    wIndex, USBH_PORTSTAT(wIndex - 1));
+		*(__le32 *) buf = readl(imx21->regs +
+			USBH_PORTSTAT(wIndex - 1));
+		break;
+
+	case SetHubFeature:
+		dev_dbg(imx21->dev, "SetHubFeature\n");
+		switch (wValue) {
+		case C_HUB_OVER_CURRENT:
+			dev_dbg(imx21->dev, "    OVER_CURRENT\n");
+			break;
+
+		case C_HUB_LOCAL_POWER:
+			dev_dbg(imx21->dev, "    LOCAL_POWER\n");
+			break;
+		default:
+			dev_dbg(imx21->dev, "    unknown\n");
+			rc = -EINVAL;
+			break;
+		}
+
+		break;
+
+	case SetPortFeature:
+		dev_dbg(imx21->dev, "SetPortFeature\n");
+		switch (wValue) {
+		case USB_PORT_FEAT_SUSPEND:
+			dev_dbg(imx21->dev, "    SUSPEND\n");
+			status_write = USBH_PORTSTAT_PRTSUSPST;
+			break;
+		case USB_PORT_FEAT_POWER:
+			dev_dbg(imx21->dev, "    POWER\n");
+			status_write = USBH_PORTSTAT_PRTPWRST;
+			break;
+		case USB_PORT_FEAT_RESET:
+			dev_dbg(imx21->dev, "    RESET\n");
+			status_write = USBH_PORTSTAT_PRTRSTST;
+			break;
+		default:
+			dev_dbg(imx21->dev, "    unknown\n");
+			rc = -EINVAL;
+			break;
+		}
+		break;
+
+	default:
+		dev_dbg(imx21->dev, "  unknown\n");
+		rc = -EINVAL;
+		break;
+	}
+
+	if (status_write)
+		writel(status_write, imx21->regs + USBH_PORTSTAT(wIndex - 1));
+	return rc;
+}
+
+/* =========================================== */
+/* Host controller management 			*/
+/* =========================================== */
+
+static int imx21_hc_reset(struct usb_hcd *hcd)
+{
+	struct imx21 *imx21 = hcd_to_imx21(hcd);
+	unsigned long timeout;
+	unsigned long flags;
+
+	spin_lock_irqsave(&imx21->lock, flags);
+
+	/* Reset the Host controler modules */
+	writel(USBOTG_RST_RSTCTRL | USBOTG_RST_RSTRH |
+		USBOTG_RST_RSTHSIE | USBOTG_RST_RSTHC,
+		imx21->regs + USBOTG_RST_CTRL);
+
+	/* Wait for reset to finish */
+	timeout = jiffies + HZ;
+	while (readl(imx21->regs + USBOTG_RST_CTRL) != 0) {
+		if (time_after(jiffies, timeout)) {
+			spin_unlock_irqrestore(&imx21->lock, flags);
+			dev_err(imx21->dev, "timeout waiting for reset\n");
+			return -ETIMEDOUT;
+		}
+		spin_unlock_irq(&imx21->lock);
+		schedule_timeout(1);
+		spin_lock_irq(&imx21->lock);
+	}
+	spin_unlock_irqrestore(&imx21->lock, flags);
+	return 0;
+}
+
+static int __devinit imx21_hc_start(struct usb_hcd *hcd)
+{
+	struct imx21 *imx21 = hcd_to_imx21(hcd);
+	unsigned long flags;
+	int i, j;
+	u32 hw_mode = USBOTG_HWMODE_CRECFG_HOST;
+	u32 usb_control = 0;
+
+	hw_mode |= ((imx21->pdata->host_xcvr << USBOTG_HWMODE_HOSTXCVR_SHIFT) &
+			USBOTG_HWMODE_HOSTXCVR_MASK);
+	hw_mode |= ((imx21->pdata->otg_xcvr << USBOTG_HWMODE_OTGXCVR_SHIFT) &
+			USBOTG_HWMODE_OTGXCVR_MASK);
+
+	if (imx21->pdata->host1_txenoe)
+		usb_control |= USBCTRL_HOST1_TXEN_OE;
+
+	if (!imx21->pdata->host1_xcverless)
+		usb_control |= USBCTRL_HOST1_BYP_TLL;
+
+	if (imx21->pdata->otg_ext_xcvr)
+		usb_control |= USBCTRL_OTC_RCV_RXDP;
+
+
+	spin_lock_irqsave(&imx21->lock, flags);
+
+	writel((USBOTG_CLK_CTRL_HST | USBOTG_CLK_CTRL_MAIN),
+		imx21->regs + USBOTG_CLK_CTRL);
+	writel(hw_mode, imx21->regs + USBOTG_HWMODE);
+	writel(usb_control, imx21->regs + USBCTRL);
+	writel(USB_MISCCONTROL_SKPRTRY  | USB_MISCCONTROL_ARBMODE,
+		imx21->regs + USB_MISCCONTROL);
+
+	/* Clear the ETDs */
+	for (i = 0; i < USB_NUM_ETD; i++)
+		for (j = 0; j < 4; j++)
+			etd_writel(imx21, i, j, 0);
+
+	/* Take the HC out of reset */
+	writel(USBH_HOST_CTRL_HCUSBSTE_OPERATIONAL | USBH_HOST_CTRL_CTLBLKSR_1,
+		imx21->regs + USBH_HOST_CTRL);
+
+	/* Enable ports */
+	if (imx21->pdata->enable_otg_host)
+		writel(USBH_PORTSTAT_PRTPWRST | USBH_PORTSTAT_PRTENABST,
+			imx21->regs + USBH_PORTSTAT(0));
+
+	if (imx21->pdata->enable_host1)
+		writel(USBH_PORTSTAT_PRTPWRST | USBH_PORTSTAT_PRTENABST,
+			imx21->regs + USBH_PORTSTAT(1));
+
+	if (imx21->pdata->enable_host2)
+		writel(USBH_PORTSTAT_PRTPWRST | USBH_PORTSTAT_PRTENABST,
+			imx21->regs + USBH_PORTSTAT(2));
+
+
+	hcd->state = HC_STATE_RUNNING;
+
+	/* Enable host controller interrupts */
+	set_register_bits(imx21, USBH_SYSIEN,
+		USBH_SYSIEN_HERRINT |
+		USBH_SYSIEN_DONEINT | USBH_SYSIEN_SORINT);
+	set_register_bits(imx21, USBOTG_CINT_STEN, USBOTG_HCINT);
+
+	spin_unlock_irqrestore(&imx21->lock, flags);
+
+	return 0;
+}
+
+static void imx21_hc_stop(struct usb_hcd *hcd)
+{
+	struct imx21 *imx21 = hcd_to_imx21(hcd);
+	unsigned long flags;
+
+	spin_lock_irqsave(&imx21->lock, flags);
+
+	writel(0, imx21->regs + USBH_SYSIEN);
+	clear_register_bits(imx21, USBOTG_CINT_STEN, USBOTG_HCINT);
+	clear_register_bits(imx21, USBOTG_CLK_CTRL_HST | USBOTG_CLK_CTRL_MAIN,
+					USBOTG_CLK_CTRL);
+	spin_unlock_irqrestore(&imx21->lock, flags);
+}
+
+/* =========================================== */
+/* Driver glue		 			*/
+/* =========================================== */
+
+static struct hc_driver imx21_hc_driver = {
+	.description = hcd_name,
+	.product_desc = "IMX21 USB Host Controller",
+	.hcd_priv_size = sizeof(struct imx21),
+
+	.flags = HCD_USB11,
+	.irq = imx21_irq,
+
+	.reset = imx21_hc_reset,
+	.start = imx21_hc_start,
+	.stop = imx21_hc_stop,
+
+	/* I/O requests */
+	.urb_enqueue = imx21_hc_urb_enqueue,
+	.urb_dequeue = imx21_hc_urb_dequeue,
+	.endpoint_disable = imx21_hc_endpoint_disable,
+
+	/* scheduling support */
+	.get_frame_number = imx21_hc_get_frame,
+
+	/* Root hub support */
+	.hub_status_data = imx21_hc_hub_status_data,
+	.hub_control = imx21_hc_hub_control,
+
+};
+
+static struct mx21_usbh_platform_data default_pdata = {
+	.host_xcvr = MX21_USBXCVR_TXDIF_RXDIF,
+	.otg_xcvr = MX21_USBXCVR_TXDIF_RXDIF,
+	.enable_host1 = 1,
+	.enable_host2 = 1,
+	.enable_otg_host = 1,
+
+};
+
+static int imx21_remove(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(pdev);
+	struct imx21 *imx21 = hcd_to_imx21(hcd);
+	struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	remove_debug_files(imx21);
+	usb_remove_hcd(hcd);
+
+	if (res != NULL) {
+		clk_disable(imx21->clk);
+		clk_put(imx21->clk);
+		iounmap(imx21->regs);
+		release_mem_region(res->start, resource_size(res));
+	}
+
+	kfree(hcd);
+	return 0;
+}
+
+
+static int imx21_probe(struct platform_device *pdev)
+{
+	struct usb_hcd *hcd;
+	struct imx21 *imx21;
+	struct resource *res;
+	int ret;
+	int irq;
+
+	printk(KERN_INFO "%s\n", imx21_hc_driver.product_desc);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENODEV;
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return -ENXIO;
+
+	hcd = usb_create_hcd(&imx21_hc_driver,
+		&pdev->dev, dev_name(&pdev->dev));
+	if (hcd == NULL) {
+		dev_err(&pdev->dev, "Cannot create hcd (%s)\n",
+		    dev_name(&pdev->dev));
+		return -ENOMEM;
+	}
+
+	imx21 = hcd_to_imx21(hcd);
+	imx21->dev = &pdev->dev;
+	imx21->pdata = pdev->dev.platform_data;
+	if (!imx21->pdata)
+		imx21->pdata = &default_pdata;
+
+	spin_lock_init(&imx21->lock);
+	INIT_LIST_HEAD(&imx21->dmem_list);
+	INIT_LIST_HEAD(&imx21->queue_for_etd);
+	INIT_LIST_HEAD(&imx21->queue_for_dmem);
+	create_debug_files(imx21);
+
+	res = request_mem_region(res->start, resource_size(res), hcd_name);
+	if (!res) {
+		ret = -EBUSY;
+		goto failed_request_mem;
+	}
+
+	imx21->regs = ioremap(res->start, resource_size(res));
+	if (imx21->regs == NULL) {
+		dev_err(imx21->dev, "Cannot map registers\n");
+		ret = -ENOMEM;
+		goto failed_ioremap;
+	}
+
+	/* Enable clocks source */
+	imx21->clk = clk_get(imx21->dev, NULL);
+	if (IS_ERR(imx21->clk)) {
+		dev_err(imx21->dev, "no clock found\n");
+		ret = PTR_ERR(imx21->clk);
+		goto failed_clock_get;
+	}
+
+	ret = clk_set_rate(imx21->clk, clk_round_rate(imx21->clk, 48000000));
+	if (ret)
+		goto failed_clock_set;
+	ret = clk_enable(imx21->clk);
+	if (ret)
+		goto failed_clock_enable;
+
+	dev_info(imx21->dev, "Hardware HC revision: 0x%02X\n",
+		(readl(imx21->regs + USBOTG_HWMODE) >> 16) & 0xFF);
+
+	ret = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+	if (ret != 0) {
+		dev_err(imx21->dev, "usb_add_hcd() returned %d\n", ret);
+		goto failed_add_hcd;
+	}
+
+	return 0;
+
+failed_add_hcd:
+	clk_disable(imx21->clk);
+failed_clock_enable:
+failed_clock_set:
+	clk_put(imx21->clk);
+failed_clock_get:
+	iounmap(imx21->regs);
+failed_ioremap:
+	release_mem_region(res->start, res->end - res->start);
+failed_request_mem:
+	remove_debug_files(imx21);
+	usb_put_hcd(hcd);
+	return ret;
+}
+
+static struct platform_driver imx21_hcd_driver = {
+	.driver = {
+		   .name = (char *)hcd_name,
+		   },
+	.probe = imx21_probe,
+	.remove = imx21_remove,
+	.suspend = NULL,
+	.resume = NULL,
+};
+
+static int __init imx21_hcd_init(void)
+{
+	return platform_driver_register(&imx21_hcd_driver);
+}
+
+static void __exit imx21_hcd_cleanup(void)
+{
+	platform_driver_unregister(&imx21_hcd_driver);
+}
+
+module_init(imx21_hcd_init);
+module_exit(imx21_hcd_cleanup);
+
+MODULE_DESCRIPTION("i.MX21 USB Host controller");
+MODULE_AUTHOR("Martin Fuzzey");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:imx21-hcd");

+ 436 - 0
drivers/usb/host/imx21-hcd.h

@@ -0,0 +1,436 @@
+/*
+ * Macros and prototypes for i.MX21
+ *
+ * Copyright (C) 2006 Loping Dog Embedded Systems
+ * Copyright (C) 2009 Martin Fuzzey
+ * Originally written by Jay Monkman <jtm@lopingdog.com>
+ * Ported to 2.6.30, debugged and enhanced by Martin Fuzzey
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.	 See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_IMX21_HCD_H__
+#define __LINUX_IMX21_HCD_H__
+
+#include <mach/mx21-usbhost.h>
+
+#define NUM_ISO_ETDS 	2
+#define USB_NUM_ETD	32
+#define DMEM_SIZE   	4096
+
+/* Register definitions */
+#define USBOTG_HWMODE		0x00
+#define USBOTG_HWMODE_ANASDBEN		(1 << 14)
+#define USBOTG_HWMODE_OTGXCVR_SHIFT	6
+#define USBOTG_HWMODE_OTGXCVR_MASK	(3 << 6)
+#define USBOTG_HWMODE_OTGXCVR_TD_RD	(0 << 6)
+#define USBOTG_HWMODE_OTGXCVR_TS_RD	(2 << 6)
+#define USBOTG_HWMODE_OTGXCVR_TD_RS	(1 << 6)
+#define USBOTG_HWMODE_OTGXCVR_TS_RS	(3 << 6)
+#define USBOTG_HWMODE_HOSTXCVR_SHIFT	4
+#define USBOTG_HWMODE_HOSTXCVR_MASK	(3 << 4)
+#define USBOTG_HWMODE_HOSTXCVR_TD_RD	(0 << 4)
+#define USBOTG_HWMODE_HOSTXCVR_TS_RD	(2 << 4)
+#define USBOTG_HWMODE_HOSTXCVR_TD_RS	(1 << 4)
+#define USBOTG_HWMODE_HOSTXCVR_TS_RS	(3 << 4)
+#define USBOTG_HWMODE_CRECFG_MASK	(3 << 0)
+#define USBOTG_HWMODE_CRECFG_HOST	(1 << 0)
+#define USBOTG_HWMODE_CRECFG_FUNC	(2 << 0)
+#define USBOTG_HWMODE_CRECFG_HNP	(3 << 0)
+
+#define USBOTG_CINT_STAT	0x04
+#define USBOTG_CINT_STEN	0x08
+#define USBOTG_ASHNPINT			(1 << 5)
+#define USBOTG_ASFCINT			(1 << 4)
+#define USBOTG_ASHCINT			(1 << 3)
+#define USBOTG_SHNPINT			(1 << 2)
+#define USBOTG_FCINT			(1 << 1)
+#define USBOTG_HCINT			(1 << 0)
+
+#define USBOTG_CLK_CTRL		0x0c
+#define USBOTG_CLK_CTRL_FUNC		(1 << 2)
+#define USBOTG_CLK_CTRL_HST		(1 << 1)
+#define USBOTG_CLK_CTRL_MAIN		(1 << 0)
+
+#define USBOTG_RST_CTRL		0x10
+#define USBOTG_RST_RSTI2C		(1 << 15)
+#define USBOTG_RST_RSTCTRL		(1 << 5)
+#define USBOTG_RST_RSTFC		(1 << 4)
+#define USBOTG_RST_RSTFSKE		(1 << 3)
+#define USBOTG_RST_RSTRH		(1 << 2)
+#define USBOTG_RST_RSTHSIE		(1 << 1)
+#define USBOTG_RST_RSTHC		(1 << 0)
+
+#define USBOTG_FRM_INTVL    	0x14
+#define USBOTG_FRM_REMAIN   	0x18
+#define USBOTG_HNP_CSR	    	0x1c
+#define USBOTG_HNP_ISR	    	0x2c
+#define USBOTG_HNP_IEN	    	0x30
+
+#define USBOTG_I2C_TXCVR_REG(x)	(0x100 + (x))
+#define USBOTG_I2C_XCVR_DEVAD		0x118
+#define USBOTG_I2C_SEQ_OP_REG		0x119
+#define USBOTG_I2C_SEQ_RD_STARTAD	0x11a
+#define USBOTG_I2C_OP_CTRL_REG	     	0x11b
+#define USBOTG_I2C_SCLK_TO_SCK_HPER  	0x11e
+#define USBOTG_I2C_MASTER_INT_REG    	0x11f
+
+#define USBH_HOST_CTRL		0x80
+#define USBH_HOST_CTRL_HCRESET			(1 << 31)
+#define USBH_HOST_CTRL_SCHDOVR(x)		((x) << 16)
+#define USBH_HOST_CTRL_RMTWUEN			(1 << 4)
+#define USBH_HOST_CTRL_HCUSBSTE_RESET		(0 << 2)
+#define USBH_HOST_CTRL_HCUSBSTE_RESUME		(1 << 2)
+#define USBH_HOST_CTRL_HCUSBSTE_OPERATIONAL	(2 << 2)
+#define USBH_HOST_CTRL_HCUSBSTE_SUSPEND	(3 << 2)
+#define USBH_HOST_CTRL_CTLBLKSR_1		(0 << 0)
+#define USBH_HOST_CTRL_CTLBLKSR_2		(1 << 0)
+#define USBH_HOST_CTRL_CTLBLKSR_3		(2 << 0)
+#define USBH_HOST_CTRL_CTLBLKSR_4		(3 << 0)
+
+#define USBH_SYSISR		0x88
+#define USBH_SYSISR_PSCINT		(1 << 6)
+#define USBH_SYSISR_FMOFINT		(1 << 5)
+#define USBH_SYSISR_HERRINT		(1 << 4)
+#define USBH_SYSISR_RESDETINT		(1 << 3)
+#define USBH_SYSISR_SOFINT		(1 << 2)
+#define USBH_SYSISR_DONEINT		(1 << 1)
+#define USBH_SYSISR_SORINT		(1 << 0)
+
+#define USBH_SYSIEN	    	0x8c
+#define USBH_SYSIEN_PSCINT		(1 << 6)
+#define USBH_SYSIEN_FMOFINT		(1 << 5)
+#define USBH_SYSIEN_HERRINT		(1 << 4)
+#define USBH_SYSIEN_RESDETINT		(1 << 3)
+#define USBH_SYSIEN_SOFINT		(1 << 2)
+#define USBH_SYSIEN_DONEINT		(1 << 1)
+#define USBH_SYSIEN_SORINT		(1 << 0)
+
+#define USBH_XBUFSTAT	    	0x98
+#define USBH_YBUFSTAT	    	0x9c
+#define USBH_XYINTEN	    	0xa0
+#define USBH_XFILLSTAT	    	0xa8
+#define USBH_YFILLSTAT	    	0xac
+#define USBH_ETDENSET	    	0xc0
+#define USBH_ETDENCLR	    	0xc4
+#define USBH_IMMEDINT	    	0xcc
+#define USBH_ETDDONESTAT    	0xd0
+#define USBH_ETDDONEEN	    	0xd4
+#define USBH_FRMNUB	    	0xe0
+#define USBH_LSTHRESH	    	0xe4
+
+#define USBH_ROOTHUBA	    	0xe8
+#define USBH_ROOTHUBA_PWRTOGOOD_MASK	(0xff)
+#define USBH_ROOTHUBA_PWRTOGOOD_SHIFT	(24)
+#define USBH_ROOTHUBA_NOOVRCURP	(1 << 12)
+#define USBH_ROOTHUBA_OVRCURPM		(1 << 11)
+#define USBH_ROOTHUBA_DEVTYPE		(1 << 10)
+#define USBH_ROOTHUBA_PWRSWTMD		(1 << 9)
+#define USBH_ROOTHUBA_NOPWRSWT		(1 << 8)
+#define USBH_ROOTHUBA_NDNSTMPRT_MASK	(0xff)
+
+#define USBH_ROOTHUBB		0xec
+#define USBH_ROOTHUBB_PRTPWRCM(x)	(1 << ((x) + 16))
+#define USBH_ROOTHUBB_DEVREMOVE(x)	(1 << (x))
+
+#define USBH_ROOTSTAT		0xf0
+#define USBH_ROOTSTAT_CLRRMTWUE	(1 << 31)
+#define USBH_ROOTSTAT_OVRCURCHG	(1 << 17)
+#define USBH_ROOTSTAT_DEVCONWUE	(1 << 15)
+#define USBH_ROOTSTAT_OVRCURI		(1 << 1)
+#define USBH_ROOTSTAT_LOCPWRS		(1 << 0)
+
+#define USBH_PORTSTAT(x)	(0xf4 + ((x) * 4))
+#define USBH_PORTSTAT_PRTRSTSC		(1 << 20)
+#define USBH_PORTSTAT_OVRCURIC		(1 << 19)
+#define USBH_PORTSTAT_PRTSTATSC	(1 << 18)
+#define USBH_PORTSTAT_PRTENBLSC	(1 << 17)
+#define USBH_PORTSTAT_CONNECTSC	(1 << 16)
+#define USBH_PORTSTAT_LSDEVCON		(1 << 9)
+#define USBH_PORTSTAT_PRTPWRST		(1 << 8)
+#define USBH_PORTSTAT_PRTRSTST		(1 << 4)
+#define USBH_PORTSTAT_PRTOVRCURI	(1 << 3)
+#define USBH_PORTSTAT_PRTSUSPST	(1 << 2)
+#define USBH_PORTSTAT_PRTENABST	(1 << 1)
+#define USBH_PORTSTAT_CURCONST		(1 << 0)
+
+#define USB_DMAREV		0x800
+#define USB_DMAINTSTAT	    	0x804
+#define USB_DMAINTSTAT_EPERR		(1 << 1)
+#define USB_DMAINTSTAT_ETDERR		(1 << 0)
+
+#define USB_DMAINTEN	    	0x808
+#define USB_DMAINTEN_EPERRINTEN	(1 << 1)
+#define USB_DMAINTEN_ETDERRINTEN	(1 << 0)
+
+#define USB_ETDDMAERSTAT    	0x80c
+#define USB_EPDMAERSTAT	    	0x810
+#define USB_ETDDMAEN	    	0x820
+#define USB_EPDMAEN	    	0x824
+#define USB_ETDDMAXTEN	    	0x828
+#define USB_EPDMAXTEN	    	0x82c
+#define USB_ETDDMAENXYT	    	0x830
+#define USB_EPDMAENXYT	    	0x834
+#define USB_ETDDMABST4EN    	0x838
+#define USB_EPDMABST4EN	    	0x83c
+
+#define USB_MISCCONTROL	    	0x840
+#define USB_MISCCONTROL_ISOPREVFRM	(1 << 3)
+#define USB_MISCCONTROL_SKPRTRY	(1 << 2)
+#define USB_MISCCONTROL_ARBMODE	(1 << 1)
+#define USB_MISCCONTROL_FILTCC		(1 << 0)
+
+#define USB_ETDDMACHANLCLR  	0x848
+#define USB_EPDMACHANLCLR   	0x84c
+#define USB_ETDSMSA(x)	    	(0x900 + ((x) * 4))
+#define USB_EPSMSA(x)	    	(0x980 + ((x) * 4))
+#define USB_ETDDMABUFPTR(x) 	(0xa00 + ((x) * 4))
+#define USB_EPDMABUFPTR(x)  	(0xa80 + ((x) * 4))
+
+#define USB_ETD_DWORD(x, w)	(0x200 + ((x) * 16) + ((w) * 4))
+#define DW0_ADDRESS	0
+#define	DW0_ENDPNT	7
+#define	DW0_DIRECT	11
+#define	DW0_SPEED	13
+#define DW0_FORMAT	14
+#define DW0_MAXPKTSIZ	16
+#define DW0_HALTED	27
+#define	DW0_TOGCRY	28
+#define	DW0_SNDNAK	30
+
+#define DW1_XBUFSRTAD	0
+#define DW1_YBUFSRTAD	16
+
+#define DW2_RTRYDELAY	0
+#define DW2_POLINTERV	0
+#define DW2_STARTFRM	0
+#define DW2_RELPOLPOS	8
+#define DW2_DIRPID	16
+#define	DW2_BUFROUND	18
+#define DW2_DELAYINT	19
+#define DW2_DATATOG	22
+#define DW2_ERRORCNT	24
+#define	DW2_COMPCODE	28
+
+#define DW3_TOTBYECNT	0
+#define DW3_PKTLEN0	0
+#define DW3_COMPCODE0	12
+#define DW3_PKTLEN1	16
+#define DW3_BUFSIZE	21
+#define DW3_COMPCODE1	28
+
+#define USBCTRL		    	0x600
+#define USBCTRL_I2C_WU_INT_STAT	(1 << 27)
+#define USBCTRL_OTG_WU_INT_STAT	(1 << 26)
+#define USBCTRL_HOST_WU_INT_STAT	(1 << 25)
+#define USBCTRL_FNT_WU_INT_STAT	(1 << 24)
+#define USBCTRL_I2C_WU_INT_EN		(1 << 19)
+#define USBCTRL_OTG_WU_INT_EN		(1 << 18)
+#define USBCTRL_HOST_WU_INT_EN		(1 << 17)
+#define USBCTRL_FNT_WU_INT_EN		(1 << 16)
+#define USBCTRL_OTC_RCV_RXDP		(1 << 13)
+#define USBCTRL_HOST1_BYP_TLL		(1 << 12)
+#define USBCTRL_OTG_BYP_VAL(x)		((x) << 10)
+#define USBCTRL_HOST1_BYP_VAL(x)	((x) << 8)
+#define USBCTRL_OTG_PWR_MASK		(1 << 6)
+#define USBCTRL_HOST1_PWR_MASK		(1 << 5)
+#define USBCTRL_HOST2_PWR_MASK		(1 << 4)
+#define USBCTRL_USB_BYP			(1 << 2)
+#define USBCTRL_HOST1_TXEN_OE		(1 << 1)
+
+
+/* Values in TD blocks */
+#define TD_DIR_SETUP	    0
+#define TD_DIR_OUT	    1
+#define TD_DIR_IN	    2
+#define TD_FORMAT_CONTROL   0
+#define TD_FORMAT_ISO	    1
+#define TD_FORMAT_BULK	    2
+#define TD_FORMAT_INT	    3
+#define TD_TOGGLE_CARRY	    0
+#define TD_TOGGLE_DATA0	    2
+#define TD_TOGGLE_DATA1	    3
+
+/* control transfer states */
+#define US_CTRL_SETUP	2
+#define US_CTRL_DATA	1
+#define US_CTRL_ACK	0
+
+/* bulk transfer main state and 0-length packet */
+#define US_BULK		1
+#define US_BULK0	0
+
+/*ETD format description*/
+#define IMX_FMT_CTRL   0x0
+#define IMX_FMT_ISO    0x1
+#define IMX_FMT_BULK   0x2
+#define IMX_FMT_INT    0x3
+
+static char fmt_urb_to_etd[4] = {
+/*PIPE_ISOCHRONOUS*/ IMX_FMT_ISO,
+/*PIPE_INTERRUPT*/ IMX_FMT_INT,
+/*PIPE_CONTROL*/ IMX_FMT_CTRL,
+/*PIPE_BULK*/ IMX_FMT_BULK
+};
+
+/* condition (error) CC codes and mapping (OHCI like) */
+
+#define TD_CC_NOERROR		0x00
+#define TD_CC_CRC		0x01
+#define TD_CC_BITSTUFFING	0x02
+#define TD_CC_DATATOGGLEM	0x03
+#define TD_CC_STALL		0x04
+#define TD_DEVNOTRESP		0x05
+#define TD_PIDCHECKFAIL		0x06
+/*#define TD_UNEXPECTEDPID	0x07 - reserved, not active on MX2*/
+#define TD_DATAOVERRUN		0x08
+#define TD_DATAUNDERRUN		0x09
+#define TD_BUFFEROVERRUN	0x0C
+#define TD_BUFFERUNDERRUN	0x0D
+#define	TD_SCHEDULEOVERRUN	0x0E
+#define TD_NOTACCESSED		0x0F
+
+static const int cc_to_error[16] = {
+	/* No  Error  */ 0,
+	/* CRC Error  */ -EILSEQ,
+	/* Bit Stuff  */ -EPROTO,
+	/* Data Togg  */ -EILSEQ,
+	/* Stall      */ -EPIPE,
+	/* DevNotResp */ -ETIMEDOUT,
+	/* PIDCheck   */ -EPROTO,
+	/* UnExpPID   */ -EPROTO,
+	/* DataOver   */ -EOVERFLOW,
+	/* DataUnder  */ -EREMOTEIO,
+	/* (for hw)   */ -EIO,
+	/* (for hw)   */ -EIO,
+	/* BufferOver */ -ECOMM,
+	/* BuffUnder  */ -ENOSR,
+	/* (for HCD)  */ -ENOSPC,
+	/* (for HCD)  */ -EALREADY
+};
+
+/* HCD data associated with a usb core URB */
+struct urb_priv {
+	struct urb *urb;
+	struct usb_host_endpoint *ep;
+	int active;
+	int state;
+	struct td *isoc_td;
+	int isoc_remaining;
+	int isoc_status;
+};
+
+/* HCD data associated with a usb core endpoint */
+struct ep_priv {
+	struct usb_host_endpoint *ep;
+	struct list_head td_list;
+	struct list_head queue;
+	int etd[NUM_ISO_ETDS];
+	int waiting_etd;
+};
+
+/* isoc packet */
+struct td {
+	struct list_head list;
+	struct urb *urb;
+	struct usb_host_endpoint *ep;
+	dma_addr_t data;
+	unsigned long buf_addr;
+	int len;
+	int frame;
+	int isoc_index;
+};
+
+/* HCD data associated with a hardware ETD */
+struct etd_priv {
+	struct usb_host_endpoint *ep;
+	struct urb *urb;
+	struct td *td;
+	struct list_head queue;
+	dma_addr_t dma_handle;
+	int alloc;
+	int len;
+	int dmem_size;
+	int dmem_offset;
+	int active_count;
+#ifdef DEBUG
+	int activated_frame;
+	int disactivated_frame;
+	int last_int_frame;
+	int last_req_frame;
+	u32 submitted_dwords[4];
+#endif
+};
+
+/* Hardware data memory info */
+struct imx21_dmem_area {
+	struct usb_host_endpoint *ep;
+	unsigned int offset;
+	unsigned int size;
+	struct list_head list;
+};
+
+#ifdef DEBUG
+struct debug_usage_stats {
+	unsigned int value;
+	unsigned int maximum;
+};
+
+struct debug_stats {
+	unsigned long submitted;
+	unsigned long completed_ok;
+	unsigned long completed_failed;
+	unsigned long unlinked;
+	unsigned long queue_etd;
+	unsigned long queue_dmem;
+};
+
+struct debug_isoc_trace {
+	int schedule_frame;
+	int submit_frame;
+	int request_len;
+	int done_frame;
+	int done_len;
+	int cc;
+	struct td *td;
+};
+#endif
+
+/* HCD data structure */
+struct imx21 {
+	spinlock_t lock;
+	struct device *dev;
+	struct mx21_usbh_platform_data *pdata;
+	struct list_head dmem_list;
+	struct list_head queue_for_etd; /* eps queued due to etd shortage */
+	struct list_head queue_for_dmem; /* etds queued due to dmem shortage */
+	struct etd_priv etd[USB_NUM_ETD];
+	struct clk *clk;
+	void __iomem *regs;
+#ifdef DEBUG
+	struct dentry *debug_root;
+	struct debug_stats nonisoc_stats;
+	struct debug_stats isoc_stats;
+	struct debug_usage_stats etd_usage;
+	struct debug_usage_stats dmem_usage;
+	struct debug_isoc_trace isoc_trace[20];
+	struct debug_isoc_trace isoc_trace_failed[20];
+	unsigned long debug_unblocks;
+	int isoc_trace_index;
+	int isoc_trace_index_failed;
+#endif
+};
+
+#endif

+ 1 - 14
drivers/usb/host/isp1362-hcd.c

@@ -1257,7 +1257,7 @@ static int isp1362_urb_enqueue(struct usb_hcd *hcd,
 
 
 	/* avoid all allocations within spinlocks: request or endpoint */
 	/* avoid all allocations within spinlocks: request or endpoint */
 	if (!hep->hcpriv) {
 	if (!hep->hcpriv) {
-		ep = kcalloc(1, sizeof *ep, mem_flags);
+		ep = kzalloc(sizeof *ep, mem_flags);
 		if (!ep)
 		if (!ep)
 			return -ENOMEM;
 			return -ENOMEM;
 	}
 	}
@@ -2719,24 +2719,11 @@ static int __init isp1362_probe(struct platform_device *pdev)
 	}
 	}
 	irq = irq_res->start;
 	irq = irq_res->start;
 
 
-#ifdef CONFIG_USB_HCD_DMA
-	if (pdev->dev.dma_mask) {
-		struct resource *dma_res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
-
-		if (!dma_res) {
-			retval = -ENODEV;
-			goto err1;
-		}
-		isp1362_hcd->data_dma = dma_res->start;
-		isp1362_hcd->max_dma_size = resource_len(dma_res);
-	}
-#else
 	if (pdev->dev.dma_mask) {
 	if (pdev->dev.dma_mask) {
 		DBG(1, "won't do DMA");
 		DBG(1, "won't do DMA");
 		retval = -ENODEV;
 		retval = -ENODEV;
 		goto err1;
 		goto err1;
 	}
 	}
-#endif
 
 
 	if (!request_mem_region(addr->start, resource_len(addr), hcd_name)) {
 	if (!request_mem_region(addr->start, resource_len(addr), hcd_name)) {
 		retval = -EBUSY;
 		retval = -EBUSY;

+ 10 - 0
drivers/usb/host/isp1760-hcd.c

@@ -17,7 +17,9 @@
 #include <linux/debugfs.h>
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/io.h>
+#include <linux/mm.h>
 #include <asm/unaligned.h>
 #include <asm/unaligned.h>
+#include <asm/cacheflush.h>
 
 
 #include "../core/hcd.h"
 #include "../core/hcd.h"
 #include "isp1760-hcd.h"
 #include "isp1760-hcd.h"
@@ -904,6 +906,14 @@ __acquires(priv->lock)
 			status = 0;
 			status = 0;
 	}
 	}
 
 
+	if (usb_pipein(urb->pipe) && usb_pipetype(urb->pipe) != PIPE_CONTROL) {
+		void *ptr;
+		for (ptr = urb->transfer_buffer;
+		     ptr < urb->transfer_buffer + urb->transfer_buffer_length;
+		     ptr += PAGE_SIZE)
+			flush_dcache_page(virt_to_page(ptr));
+	}
+
 	/* complete() can reenter this HCD */
 	/* complete() can reenter this HCD */
 	usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb);
 	usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb);
 	spin_unlock(&priv->lock);
 	spin_unlock(&priv->lock);

+ 1 - 1
drivers/usb/host/isp1760-if.c

@@ -109,7 +109,7 @@ static int of_isp1760_remove(struct of_device *dev)
 	return 0;
 	return 0;
 }
 }
 
 
-static struct of_device_id of_isp1760_match[] = {
+static const struct of_device_id of_isp1760_match[] = {
 	{
 	{
 		.compatible = "nxp,usb-isp1760",
 		.compatible = "nxp,usb-isp1760",
 	},
 	},

+ 456 - 0
drivers/usb/host/ohci-da8xx.c

@@ -0,0 +1,456 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * TI DA8xx (OMAP-L1x) Bus Glue
+ *
+ * Derived from: ohci-omap.c and ohci-s3c2410.c
+ * Copyright (C) 2008-2009 MontaVista Software, Inc. <source@mvista.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <mach/da8xx.h>
+#include <mach/usb.h>
+
+#ifndef CONFIG_ARCH_DAVINCI_DA8XX
+#error "This file is DA8xx bus glue.  Define CONFIG_ARCH_DAVINCI_DA8XX."
+#endif
+
+#define CFGCHIP2	DA8XX_SYSCFG_VIRT(DA8XX_CFGCHIP2_REG)
+
+static struct clk *usb11_clk;
+static struct clk *usb20_clk;
+
+/* Over-current indicator change bitmask */
+static volatile u16 ocic_mask;
+
+static void ohci_da8xx_clock(int on)
+{
+	u32 cfgchip2;
+
+	cfgchip2 = __raw_readl(CFGCHIP2);
+	if (on) {
+		clk_enable(usb11_clk);
+
+		/*
+		 * If USB 1.1 reference clock is sourced from USB 2.0 PHY, we
+		 * need to enable the USB 2.0 module clocking, start its PHY,
+		 * and not allow it to stop the clock during USB 2.0 suspend.
+		 */
+		if (!(cfgchip2 & CFGCHIP2_USB1PHYCLKMUX)) {
+			clk_enable(usb20_clk);
+
+			cfgchip2 &= ~(CFGCHIP2_RESET | CFGCHIP2_PHYPWRDN);
+			cfgchip2 |= CFGCHIP2_PHY_PLLON;
+			__raw_writel(cfgchip2, CFGCHIP2);
+
+			pr_info("Waiting for USB PHY clock good...\n");
+			while (!(__raw_readl(CFGCHIP2) & CFGCHIP2_PHYCLKGD))
+				cpu_relax();
+		}
+
+		/* Enable USB 1.1 PHY */
+		cfgchip2 |= CFGCHIP2_USB1SUSPENDM;
+	} else {
+		clk_disable(usb11_clk);
+		if (!(cfgchip2 & CFGCHIP2_USB1PHYCLKMUX))
+			clk_disable(usb20_clk);
+
+		/* Disable USB 1.1 PHY */
+		cfgchip2 &= ~CFGCHIP2_USB1SUSPENDM;
+	}
+	__raw_writel(cfgchip2, CFGCHIP2);
+}
+
+/*
+ * Handle the port over-current indicator change.
+ */
+static void ohci_da8xx_ocic_handler(struct da8xx_ohci_root_hub *hub,
+				    unsigned port)
+{
+	ocic_mask |= 1 << port;
+
+	/* Once over-current is detected, the port needs to be powered down */
+	if (hub->get_oci(port) > 0)
+		hub->set_power(port, 0);
+}
+
+static int ohci_da8xx_init(struct usb_hcd *hcd)
+{
+	struct device *dev		= hcd->self.controller;
+	struct da8xx_ohci_root_hub *hub	= dev->platform_data;
+	struct ohci_hcd	*ohci		= hcd_to_ohci(hcd);
+	int result;
+	u32 rh_a;
+
+	dev_dbg(dev, "starting USB controller\n");
+
+	ohci_da8xx_clock(1);
+
+	/*
+	 * DA8xx only have 1 port connected to the pins but the HC root hub
+	 * register A reports 2 ports, thus we'll have to override it...
+	 */
+	ohci->num_ports = 1;
+
+	result = ohci_init(ohci);
+	if (result < 0)
+		return result;
+
+	/*
+	 * Since we're providing a board-specific root hub port power control
+	 * and over-current reporting, we have to override the HC root hub A
+	 * register's default value, so that ohci_hub_control() could return
+	 * the correct hub descriptor...
+	 */
+	rh_a = ohci_readl(ohci, &ohci->regs->roothub.a);
+	if (hub->set_power) {
+		rh_a &= ~RH_A_NPS;
+		rh_a |=  RH_A_PSM;
+	}
+	if (hub->get_oci) {
+		rh_a &= ~RH_A_NOCP;
+		rh_a |=  RH_A_OCPM;
+	}
+	rh_a &= ~RH_A_POTPGT;
+	rh_a |= hub->potpgt << 24;
+	ohci_writel(ohci, rh_a, &ohci->regs->roothub.a);
+
+	return result;
+}
+
+static void ohci_da8xx_stop(struct usb_hcd *hcd)
+{
+	ohci_stop(hcd);
+	ohci_da8xx_clock(0);
+}
+
+static int ohci_da8xx_start(struct usb_hcd *hcd)
+{
+	struct ohci_hcd	*ohci		= hcd_to_ohci(hcd);
+	int result;
+
+	result = ohci_run(ohci);
+	if (result < 0)
+		ohci_da8xx_stop(hcd);
+
+	return result;
+}
+
+/*
+ * Update the status data from the hub with the over-current indicator change.
+ */
+static int ohci_da8xx_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+	int length		= ohci_hub_status_data(hcd, buf);
+
+	/* See if we have OCIC bit set on port 1 */
+	if (ocic_mask & (1 << 1)) {
+		dev_dbg(hcd->self.controller, "over-current indicator change "
+			"on port 1\n");
+
+		if (!length)
+			length = 1;
+
+		buf[0] |= 1 << 1;
+	}
+	return length;
+}
+
+/*
+ * Look at the control requests to the root hub and see if we need to override.
+ */
+static int ohci_da8xx_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
+				  u16 wIndex, char *buf, u16 wLength)
+{
+	struct device *dev		= hcd->self.controller;
+	struct da8xx_ohci_root_hub *hub	= dev->platform_data;
+	int temp;
+
+	switch (typeReq) {
+	case GetPortStatus:
+		/* Check the port number */
+		if (wIndex != 1)
+			break;
+
+		dev_dbg(dev, "GetPortStatus(%u)\n", wIndex);
+
+		temp = roothub_portstatus(hcd_to_ohci(hcd), wIndex - 1);
+
+		/* The port power status (PPS) bit defaults to 1 */
+		if (hub->get_power && hub->get_power(wIndex) == 0)
+			temp &= ~RH_PS_PPS;
+
+		/* The port over-current indicator (POCI) bit is always 0 */
+		if (hub->get_oci && hub->get_oci(wIndex) > 0)
+			temp |=  RH_PS_POCI;
+
+		/* The over-current indicator change (OCIC) bit is 0 too */
+		if (ocic_mask & (1 << wIndex))
+			temp |=  RH_PS_OCIC;
+
+		put_unaligned(cpu_to_le32(temp), (__le32 *)buf);
+		return 0;
+	case SetPortFeature:
+		temp = 1;
+		goto check_port;
+	case ClearPortFeature:
+		temp = 0;
+
+check_port:
+		/* Check the port number */
+		if (wIndex != 1)
+			break;
+
+		switch (wValue) {
+		case USB_PORT_FEAT_POWER:
+			dev_dbg(dev, "%sPortFeature(%u): %s\n",
+				temp ? "Set" : "Clear", wIndex, "POWER");
+
+			if (!hub->set_power)
+				return -EPIPE;
+
+			return hub->set_power(wIndex, temp) ? -EPIPE : 0;
+		case USB_PORT_FEAT_C_OVER_CURRENT:
+			dev_dbg(dev, "%sPortFeature(%u): %s\n",
+				temp ? "Set" : "Clear", wIndex,
+				"C_OVER_CURRENT");
+
+			if (temp)
+				ocic_mask |= 1 << wIndex;
+			else
+				ocic_mask &= ~(1 << wIndex);
+			return 0;
+		}
+	}
+
+	return ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
+}
+
+static const struct hc_driver ohci_da8xx_hc_driver = {
+	.description		= hcd_name,
+	.product_desc		= "DA8xx OHCI",
+	.hcd_priv_size		= sizeof(struct ohci_hcd),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq			= ohci_irq,
+	.flags			= HCD_USB11 | HCD_MEMORY,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset			= ohci_da8xx_init,
+	.start			= ohci_da8xx_start,
+	.stop			= ohci_da8xx_stop,
+	.shutdown		= ohci_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue		= ohci_urb_enqueue,
+	.urb_dequeue		= ohci_urb_dequeue,
+	.endpoint_disable	= ohci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number	= ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data	= ohci_da8xx_hub_status_data,
+	.hub_control		= ohci_da8xx_hub_control,
+
+#ifdef	CONFIG_PM
+	.bus_suspend		= ohci_bus_suspend,
+	.bus_resume		= ohci_bus_resume,
+#endif
+	.start_port_reset	= ohci_start_port_reset,
+};
+
+/*-------------------------------------------------------------------------*/
+
+
+/**
+ * usb_hcd_da8xx_probe - initialize DA8xx-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ */
+static int usb_hcd_da8xx_probe(const struct hc_driver *driver,
+			       struct platform_device *pdev)
+{
+	struct da8xx_ohci_root_hub *hub	= pdev->dev.platform_data;
+	struct usb_hcd	*hcd;
+	struct resource *mem;
+	int error, irq;
+
+	if (hub == NULL)
+		return -ENODEV;
+
+	usb11_clk = clk_get(&pdev->dev, "usb11");
+	if (IS_ERR(usb11_clk))
+		return PTR_ERR(usb11_clk);
+
+	usb20_clk = clk_get(&pdev->dev, "usb20");
+	if (IS_ERR(usb20_clk)) {
+		error = PTR_ERR(usb20_clk);
+		goto err0;
+	}
+
+	hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
+	if (!hcd) {
+		error = -ENOMEM;
+		goto err1;
+	}
+
+	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!mem) {
+		error = -ENODEV;
+		goto err2;
+	}
+	hcd->rsrc_start = mem->start;
+	hcd->rsrc_len = mem->end - mem->start + 1;
+
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		dev_dbg(&pdev->dev, "request_mem_region failed\n");
+		error = -EBUSY;
+		goto err2;
+	}
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		error = -ENOMEM;
+		goto err3;
+	}
+
+	ohci_hcd_init(hcd_to_ohci(hcd));
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		error = -ENODEV;
+		goto err4;
+	}
+	error = usb_add_hcd(hcd, irq, IRQF_DISABLED);
+	if (error)
+		goto err4;
+
+	if (hub->ocic_notify) {
+		error = hub->ocic_notify(ohci_da8xx_ocic_handler);
+		if (!error)
+			return 0;
+	}
+
+	usb_remove_hcd(hcd);
+err4:
+	iounmap(hcd->regs);
+err3:
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err2:
+	usb_put_hcd(hcd);
+err1:
+	clk_put(usb20_clk);
+err0:
+	clk_put(usb11_clk);
+	return error;
+}
+
+/**
+ * usb_hcd_da8xx_remove - shutdown processing for DA8xx-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_da8xx_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ */
+static inline void
+usb_hcd_da8xx_remove(struct usb_hcd *hcd, struct platform_device *pdev)
+{
+	struct da8xx_ohci_root_hub *hub	= pdev->dev.platform_data;
+
+	hub->ocic_notify(NULL);
+	usb_remove_hcd(hcd);
+	iounmap(hcd->regs);
+	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+	clk_put(usb20_clk);
+	clk_put(usb11_clk);
+}
+
+static int ohci_hcd_da8xx_drv_probe(struct platform_device *dev)
+{
+	return usb_hcd_da8xx_probe(&ohci_da8xx_hc_driver, dev);
+}
+
+static int ohci_hcd_da8xx_drv_remove(struct platform_device *dev)
+{
+	struct usb_hcd	*hcd = platform_get_drvdata(dev);
+
+	usb_hcd_da8xx_remove(hcd, dev);
+	platform_set_drvdata(dev, NULL);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+static int ohci_da8xx_suspend(struct platform_device *dev, pm_message_t message)
+{
+	struct usb_hcd	*hcd	= platform_get_drvdata(dev);
+	struct ohci_hcd	*ohci	= hcd_to_ohci(hcd);
+
+	if (time_before(jiffies, ohci->next_statechange))
+		msleep(5);
+	ohci->next_statechange = jiffies;
+
+	ohci_da8xx_clock(0);
+	hcd->state = HC_STATE_SUSPENDED;
+	dev->dev.power.power_state = PMSG_SUSPEND;
+	return 0;
+}
+
+static int ohci_da8xx_resume(struct platform_device *dev)
+{
+	struct usb_hcd	*hcd	= platform_get_drvdata(dev);
+	struct ohci_hcd	*ohci	= hcd_to_ohci(hcd);
+
+	if (time_before(jiffies, ohci->next_statechange))
+		msleep(5);
+	ohci->next_statechange = jiffies;
+
+	ohci_da8xx_clock(1);
+	dev->dev.power.power_state = PMSG_ON;
+	usb_hcd_resume_root_hub(hcd);
+	return 0;
+}
+#endif
+
+/*
+ * Driver definition to register with platform structure.
+ */
+static struct platform_driver ohci_hcd_da8xx_driver = {
+	.probe		= ohci_hcd_da8xx_drv_probe,
+	.remove		= ohci_hcd_da8xx_drv_remove,
+	.shutdown 	= usb_hcd_platform_shutdown,
+#ifdef	CONFIG_PM
+	.suspend	= ohci_da8xx_suspend,
+	.resume		= ohci_da8xx_resume,
+#endif
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "ohci",
+	},
+};

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

@@ -53,13 +53,13 @@ urb_print(struct urb * urb, char * str, int small, int status)
 		int i, len;
 		int i, len;
 
 
 		if (usb_pipecontrol (pipe)) {
 		if (usb_pipecontrol (pipe)) {
-			printk (KERN_DEBUG __FILE__ ": setup(8):");
+			printk (KERN_DEBUG "%s: setup(8):", __FILE__);
 			for (i = 0; i < 8 ; i++)
 			for (i = 0; i < 8 ; i++)
 				printk (" %02x", ((__u8 *) urb->setup_packet) [i]);
 				printk (" %02x", ((__u8 *) urb->setup_packet) [i]);
 			printk ("\n");
 			printk ("\n");
 		}
 		}
 		if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
 		if (urb->transfer_buffer_length > 0 && urb->transfer_buffer) {
-			printk (KERN_DEBUG __FILE__ ": data(%d/%d):",
+			printk (KERN_DEBUG "%s: data(%d/%d):", __FILE__,
 				urb->actual_length,
 				urb->actual_length,
 				urb->transfer_buffer_length);
 				urb->transfer_buffer_length);
 			len = usb_pipeout (pipe)?
 			len = usb_pipeout (pipe)?

+ 5 - 0
drivers/usb/host/ohci-hcd.c

@@ -1051,6 +1051,11 @@ MODULE_LICENSE ("GPL");
 #define PLATFORM_DRIVER		usb_hcd_pnx4008_driver
 #define PLATFORM_DRIVER		usb_hcd_pnx4008_driver
 #endif
 #endif
 
 
+#ifdef CONFIG_ARCH_DAVINCI_DA8XX
+#include "ohci-da8xx.c"
+#define PLATFORM_DRIVER		ohci_hcd_da8xx_driver
+#endif
+
 #if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
 #if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
     defined(CONFIG_CPU_SUBTYPE_SH7721) || \
     defined(CONFIG_CPU_SUBTYPE_SH7721) || \
     defined(CONFIG_CPU_SUBTYPE_SH7763) || \
     defined(CONFIG_CPU_SUBTYPE_SH7763) || \

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

@@ -28,8 +28,8 @@ extern int usb_disabled(void);
 
 
 static void lh7a404_start_hc(struct platform_device *dev)
 static void lh7a404_start_hc(struct platform_device *dev)
 {
 {
-	printk(KERN_DEBUG __FILE__
-	       ": starting LH7A404 OHCI USB Controller\n");
+	printk(KERN_DEBUG "%s: starting LH7A404 OHCI USB Controller\n",
+	       __FILE__);
 
 
 	/*
 	/*
 	 * Now, carefully enable the USB clock, and take
 	 * Now, carefully enable the USB clock, and take
@@ -39,14 +39,13 @@ static void lh7a404_start_hc(struct platform_device *dev)
 	udelay(1000);
 	udelay(1000);
 	USBH_CMDSTATUS = OHCI_HCR;
 	USBH_CMDSTATUS = OHCI_HCR;
 
 
-	printk(KERN_DEBUG __FILE__
-		   ": Clock to USB host has been enabled \n");
+	printk(KERN_DEBUG "%s: Clock to USB host has been enabled \n", __FILE__);
 }
 }
 
 
 static void lh7a404_stop_hc(struct platform_device *dev)
 static void lh7a404_stop_hc(struct platform_device *dev)
 {
 {
-	printk(KERN_DEBUG __FILE__
-	       ": stopping LH7A404 OHCI USB Controller\n");
+	printk(KERN_DEBUG "%s: stopping LH7A404 OHCI USB Controller\n",
+	       __FILE__);
 
 
 	CSC_PWRCNT &= ~CSC_PWRCNT_USBH_EN; /* Disable clock */
 	CSC_PWRCNT &= ~CSC_PWRCNT_USBH_EN; /* Disable clock */
 }
 }

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

@@ -327,7 +327,7 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
 	}
 	}
 	i2c_adap = i2c_get_adapter(2);
 	i2c_adap = i2c_get_adapter(2);
 	memset(&i2c_info, 0, sizeof(struct i2c_board_info));
 	memset(&i2c_info, 0, sizeof(struct i2c_board_info));
-	strlcpy(i2c_info.name, "isp1301_pnx", I2C_NAME_SIZE);
+	strlcpy(i2c_info.type, "isp1301_pnx", I2C_NAME_SIZE);
 	isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
 	isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
 						   normal_i2c);
 						   normal_i2c);
 	i2c_put_adapter(i2c_adap);
 	i2c_put_adapter(i2c_adap);
@@ -411,7 +411,7 @@ out3:
 out2:
 out2:
 	clk_put(usb_clk);
 	clk_put(usb_clk);
 out1:
 out1:
-	i2c_unregister_client(isp1301_i2c_client);
+	i2c_unregister_device(isp1301_i2c_client);
 	isp1301_i2c_client = NULL;
 	isp1301_i2c_client = NULL;
 out_i2c_driver:
 out_i2c_driver:
 	i2c_del_driver(&isp1301_driver);
 	i2c_del_driver(&isp1301_driver);
@@ -430,7 +430,7 @@ static int usb_hcd_pnx4008_remove(struct platform_device *pdev)
 	pnx4008_unset_usb_bits();
 	pnx4008_unset_usb_bits();
 	clk_disable(usb_clk);
 	clk_disable(usb_clk);
 	clk_put(usb_clk);
 	clk_put(usb_clk);
-	i2c_unregister_client(isp1301_i2c_client);
+	i2c_unregister_device(isp1301_i2c_client);
 	isp1301_i2c_client = NULL;
 	isp1301_i2c_client = NULL;
 	i2c_del_driver(&isp1301_driver);
 	i2c_del_driver(&isp1301_driver);
 
 

+ 5 - 5
drivers/usb/host/ohci-ppc-of.c

@@ -114,21 +114,21 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
 	hcd->rsrc_len = res.end - res.start + 1;
 	hcd->rsrc_len = res.end - res.start + 1;
 
 
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		printk(KERN_ERR __FILE__ ": request_mem_region failed\n");
+		printk(KERN_ERR "%s: request_mem_region failed\n", __FILE__);
 		rv = -EBUSY;
 		rv = -EBUSY;
 		goto err_rmr;
 		goto err_rmr;
 	}
 	}
 
 
 	irq = irq_of_parse_and_map(dn, 0);
 	irq = irq_of_parse_and_map(dn, 0);
 	if (irq == NO_IRQ) {
 	if (irq == NO_IRQ) {
-		printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+		printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
 		rv = -EBUSY;
 		rv = -EBUSY;
 		goto err_irq;
 		goto err_irq;
 	}
 	}
 
 
 	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 	if (!hcd->regs) {
 	if (!hcd->regs) {
-		printk(KERN_ERR __FILE__ ": ioremap failed\n");
+		printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
 		rv = -ENOMEM;
 		rv = -ENOMEM;
 		goto err_ioremap;
 		goto err_ioremap;
 	}
 	}
@@ -169,7 +169,7 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
 			} else
 			} else
 				release_mem_region(res.start, 0x4);
 				release_mem_region(res.start, 0x4);
 		} else
 		} else
-		    pr_debug(__FILE__ ": cannot get ehci offset from fdt\n");
+			pr_debug("%s: cannot get ehci offset from fdt\n", __FILE__);
 	}
 	}
 
 
 	iounmap(hcd->regs);
 	iounmap(hcd->regs);
@@ -212,7 +212,7 @@ static int ohci_hcd_ppc_of_shutdown(struct of_device *op)
 }
 }
 
 
 
 
-static struct of_device_id ohci_hcd_ppc_of_match[] = {
+static const struct of_device_id ohci_hcd_ppc_of_match[] = {
 #ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
 #ifdef CONFIG_USB_OHCI_HCD_PPC_OF_BE
 	{
 	{
 		.name = "usb",
 		.name = "usb",

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

@@ -41,14 +41,14 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
 
 
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 	if (!res) {
 	if (!res) {
-		pr_debug(__FILE__ ": no irq\n");
+		pr_debug("%s: no irq\n", __FILE__);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 	irq = res->start;
 	irq = res->start;
 
 
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	if (!res) {
 	if (!res) {
-		pr_debug(__FILE__ ": no reg addr\n");
+		pr_debug("%s: no reg addr\n", __FILE__);
 		return -ENODEV;
 		return -ENODEV;
 	}
 	}
 
 
@@ -59,14 +59,14 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
 	hcd->rsrc_len = res->end - res->start + 1;
 	hcd->rsrc_len = res->end - res->start + 1;
 
 
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
 	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
-		pr_debug(__FILE__ ": request_mem_region failed\n");
+		pr_debug("%s: request_mem_region failed\n", __FILE__);
 		retval = -EBUSY;
 		retval = -EBUSY;
 		goto err1;
 		goto err1;
 	}
 	}
 
 
 	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
 	if (!hcd->regs) {
 	if (!hcd->regs) {
-		pr_debug(__FILE__ ": ioremap failed\n");
+		pr_debug("%s: ioremap failed\n", __FILE__);
 		retval = -ENOMEM;
 		retval = -ENOMEM;
 		goto err2;
 		goto err2;
 	}
 	}

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

@@ -31,8 +31,8 @@ static void sa1111_start_hc(struct sa1111_dev *dev)
 {
 {
 	unsigned int usb_rst = 0;
 	unsigned int usb_rst = 0;
 
 
-	printk(KERN_DEBUG __FILE__
-	       ": starting SA-1111 OHCI USB Controller\n");
+	printk(KERN_DEBUG "%s: starting SA-1111 OHCI USB Controller\n",
+	       __FILE__);
 
 
 #ifdef CONFIG_SA1100_BADGE4
 #ifdef CONFIG_SA1100_BADGE4
 	if (machine_is_badge4()) {
 	if (machine_is_badge4()) {
@@ -65,8 +65,8 @@ static void sa1111_start_hc(struct sa1111_dev *dev)
 static void sa1111_stop_hc(struct sa1111_dev *dev)
 static void sa1111_stop_hc(struct sa1111_dev *dev)
 {
 {
 	unsigned int usb_rst;
 	unsigned int usb_rst;
-	printk(KERN_DEBUG __FILE__
-	       ": stopping SA-1111 OHCI USB Controller\n");
+	printk(KERN_DEBUG "%s: stopping SA-1111 OHCI USB Controller\n",
+	       __FILE__);
 
 
 	/*
 	/*
 	 * Put the USB host controller into reset.
 	 * Put the USB host controller into reset.

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

@@ -51,6 +51,7 @@
 #include <asm/irq.h>
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
 #include <asm/byteorder.h>
+#include <asm/unaligned.h>
 
 
 #include "../core/hcd.h"
 #include "../core/hcd.h"
 #include "sl811.h"
 #include "sl811.h"
@@ -1272,12 +1273,12 @@ sl811h_hub_control(
 		sl811h_hub_descriptor(sl811, (struct usb_hub_descriptor *) buf);
 		sl811h_hub_descriptor(sl811, (struct usb_hub_descriptor *) buf);
 		break;
 		break;
 	case GetHubStatus:
 	case GetHubStatus:
-		*(__le32 *) buf = cpu_to_le32(0);
+		put_unaligned_le32(0, buf);
 		break;
 		break;
 	case GetPortStatus:
 	case GetPortStatus:
 		if (wIndex != 1)
 		if (wIndex != 1)
 			goto error;
 			goto error;
-		*(__le32 *) buf = cpu_to_le32(sl811->port1);
+		put_unaligned_le32(sl811->port1, buf);
 
 
 #ifndef	VERBOSE
 #ifndef	VERBOSE
 	if (*(u16*)(buf+2))	/* only if wPortChange is interesting */
 	if (*(u16*)(buf+2))	/* only if wPortChange is interesting */

+ 1 - 0
drivers/usb/host/uhci-hcd.c

@@ -735,6 +735,7 @@ static void uhci_stop(struct usb_hcd *hcd)
 		uhci_hc_died(uhci);
 		uhci_hc_died(uhci);
 	uhci_scan_schedule(uhci);
 	uhci_scan_schedule(uhci);
 	spin_unlock_irq(&uhci->lock);
 	spin_unlock_irq(&uhci->lock);
+	synchronize_irq(hcd->irq);
 
 
 	del_timer_sync(&uhci->fsbr_timer);
 	del_timer_sync(&uhci->fsbr_timer);
 	release_uhci(uhci);
 	release_uhci(uhci);

+ 19 - 0
drivers/usb/host/xhci-dbg.c

@@ -406,6 +406,25 @@ static void dbg_rsvd64(struct xhci_hcd *xhci, u64 *ctx, dma_addr_t dma)
 	}
 	}
 }
 }
 
 
+char *xhci_get_slot_state(struct xhci_hcd *xhci,
+		struct xhci_container_ctx *ctx)
+{
+	struct xhci_slot_ctx *slot_ctx = xhci_get_slot_ctx(xhci, ctx);
+
+	switch (GET_SLOT_STATE(slot_ctx->dev_state)) {
+	case 0:
+		return "enabled/disabled";
+	case 1:
+		return "default";
+	case 2:
+		return "addressed";
+	case 3:
+		return "configured";
+	default:
+		return "reserved";
+	}
+}
+
 void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx)
 void xhci_dbg_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx)
 {
 {
 	/* Fields are 32 bits wide, DMA addresses are in bytes */
 	/* Fields are 32 bits wide, DMA addresses are in bytes */

+ 5 - 2
drivers/usb/host/xhci-ext-caps.h

@@ -101,12 +101,15 @@ static inline int xhci_find_next_cap_offset(void __iomem *base, int ext_offset)
 
 
 	next = readl(base + ext_offset);
 	next = readl(base + ext_offset);
 
 
-	if (ext_offset == XHCI_HCC_PARAMS_OFFSET)
+	if (ext_offset == XHCI_HCC_PARAMS_OFFSET) {
 		/* Find the first extended capability */
 		/* Find the first extended capability */
 		next = XHCI_HCC_EXT_CAPS(next);
 		next = XHCI_HCC_EXT_CAPS(next);
-	else
+		ext_offset = 0;
+	} else {
 		/* Find the next extended capability */
 		/* Find the next extended capability */
 		next = XHCI_EXT_CAPS_NEXT(next);
 		next = XHCI_EXT_CAPS_NEXT(next);
+	}
+
 	if (!next)
 	if (!next)
 		return 0;
 		return 0;
 	/*
 	/*

+ 130 - 20
drivers/usb/host/xhci-hcd.c

@@ -1007,7 +1007,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
 	 * for usb_set_interface() and usb_set_configuration() claim).
 	 * for usb_set_interface() and usb_set_configuration() claim).
 	 */
 	 */
 	if (xhci_endpoint_init(xhci, xhci->devs[udev->slot_id],
 	if (xhci_endpoint_init(xhci, xhci->devs[udev->slot_id],
-				udev, ep, GFP_KERNEL) < 0) {
+				udev, ep, GFP_NOIO) < 0) {
 		dev_dbg(&udev->dev, "%s - could not initialize ep %#x\n",
 		dev_dbg(&udev->dev, "%s - could not initialize ep %#x\n",
 				__func__, ep->desc.bEndpointAddress);
 				__func__, ep->desc.bEndpointAddress);
 		return -ENOMEM;
 		return -ENOMEM;
@@ -1181,6 +1181,8 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
 		ret = xhci_queue_evaluate_context(xhci, in_ctx->dma,
 		ret = xhci_queue_evaluate_context(xhci, in_ctx->dma,
 				udev->slot_id);
 				udev->slot_id);
 	if (ret < 0) {
 	if (ret < 0) {
+		if (command)
+			list_del(&command->cmd_list);
 		spin_unlock_irqrestore(&xhci->lock, flags);
 		spin_unlock_irqrestore(&xhci->lock, flags);
 		xhci_dbg(xhci, "FIXME allocate a new ring segment\n");
 		xhci_dbg(xhci, "FIXME allocate a new ring segment\n");
 		return -ENOMEM;
 		return -ENOMEM;
@@ -1264,30 +1266,13 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
 	xhci_zero_in_ctx(xhci, virt_dev);
 	xhci_zero_in_ctx(xhci, virt_dev);
 	/* Install new rings and free or cache any old rings */
 	/* Install new rings and free or cache any old rings */
 	for (i = 1; i < 31; ++i) {
 	for (i = 1; i < 31; ++i) {
-		int rings_cached;
-
 		if (!virt_dev->eps[i].new_ring)
 		if (!virt_dev->eps[i].new_ring)
 			continue;
 			continue;
 		/* Only cache or free the old ring if it exists.
 		/* Only cache or free the old ring if it exists.
 		 * It may not if this is the first add of an endpoint.
 		 * It may not if this is the first add of an endpoint.
 		 */
 		 */
 		if (virt_dev->eps[i].ring) {
 		if (virt_dev->eps[i].ring) {
-			rings_cached = virt_dev->num_rings_cached;
-			if (rings_cached < XHCI_MAX_RINGS_CACHED) {
-				virt_dev->num_rings_cached++;
-				rings_cached = virt_dev->num_rings_cached;
-				virt_dev->ring_cache[rings_cached] =
-					virt_dev->eps[i].ring;
-				xhci_dbg(xhci, "Cached old ring, "
-						"%d ring%s cached\n",
-						rings_cached,
-						(rings_cached > 1) ? "s" : "");
-			} else {
-				xhci_ring_free(xhci, virt_dev->eps[i].ring);
-				xhci_dbg(xhci, "Ring cache full (%d rings), "
-						"freeing ring\n",
-						virt_dev->num_rings_cached);
-			}
+			xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
 		}
 		}
 		virt_dev->eps[i].ring = virt_dev->eps[i].new_ring;
 		virt_dev->eps[i].ring = virt_dev->eps[i].new_ring;
 		virt_dev->eps[i].new_ring = NULL;
 		virt_dev->eps[i].new_ring = NULL;
@@ -1457,6 +1442,131 @@ void xhci_endpoint_reset(struct usb_hcd *hcd,
 		xhci_warn(xhci, "FIXME allocate a new ring segment\n");
 		xhci_warn(xhci, "FIXME allocate a new ring segment\n");
 }
 }
 
 
+/*
+ * This submits a Reset Device Command, which will set the device state to 0,
+ * set the device address to 0, and disable all the endpoints except the default
+ * control endpoint.  The USB core should come back and call
+ * xhci_address_device(), and then re-set up the configuration.  If this is
+ * called because of a usb_reset_and_verify_device(), then the old alternate
+ * settings will be re-installed through the normal bandwidth allocation
+ * functions.
+ *
+ * Wait for the Reset Device command to finish.  Remove all structures
+ * associated with the endpoints that were disabled.  Clear the input device
+ * structure?  Cache the rings?  Reset the control endpoint 0 max packet size?
+ */
+int xhci_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
+{
+	int ret, i;
+	unsigned long flags;
+	struct xhci_hcd *xhci;
+	unsigned int slot_id;
+	struct xhci_virt_device *virt_dev;
+	struct xhci_command *reset_device_cmd;
+	int timeleft;
+	int last_freed_endpoint;
+
+	ret = xhci_check_args(hcd, udev, NULL, 0, __func__);
+	if (ret <= 0)
+		return ret;
+	xhci = hcd_to_xhci(hcd);
+	slot_id = udev->slot_id;
+	virt_dev = xhci->devs[slot_id];
+	if (!virt_dev) {
+		xhci_dbg(xhci, "%s called with invalid slot ID %u\n",
+				__func__, slot_id);
+		return -EINVAL;
+	}
+
+	xhci_dbg(xhci, "Resetting device with slot ID %u\n", slot_id);
+	/* Allocate the command structure that holds the struct completion.
+	 * Assume we're in process context, since the normal device reset
+	 * process has to wait for the device anyway.  Storage devices are
+	 * reset as part of error handling, so use GFP_NOIO instead of
+	 * GFP_KERNEL.
+	 */
+	reset_device_cmd = xhci_alloc_command(xhci, false, true, GFP_NOIO);
+	if (!reset_device_cmd) {
+		xhci_dbg(xhci, "Couldn't allocate command structure.\n");
+		return -ENOMEM;
+	}
+
+	/* Attempt to submit the Reset Device command to the command ring */
+	spin_lock_irqsave(&xhci->lock, flags);
+	reset_device_cmd->command_trb = xhci->cmd_ring->enqueue;
+	list_add_tail(&reset_device_cmd->cmd_list, &virt_dev->cmd_list);
+	ret = xhci_queue_reset_device(xhci, slot_id);
+	if (ret) {
+		xhci_dbg(xhci, "FIXME: allocate a command ring segment\n");
+		list_del(&reset_device_cmd->cmd_list);
+		spin_unlock_irqrestore(&xhci->lock, flags);
+		goto command_cleanup;
+	}
+	xhci_ring_cmd_db(xhci);
+	spin_unlock_irqrestore(&xhci->lock, flags);
+
+	/* Wait for the Reset Device command to finish */
+	timeleft = wait_for_completion_interruptible_timeout(
+			reset_device_cmd->completion,
+			USB_CTRL_SET_TIMEOUT);
+	if (timeleft <= 0) {
+		xhci_warn(xhci, "%s while waiting for reset device command\n",
+				timeleft == 0 ? "Timeout" : "Signal");
+		spin_lock_irqsave(&xhci->lock, flags);
+		/* The timeout might have raced with the event ring handler, so
+		 * only delete from the list if the item isn't poisoned.
+		 */
+		if (reset_device_cmd->cmd_list.next != LIST_POISON1)
+			list_del(&reset_device_cmd->cmd_list);
+		spin_unlock_irqrestore(&xhci->lock, flags);
+		ret = -ETIME;
+		goto command_cleanup;
+	}
+
+	/* The Reset Device command can't fail, according to the 0.95/0.96 spec,
+	 * unless we tried to reset a slot ID that wasn't enabled,
+	 * or the device wasn't in the addressed or configured state.
+	 */
+	ret = reset_device_cmd->status;
+	switch (ret) {
+	case COMP_EBADSLT: /* 0.95 completion code for bad slot ID */
+	case COMP_CTX_STATE: /* 0.96 completion code for same thing */
+		xhci_info(xhci, "Can't reset device (slot ID %u) in %s state\n",
+				slot_id,
+				xhci_get_slot_state(xhci, virt_dev->out_ctx));
+		xhci_info(xhci, "Not freeing device rings.\n");
+		/* Don't treat this as an error.  May change my mind later. */
+		ret = 0;
+		goto command_cleanup;
+	case COMP_SUCCESS:
+		xhci_dbg(xhci, "Successful reset device command.\n");
+		break;
+	default:
+		if (xhci_is_vendor_info_code(xhci, ret))
+			break;
+		xhci_warn(xhci, "Unknown completion code %u for "
+				"reset device command.\n", ret);
+		ret = -EINVAL;
+		goto command_cleanup;
+	}
+
+	/* Everything but endpoint 0 is disabled, so free or cache the rings. */
+	last_freed_endpoint = 1;
+	for (i = 1; i < 31; ++i) {
+		if (!virt_dev->eps[i].ring)
+			continue;
+		xhci_free_or_cache_endpoint_ring(xhci, virt_dev, i);
+		last_freed_endpoint = i;
+	}
+	xhci_dbg(xhci, "Output context after successful reset device cmd:\n");
+	xhci_dbg_ctx(xhci, virt_dev->out_ctx, last_freed_endpoint);
+	ret = 0;
+
+command_cleanup:
+	xhci_free_command(xhci, reset_device_cmd);
+	return ret;
+}
+
 /*
 /*
  * At this point, the struct usb_device is about to go away, the device has
  * At this point, the struct usb_device is about to go away, the device has
  * disconnected, and all traffic has been stopped and the endpoints have been
  * disconnected, and all traffic has been stopped and the endpoints have been
@@ -1694,7 +1804,7 @@ int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
 		xhci_warn(xhci, "Cannot update hub desc for unknown device.\n");
 		xhci_warn(xhci, "Cannot update hub desc for unknown device.\n");
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
-	config_cmd = xhci_alloc_command(xhci, true, mem_flags);
+	config_cmd = xhci_alloc_command(xhci, true, true, mem_flags);
 	if (!config_cmd) {
 	if (!config_cmd) {
 		xhci_dbg(xhci, "Could not allocate xHCI command structure.\n");
 		xhci_dbg(xhci, "Could not allocate xHCI command structure.\n");
 		return -ENOMEM;
 		return -ENOMEM;

+ 50 - 15
drivers/usb/host/xhci-hub.c

@@ -129,6 +129,50 @@ static u32 xhci_port_state_to_neutral(u32 state)
 	return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS);
 	return (state & XHCI_PORT_RO) | (state & XHCI_PORT_RWS);
 }
 }
 
 
+static void xhci_disable_port(struct xhci_hcd *xhci, u16 wIndex,
+		u32 __iomem *addr, u32 port_status)
+{
+	/* Write 1 to disable the port */
+	xhci_writel(xhci, port_status | PORT_PE, addr);
+	port_status = xhci_readl(xhci, addr);
+	xhci_dbg(xhci, "disable port, actual port %d status  = 0x%x\n",
+			wIndex, port_status);
+}
+
+static void xhci_clear_port_change_bit(struct xhci_hcd *xhci, u16 wValue,
+		u16 wIndex, u32 __iomem *addr, u32 port_status)
+{
+	char *port_change_bit;
+	u32 status;
+
+	switch (wValue) {
+	case USB_PORT_FEAT_C_RESET:
+		status = PORT_RC;
+		port_change_bit = "reset";
+		break;
+	case USB_PORT_FEAT_C_CONNECTION:
+		status = PORT_CSC;
+		port_change_bit = "connect";
+		break;
+	case USB_PORT_FEAT_C_OVER_CURRENT:
+		status = PORT_OCC;
+		port_change_bit = "over-current";
+		break;
+	case USB_PORT_FEAT_C_ENABLE:
+		status = PORT_PEC;
+		port_change_bit = "enable/disable";
+		break;
+	default:
+		/* Should never happen */
+		return;
+	}
+	/* Change bits are all write 1 to clear */
+	xhci_writel(xhci, port_status | status, addr);
+	port_status = xhci_readl(xhci, addr);
+	xhci_dbg(xhci, "clear port %s change, actual port %d status  = 0x%x\n",
+			port_change_bit, wIndex, port_status);
+}
+
 int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 		u16 wIndex, char *buf, u16 wLength)
 		u16 wIndex, char *buf, u16 wLength)
 {
 {
@@ -138,7 +182,6 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 	u32 temp, status;
 	u32 temp, status;
 	int retval = 0;
 	int retval = 0;
 	u32 __iomem *addr;
 	u32 __iomem *addr;
-	char *port_change_bit;
 
 
 	ports = HCS_MAX_PORTS(xhci->hcs_params1);
 	ports = HCS_MAX_PORTS(xhci->hcs_params1);
 
 
@@ -229,26 +272,18 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
 		temp = xhci_port_state_to_neutral(temp);
 		temp = xhci_port_state_to_neutral(temp);
 		switch (wValue) {
 		switch (wValue) {
 		case USB_PORT_FEAT_C_RESET:
 		case USB_PORT_FEAT_C_RESET:
-			status = PORT_RC;
-			port_change_bit = "reset";
-			break;
 		case USB_PORT_FEAT_C_CONNECTION:
 		case USB_PORT_FEAT_C_CONNECTION:
-			status = PORT_CSC;
-			port_change_bit = "connect";
-			break;
 		case USB_PORT_FEAT_C_OVER_CURRENT:
 		case USB_PORT_FEAT_C_OVER_CURRENT:
-			status = PORT_OCC;
-			port_change_bit = "over-current";
+		case USB_PORT_FEAT_C_ENABLE:
+			xhci_clear_port_change_bit(xhci, wValue, wIndex,
+					addr, temp);
+			break;
+		case USB_PORT_FEAT_ENABLE:
+			xhci_disable_port(xhci, wIndex, addr, temp);
 			break;
 			break;
 		default:
 		default:
 			goto error;
 			goto error;
 		}
 		}
-		/* Change bits are all write 1 to clear */
-		xhci_writel(xhci, temp | status, addr);
-		temp = xhci_readl(xhci, addr);
-		xhci_dbg(xhci, "clear port %s change, actual port %d status  = 0x%x\n",
-				port_change_bit, wIndex, temp);
-		temp = xhci_readl(xhci, addr); /* unblock any posted writes */
 		break;
 		break;
 	default:
 	default:
 error:
 error:

Some files were not shown because too many files changed in this diff