]> bbs.cooldavid.org Git - net-next-2.6.git/commitdiff
Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6
authorLinus Torvalds <torvalds@linux-foundation.org>
Wed, 3 Mar 2010 16:48:58 +0000 (08:48 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 3 Mar 2010 16:48:58 +0000 (08:48 -0800)
* 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
  ...

218 files changed:
Documentation/ABI/testing/sysfs-bus-usb
Documentation/ioctl/ioctl-number.txt
Documentation/networking/00-INDEX
Documentation/networking/cxacru-cf.py [new file with mode: 0644]
Documentation/networking/cxacru.txt
Documentation/usb/error-codes.txt
Documentation/usb/power-management.txt
arch/arm/configs/rx51_defconfig
arch/arm/mach-mx2/devices.c
arch/arm/mach-mx2/devices.h
arch/arm/plat-mxc/include/mach/mx21-usbhost.h [new file with mode: 0644]
arch/avr32/mach-at32ap/at32ap700x.c
drivers/char/tty_buffer.c
drivers/hid/usbhid/hiddev.c
drivers/media/video/dabusb.c
drivers/staging/usbip/vhci_sysfs.c
drivers/usb/Kconfig
drivers/usb/Makefile
drivers/usb/atm/cxacru.c
drivers/usb/atm/usbatm.c
drivers/usb/atm/usbatm.h
drivers/usb/c67x00/c67x00-drv.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-acm.h
drivers/usb/class/cdc-wdm.c
drivers/usb/class/usblp.c
drivers/usb/class/usbtmc.c
drivers/usb/core/Kconfig
drivers/usb/core/devices.c
drivers/usb/core/devio.c
drivers/usb/core/driver.c
drivers/usb/core/file.c
drivers/usb/core/hcd.c
drivers/usb/core/hcd.h
drivers/usb/core/hub.c
drivers/usb/core/message.c
drivers/usb/core/quirks.c
drivers/usb/core/sysfs.c
drivers/usb/core/urb.c
drivers/usb/core/usb.c
drivers/usb/core/usb.h
drivers/usb/early/ehci-dbgp.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/Makefile
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/atmel_usba_udc.c
drivers/usb/gadget/atmel_usba_udc.h
drivers/usb/gadget/epautoconf.c
drivers/usb/gadget/ether.c
drivers/usb/gadget/f_acm.c
drivers/usb/gadget/f_ecm.c
drivers/usb/gadget/f_mass_storage.c
drivers/usb/gadget/f_rndis.c
drivers/usb/gadget/file_storage.c
drivers/usb/gadget/fsl_qe_udc.c
drivers/usb/gadget/gadget_chips.h
drivers/usb/gadget/gmidi.c
drivers/usb/gadget/goku_udc.c
drivers/usb/gadget/inode.c
drivers/usb/gadget/mass_storage.c
drivers/usb/gadget/nokia.c [new file with mode: 0644]
drivers/usb/gadget/printer.c
drivers/usb/gadget/pxa27x_udc.c
drivers/usb/gadget/pxa27x_udc.h
drivers/usb/gadget/s3c-hsotg.c
drivers/usb/gadget/u_ether.c
drivers/usb/gadget/u_ether.h
drivers/usb/gadget/zero.c
drivers/usb/host/Kconfig
drivers/usb/host/Makefile
drivers/usb/host/ehci-atmel.c
drivers/usb/host/ehci-au1xxx.c
drivers/usb/host/ehci-fsl.c
drivers/usb/host/ehci-mxc.c
drivers/usb/host/ehci-omap.c
drivers/usb/host/ehci-orion.c
drivers/usb/host/ehci-ppc-of.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/ehci-xilinx-of.c
drivers/usb/host/fhci-hcd.c
drivers/usb/host/imx21-dbg.c [new file with mode: 0644]
drivers/usb/host/imx21-hcd.c [new file with mode: 0644]
drivers/usb/host/imx21-hcd.h [new file with mode: 0644]
drivers/usb/host/isp1362-hcd.c
drivers/usb/host/isp1760-hcd.c
drivers/usb/host/isp1760-if.c
drivers/usb/host/ohci-da8xx.c [new file with mode: 0644]
drivers/usb/host/ohci-dbg.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-lh7a404.c
drivers/usb/host/ohci-pnx4008.c
drivers/usb/host/ohci-ppc-of.c
drivers/usb/host/ohci-ppc-soc.c
drivers/usb/host/ohci-sa1111.c
drivers/usb/host/sl811-hcd.c
drivers/usb/host/uhci-hcd.c
drivers/usb/host/xhci-dbg.c
drivers/usb/host/xhci-ext-caps.h
drivers/usb/host/xhci-hcd.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-pci.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.h
drivers/usb/image/mdc800.c
drivers/usb/image/microtek.c
drivers/usb/misc/Kconfig
drivers/usb/misc/Makefile
drivers/usb/misc/adutux.c
drivers/usb/misc/appledisplay.c
drivers/usb/misc/berry_charge.c [deleted file]
drivers/usb/misc/cypress_cy7c63.c
drivers/usb/misc/cytherm.c
drivers/usb/misc/emi26.c
drivers/usb/misc/emi62.c
drivers/usb/misc/ftdi-elan.c
drivers/usb/misc/idmouse.c
drivers/usb/misc/iowarrior.c
drivers/usb/misc/isight_firmware.c
drivers/usb/misc/ldusb.c
drivers/usb/misc/legousbtower.c
drivers/usb/misc/rio500.c
drivers/usb/misc/sisusbvga/sisusb.c
drivers/usb/misc/trancevibrator.c
drivers/usb/misc/usblcd.c
drivers/usb/misc/usbled.c
drivers/usb/misc/usbsevseg.c
drivers/usb/misc/usbtest.c
drivers/usb/misc/uss720.c
drivers/usb/misc/vstusb.c [deleted file]
drivers/usb/mon/mon_bin.c
drivers/usb/mon/mon_text.c
drivers/usb/musb/blackfin.c
drivers/usb/musb/cppi_dma.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musb_host.c
drivers/usb/musb/musb_regs.h
drivers/usb/musb/musbhsdma.c
drivers/usb/musb/musbhsdma.h
drivers/usb/musb/omap2430.c
drivers/usb/musb/omap2430.h
drivers/usb/musb/tusb6010.c
drivers/usb/musb/tusb6010_omap.c
drivers/usb/otg/twl4030-usb.c
drivers/usb/serial/Kconfig
drivers/usb/serial/Makefile
drivers/usb/serial/aircable.c
drivers/usb/serial/ark3116.c
drivers/usb/serial/belkin_sa.c
drivers/usb/serial/ch341.c
drivers/usb/serial/cp210x.c
drivers/usb/serial/cyberjack.c
drivers/usb/serial/cypress_m8.c
drivers/usb/serial/digi_acceleport.c
drivers/usb/serial/empeg.c
drivers/usb/serial/ftdi_sio.c
drivers/usb/serial/ftdi_sio.h
drivers/usb/serial/ftdi_sio_ids.h
drivers/usb/serial/funsoft.c
drivers/usb/serial/garmin_gps.c
drivers/usb/serial/generic.c
drivers/usb/serial/hp4x.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_tables.h
drivers/usb/serial/io_ti.c
drivers/usb/serial/ipaq.c
drivers/usb/serial/ipw.c
drivers/usb/serial/ir-usb.c
drivers/usb/serial/iuu_phoenix.c
drivers/usb/serial/keyspan.c
drivers/usb/serial/keyspan.h
drivers/usb/serial/keyspan_pda.c
drivers/usb/serial/kl5kusb105.c
drivers/usb/serial/kobil_sct.c
drivers/usb/serial/mct_u232.c
drivers/usb/serial/mct_u232.h
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.c
drivers/usb/serial/moto_modem.c
drivers/usb/serial/navman.c
drivers/usb/serial/omninet.c
drivers/usb/serial/opticon.c
drivers/usb/serial/option.c
drivers/usb/serial/oti6858.c
drivers/usb/serial/pl2303.c
drivers/usb/serial/qcaux.c [new file with mode: 0644]
drivers/usb/serial/qcserial.c
drivers/usb/serial/siemens_mpi.c
drivers/usb/serial/sierra.c
drivers/usb/serial/spcp8x5.c
drivers/usb/serial/symbolserial.c
drivers/usb/serial/ti_usb_3410_5052.c
drivers/usb/serial/usb-serial.c
drivers/usb/serial/usb_debug.c
drivers/usb/serial/visor.c
drivers/usb/serial/vivopay-serial.c [new file with mode: 0644]
drivers/usb/serial/whiteheat.c
drivers/usb/storage/onetouch.c
drivers/usb/storage/scsiglue.c
drivers/usb/storage/shuttle_usbat.c
drivers/usb/storage/transport.c
drivers/usb/storage/unusual_devs.h
drivers/usb/usb-skeleton.c
drivers/usb/wusbcore/cbaf.c
drivers/usb/wusbcore/devconnect.c
drivers/usb/wusbcore/mmc.c
include/linux/tty_flip.h
include/linux/usb.h
include/linux/usb/Kbuild
include/linux/usb/atmel_usba_udc.h
include/linux/usb/ch9.h
include/linux/usb/musb.h
include/linux/usb/otg.h
include/linux/usb/quirks.h
include/linux/usb/serial.h
include/linux/usb/vstusb.h [deleted file]

index a07c0f366f91827fa869ec4751d3586280aff2d4..a986e9bbba3d2972770f9e2a8196bea6eb119a0f 100644 (file)
@@ -159,3 +159,14 @@ Description:
                device.  This is useful to ensure auto probing won't
                match the driver to the device.  For example:
                # 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
index 35cf64d4436d0731c4365902a31278dee824f17a..35c9b51d20ea850b9ae58f16413e5a7595bcdb45 100644 (file)
@@ -139,7 +139,6 @@ Code  Seq#(hex)     Include File            Comments
 'K'    all     linux/kd.h
 'L'    00-1F   linux/loop.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
                                        <http://linux01.gwdg.de/~alatham/ppdd.html>
 'M'    all     linux/soundcard.h       conflict!
index 50189bf07d5364ee1326c2c8f334b49259152c1a..fe5c099b8fc8884210aecc8ccfca1c642d2beb95 100644 (file)
@@ -32,6 +32,8 @@ cs89x0.txt
        - the Crystal LAN (CS8900/20-based) Ethernet ISA adapter driver
 cxacru.txt
        - Conexant AccessRunner USB ADSL Modem
+cxacru-cf.py
+       - Conexant AccessRunner USB ADSL Modem configuration file parser
 de4x5.txt
        - the Digital EtherWORKS DE4?? and DE5?? PCI Ethernet driver
 decnet.txt
diff --git a/Documentation/networking/cxacru-cf.py b/Documentation/networking/cxacru-cf.py
new file mode 100644 (file)
index 0000000..b41d298
--- /dev/null
@@ -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")
index b074681a963e0a5acf7d1f0849d940ddbda4b696..2cce04457b4d5c52482d5ef212bf09544f07c5eb 100644 (file)
@@ -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
 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/
 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
@@ -15,6 +21,15 @@ several sysfs attribute files for retrieving device statistics:
 * adsl_headend_environment
        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_bits_per_frame
 * downstream_rate (kbps)
@@ -61,6 +76,7 @@ several sysfs attribute files for retrieving device statistics:
 * mac_address
 
 * modulation
+       "" (when not connected)
        "ANSI T1.413"
        "ITU-T G.992.1 (G.DMT)"
        "ITU-T G.992.2 (G.LITE)"
index 9cf83e8c27b8f94208d7ad0ebc4587d82430164d..d83703ea74b21285fbe6fea9eff1d00753eb51e0 100644 (file)
@@ -41,8 +41,8 @@ USB-specific:
 
 -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
                    in the current interface altsetting.
@@ -60,6 +60,8 @@ USB-specific:
 
 -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               *
index 3bf6818c8cf58dd386e03a2c6e085718f58d0004..2790ad48cfc270925120728c79902c61119a3212 100644 (file)
@@ -2,7 +2,7 @@
 
                 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).
 
 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?
@@ -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
 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
 autosuspend there are still problems.  For example, there are
 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_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.
-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_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,
        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_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_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
 reason or another.  For example, the power/level attribute might be
 set to "on", or another interface in the same device might not be
 idle.  This is perfectly normal.  If the reason for failure was that
-the device hasn't been idle for long enough, a delayed workqueue
-routine is automatically set up to carry out the operation when the
-autosuspend idle-delay has expired.
+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
 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
        -----------------------------------
 
+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
 during autosuspend.  For example, there's not much point
 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
 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);
 
-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,
 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
 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
-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
@@ -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
 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
 suspend is underway.  The window for this is short, since system
index 426ae948aefe69020cc2f8e4ede1e0459d51a3a1..193bd334fbbffbfd08c18955107339040980c962 100644 (file)
@@ -445,6 +445,8 @@ CONFIG_IP_NF_FILTER=m
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
+CONFIG_PHONET=y
+# CONFIG_IEEE802154 is not set
 # CONFIG_NET_SCHED 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_OMAP 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_S3C2410 is not set
+# CONFIG_USB_GADGET_S3C_HSOTG 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_AMD5536UDC is not set
 # CONFIG_USB_GADGET_FSL_QE is not set
 # CONFIG_USB_GADGET_CI13XXX is not set
 # CONFIG_USB_GADGET_NET2280 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_DUALSPEED=y
 CONFIG_USB_ZERO=m
 # CONFIG_USB_ZERO_HNPTEST is not set
+# CONFIG_USB_AUDIO is not set
 # CONFIG_USB_ETH is not set
 # CONFIG_USB_GADGETFS is not set
 CONFIG_USB_FILE_STORAGE=m
 # CONFIG_USB_FILE_STORAGE_TEST is not set
+# CONFIG_USB_MASS_STORAGE is not set
 # CONFIG_USB_G_SERIAL is not set
 # CONFIG_USB_MIDI_GADGET is not set
 # CONFIG_USB_G_PRINTER 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
index 3d398ce09b310d15cccb907abe01d35c81282dc6..3956d82b7c4e8a993987dd7a2915ec7f32f8c2d8 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/gpio.h>
+#include <linux/dma-mapping.h>
 
 #include <mach/irqs.h>
 #include <mach/hardware.h>
@@ -292,7 +293,7 @@ struct platform_device mxc_fb_device = {
        .num_resources = ARRAY_SIZE(mxc_fb),
        .resource = mxc_fb,
        .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 = {
-       .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[] = {
@@ -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 = {
-       .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
@@ -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 */
 struct platform_device mxc_otg_udc_device = {
@@ -458,7 +459,7 @@ struct platform_device mxc_otg_udc_device = {
        .id             = -1,
        .dev            = {
                .dma_mask               = &otg_dmamask,
-               .coherent_dma_mask      = 0xffffffffUL,
+               .coherent_dma_mask      = DMA_BIT_MASK(32),
        },
        .resource       = otg_resources,
        .num_resources  = ARRAY_SIZE(otg_resources),
@@ -469,7 +470,7 @@ struct platform_device mxc_otg_host = {
        .name = "mxc-ehci",
        .id = 0,
        .dev = {
-               .coherent_dma_mask = 0xffffffff,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
                .dma_mask = &otg_dmamask,
        },
        .resource = otg_resources,
@@ -478,7 +479,7 @@ struct platform_device mxc_otg_host = {
 
 /* USB host 1 */
 
-static u64 usbh1_dmamask = 0xffffffffUL;
+static u64 usbh1_dmamask = DMA_BIT_MASK(32);
 
 static struct resource mxc_usbh1_resources[] = {
        {
@@ -496,7 +497,7 @@ struct platform_device mxc_usbh1 = {
        .name = "mxc-ehci",
        .id = 1,
        .dev = {
-               .coherent_dma_mask = 0xffffffff,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
                .dma_mask = &usbh1_dmamask,
        },
        .resource = mxc_usbh1_resources,
@@ -504,7 +505,7 @@ struct platform_device mxc_usbh1 = {
 };
 
 /* USB host 2 */
-static u64 usbh2_dmamask = 0xffffffffUL;
+static u64 usbh2_dmamask = DMA_BIT_MASK(32);
 
 static struct resource mxc_usbh2_resources[] = {
        {
@@ -522,7 +523,7 @@ struct platform_device mxc_usbh2 = {
        .name = "mxc-ehci",
        .id = 2,
        .dev = {
-               .coherent_dma_mask = 0xffffffff,
+               .coherent_dma_mask = DMA_BIT_MASK(32),
                .dma_mask = &usbh2_dmamask,
        },
        .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));
 }
+
+#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
+
index 97306aa18f1c5cde57f709e4a4dce9ee5003f0db..f12694b073692f63869e596f3cc2ccaa0d662811 100644 (file)
@@ -26,5 +26,6 @@ extern struct platform_device mxc_usbh2;
 extern struct platform_device mxc_spi_device0;
 extern struct platform_device mxc_spi_device1;
 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_device1;
diff --git a/arch/arm/plat-mxc/include/mach/mx21-usbhost.h b/arch/arm/plat-mxc/include/mach/mx21-usbhost.h
new file mode 100644 (file)
index 0000000..22d0b59
--- /dev/null
@@ -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 */
index b13d1879e51b9f0d961fdff8af8c15b9950dcd0e..3a4bc1a18433ff52ac5ba10565f70abee1b38028 100644 (file)
@@ -1770,10 +1770,13 @@ at32_add_device_usba(unsigned int id, struct usba_platform_data *data)
                                          ARRAY_SIZE(usba0_resource)))
                goto out_free_pdev;
 
-       if (data)
+       if (data) {
                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_inverted = -EINVAL;
+       }
 
        data = &usba_data.pdata;
        data->num_ep = ARRAY_SIZE(at32_usba_ep);
index f27c4d6d956ec7e6501a6990ffd81b736750d478..af8d97715728b4829ec152dcd22b5fa4516e9bbc 100644 (file)
@@ -231,9 +231,10 @@ int tty_buffer_request_room(struct tty_struct *tty, size_t size)
 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
  *     @chars: characters
+ *     @flag: flag value for each character
  *     @size: size
  *
  *     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
  */
 
-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;
        do {
@@ -254,7 +255,7 @@ int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
                if (unlikely(space == 0))
                        break;
                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;
                copied += space;
                chars += space;
@@ -263,7 +264,7 @@ int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars,
        } while (unlikely(size > 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
index 867e08433e4b07557e303033b2ba2cc940a54d12..433602aed4688e07167a074b27480b338b008aa6 100644 (file)
@@ -265,9 +265,10 @@ static int hiddev_release(struct inode * inode, struct file * file)
 static int hiddev_open(struct inode *inode, struct file *file)
 {
        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])
                return -ENODEV;
@@ -313,10 +314,12 @@ static int hiddev_open(struct inode *inode, struct file *file)
                        usbhid_open(hid);
                }
 
+       unlock_kernel();
        return 0;
 bail:
        file->private_data = NULL;
        kfree(list);
+       unlock_kernel();
        return res;
 }
 
index 9b413a35e048e3e96790a98b810a4cb41d282ddd..0f505086774c73b45e94636fb0fc3b2182ccb49e 100644 (file)
@@ -616,10 +616,12 @@ static int dabusb_open (struct inode *inode, struct file *file)
 {
        int devnum = iminor(inode);
        pdabusb_t s;
+       int r;
 
        if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB))
                return -EIO;
 
+       lock_kernel();
        s = &dabusb[devnum - DABUSB_MINOR];
 
        dbg("dabusb_open");
@@ -634,6 +636,7 @@ static int dabusb_open (struct inode *inode, struct file *file)
                msleep_interruptible(500);
 
                if (signal_pending (current)) {
+                       unlock_kernel();
                        return -EAGAIN;
                }
                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) {
                mutex_unlock(&s->mutex);
                dev_err(&s->usbdev->dev, "set_interface failed\n");
+               unlock_kernel();
                return -EINVAL;
        }
        s->opened = 1;
@@ -649,7 +653,9 @@ static int dabusb_open (struct inode *inode, struct file *file)
        file->f_pos = 0;
        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)
index d8992d10d5558def219d59269983e140a97c2cf3..f6e34e03c8e47afd92ad7416e13fd67658f51031 100644 (file)
@@ -144,7 +144,7 @@ static int valid_args(__u32 rhport, enum usb_device_speed speed)
        case USB_SPEED_LOW:
        case USB_SPEED_FULL:
        case USB_SPEED_HIGH:
-       case USB_SPEED_VARIABLE:
+       case USB_SPEED_WIRELESS:
                break;
        default:
                usbip_uerr("speed %d\n", speed);
index 4f5bb5698f5d7b5201ae405a397223e7fb6259da..6a58cb1330c1dc016eeebd89f3ce74cc656d5c76 100644 (file)
@@ -21,6 +21,7 @@ config USB_ARCH_HAS_HCD
        default y if USB_ARCH_HAS_EHCI
        default y if PCMCIA && !M32R                    # sl811_cs
        default y if ARM                                # SL-811
+       default y if BLACKFIN                           # SL-811
        default y if SUPERH                             # r8a66597-hcd
        default PCI
 
@@ -39,6 +40,7 @@ config USB_ARCH_HAS_OHCI
        default y if ARCH_PNX4008 && I2C
        default y if MFD_TC6393XB
        default y if ARCH_W90X900
+       default y if ARCH_DAVINCI_DA8XX
        # PPC:
        default y if STB03xxx
        default y if PPC_MPC52xx
index be3c9b80bc9fb1bfda456f77fc9e83b681ca4dec..80b4008c89baf044c2726b4f0c54cbfb61474bac 100644 (file)
@@ -21,6 +21,7 @@ obj-$(CONFIG_USB_U132_HCD)    += host/
 obj-$(CONFIG_USB_R8A66597_HCD) += host/
 obj-$(CONFIG_USB_HWA_HCD)      += host/
 obj-$(CONFIG_USB_ISP1760_HCD)  += host/
+obj-$(CONFIG_USB_IMX21_HCD)    += host/
 
 obj-$(CONFIG_USB_C67X00_HCD)   += c67x00/
 
index 56802d2e994ba24cd672e6671e56cc49e90ecde1..c89990f5e0183a6c4701c103d5bb16b6182f7a14 100644 (file)
@@ -5,6 +5,7 @@
  *  Copyright (C) 2004 David Woodhouse, Duncan Sands, Roman Kagan
  *  Copyright (C) 2005 Duncan Sands, Roman Kagan (rkagan % mail ! ru)
  *  Copyright (C) 2007 Simon Arlott
+ *  Copyright (C) 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
@@ -43,7 +44,7 @@
 #include "usbatm.h"
 
 #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"
 
 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 CMD_PACKET_SIZE                64      /* Should be maxpacket(ep)? */
+#define CMD_MAX_CONFIG         ((CMD_PACKET_SIZE / 4 - 1) / 2)
 
 /* Addresses */
 #define PLLFCLK_ADDR   0x00350068
@@ -105,6 +107,26 @@ enum cxacru_cm_request {
        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 */
 enum cxacru_cm_status {
        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, \
        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) \
 static ssize_t cxacru_sysfs_show_##_name(struct device *dev, \
        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); \
 } \
 CXACRU__ATTR_INIT(_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_SET_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_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)
 
 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 char *str[] = {
-                       NULL,
+                       "",
                        "ANSI T1.413",
                        "ITU-T G.992.1 (G.DMT)",
                        "ITU-T G.992.2 (G.LITE)"
        };
-       if (unlikely(value >= ARRAY_SIZE(str) || str[value] == NULL))
+       if (unlikely(value >= ARRAY_SIZE(str)))
                return snprintf(buf, PAGE_SIZE, "%u\n", 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,
        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,
        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" };
+       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)))
                return snprintf(buf, PAGE_SIZE, "%u\n", 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,
        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 poll = -1;
        char str_cmd[8];
@@ -328,13 +364,16 @@ static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
                return -EINVAL;
        ret = 0;
 
+       if (instance == NULL)
+               return -ENODEV;
+
        if (mutex_lock_interruptible(&instance->adsl_state_serialize))
                return -ERESTARTSYS;
 
        if (!strcmp(str_cmd, "stop") || !strcmp(str_cmd, "restart")) {
                ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_STOP, NULL, 0, NULL, 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);
 
                        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")) {
                ret = cxacru_cm(instance, CM_REQUEST_CHIP_ADSL_LINE_START, NULL, 0, NULL, 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);
 
                        ret = -EIO;
@@ -407,6 +446,72 @@ static ssize_t cxacru_sysfs_store_adsl_state(struct device *dev,
        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
  * 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_ENVIRONMENT,  u32,  adsl_headend_environment); \
 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);
 
@@ -596,7 +702,7 @@ static int cxacru_cm_get_array(struct cxacru_data *instance, enum cxacru_cm_requ
        len = ret / 4;
        for (offb = 0; offb < len; ) {
                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())
                                usb_err(instance->usbatm, "invalid data length from cm %#x: %d\n",
                                        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 usb_interface *intf = usbatm_instance->usb_intf;
-       /*
-       struct atm_dev *atm_dev = usbatm_instance->atm_dev;
-       */
        int ret;
        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->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)
                cxacru_poll_status(&instance->poll_work.work);
        return 0;
@@ -873,11 +979,9 @@ cleanup:
 
 static void cxacru_upload_firmware(struct cxacru_data *instance,
                                   const struct firmware *fw,
-                                  const struct firmware *bp,
-                                  const struct firmware *cf)
+                                  const struct firmware *bp)
 {
        int ret;
-       int off;
        struct usbatm_data *usbatm = instance->usbatm;
        struct usb_device *usb_dev = usbatm->usb_dev;
        __le16 signature[] = { usb_dev->descriptor.idVendor,
@@ -911,6 +1015,7 @@ static void cxacru_upload_firmware(struct cxacru_data *instance,
        }
 
        /* Firmware */
+       usb_info(usbatm, "loading firmware\n");
        ret = cxacru_fw(usb_dev, FW_WRITE_MEM, 0x2, 0x0, FW_ADDR, fw->data, fw->size);
        if (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 */
        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);
                if (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;
        }
 
+       usb_info(usbatm, "starting device\n");
        if (instance->modem_type->boot_rom_patch) {
                val = cpu_to_le32(BR_ADDR);
                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);
                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,
@@ -1003,7 +1090,7 @@ static int cxacru_find_firmware(struct cxacru_data *instance,
 static int cxacru_heavy_init(struct usbatm_data *usbatm_instance,
                             struct usb_interface *usb_intf)
 {
-       const struct firmware *fw, *bp, *cf;
+       const struct firmware *fw, *bp;
        struct cxacru_data *instance = usbatm_instance->driver_data;
 
        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)
                release_firmware(bp);
        release_firmware(fw);
index fbea8563df1ede695f0ccf7b5dc8d367c6f623dc..9b53e8df464814a05b74fbef822d57554a11ce8e 100644 (file)
@@ -1333,6 +1333,7 @@ void usbatm_usb_disconnect(struct usb_interface *intf)
        if (instance->atm_dev) {
                sysfs_remove_link(&instance->atm_dev->class_dev.kobj, "device");
                atm_dev_deregister(instance->atm_dev);
+               instance->atm_dev = NULL;
        }
 
        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);
 
-       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);
                return -EIO;
        }
index f6f4508a9d425a38314e1b7dd64d3eca88fee417..0863f85fcc2670dc112513968dd4f282efe51ad9 100644 (file)
@@ -204,4 +204,19 @@ struct usbatm_data {
        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_ */
index 5633bc5c8bf23a7bd21b9755886c0731748e6769..029ee4a8a1f33b4b3bf4d28dd4a46723b9fdc72a 100644 (file)
@@ -137,13 +137,13 @@ static int __devinit c67x00_drv_probe(struct platform_device *pdev)
        if (!c67x00)
                return -ENOMEM;
 
-       if (!request_mem_region(res->start, res->end - res->start + 1,
+       if (!request_mem_region(res->start, resource_size(res),
                                pdev->name)) {
                dev_err(&pdev->dev, "Memory region busy\n");
                ret = -EBUSY;
                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) {
                dev_err(&pdev->dev, "Unable to map HPI registers\n");
                ret = -EIO;
@@ -182,7 +182,7 @@ static int __devinit c67x00_drv_probe(struct platform_device *pdev)
  request_irq_failed:
        iounmap(c67x00->hpi.base);
  map_failed:
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
  request_mem_failed:
        kfree(c67x00);
 
@@ -208,7 +208,7 @@ static int __devexit c67x00_drv_remove(struct platform_device *pdev)
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (res)
-               release_mem_region(res->start, res->end - res->start + 1);
+               release_mem_region(res->start, resource_size(res));
 
        kfree(c67x00);
 
index 34d4eb98829e0db97271e6e6e5f5adc6bffe3e33..975d556b47874e5148b1520ff5bb5cc6a8c072bc 100644 (file)
@@ -170,6 +170,7 @@ static void acm_write_done(struct acm *acm, struct acm_wb *wb)
 {
        wb->use = 0;
        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);
+       usb_autopm_get_interface_async(acm->control);
        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);
                return 0;       /* A white lie */
        }
@@ -424,7 +428,6 @@ next_buffer:
                throttled = acm->throttle;
                spin_unlock_irqrestore(&acm->throttle_lock, flags);
                if (!throttled) {
-                       tty_buffer_request_room(tty, buf->size);
                        tty_insert_flip_string(tty, buf->base, buf->size);
                        tty_flip_buffer_push(tty);
                } else {
@@ -534,23 +537,6 @@ static void acm_softint(struct work_struct *work)
        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
  */
@@ -566,7 +552,7 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
 
        acm = acm_table[tty->index];
        if (!acm || !acm->dev)
-               goto err_out;
+               goto out;
        else
                rv = 0;
 
@@ -582,8 +568,9 @@ static int acm_tty_open(struct tty_struct *tty, struct file *filp)
 
        mutex_lock(&acm->mutex);
        if (acm->port.count++) {
+               mutex_unlock(&acm->mutex);
                usb_autopm_put_interface(acm->control);
-               goto done;
+               goto out;
        }
 
        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);
        rv = tty_port_block_til_ready(&acm->port, tty, filp);
        tasklet_schedule(&acm->urb_task);
-done:
+
        mutex_unlock(&acm->mutex);
-err_out:
+out:
        mutex_unlock(&open_mutex);
        return rv;
 
 full_bailout:
        usb_kill_urb(acm->ctrlurb);
 bail_out:
-       usb_autopm_put_interface(acm->control);
        acm->port.count--;
        mutex_unlock(&acm->mutex);
+       usb_autopm_put_interface(acm->control);
 early_bail:
        mutex_unlock(&open_mutex);
        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:
                        call_management_function = buffer[3];
                        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");
                        break;
                default:
@@ -1178,7 +1165,6 @@ made_compressed_probe:
        acm->urb_task.func = acm_rx_tasklet;
        acm->urb_task.data = (unsigned long) acm;
        INIT_WORK(&acm->work, acm_softint);
-       INIT_WORK(&acm->waker, acm_waker);
        init_waitqueue_head(&acm->drain_wait);
        spin_lock_init(&acm->throttle_lock);
        spin_lock_init(&acm->write_lock);
@@ -1343,7 +1329,6 @@ static void stop_data_traffic(struct acm *acm)
        tasklet_enable(&acm->urb_task);
 
        cancel_work_sync(&acm->work);
-       cancel_work_sync(&acm->waker);
 }
 
 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)
 {
        struct acm *acm = usb_get_intfdata(intf);
+       struct acm_wb *wb;
        int rv = 0;
        int cnt;
 
@@ -1449,6 +1435,21 @@ static int acm_resume(struct usb_interface *intf)
        mutex_lock(&acm->mutex);
        if (acm->port.count) {
                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)
                        goto err_out;
 
@@ -1460,6 +1461,23 @@ err_out:
        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 */
 
 #define NOKIA_PCSUITE_ACM_INFO(x) \
@@ -1471,7 +1489,7 @@ err_out:
  * USB driver structure.
  */
 
-static struct usb_device_id acm_ids[] = {
+static const struct usb_device_id acm_ids[] = {
        /* quirky and broken devices */
        { USB_DEVICE(0x0870, 0x0001), /* Metricom GS Modem */
        .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! */
 
+       /* Support Lego NXT using pbLua firmware */
+       { USB_DEVICE(0x0694, 0xff00),
+       .driver_info = NOT_A_MODEM,
+               },
+
        /* control interfaces with various AT-command sets */
        { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
                USB_CDC_ACM_PROTO_AT_V25TER) },
@@ -1602,6 +1625,7 @@ static struct usb_driver acm_driver = {
 #ifdef CONFIG_PM
        .suspend =      acm_suspend,
        .resume =       acm_resume,
+       .reset_resume = acm_reset_resume,
 #endif
        .id_table =     acm_ids,
 #ifdef CONFIG_PM
index c4a0ee8ffccfb3ae4203c8cac4d091d88177b478..4a8e87ec6ce9de397882907827828de329851a09 100644 (file)
@@ -112,7 +112,6 @@ struct acm {
        struct mutex mutex;
        struct usb_cdc_line_coding line;                /* bits, stop, parity */
        struct work_struct work;                        /* work queue entry for line discipline waking up */
-       struct work_struct waker;
        wait_queue_head_t drain_wait;                   /* close processing */
        struct tasklet_struct urb_task;                 /* rx processing */
        spinlock_t throttle_lock;                       /* synchronize throtteling and read callback */
@@ -137,3 +136,4 @@ struct acm {
 #define NO_UNION_NORMAL                        1
 #define SINGLE_RX_URB                  2
 #define NO_CAP_LINE                    4
+#define NOT_A_MODEM                    8
index 3e564bfe17d16b8673f26bdd32fc4da64e201fdc..18aafcb08fc8be08536a4ff3caf75859bc003116 100644 (file)
@@ -31,7 +31,7 @@
 #define DRIVER_AUTHOR "Oliver Neukum"
 #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 |
                                 USB_DEVICE_ID_MATCH_INT_SUBCLASS,
index 9bc112ee7803a350f1d83dcc010545a4707469b9..93b5f85d7cebda8f1dcae4e248ab9f3f8adc2285 100644 (file)
@@ -163,7 +163,6 @@ struct usblp {
        unsigned char           used;                   /* True if open */
        unsigned char           present;                /* True if not disconnected */
        unsigned char           bidir;                  /* interface is bidirectional */
-       unsigned char           sleeping;               /* interface is suspended */
        unsigned char           no_paper;               /* Paper Out happened */
        unsigned char           *device_id_string;      /* IEEE 1284 DEVICE ID string (ptr) */
                                                        /* first 2 bytes are (big-endian) length */
@@ -191,7 +190,6 @@ static void usblp_dump(struct usblp *usblp) {
        dbg("quirks=%d", usblp->quirks);
        dbg("used=%d", usblp->used);
        dbg("bidir=%d", usblp->bidir);
-       dbg("sleeping=%d", usblp->sleeping);
        dbg("device_id_string=\"%s\"",
                usblp->device_id_string ?
                        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)
 {
-       if (usblp->bidir && usblp->used && !usblp->sleeping) {
+       if (usblp->bidir && usblp->used) {
                if (usblp_submit_read(usblp) < 0)
                        return -EIO;
        }
@@ -503,11 +501,6 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                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),
                _IOC_NR(cmd), _IOC_SIZE(cmd), _IOC_DIR(cmd) );
 
@@ -914,8 +907,6 @@ static int usblp_wtest(struct usblp *usblp, int nonblock)
                return 0;
        }
        spin_unlock_irqrestore(&usblp->lock, flags);
-       if (usblp->sleeping)
-               return -ENODEV;
        if (nonblock)
                return -EAGAIN;
        return 1;
@@ -968,8 +959,6 @@ static int usblp_rtest(struct usblp *usblp, int nonblock)
                return 0;
        }
        spin_unlock_irqrestore(&usblp->lock, flags);
-       if (usblp->sleeping)
-               return -ENODEV;
        if (nonblock)
                return -EAGAIN;
        return 1;
@@ -1377,12 +1366,10 @@ static void usblp_disconnect(struct usb_interface *intf)
        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);
 
-       /* we take no more IO */
-       usblp->sleeping = 1;
        usblp_unlink_urbs(usblp);
 #if 0 /* XXX Do we want this? What if someone is reading, should we fail? */
        /* not strictly necessary, but just in case */
@@ -1393,18 +1380,17 @@ static int usblp_suspend (struct usb_interface *intf, pm_message_t message)
        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);
        int r;
 
-       usblp->sleeping = 0;
        r = handle_bidir (usblp);
 
        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, 2) },
        { USB_DEVICE_INFO(7, 1, 3) },
index 7c5f4e32c9202b9f7ac0b0b95c92fc5a3343f482..8588c0937a89ea948dd8d839af7902e815e7d02e 100644 (file)
@@ -48,7 +48,7 @@
  */
 #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, 1), },
        { 0, } /* terminating entry */
index ad925946f869ea1ed435851b1efebd0cf7d200b4..97a819c23ef365a8d52dd63c13d7c94891d5f54d 100644 (file)
@@ -91,8 +91,8 @@ config USB_DYNAMIC_MINORS
          If you are unsure about this, say N here.
 
 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
          If you say Y here, you can use driver calls or the sysfs
          "power/level" file to suspend or resume individual USB
index 355dffcc23b0f33a341e53d8b27218b175f7e221..c83c975152a6ae7f2e3fe09d275d4946c6c67ffb 100644 (file)
@@ -118,6 +118,7 @@ static const char *format_endpt =
  */
 
 static DECLARE_WAIT_QUEUE_HEAD(deviceconndiscwq);
+/* guarded by usbfs_mutex */
 static unsigned int conndiscevcnt;
 
 /* 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)
 {
+       mutex_lock(&usbfs_mutex);
        conndiscevcnt++;
+       mutex_unlock(&usbfs_mutex);
        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,
                                    struct poll_table_struct *wait)
 {
-       struct usb_device_status *st = file->private_data;
+       struct usb_device_status *st;
        unsigned int mask = 0;
 
-       lock_kernel();
+       mutex_lock(&usbfs_mutex);
+       st = file->private_data;
        if (!st) {
                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) {
-                       unlock_kernel();
+                       mutex_unlock(&usbfs_mutex);
                        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;
                file->private_data = st;
                mask = POLLIN;
        }
-lost_race:
+
        if (file->f_mode & FMODE_READ)
                poll_wait(file, &deviceconndiscwq, wait);
        if (st->lastev != conndiscevcnt)
                mask |= POLLIN;
        st->lastev = conndiscevcnt;
-       unlock_kernel();
+       mutex_unlock(&usbfs_mutex);
        return mask;
 }
 
@@ -685,7 +675,7 @@ static loff_t usb_device_lseek(struct file *file, loff_t offset, int orig)
 {
        loff_t ret;
 
-       lock_kernel();
+       mutex_lock(&file->f_dentry->d_inode->i_mutex);
 
        switch (orig) {
        case 0:
@@ -701,7 +691,7 @@ static loff_t usb_device_lseek(struct file *file, loff_t offset, int orig)
                ret = -EINVAL;
        }
 
-       unlock_kernel();
+       mutex_unlock(&file->f_dentry->d_inode->i_mutex);
        return ret;
 }
 
index a678186f218fa84dc8b5fadcb8b196ff54898b06..e909ff7b9094051c1ea1812d1252718d96ba23cc 100644 (file)
@@ -122,7 +122,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
 {
        loff_t ret;
 
-       lock_kernel();
+       mutex_lock(&file->f_dentry->d_inode->i_mutex);
 
        switch (orig) {
        case 0:
@@ -138,7 +138,7 @@ static loff_t usbdev_lseek(struct file *file, loff_t offset, int orig)
                ret = -EINVAL;
        }
 
-       unlock_kernel();
+       mutex_unlock(&file->f_dentry->d_inode->i_mutex);
        return ret;
 }
 
@@ -310,7 +310,8 @@ static struct async *async_getpending(struct dev_state *ps,
 
 static void snoop_urb(struct usb_device *udev,
                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 *dirs[] = {"out", "in"};
@@ -344,6 +345,11 @@ static void snoop_urb(struct usb_device *udev,
                                        "status %d\n",
                                        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
@@ -410,7 +416,9 @@ static void async_completed(struct urb *urb)
        }
        snoop(&urb->dev->dev, "urb complete\n");
        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 &&
                        as->status != -ENOENT)
                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();
        int ret;
 
-       lock_kernel();
-       /* Protect against simultaneous removal or release */
-       mutex_lock(&usbfs_mutex);
-
        ret = -ENOMEM;
        ps = kmalloc(sizeof(struct dev_state), GFP_KERNEL);
        if (!ps)
-               goto out;
+               goto out_free_ps;
 
        ret = -ENODEV;
 
+       /* Protect against simultaneous removal or release */
+       mutex_lock(&usbfs_mutex);
+
        /* usbdev device-node */
        if (imajor(inode) == USB_DEVICE_MAJOR)
                dev = usbdev_lookup_by_devt(inode->i_rdev);
+
 #ifdef CONFIG_USB_DEVICEFS
        /* procfs file */
        if (!dev) {
@@ -678,13 +686,19 @@ static int usbdev_open(struct inode *inode, struct file *file)
                        dev = NULL;
        }
 #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);
        if (ret)
-               goto out;
+               goto out_unlock_device;
 
-       ret = 0;
        ps->dev = dev;
        ps->file = file;
        spin_lock_init(&ps->lock);
@@ -702,15 +716,16 @@ static int usbdev_open(struct inode *inode, struct file *file)
        smp_wmb();
        list_add_tail(&ps->list, &dev->filelist);
        file->private_data = ps;
+       usb_unlock_device(dev);
        snoop(&dev->dev, "opened by process %d: %s\n", task_pid_nr(current),
                        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;
 }
 
@@ -724,10 +739,7 @@ static int usbdev_release(struct inode *inode, struct file *file)
        usb_lock_device(dev);
        usb_hub_release_all_ports(dev, ps);
 
-       /* Protect against simultaneous open */
-       mutex_lock(&usbfs_mutex);
        list_del_init(&ps->list);
-       mutex_unlock(&usbfs_mutex);
 
        for (ifnum = 0; ps->ifclaimed && ifnum < 8*sizeof(ps->ifclaimed);
                        ifnum++) {
@@ -770,6 +782,13 @@ static int proc_control(struct dev_state *ps, void __user *arg)
        if (!tbuf)
                return -ENOMEM;
        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.wLength && !access_ok(VERIFY_WRITE, ctrl.data,
                                               ctrl.wLength)) {
@@ -777,15 +796,15 @@ static int proc_control(struct dev_state *ps, void __user *arg)
                        return -EINVAL;
                }
                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);
                i = usb_control_msg(dev, pipe, ctrl.bRequest,
                                    ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
                                    tbuf, ctrl.wLength, tmo);
                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 (copy_to_user(ctrl.data, tbuf, i)) {
                                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);
-               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);
                i = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), ctrl.bRequest,
                                    ctrl.bRequestType, ctrl.wValue, ctrl.wIndex,
                                    tbuf, ctrl.wLength, tmo);
                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);
        if (i < 0 && i != -EPIPE) {
@@ -853,12 +873,12 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
                        kfree(tbuf);
                        return -EINVAL;
                }
-               snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT);
+               snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0);
 
                usb_unlock_device(dev);
                i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
                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 (copy_to_user(bulk.data, tbuf, len2)) {
@@ -873,12 +893,12 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
                                return -EFAULT;
                        }
                }
-               snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT);
+               snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, tbuf, len1);
 
                usb_unlock_device(dev);
                i = usb_bulk_msg(dev, pipe, tbuf, len1, &len2, tmo);
                usb_lock_device(dev);
-               snoop_urb(dev, NULL, pipe, len2, i, COMPLETE);
+               snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, NULL, 0);
        }
        kfree(tbuf);
        if (i < 0)
@@ -1097,6 +1117,13 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                        is_in = 0;
                        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;
 
        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_ISOC:
                        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;
                if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
                        return -EINVAL;
                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:
                /* arbitrary limit */
                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;
                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:
                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,
-                       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);
 
        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,
                           "usbfs: usb_submit_urb returned %d\n", ret);
                snoop_urb(ps->dev, as->userurb, as->urb->pipe,
-                               0, ret, COMPLETE);
+                               0, ret, COMPLETE, NULL, 0);
                async_removepending(as);
                free_async(as);
                return ret;
@@ -1628,7 +1661,10 @@ static int proc_ioctl(struct dev_state *ps, struct usbdevfs_ioctl *ctl)
                if (driver == NULL || driver->ioctl == NULL) {
                        retval = -ENOTTY;
                } else {
+                       /* keep API that guarantees BKL */
+                       lock_kernel();
                        retval = driver->ioctl(intf, ctl->ioctl_code, buf);
+                       unlock_kernel();
                        if (retval == -ENOIOCTLCMD)
                                retval = -ENOTTY;
                }
@@ -1711,6 +1747,7 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
 
        if (!(file->f_mode & FMODE_WRITE))
                return -EPERM;
+
        usb_lock_device(dev);
        if (!connected(ps)) {
                usb_unlock_device(dev);
@@ -1877,9 +1914,7 @@ static long usbdev_ioctl(struct file *file, unsigned int cmd,
 {
        int ret;
 
-       lock_kernel();
        ret = usbdev_do_ioctl(file, cmd, (void __user *)arg);
-       unlock_kernel();
 
        return ret;
 }
@@ -1890,9 +1925,7 @@ static long usbdev_compat_ioctl(struct file *file, unsigned int cmd,
 {
        int ret;
 
-       lock_kernel();
        ret = usbdev_do_ioctl(file, cmd, compat_ptr(arg));
-       unlock_kernel();
 
        return ret;
 }
index f2f055eb6831d73dc006b7e3f54e1e954437c6f4..a7037bf81688df84e47db4f9289841bb918aed86 100644 (file)
@@ -25,7 +25,7 @@
 #include <linux/device.h>
 #include <linux/usb.h>
 #include <linux/usb/quirks.h>
-#include <linux/workqueue.h>
+#include <linux/pm_runtime.h>
 #include "hcd.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 *udev = to_usb_device(dev);
-       int error = -ENODEV;
+       int error = 0;
 
        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
         * 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;
 }
 
 /* called from driver core with dev locked */
 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);
 
-       udriver->disconnect(to_usb_device(dev));
+       udriver->disconnect(udev);
+       if (!udriver->supports_autosuspend)
+               usb_autosuspend_device(udev);
        return 0;
 }
 
@@ -274,60 +279,62 @@ static int usb_probe_interface(struct device *dev)
        intf->needs_binding = 0;
 
        if (usb_device_is_owned(udev))
-               return -ENODEV;
+               return error;
 
        if (udev->authorized == 0) {
                dev_err(&intf->dev, "Device is not authorized for usage\n");
-               return -ENODEV;
+               return error;
        }
 
        id = usb_match_id(intf, driver->id_table);
        if (!id)
                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;
-
-               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;
 
-err:
-       mark_quiesced(intf);
+ err:
        intf->needs_remote_wakeup = 0;
        intf->condition = USB_INTERFACE_UNBOUND;
        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);
        return error;
 }
@@ -377,9 +384,17 @@ static int usb_unbind_interface(struct device *dev)
        usb_set_intfdata(intf, NULL);
 
        intf->condition = USB_INTERFACE_UNBOUND;
-       mark_quiesced(intf);
        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)
                usb_autosuspend_device(udev);
 
@@ -410,7 +425,6 @@ int usb_driver_claim_interface(struct usb_driver *driver,
                                struct usb_interface *iface, void *priv)
 {
        struct device *dev = &iface->dev;
-       struct usb_device *udev = interface_to_usbdev(iface);
        int retval = 0;
 
        if (dev->driver)
@@ -420,11 +434,16 @@ int usb_driver_claim_interface(struct usb_driver *driver,
        usb_set_intfdata(iface, priv);
        iface->needs_binding = 0;
 
-       usb_pm_lock(udev);
        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
         * 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;
 
-       /* driver is often null here; dev_dbg() would oops */
-       pr_debug("usb %s: uevent\n", dev_name(dev));
-
        if (is_usb_device(dev)) {
                usb_dev = to_usb_device(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) {
+               /* driver is often null here; dev_dbg() would oops */
                pr_debug("usb %s: already deleted?\n", dev_name(dev));
                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)
 {
        struct usb_device_driver        *udriver;
@@ -1007,7 +1023,6 @@ static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
        return status;
 }
 
-/* Caller has locked udev's pm_mutex */
 static int usb_resume_device(struct usb_device *udev, pm_message_t msg)
 {
        struct usb_device_driver        *udriver;
@@ -1041,27 +1056,20 @@ static int usb_resume_device(struct usb_device *udev, pm_message_t msg)
        return status;
 }
 
-/* Caller has locked intf's usb_device's pm mutex */
 static int usb_suspend_interface(struct usb_device *udev,
                struct usb_interface *intf, pm_message_t msg)
 {
        struct usb_driver       *driver;
        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;
        driver = to_usb_driver(intf->dev.driver);
 
        if (driver->suspend) {
                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",
                                        "suspend", status);
        } else {
@@ -1069,7 +1077,6 @@ static int usb_suspend_interface(struct usb_device *udev,
                intf->needs_binding = 1;
                dev_warn(&intf->dev, "no %s for driver %s?\n",
                                "suspend", driver->name);
-               mark_quiesced(intf);
        }
 
  done:
@@ -1077,14 +1084,13 @@ static int usb_suspend_interface(struct usb_device *udev,
        return status;
 }
 
-/* Caller has locked intf's usb_device's pm_mutex */
 static int usb_resume_interface(struct usb_device *udev,
                struct usb_interface *intf, pm_message_t msg, int reset_resume)
 {
        struct usb_driver       *driver;
        int                     status = 0;
 
-       if (udev->state == USB_STATE_NOTATTACHED || is_active(intf))
+       if (udev->state == USB_STATE_NOTATTACHED)
                goto done;
 
        /* Don't let autoresume interfere with unbinding */
@@ -1135,90 +1141,11 @@ static int usb_resume_interface(struct usb_device *udev,
 
 done:
        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 */
        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
  * @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
  * 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.
  */
@@ -1259,20 +1171,11 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
        int                     status = 0;
        int                     i = 0;
        struct usb_interface    *intf;
-       struct usb_device       *parent = udev->parent;
 
        if (udev->state == USB_STATE_NOTATTACHED ||
                        udev->state == USB_STATE_SUSPENDED)
                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 */
        if (udev->actconfig) {
                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 (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) {
                        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 {
-               cancel_delayed_work(&udev->autosuspend);
                udev->can_submit = 0;
                for (i = 0; i < 16; ++i) {
                        usb_hcd_flush_endpoint(udev, udev->ep_out[i]);
                        usb_hcd_flush_endpoint(udev, udev->ep_in[i]);
                }
-
-               /* If this is just a FREEZE or a PRETHAW, udev might
-                * not really be suspended.  Only true suspends get
-                * propagated up the device tree.
-                */
-               if (parent && udev->state == USB_STATE_SUSPENDED)
-                       usb_autosuspend_device(parent);
        }
 
  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 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.
  */
@@ -1357,48 +1235,18 @@ static int usb_resume_both(struct usb_device *udev, pm_message_t msg)
        int                     status = 0;
        int                     i;
        struct usb_interface    *intf;
-       struct usb_device       *parent = udev->parent;
 
-       cancel_delayed_work(&udev->autosuspend);
        if (udev->state == USB_STATE_NOTATTACHED) {
                status = -ENODEV;
                goto done;
        }
        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);
 
+       /* Resume the interfaces */
        if (status == 0 && udev->actconfig) {
                for (i = 0; i < udev->actconfig->desc.bNumInterfaces; 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;
 }
 
-#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;
-       } 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;
 }
 
-/* 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
@@ -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'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.
  */
@@ -1488,9 +1371,11 @@ void usb_autosuspend_device(struct usb_device *udev)
 {
        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
  * 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.
  */
 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
  * 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.
  *
  * @udev's usage counter is incremented to prevent subsequent autosuspends.
  * 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.
  */
@@ -1536,42 +1425,14 @@ int usb_autoresume_device(struct usb_device *udev)
 {
        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;
 }
 
@@ -1585,34 +1446,25 @@ static int usb_autopm_do_interface(struct usb_interface *intf,
  * closed.
  *
  * 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
  * 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.
  */
 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);
 
@@ -1620,11 +1472,11 @@ EXPORT_SYMBOL_GPL(usb_autopm_put_interface);
  * usb_autopm_put_interface_async - decrement a USB interface's PM-usage counter
  * @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
  * 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)
 {
        struct usb_device       *udev = interface_to_usbdev(intf);
+       unsigned long           last_busy;
        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(
-                                               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);
 
+/**
+ * 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
  * @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
  * 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.
  */
@@ -1693,9 +1558,16 @@ int usb_autopm_get_interface(struct usb_interface *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));
+       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;
 }
 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
  *
  * 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.
  */
 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);
-               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;
 }
 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 = {
        .name =         "usb",
        .match =        usb_device_match,
        .uevent =       usb_uevent,
+       .pm =           &usb_bus_pm_ops,
 };
index bfc6c2eea6471d87bdf77455e4e4d8ca3e160ca1..c3536f151f029674bfd49d33a093a30069ce8904 100644 (file)
@@ -34,7 +34,6 @@ static int usb_open(struct inode * inode, struct file * file)
        int err = -ENODEV;
        const struct file_operations *old_fops, *new_fops = NULL;
 
-       lock_kernel();
        down_read(&minor_rwsem);
        c = usb_minors[minor];
 
@@ -53,7 +52,6 @@ static int usb_open(struct inode * inode, struct file * file)
        fops_put(old_fops);
  done:
        up_read(&minor_rwsem);
-       unlock_kernel();
        return err;
 }
 
index 80995ef0868c17e553dd6575a951b71973df27f1..2f8cedda8007592f8b480eb44a90f04f76d03403 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/platform_device.h>
 #include <linux/workqueue.h>
 #include <linux/mutex.h>
+#include <linux/pm_runtime.h>
 
 #include <linux/usb.h>
 
@@ -141,7 +142,7 @@ static const u8 usb3_rh_dev_descriptor[18] = {
        0x09,       /*  __u8  bMaxPacketSize0; 2^9 = 512 Bytes */
 
        0x6b, 0x1d, /*  __le16 idVendor; Linux Foundation */
-       0x02, 0x00, /*  __le16 idProduct; device 0x0002 */
+       0x03, 0x00, /*  __le16 idProduct; device 0x0003 */
        KERNEL_VER, KERNEL_REL, /*  __le16 bcdDevice */
 
        0x03,       /*  __u8  iManufacturer; */
@@ -1670,11 +1671,16 @@ int usb_hcd_alloc_bandwidth(struct usb_device *udev,
                        }
                }
                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 */
-                       alt = usb_find_alt_setting(new_config, i, 0);
+                       alt = usb_find_alt_setting(new_config, iface_num, 0);
                        if (!alt)
                                /* 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++) {
                                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;
 }
 
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_USB_SUSPEND
+
 /* Workqueue routine for root-hub remote wakeup */
 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;
 
        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);
 }
 
@@ -1880,12 +1889,12 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
 
        spin_lock_irqsave (&hcd_root_hub_lock, flags);
        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);
 }
 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);
        hcd->rh_timer.function = rh_timer_func;
        hcd->rh_timer.data = (unsigned long) hcd;
-#ifdef CONFIG_PM
+#ifdef CONFIG_USB_SUSPEND
        INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
 #endif
        mutex_init(&hcd->bandwidth_mutex);
@@ -2230,7 +2239,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
        hcd->rh_registered = 0;
        spin_unlock_irq (&hcd_root_hub_lock);
 
-#ifdef CONFIG_PM
+#ifdef CONFIG_USB_SUSPEND
        cancel_work_sync(&hcd->wakeup_work);
 #endif
 
index bbe2b924aae8d168f4876fff4debb7e0e1d3c96b..a3cdb09734abc52bc7cf9c10fcc44a787c38c5d3 100644 (file)
@@ -80,7 +80,7 @@ struct usb_hcd {
 
        struct timer_list       rh_timer;       /* drives root-hub polling */
        struct urb              *status_urb;    /* the current status urb */
-#ifdef CONFIG_PM
+#ifdef CONFIG_USB_SUSPEND
        struct work_struct      wakeup_work;    /* for remote wakeup */
 #endif
 
@@ -248,7 +248,7 @@ struct hc_driver {
        /* xHCI specific functions */
                /* Called by usb_alloc_dev to alloc HC device structures */
        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 *);
 
        /* Bandwidth computation functions */
@@ -286,6 +286,7 @@ struct hc_driver {
                 */
        int     (*update_hub_device)(struct usb_hcd *, struct usb_device *hdev,
                        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);
@@ -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))
 
 #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 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);
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_USB_SUSPEND
+extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);
 #else
 static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
 {
        return;
 }
-#endif /* CONFIG_PM */
+#endif /* CONFIG_USB_SUSPEND */
+
 
 /*
  * USB device fs stuff
index 20ecb4cec8de56540f507d459c205b51151da148..0940ccd6f4f4fbebb8ba9bccb67dd453a7b0e990 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/kthread.h>
 #include <linux/mutex.h>
 #include <linux/freezer.h>
+#include <linux/pm_runtime.h>
 
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
@@ -71,7 +72,6 @@ struct usb_hub {
 
        unsigned                mA_per_port;    /* current for each child */
 
-       unsigned                init_done:1;
        unsigned                limited_power:1;
        unsigned                quiescing:1;
        unsigned                disconnected:1;
@@ -820,7 +820,6 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
        }
  init3:
        hub->quiescing = 0;
-       hub->init_done = 1;
 
        status = usb_submit_urb(hub->urb, GFP_NOIO);
        if (status < 0)
@@ -861,11 +860,6 @@ static void hub_quiesce(struct usb_hub *hub, enum hub_quiescing_type type)
        int i;
 
        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 */
        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;
        hdev = interface_to_usbdev(intf);
 
+       /* Hubs have proper suspend/resume support */
+       usb_enable_autosuspend(hdev);
+
        if (hdev->level == MAX_TOPO_LEVEL) {
                dev_err(&intf->dev,
                        "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])
                        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->state = USB_STATE_NOTATTACHED;
 }
 
@@ -1448,11 +1443,11 @@ void usb_set_device_state(struct usb_device *udev,
                                        || new_state == USB_STATE_SUSPENDED)
                                ;       /* No change to wakeup settings */
                        else if (new_state == USB_STATE_CONFIGURED)
-                               device_init_wakeup(&udev->dev,
+                               device_set_wakeup_capable(&udev->dev,
                                        (udev->actconfig->desc.bmAttributes
                                         & USB_CONFIG_ATT_WAKEUP));
                        else
-                               device_init_wakeup(&udev->dev, 0);
+                               device_set_wakeup_capable(&udev->dev, 0);
                }
                if (udev->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;
 }
 
-#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)
  * @pdev: pointer to device being disconnected
@@ -1622,7 +1601,7 @@ void usb_disconnect(struct usb_device **pdev)
        *pdev = NULL;
        spin_unlock_irq(&device_state_lock);
 
-       usb_stop_pm(udev);
+       hub_free_dev(udev);
 
        put_device(&udev->dev);
 }
@@ -1799,9 +1778,18 @@ int usb_new_device(struct usb_device *udev)
 {
        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);
        err = usb_enumerate_device(udev);       /* Read descriptors */
@@ -1833,7 +1821,8 @@ int usb_new_device(struct usb_device *udev)
 
 fail:
        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;
 }
 
@@ -1982,7 +1971,7 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
                if (!(portstatus & USB_PORT_STAT_RESET) &&
                    (portstatus & USB_PORT_STAT_ENABLE)) {
                        if (hub_is_wusb(hub))
-                               udev->speed = USB_SPEED_VARIABLE;
+                               udev->speed = USB_SPEED_WIRELESS;
                        else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
                                udev->speed = USB_SPEED_HIGH;
                        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)
 {
        int i, status;
+       struct usb_hcd *hcd;
 
+       hcd = bus_to_hcd(udev->bus);
        /* Block EHCI CF initialization during the port reset.
         * 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 */
                        msleep(10 + 40);
                        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 */
                case -ENOTCONN:
                case -ENODEV:
@@ -2381,14 +2380,17 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
 }
 
 /* caller has locked udev */
-static int remote_wakeup(struct usb_device *udev)
+int usb_remote_wakeup(struct usb_device *udev)
 {
        int     status = 0;
 
        if (udev->state == USB_STATE_SUSPENDED) {
                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;
 }
@@ -2425,11 +2427,6 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
        return status;
 }
 
-static inline int remote_wakeup(struct usb_device *udev)
-{
-       return 0;
-}
-
 #endif
 
 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 */
 
-static inline int remote_wakeup(struct usb_device *udev)
-{
-       return 0;
-}
-
 #define hub_suspend            NULL
 #define hub_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);
 
-       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 */
                usb_set_device_state(udev, USB_STATE_DEFAULT);
        } else {
@@ -2678,7 +2663,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
         */
        switch (udev->speed) {
        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);
                break;
        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:
                                speed = "super";
                                break;
-       case USB_SPEED_VARIABLE:
+       case USB_SPEED_WIRELESS:
                                speed = "variable";
                                type = "Wireless ";
                                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
                         * remote wakeup event.
                         */
-                       status = remote_wakeup(udev);
+                       status = usb_remote_wakeup(udev);
 #endif
 
                } else {
@@ -3192,6 +3177,7 @@ loop_disable:
 loop:
                usb_ep0_reinit(udev);
                release_address(udev);
+               hub_free_dev(udev);
                usb_put_dev(udev);
                if ((status == -ENOTCONN) || (status == -ENOTSUPP))
                        break;
@@ -3259,7 +3245,7 @@ static void hub_events(void)
                 * disconnected while waiting for the lock to succeed. */
                usb_lock_device(hdev);
                if (unlikely(hub->disconnected))
-                       goto loop2;
+                       goto loop_disconnected;
 
                /* If the hub has died, clean up after it */
                if (hdev->state == USB_STATE_NOTATTACHED) {
@@ -3352,7 +3338,7 @@ static void hub_events(void)
                                        msleep(10);
 
                                        usb_lock_device(udev);
-                                       ret = remote_wakeup(hdev->
+                                       ret = usb_remote_wakeup(hdev->
                                                        children[i-1]);
                                        usb_unlock_device(udev);
                                        if (ret < 0)
@@ -3419,7 +3405,7 @@ static void hub_events(void)
                 * kick_khubd() and allow autosuspend.
                 */
                usb_autopm_put_interface(intf);
- loop2:
+ loop_disconnected:
                usb_unlock_device(hdev);
                kref_put(&hub->kref, hub_release);
 
@@ -3446,7 +3432,7 @@ static int hub_thread(void *__unused)
        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,
       .bDeviceClass = USB_CLASS_HUB},
     { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS,
index df73574a9cc9e567fc621a00d935f423923ac762..cd220277c6c3005d0cbcfa26ca24fdac7fd5abdf 100644 (file)
@@ -1316,7 +1316,7 @@ int usb_set_interface(struct usb_device *dev, int interface, int alternate)
 
        alt = usb_altnum_to_altsetting(iface, alternate);
        if (!alt) {
-               dev_warn(&dev->dev, "selecting invalid altsetting %d",
+               dev_warn(&dev->dev, "selecting invalid altsetting %d\n",
                         alternate);
                return -EINVAL;
        }
@@ -1471,7 +1471,7 @@ int usb_reset_configuration(struct usb_device *dev)
        /* If not, reinstate the old alternate settings */
        if (retval < 0) {
 reset_old_alts:
-               for (; i >= 0; i--) {
+               for (i--; i >= 0; i--) {
                        struct usb_interface *intf = config->interface[i];
                        struct usb_host_interface *alt;
 
@@ -1843,7 +1843,6 @@ free_interfaces:
                intf->dev.dma_mask = dev->dev.dma_mask;
                INIT_WORK(&intf->reset_ws, __usb_queue_reset_device);
                device_initialize(&intf->dev);
-               mark_quiesced(intf);
                dev_set_name(&intf->dev, "%d-%s:%d.%d",
                        dev->bus->busnum, dev->devpath,
                        configuration, alt->desc.bInterfaceNumber);
index ab93918d92076dedec3575b49e5eaacfb2c32e71..f073c5cb4e7bc64e1c6f0b2f2f241592a6ebf151 100644 (file)
@@ -103,10 +103,19 @@ void usb_detect_quirks(struct usb_device *udev)
                dev_dbg(&udev->dev, "USB quirks for this device: %x\n",
                                udev->quirks);
 
-       /* By default, disable autosuspend for all non-hubs */
 #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
 
        /* 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
         * and EMF-related port disables.
         */
-       udev->persist_enabled = 1;
+       if (!(udev->quirks & USB_QUIRK_RESET_MORPHS))
+               udev->persist_enabled = 1;
 #endif /* CONFIG_PM */
 }
index 5f3908f6e2dc12f455b9036da9621478976a3dd9..43c002e3a9aab2a819da74fd35f684f1ef5e83e2 100644 (file)
@@ -115,7 +115,7 @@ show_speed(struct device *dev, struct device_attribute *attr, char *buf)
        case USB_SPEED_HIGH:
                speed = "480";
                break;
-       case USB_SPEED_VARIABLE:
+       case USB_SPEED_WIRELESS:
                speed = "480";
                break;
        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 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
 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)
                return -EINVAL;
-       usb_pm_lock(udev);
+
+       usb_lock_device(udev);
        udev->persist_enabled = !!value;
-       usb_pm_unlock(udev);
+       usb_unlock_device(udev);
        return count;
 }
 
@@ -315,20 +346,34 @@ set_autosuspend(struct device *dev, struct device_attribute *attr,
                const char *buf, size_t count)
 {
        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 ||
                        value <= - INT_MAX/HZ)
                return -EINVAL;
        value *= HZ;
 
+       usb_lock_device(udev);
+       old_delay = udev->autosuspend_delay;
        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);
+       } 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;
 }
 
@@ -356,34 +401,25 @@ set_level(struct device *dev, struct device_attribute *attr,
        struct usb_device *udev = to_usb_device(dev);
        int len = count;
        char *cp;
-       int rc = 0;
-       int old_autosuspend_disabled;
+       int rc;
 
        cp = memchr(buf, '\n', count);
        if (cp)
                len = cp - buf;
 
        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 &&
-                       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;
 
-       if (rc)
-               udev->autosuspend_disabled = old_autosuspend_disabled;
        usb_unlock_device(udev);
        return (rc < 0 ? rc : count);
 }
@@ -558,6 +594,7 @@ static struct attribute *dev_attrs[] = {
        &dev_attr_version.attr,
        &dev_attr_maxchild.attr,
        &dev_attr_quirks.attr,
+       &dev_attr_avoid_reset_quirk.attr,
        &dev_attr_authorized.attr,
        &dev_attr_remove.attr,
        NULL,
index e7cae1334693cf6a88327c331104411ce8092880..27080561a1c2386567160b7aec7394028e1a60b3 100644 (file)
@@ -387,6 +387,13 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
        {
        unsigned int    orig_flags = urb->transfer_flags;
        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 */
        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:
                /* too small? */
                switch (dev->speed) {
-               case USB_SPEED_VARIABLE:
+               case USB_SPEED_WIRELESS:
                        if (urb->interval < 6)
                                return -EINVAL;
                        break;
@@ -446,7 +453,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                        if (urb->interval > (1 << 15))
                                return -EINVAL;
                        max = 1 << 15;
-               case USB_SPEED_VARIABLE:
+               case USB_SPEED_WIRELESS:
                        if (urb->interval > 16)
                                return -EINVAL;
                        break;
@@ -473,7 +480,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
                default:
                        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 */
                        urb->interval = min(max, 1 << ilog2(urb->interval));
                }
index 0daff0d968ba48fd079f86e74e90dc190de109ea..1297e9b16a5101bb941dbfeda831b3c2c3be350d 100644 (file)
@@ -49,9 +49,6 @@ const char *usbcore_name = "usbcore";
 
 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
 static int usb_autosuspend_delay = 2;          /* Default delay value,
                                                 * in seconds */
@@ -228,9 +225,6 @@ static void usb_release_dev(struct device *dev)
        hcd = bus_to_hcd(udev->bus);
 
        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);
        kfree(udev->product);
        kfree(udev->manufacturer);
@@ -264,23 +258,6 @@ static int usb_dev_uevent(struct device *dev, struct kobj_uevent_env *env)
 
 #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.
  * There's no need to distinguish here between quiescing a USB device
  * 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)
 {
        /* 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)
@@ -342,9 +319,7 @@ static const struct dev_pm_ops usb_device_pm_ops = {
 
 #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 */
 
@@ -472,9 +447,6 @@ struct usb_device *usb_alloc_dev(struct usb_device *parent,
        INIT_LIST_HEAD(&dev->filelist);
 
 #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->connect_time = jiffies;
        dev->active_duration = -jiffies;
@@ -1117,9 +1089,6 @@ static int __init usb_init(void)
        if (retval)
                goto out;
 
-       retval = ksuspend_usb_init();
-       if (retval)
-               goto out;
        retval = bus_register(&usb_bus_type);
        if (retval)
                goto bus_register_failed;
@@ -1159,7 +1128,7 @@ major_init_failed:
 bus_notifier_failed:
        bus_unregister(&usb_bus_type);
 bus_register_failed:
-       ksuspend_usb_cleanup();
+       usb_debugfs_cleanup();
 out:
        return retval;
 }
@@ -1181,7 +1150,6 @@ static void __exit usb_exit(void)
        usb_hub_cleanup();
        bus_unregister_notifier(&usb_bus_type, &usb_bus_nb);
        bus_unregister(&usb_bus_type);
-       ksuspend_usb_cleanup();
        usb_debugfs_cleanup();
 }
 
index 4c36c7f512a05e03728ef7575c5b0e4cefa93295..cd882203ad340e66ba00cfd3e1c44829a8b64dc0 100644 (file)
@@ -55,24 +55,8 @@ extern void usb_major_cleanup(void);
 extern int usb_suspend(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_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
 
@@ -86,9 +70,6 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg)
        return 0;
 }
 
-static inline void usb_pm_lock(struct usb_device *udev) {}
-static inline void usb_pm_unlock(struct usb_device *udev) {}
-
 #endif
 
 #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_try_autosuspend_device(struct usb_device *udev);
 extern int usb_autoresume_device(struct usb_device *udev);
+extern int usb_remote_wakeup(struct usb_device *dev);
 
 #else
 
@@ -106,9 +88,13 @@ static inline int usb_autoresume_device(struct usb_device *udev)
        return 0;
 }
 
+static inline int usb_remote_wakeup(struct usb_device *udev)
+{
+       return 0;
+}
+
 #endif
 
-extern struct workqueue_struct *ksuspend_usb_wq;
 extern struct bus_type usb_bus_type;
 extern struct device_type usb_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;
 }
 
-/* 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 */
 extern const char *usbcore_name;
index 2958a1271b20b5b82b7d6d448a30c848a11f5861..6e98a369784473e08ab9efaa462de09a86ba8b8c 100644 (file)
@@ -66,8 +66,6 @@ static struct ehci_dev ehci_dev;
 
 #define USB_DEBUG_DEVNUM 127
 
-#define DBGP_DATA_TOGGLE       0x8800
-
 #ifdef DBGP_DEBUG
 #define dbgp_printk printk
 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, ...) { }
 #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)
 {
        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_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)
 {
@@ -180,7 +186,7 @@ static int dbgp_wait_until_done(unsigned ctrl)
 {
        u32 pids, lpid;
        int ret;
-       int loop = 3;
+       int loop = DBGP_LOOPS;
 
 retry:
        writel(ctrl | DBGP_GO, &ehci_debug->control);
@@ -197,6 +203,8 @@ retry:
                 */
                if (ret == -DBGP_TIMEOUT && !dbgp_not_safe)
                        dbgp_not_safe = 1;
+               if (ret == -DBGP_ERR_BAD && --loop > 0)
+                       goto retry;
                return ret;
        }
 
@@ -245,12 +253,20 @@ static inline void dbgp_get_data(void *buf, int size)
                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;
 
+       if (size > DBGP_MAX_PACKET)
+               return -1;
+
+       addr = DBGP_EPADDR(devnum, endpoint);
+
        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 = 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);
        writel(addr, &ehci_debug->address);
        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;
 }
@@ -304,7 +293,7 @@ static int dbgp_bulk_read(unsigned devnum, unsigned endpoint, void *data,
        addr = DBGP_EPADDR(devnum, endpoint);
 
        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 = 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);
 }
 
-
 /* Find a PCI capability */
 static u32 __init find_cap(u32 num, u32 slot, u32 func, int cap)
 {
index ee411206c699c8b5d1812f94d510dc95f79359aa..7460cd797f454fd13f23dc157e6845a788dbe505 100644 (file)
@@ -812,6 +812,16 @@ config USB_CDC_COMPOSITE
          Say "y" to link the driver statically, or "m" to build a
          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
        tristate "Multifunction Composite Gadget (EXPERIMENTAL)"
        depends on BLOCK && NET
index 2e2c047262b78e12e71df90330219a0bf7219f71..43b51da8d7278f909733811cafeb56d3d96029f4 100644 (file)
@@ -43,6 +43,7 @@ g_mass_storage-objs           := mass_storage.o
 g_printer-objs                 := printer.o
 g_cdc-objs                     := cdc2.o
 g_multi-objs                   := multi.o
+g_nokia-objs                   := nokia.o
 
 obj-$(CONFIG_USB_ZERO)         += g_zero.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_CDC_COMPOSITE) += g_cdc.o
 obj-$(CONFIG_USB_G_MULTI)      += g_multi.o
+obj-$(CONFIG_USB_G_NOKIA)      += g_nokia.o
 
index 043e04db2a0555e7548782d8ddeb967a31772bd7..12ac9cd32a07562ec665f04636b75a263f68d9a8 100644 (file)
@@ -1656,9 +1656,7 @@ static int __init at91udc_probe(struct platform_device *pdev)
        if (!res)
                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");
                return -EBUSY;
        }
@@ -1699,7 +1697,7 @@ static int __init at91udc_probe(struct platform_device *pdev)
                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) {
                retval = -ENOMEM;
                goto fail0a;
@@ -1781,7 +1779,7 @@ fail0a:
        if (cpu_is_at91rm9200())
                gpio_free(udc->board.pullup_pin);
 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);
        return retval;
 }
@@ -1813,7 +1811,7 @@ static int __exit at91udc_remove(struct platform_device *pdev)
                gpio_free(udc->board.pullup_pin);
 
        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->fclk);
index 4e970cf0e29ae364b34c5e7436906e95db313952..f79bdfe4bed9f9e694146a38970c11d32fd1719f 100644 (file)
@@ -320,7 +320,7 @@ static inline void usba_cleanup_debugfs(struct usba_udc *udc)
 static int vbus_is_present(struct usba_udc *udc)
 {
        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 */
        return 1;
@@ -1763,7 +1763,7 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
        if (!udc->driver)
                goto out;
 
-       vbus = gpio_get_value(udc->vbus_pin);
+       vbus = vbus_is_present(udc);
        if (vbus != udc->vbus_prev) {
                if (vbus) {
                        toggle_bias(1);
@@ -1914,14 +1914,14 @@ static int __init usba_udc_probe(struct platform_device *pdev)
        udc->vbus_pin = -ENODEV;
 
        ret = -ENOMEM;
-       udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+       udc->regs = ioremap(regs->start, resource_size(regs));
        if (!udc->regs) {
                dev_err(&pdev->dev, "Unable to map I/O memory, aborting.\n");
                goto err_map_regs;
        }
        dev_info(&pdev->dev, "MMIO registers at 0x%08lx mapped at %p\n",
                 (unsigned long)regs->start, udc->regs);
-       udc->fifo = ioremap(fifo->start, fifo->end - fifo->start + 1);
+       udc->fifo = ioremap(fifo->start, resource_size(fifo));
        if (!udc->fifo) {
                dev_err(&pdev->dev, "Unable to map FIFO, aborting.\n");
                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_request(pdata->vbus_pin, "atmel_usba_udc")) {
                        udc->vbus_pin = pdata->vbus_pin;
+                       udc->vbus_pin_inverted = pdata->vbus_pin_inverted;
 
                        ret = request_irq(gpio_to_irq(udc->vbus_pin),
                                        usba_vbus_irq, 0,
index f7baea307f0d00be4433c2df62a1f64c6b7b5567..88a2e07a11a8da2562d4721d5a245f4d54d83968 100644 (file)
@@ -323,6 +323,7 @@ struct usba_udc {
        struct platform_device *pdev;
        int irq;
        int vbus_pin;
+       int vbus_pin_inverted;
        struct clk *pclk;
        struct clk *hclk;
 
index cd0914ec898eff0c6591914b74e5118fad4f5c09..65a5f94cbc0435153dfe76fda74bc5e4ff3481a5 100644 (file)
@@ -265,16 +265,24 @@ struct usb_ep * __init usb_ep_autoconfig (
                                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))
                        return ep;
+#endif
        }
 
        /* Second, look at endpoints until an unclaimed one looks usable */
index 141372b6e7a143b9a2497a1abf5d21b5f9ca3249..400f80372d938e1af5130bb7ea594f8b8cf3b844 100644 (file)
@@ -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;
 #else
 static int use_eem;
index d10353d46b8604f927e4e051e61ff159932c2cc9..e49c7325dce2e8c4eeef62f38b8217febd8b079e 100644 (file)
@@ -702,14 +702,6 @@ acm_unbind(struct usb_configuration *c, struct usb_function *f)
 /* Some controllers can't support CDC ACM ... */
 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 ... */
        return true;
 }
index ecf5bdd0ae069d277e41a26aa613a6dac28678e3..2fff530efc19f163eb466cf2d577cfdc525a5ac1 100644 (file)
@@ -497,12 +497,9 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
                        struct net_device       *net;
 
                        /* 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;
                        DBG(cdev, "activate ecm\n");
index a37640eba4344b144cc6d5747d155f55ec6f8239..b1935fe156a0320769481cf6419c4d58286c52bc 100644 (file)
@@ -368,7 +368,7 @@ struct fsg_common {
        struct task_struct      *thread_task;
 
        /* 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. */
        void                    *private_data;
 
@@ -392,8 +392,12 @@ struct fsg_config {
        const char              *lun_name_format;
        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. */
        void                    *private_data;
 
@@ -614,7 +618,12 @@ static int fsg_setup(struct usb_function *f,
                        return -EDOM;
                VDBG(fsg, "get max LUN\n");
                *(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,
@@ -2524,14 +2533,6 @@ static void handle_exception(struct fsg_common *common)
 
        case FSG_STATE_CONFIG_CHANGE:
                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;
 
        case FSG_STATE_EXIT:
@@ -2615,8 +2616,20 @@ static int fsg_main_thread(void *common_)
        common->thread_task = NULL;
        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 */
        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) {
                i = cfg->release;
        } 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) {
                        i = 0x0300 + i;
                } else {
@@ -2791,8 +2801,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
         * disable stalls.
         */
        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);
@@ -2852,7 +2861,6 @@ error_release:
        /* Call fsg_common_release() directly, ref might be not
         * initialised */
        fsg_common_release(&common->ref);
-       complete(&common->thread_notifier);
        return ERR_PTR(rc);
 }
 
index 95dae4c1ea40d8cabaea0f1698b4f6b16acf847f..a30e60c7f129dc19ec732b51d9b7465ff7e71317 100644 (file)
@@ -769,10 +769,6 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f)
 /* Some controllers can't support RNDIS ... */
 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 */
        return true;
 }
index 29dfb0277ffbf5c9d6adcd80d2b68b274401c17d..a90dd2db04889aa5b20fa0f938d367c8cf31c9c7 100644 (file)
@@ -3208,15 +3208,11 @@ static int __init check_parameters(struct fsg_dev *fsg)
         * halt bulk endpoints correctly.  If one of them is present,
         * disable stalls.
         */
-       if (gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget))
+       if (gadget_is_at91(fsg->gadget))
                mod_data.can_stall = 0;
 
        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)
                        mod_data.release = 0x0300 + gcnum;
                else {
index 7881f12413c40386924629ad0f5a3ff30ea09440..3537d51073b2e9216e9dd02891894f46e9f0fc63 100644 (file)
@@ -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",
                .data = (void *)PORT_QE,
index f2d270b202f257229cb9120005b7ec3af223191a..1edbc12fff18fdc172cd44627fc8e7d397f0b46c 100644 (file)
 #define        gadget_is_goku(g)       0
 #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
 #define        gadget_is_lh7a40x(g)    !strcmp("lh7a40x_udc", (g)->name)
 #else
 #define        gadget_is_lh7a40x(g)    0
 #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
 #define        gadget_is_omap(g)       !strcmp("omap_udc", (g)->name)
 #else
 #define        gadget_is_omap(g)       0
 #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 */
 #ifdef CONFIG_USB_GADGET_PXA27X
 #define        gadget_is_pxa27x(g)     !strcmp("pxa27x_udc", (g)->name)
 #define gadget_is_fsl_usb2(g)  0
 #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 */
 #ifdef CONFIG_USB_GADGET_MUSB_HDRC
 #define gadget_is_musbhdrc(g)  !strcmp("musb_hdrc", (g)->name)
 #define gadget_is_langwell(g)  0
 #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
 #define        gadget_is_m66592(g)     !strcmp("m66592_udc", (g)->name)
 #else
@@ -203,20 +160,12 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
                return 0x02;
        else if (gadget_is_pxa(gadget))
                return 0x03;
-       else if (gadget_is_sh(gadget))
-               return 0x04;
-       else if (gadget_is_sa1100(gadget))
-               return 0x05;
        else if (gadget_is_goku(gadget))
                return 0x06;
-       else if (gadget_is_mq11xx(gadget))
-               return 0x07;
        else if (gadget_is_omap(gadget))
                return 0x08;
        else if (gadget_is_lh7a40x(gadget))
                return 0x09;
-       else if (gadget_is_n9604(gadget))
-               return 0x10;
        else if (gadget_is_pxa27x(gadget))
                return 0x11;
        else if (gadget_is_s3c2410(gadget))
@@ -225,12 +174,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
                return 0x13;
        else if (gadget_is_imx(gadget))
                return 0x14;
-       else if (gadget_is_musbhsfc(gadget))
-               return 0x15;
        else if (gadget_is_musbhdrc(gadget))
                return 0x16;
-       else if (gadget_is_mpc8272(gadget))
-               return 0x17;
        else if (gadget_is_atmel_usba(gadget))
                return 0x18;
        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))
                return false;
 
-       /* SH3 hardware just doesn't do altsettings */
-       if (gadget_is_sh(gadget))
-               return false;
-
        /* Everything else is *presumably* fine ... */
        return true;
 }
index 5f6a2e0a9357bd680182d96b74211ccd8c7f0354..04f6224b7e06b1b65972609f37a8cf7228b43174 100644 (file)
@@ -618,11 +618,6 @@ gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags)
        }
 #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);
 
        switch (number) {
index 112bb40a427cd4a217ed69af61d73effc8863959..e8edc640381e5bdbd8275b3a580da2ea78a966ab 100644 (file)
@@ -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_mask =   ~0,
        .vendor =       0x102f,         /* Toshiba */
index bf0f6520c6df3946b91f2a40f9b1a6c786918f6d..de8a83803505032542db52582f5258bdcb6473f1 100644 (file)
@@ -194,7 +194,7 @@ enum ep_state {
 };
 
 struct ep_data {
-       struct semaphore                lock;
+       struct mutex                    lock;
        enum ep_state                   state;
        atomic_t                        count;
        struct dev_data                 *dev;
@@ -298,10 +298,10 @@ get_ready_ep (unsigned f_flags, struct ep_data *epdata)
        int     val;
 
        if (f_flags & O_NONBLOCK) {
-               if (down_trylock (&epdata->lock) != 0)
+               if (!mutex_trylock(&epdata->lock))
                        goto nonblock;
                if (epdata->state != STATE_EP_ENABLED) {
-                       up (&epdata->lock);
+                       mutex_unlock(&epdata->lock);
 nonblock:
                        val = -EAGAIN;
                } else
@@ -309,7 +309,8 @@ nonblock:
                return val;
        }
 
-       if ((val = down_interruptible (&epdata->lock)) < 0)
+       val = mutex_lock_interruptible(&epdata->lock);
+       if (val < 0)
                return val;
 
        switch (epdata->state) {
@@ -323,7 +324,7 @@ nonblock:
                // FALLTHROUGH
        case STATE_EP_UNBOUND:                  /* clean disconnect */
                val = -ENODEV;
-               up (&epdata->lock);
+               mutex_unlock(&epdata->lock);
        }
        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))
                        usb_ep_set_halt (data->ep);
                spin_unlock_irq (&data->dev->lock);
-               up (&data->lock);
+               mutex_unlock(&data->lock);
                return -EBADMSG;
        }
 
@@ -411,7 +412,7 @@ ep_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
                value = -EFAULT;
 
 free1:
-       up (&data->lock);
+       mutex_unlock(&data->lock);
        kfree (kbuf);
        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))
                        usb_ep_set_halt (data->ep);
                spin_unlock_irq (&data->dev->lock);
-               up (&data->lock);
+               mutex_unlock(&data->lock);
                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",
                data->name, len, (int) value);
 free1:
-       up (&data->lock);
+       mutex_unlock(&data->lock);
        kfree (kbuf);
        return value;
 }
@@ -466,7 +467,8 @@ ep_release (struct inode *inode, struct file *fd)
        struct ep_data          *data = fd->private_data;
        int value;
 
-       if ((value = down_interruptible(&data->lock)) < 0)
+       value = mutex_lock_interruptible(&data->lock);
+       if (value < 0)
                return value;
 
        /* clean up if this can be reopened */
@@ -476,7 +478,7 @@ ep_release (struct inode *inode, struct file *fd)
                data->hs_desc.bDescriptorType = 0;
                usb_ep_disable(data->ep);
        }
-       up (&data->lock);
+       mutex_unlock(&data->lock);
        put_ep (data);
        return 0;
 }
@@ -507,7 +509,7 @@ static long ep_ioctl(struct file *fd, unsigned code, unsigned long value)
        } else
                status = -ENODEV;
        spin_unlock_irq (&data->dev->lock);
-       up (&data->lock);
+       mutex_unlock(&data->lock);
        return status;
 }
 
@@ -673,7 +675,7 @@ fail:
                value = -ENODEV;
        spin_unlock_irq(&epdata->dev->lock);
 
-       up(&epdata->lock);
+       mutex_unlock(&epdata->lock);
 
        if (unlikely(value)) {
                kfree(priv);
@@ -765,7 +767,8 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
        u32                     tag;
        int                     value, length = len;
 
-       if ((value = down_interruptible (&data->lock)) < 0)
+       value = mutex_lock_interruptible(&data->lock);
+       if (value < 0)
                return value;
 
        if (data->state != STATE_EP_READY) {
@@ -854,7 +857,7 @@ fail:
                data->desc.bDescriptorType = 0;
                data->hs_desc.bDescriptorType = 0;
        }
-       up (&data->lock);
+       mutex_unlock(&data->lock);
        return value;
 fail0:
        value = -EINVAL;
@@ -870,7 +873,7 @@ ep_open (struct inode *inode, struct file *fd)
        struct ep_data          *data = inode->i_private;
        int                     value = -EBUSY;
 
-       if (down_interruptible (&data->lock) != 0)
+       if (mutex_lock_interruptible(&data->lock) != 0)
                return -EINTR;
        spin_lock_irq (&data->dev->lock);
        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",
                        data->name, data->state);
        spin_unlock_irq (&data->dev->lock);
-       up (&data->lock);
+       mutex_unlock(&data->lock);
        return value;
 }
 
@@ -1631,7 +1634,7 @@ static int activate_ep_files (struct dev_data *dev)
                if (!data)
                        goto enomem0;
                data->state = STATE_EP_DISABLED;
-               init_MUTEX (&data->lock);
+               mutex_init(&data->lock);
                init_waitqueue_head (&data->wait);
 
                strncpy (data->name, ep->name, sizeof (data->name) - 1);
index 19619fbf20ace5b4673520a2d0219996dc7f446f..705cc1f76327c6cc953f4b2efcc6788a77ef760d 100644 (file)
@@ -135,6 +135,12 @@ FSG_MODULE_PARAMETERS(/* no prefix */, mod_data);
 static unsigned long msg_registered = 0;
 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)
 {
        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);
-       config.thread_exits = (void(*)(struct fsg_common*))&msg_cleanup;
+       config.thread_exits = msg_thread_exits;
        common = fsg_common_init(0, c->cdev, &config);
        if (IS_ERR(common))
                return PTR_ERR(common);
diff --git a/drivers/usb/gadget/nokia.c b/drivers/usb/gadget/nokia.c
new file mode 100644 (file)
index 0000000..7d6b66a
--- /dev/null
@@ -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);
+
index 2d867fd22413f9ab0a9af24bacc9aa306cf6df85..6b8bf8c781c4938c123f475baec357b45dbf0c75 100644 (file)
@@ -949,12 +949,6 @@ printer_set_config(struct printer_dev *dev, unsigned number)
        int                     result = 0;
        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) {
        case DEV_CONFIG_VALUE:
                result = 0;
@@ -1033,12 +1027,6 @@ set_interface(struct printer_dev *dev, unsigned number)
 {
        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 */
        switch (dev->interface) {
        case PRINTER_INTERFACE:
@@ -1392,12 +1380,6 @@ printer_bind(struct usb_gadget *gadget)
                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);
        if (gcnum >= 0) {
                device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
index adda1208a1ece2bacdafd343723fe1e79cf32a49..05b892c3d686ccf0492dc87dc34fefc794e2084e 100644 (file)
@@ -742,13 +742,17 @@ static void ep_del_request(struct pxa_ep *ep, struct pxa27x_request *req)
  * @ep: pxa physical endpoint
  * @req: pxa request
  * @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.
  */
-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);
        if (likely(req->req.status == -EINPROGRESS))
                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.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);
+       local_irq_restore(flags);
+       if (pflags)
+               spin_lock_irqsave(&ep->lock, *pflags);
 }
 
 /**
  * ep_end_out_req - Ends endpoint OUT request
  * @ep: physical endpoint
  * @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).
  */
-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);
-       req_done(ep, req, 0);
+       req_done(ep, req, 0, pflags);
 }
 
 /**
  * ep0_end_out_req - Ends control endpoint OUT request (ends data stage)
  * @ep: physical endpoint
  * @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
  * 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);
-       ep_end_out_req(ep, req);
+       ep_end_out_req(ep, req, pflags);
        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: physical endpoint
  * @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).
  */
-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);
-       req_done(ep, req, 0);
+       req_done(ep, req, 0, pflags);
 }
 
 /**
  * ep0_end_in_req - Ends control endpoint IN request (ends data stage)
  * @ep: physical endpoint
  * @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
  * 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);
-       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
  * @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
  * disabled on that endpoint (because no more requests).
  */
 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)) {
                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                     is_first_req;
        unsigned                length;
+       int                     recursion_detected;
 
        req = container_of(_req, struct pxa27x_request, req);
        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;
 
        spin_lock_irqsave(&ep->lock, flags);
+       recursion_detected = ep->in_handle_ep;
 
        is_first_req = list_empty(&ep->queue);
        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) {
                _req->status = -ESHUTDOWN;
                rc = -ESHUTDOWN;
-               goto out;
+               goto out_locked;
        }
 
        if (req->in_use) {
                ep_err(ep, "refusing to queue req %p (already queued)\n", req);
-               goto out;
+               goto out_locked;
        }
 
        length = _req->length;
@@ -1174,12 +1197,13 @@ static int pxa_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
        _req->actual = 0;
 
        ep_add_request(ep, req);
+       spin_unlock_irqrestore(&ep->lock, flags);
 
        if (is_ep0(ep)) {
                switch (dev->ep0state) {
                case WAIT_ACK_SET_CONF_INTERF:
                        if (length == 0) {
-                               ep_end_in_req(ep, req);
+                               ep_end_in_req(ep, req, NULL);
                        } else {
                                ep_err(ep, "got a request of %d bytes while"
                                        "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:
                        if (!ep_is_full(ep))
                                if (write_ep0_fifo(ep, req))
-                                       ep0_end_in_req(ep, req);
+                                       ep0_end_in_req(ep, req, NULL);
                        break;
                case OUT_DATA_STAGE:
                        if ((length == 0) || !epout_has_pkt(ep))
                                if (read_ep0_fifo(ep, req))
-                                       ep0_end_out_req(ep, req);
+                                       ep0_end_out_req(ep, req, NULL);
                        break;
                default:
                        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;
                }
        } else {
-               handle_ep(ep);
+               if (!recursion_detected)
+                       handle_ep(ep);
        }
 
 out:
-       spin_unlock_irqrestore(&ep->lock, flags);
        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 */
        list_for_each_entry(req, &ep->queue, queue) {
                if (&req->req == _req) {
-                       req_done(ep, req, -ECONNRESET);
                        rc = 0;
                        break;
                }
        }
 
        spin_unlock_irqrestore(&ep->lock, flags);
+       if (!rc)
+               req_done(ep, req, -ECONNRESET, NULL);
        return rc;
 }
 
@@ -1445,7 +1473,6 @@ static int pxa_ep_disable(struct usb_ep *_ep)
 {
        struct pxa_ep           *ep;
        struct udc_usb_ep       *udc_usb_ep;
-       unsigned long           flags;
 
        if (!_ep)
                return -EINVAL;
@@ -1455,10 +1482,8 @@ static int pxa_ep_disable(struct usb_ep *_ep)
        if (!ep || is_ep0(ep) || !list_empty(&ep->queue))
                return -EINVAL;
 
-       spin_lock_irqsave(&ep->lock, flags);
        ep->enabled = 0;
        nuke(ep, -ESHUTDOWN);
-       spin_unlock_irqrestore(&ep->lock, flags);
 
        pxa_ep_fifo_flush(_ep);
        udc_usb_ep->pxa_ep = NULL;
@@ -1907,8 +1932,10 @@ static void handle_ep0_ctrl_req(struct pxa_udc *udc,
        } u;
        int i;
        int have_extrabytes = 0;
+       unsigned long flags;
 
        nuke(ep, -EPROTO);
+       spin_lock_irqsave(&ep->lock, flags);
 
        /*
         * 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 */
        ep_write_UDCCSR(ep, UDCCSR0_SA | UDCCSR0_OPC);
 
+       spin_unlock_irqrestore(&ep->lock, flags);
        i = udc->driver->setup(&udc->gadget, &u.r);
+       spin_lock_irqsave(&ep->lock, flags);
        if (i < 0)
                goto stall;
 out:
+       spin_unlock_irqrestore(&ep->lock, flags);
        return;
 stall:
        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))
                        completed = write_ep0_fifo(ep, req);
                if (completed)
-                       ep0_end_in_req(ep, req);
+                       ep0_end_in_req(ep, req, NULL);
                break;
        case OUT_DATA_STAGE:                    /* SET_DESCRIPTOR */
                if (epout_has_pkt(ep) && req)
                        completed = read_ep0_fifo(ep, req);
                if (completed)
-                       ep0_end_out_req(ep, req);
+                       ep0_end_out_req(ep, req, NULL);
                break;
        case STALL:
                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
  * 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)
 {
@@ -2100,10 +2130,17 @@ static void handle_ep(struct pxa_ep *ep)
        u32 udccsr;
        int is_in = ep->dir_in;
        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 {
                completed = 0;
                udccsr = udc_ep_readl(ep, UDCCSR);
+
                if (likely(!list_empty(&ep->queue)))
                        req = list_entry(ep->queue.next,
                                        struct pxa27x_request, queue);
@@ -2122,15 +2159,22 @@ static void handle_ep(struct pxa_ep *ep)
                if (unlikely(is_in)) {
                        if (likely(!ep_is_full(ep)))
                                completed = write_fifo(ep, req);
-                       if (completed)
-                               ep_end_in_req(ep, req);
                } else {
                        if (likely(epout_has_pkt(ep)))
                                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);
+
+       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;
 
                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++) {
@@ -2228,9 +2276,12 @@ static void irq_handle_data(int irq, struct pxa_udc *udc)
                if (!(udcisr1 & UDCISR_INT_MASK))
                        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;
-       udc->regs = ioremap(regs->start, regs->end - regs->start + 1);
+       udc->regs = ioremap(regs->start, resource_size(regs));
        if (!udc->regs) {
                dev_err(&pdev->dev, "Unable to map UDC I/O memory\n");
                goto err_map;
index e25225e26586698ea1ac7ceb5e042b38c4245574..ff61e4866e8afa4d2f072f3520009b36a9fd155d 100644 (file)
@@ -318,6 +318,11 @@ struct udc_usb_ep {
  * @queue: requests queue
  * @lock: lock to pxa_ep data (queues and stats)
  * @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)
  * @name: endpoint name (for trace/debug purpose)
  * @dir_in: 1 if IN endpoint, 0 if OUT endpoint
@@ -346,6 +351,7 @@ struct pxa_ep {
        spinlock_t              lock;           /* Protects this structure */
                                                /* (queues, stats) */
        unsigned                enabled:1;
+       unsigned                in_handle_ep:1;
 
        unsigned                idx:5;
        char                    *name;
index 5fc80a104150aef353391596fc0ed17c476136c6..7e5bf593d386d5d6f5294187fc3196a4207612e3 100644 (file)
@@ -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
  */
-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;
 
@@ -373,7 +374,7 @@ static void s3c_hsotg_unmap_dma(struct s3c_hsotg *hsotg,
                req->dma = DMA_ADDR_INVALID;
                hs_req->mapped = 0;
        } 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;
                req->dma = dma;
        } 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;
        }
 
@@ -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
  * 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 epnum, status, size;
@@ -3094,7 +3095,7 @@ static void s3c_hsotg_gate(struct platform_device *pdev, bool on)
        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)
 {
index 2fc02bd9584882b3cf523864f33dc0f412af1471..84ca195c2d10f8a2b71346bdd031ba18a15e1571 100644 (file)
@@ -746,6 +746,10 @@ static const struct net_device_ops eth_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
 };
 
+static struct device_type gadget_type = {
+       .name   = "gadget",
+};
+
 /**
  * gether_setup - initialize one ethernet-over-usb link
  * @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;
        SET_NETDEV_DEV(net, &g->dev);
+       SET_NETDEV_DEVTYPE(net, &gadget_type);
 
        status = register_netdev(net);
        if (status < 0) {
index fd55f450bc0e02e88afb55980c12008a073aacb4..3c8c0c9f9d728dd7730ae4335a3f68a410adfbbf 100644 (file)
@@ -93,13 +93,6 @@ static inline bool can_support_ecm(struct usb_gadget *gadget)
        if (!gadget_supports_altsettings(gadget))
                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
         * chancy, so be **CERTAIN** there are no hardware issues with
         * your controller.  Add it above if it can't handle CDC.
index 2d772401b7ad4879762d118e8ff12231d103a912..fac81ee193dd0100d71bcf344f4badb0d341a153 100644 (file)
@@ -297,12 +297,10 @@ static int __init zero_bind(struct usb_composite_dev *cdev)
         */
        if (loopdefault) {
                loopback_add(cdev, autoresume != 0);
-               if (!gadget_is_sh(gadget))
-                       sourcesink_add(cdev, autoresume != 0);
+               sourcesink_add(cdev, autoresume != 0);
        } else {
                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);
index 2678a1624fcce8703ef0f9af61c4a0212a4ebb36..8d3df0397de392d0ab0769d476b89eb35e703180 100644 (file)
@@ -399,3 +399,14 @@ config USB_HWA_HCD
 
          To compile this driver a module, choose M here: the module
          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".
+
index f58b2494c44a841ed87ad0edbbedaa274054f0a0..4e0c67f1f51ba1dbc5e4efb964936b01c4afe037 100644 (file)
@@ -32,3 +32,5 @@ obj-$(CONFIG_USB_U132_HCD)    += u132-hcd.o
 obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
 obj-$(CONFIG_USB_ISP1760_HCD)  += isp1760.o
 obj-$(CONFIG_USB_HWA_HCD)      += hwa-hc.o
+obj-$(CONFIG_USB_IMX21_HCD)    += imx21-hcd.o
+
index 87c1b7c34c0e82bc0684f1fcb8bd28e7f917c225..51bd0edf544fc56b9463ea130711bd4e9767d9b6 100644 (file)
@@ -149,7 +149,7 @@ static int __init ehci_atmel_drv_probe(struct platform_device *pdev)
                goto fail_request_resource;
        }
        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,
                                driver->description)) {
index dbfb482a94e37a7389c2d9c13681a5c9da408325..e3a74e75e8225585c5c85e089f82fe046e7b4796 100644 (file)
@@ -121,6 +121,7 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
 {
        struct usb_hcd *hcd;
        struct ehci_hcd *ehci;
+       struct resource *res;
        int ret;
 
        if (usb_disabled())
@@ -144,8 +145,9 @@ static int ehci_hcd_au1xxx_drv_probe(struct platform_device *pdev)
        if (!hcd)
                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)) {
                pr_debug("request_mem_region failed");
index 991174937db31ed5d829d6e1fdc0b3ea024e47bd..0e26aa13f1580c308351c208e3d8eb3bdc8ef566 100644 (file)
@@ -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
  * under the terms of the GNU General Public License as published by the
  *
  * Ported to 834x by Randy Vinson <rvinson@mvista.com> using code provided
  * 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/fsl_devices.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 */
 /* always called with process context; sleeping is OK */
 
@@ -40,8 +44,8 @@
  * 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 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().
  *
  */
-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);
        iounmap(hcd->regs);
@@ -284,10 +289,81 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
        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 = {
        .description = hcd_name,
        .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
@@ -354,6 +430,7 @@ static struct platform_driver ehci_fsl_driver = {
        .remove = ehci_fsl_drv_remove,
        .shutdown = usb_hcd_platform_shutdown,
        .driver = {
-                  .name = "fsl-ehci",
+               .name = "fsl-ehci",
+               .pm = EHCI_FSL_PM_OPS,
        },
 };
index 35c56f40bdbb1718ce2092800eeb7d5f187b8024..23cd917088b41fa73a74abad13f66fba82a9df85 100644 (file)
@@ -162,6 +162,17 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
                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 */
        priv->usbclk = clk_get(dev, "usb");
        if (IS_ERR(priv->usbclk)) {
@@ -192,18 +203,6 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
        if (ret < 0)
                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 */
        if (pdata->otg) {
                pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET;
index 74d07f4e8b7d48d74f9ea119d350ab6aed8a2dd1..f0282d6bb7aa63e42484b5868b31d96553c9fb7d 100644 (file)
  * along with this program; if not, write to the Free Software
  * 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
  *     - enable AUTOIDLE
- *     - move DPLL5 programming to clock fw
  *     - add suspend/resume
  *     - move workarounds to board-files
  */
@@ -37,6 +36,7 @@
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
 #include <plat/usb.h>
 
 /*
@@ -178,6 +178,11 @@ struct ehci_hcd_omap {
        void __iomem            *uhh_base;
        void __iomem            *tll_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 ret = -ENODEV;
+       int i;
+       char supply[7];
 
        if (!pdata) {
                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;
        }
 
+       /* 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);
        if (ret) {
                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
                + 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 */
        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);
        if (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);
 
 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);
 
 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 usb_hcd *hcd = ehci_to_hcd(omap->ehci);
+       int i;
 
        usb_remove_hcd(hcd);
        omap_stop_ehc(omap, hcd);
        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->uhh_base);
        usb_put_hcd(hcd);
+       kfree(omap);
 
        return 0;
 }
index 1d283e1b2b8de543e56f4e695e333383ee5d116d..0f87dc72820a2d6f61e99c378e29a6d5989dce86 100644 (file)
@@ -222,14 +222,14 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
                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)) {
                dev_dbg(&pdev->dev, "controller already in use\n");
                err = -EBUSY;
                goto err1;
        }
 
-       regs = ioremap(res->start, res->end - res->start + 1);
+       regs = ioremap(res->start, resource_size(res));
        if (regs == NULL) {
                dev_dbg(&pdev->dev, "error mapping memory\n");
                err = -EFAULT;
@@ -244,7 +244,7 @@ static int __devinit ehci_orion_drv_probe(struct platform_device *pdev)
        }
 
        hcd->rsrc_start = res->start;
-       hcd->rsrc_len = res->end - res->start + 1;
+       hcd->rsrc_len = resource_size(res);
        hcd->regs = regs;
 
        ehci = hcd_to_ehci(hcd);
@@ -287,7 +287,7 @@ err4:
 err3:
        iounmap(regs);
 err2:
-       release_mem_region(res->start, res->end - res->start + 1);
+       release_mem_region(res->start, resource_size(res));
 err1:
        dev_err(&pdev->dev, "init %s fail, %d\n",
                dev_name(&pdev->dev), err);
index 36f96da129f5c637208031ec04913be3f0cc6e67..8df33b8a634c4c944bf1c385cbba056f393d09db 100644 (file)
@@ -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;
 
        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;
                goto err_rmr;
        }
 
        irq = irq_of_parse_and_map(dn, 0);
        if (irq == NO_IRQ) {
-               printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+               printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
                rv = -EBUSY;
                goto err_irq;
        }
 
        hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
        if (!hcd->regs) {
-               printk(KERN_ERR __FILE__ ": ioremap failed\n");
+               printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
                rv = -ENOMEM;
                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 +
                                        OHCI_HCCTRL_OFFSET, OHCI_HCCTRL_LEN);
                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) {
-                       pr_debug(__FILE__ ": ioremap for ohci hcctrl failed\n");
+                       pr_debug("%s: ioremap for ohci hcctrl failed\n", __FILE__);
                } else {
                        ehci->has_amcc_usb23 = 1;
                }
@@ -241,7 +241,7 @@ static int ehci_hcd_ppc_of_remove(struct of_device *op)
                                else
                                        release_mem_region(res.start, 0x4);
                        else
-                               pr_debug(__FILE__ ": no ohci offset in fdt\n");
+                               pr_debug("%s: no ohci offset in fdt\n", __FILE__);
                        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",
        },
index 1e391e624c8affee6e58d699de953df4bcaa857a..39340ae00ac488bcd6a0a3f1ed5ac71931dbe63e 100644 (file)
@@ -510,6 +510,8 @@ static int disable_periodic (struct ehci_hcd *ehci)
        ehci_writel(ehci, cmd, &ehci->regs->command);
        /* posted write ... */
 
+       free_cached_itd_list(ehci);
+
        ehci->next_uframe = -1;
        return 0;
 }
@@ -2322,9 +2324,13 @@ restart:
                                 * No need to check for activity unless the
                                 * 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;
                                        q_p = &q.sitd->sitd_next;
                                        hw_p = &q.sitd->hw_next;
index a5861531ad3e052f596caf6d79c178ace0238b53..f603bb2c0a8eedba86bbbad4370e154e1b9c7b0c 100644 (file)
@@ -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;
 
        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;
                goto err_rmr;
        }
 
        irq = irq_of_parse_and_map(dn, 0);
        if (irq == NO_IRQ) {
-               printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+               printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
                rv = -EBUSY;
                goto err_irq;
        }
 
        hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
        if (!hcd->regs) {
-               printk(KERN_ERR __FILE__ ": ioremap failed\n");
+               printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
                rv = -ENOMEM;
                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",},
        {},
 };
index 78e7c3cfcb7282757d85fc331de14ab559580e4c..5dcfb3de9945788798b5fae2ce91a67706458e4d 100644 (file)
@@ -433,7 +433,7 @@ static int fhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
                return -ENOMEM;
 
        /* 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) {
                kfree(urb_priv);
                return -ENOMEM;
@@ -805,7 +805,7 @@ static int __devexit of_fhci_remove(struct of_device *ofdev)
        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", },
        {},
 };
diff --git a/drivers/usb/host/imx21-dbg.c b/drivers/usb/host/imx21-dbg.c
new file mode 100644 (file)
index 0000000..512f647
--- /dev/null
@@ -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
+
diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c
new file mode 100644 (file)
index 0000000..213e270
--- /dev/null
@@ -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");
diff --git a/drivers/usb/host/imx21-hcd.h b/drivers/usb/host/imx21-hcd.h
new file mode 100644 (file)
index 0000000..1b0d913
--- /dev/null
@@ -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
index 42971657fde2953f2d7798e5b45d4d14796fb16d..217fb5170200d3a66a9680c2d6d9a8ca81f3a1d1 100644 (file)
@@ -1257,7 +1257,7 @@ static int isp1362_urb_enqueue(struct usb_hcd *hcd,
 
        /* avoid all allocations within spinlocks: request or endpoint */
        if (!hep->hcpriv) {
-               ep = kcalloc(1, sizeof *ep, mem_flags);
+               ep = kzalloc(sizeof *ep, mem_flags);
                if (!ep)
                        return -ENOMEM;
        }
@@ -2719,24 +2719,11 @@ static int __init isp1362_probe(struct platform_device *pdev)
        }
        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) {
                DBG(1, "won't do DMA");
                retval = -ENODEV;
                goto err1;
        }
-#endif
 
        if (!request_mem_region(addr->start, resource_len(addr), hcd_name)) {
                retval = -EBUSY;
index 27b8f7cb4471e8399f8262feaca409388b11957f..9f01293600b0559e9d30ca6a11ae2244e102189b 100644 (file)
@@ -17,7 +17,9 @@
 #include <linux/debugfs.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
+#include <linux/mm.h>
 #include <asm/unaligned.h>
+#include <asm/cacheflush.h>
 
 #include "../core/hcd.h"
 #include "isp1760-hcd.h"
@@ -904,6 +906,14 @@ __acquires(priv->lock)
                        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 */
        usb_hcd_unlink_urb_from_ep(priv_to_hcd(priv), urb);
        spin_unlock(&priv->lock);
index 1c9f977a5c9c4bcfa16b86a4f295360dfc8a1059..4293cfd28d61414b425a7cff2b5330a8b4d4e7aa 100644 (file)
@@ -109,7 +109,7 @@ static int of_isp1760_remove(struct of_device *dev)
        return 0;
 }
 
-static struct of_device_id of_isp1760_match[] = {
+static const struct of_device_id of_isp1760_match[] = {
        {
                .compatible = "nxp,usb-isp1760",
        },
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
new file mode 100644 (file)
index 0000000..4aa08d3
--- /dev/null
@@ -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",
+       },
+};
index 811f5dfdc582447c18716a79e1bb055735975fff..8ad2441b02848fb071bc8c49fded093ce2bc126a 100644 (file)
@@ -53,13 +53,13 @@ urb_print(struct urb * urb, char * str, int small, int status)
                int i, len;
 
                if (usb_pipecontrol (pipe)) {
-                       printk (KERN_DEBUG __FILE__ ": setup(8):");
+                       printk (KERN_DEBUG "%s: setup(8):", __FILE__);
                        for (i = 0; i < 8 ; i++)
                                printk (" %02x", ((__u8 *) urb->setup_packet) [i]);
                        printk ("\n");
                }
                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->transfer_buffer_length);
                        len = usb_pipeout (pipe)?
index 24eb74781919d58ed4454a4e7c1dd7999e04ade1..afe59be2364594357fb5fbb875d95d4838059fce 100644 (file)
@@ -1051,6 +1051,11 @@ MODULE_LICENSE ("GPL");
 #define PLATFORM_DRIVER                usb_hcd_pnx4008_driver
 #endif
 
+#ifdef CONFIG_ARCH_DAVINCI_DA8XX
+#include "ohci-da8xx.c"
+#define PLATFORM_DRIVER                ohci_hcd_da8xx_driver
+#endif
+
 #if defined(CONFIG_CPU_SUBTYPE_SH7720) || \
     defined(CONFIG_CPU_SUBTYPE_SH7721) || \
     defined(CONFIG_CPU_SUBTYPE_SH7763) || \
index de42283149c7154608c30c9b1ceeec29e14b07ba..18d39f0463ee4f4dac4f5122f2d6670be99ad7c1 100644 (file)
@@ -28,8 +28,8 @@ extern int usb_disabled(void);
 
 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
@@ -39,14 +39,13 @@ static void lh7a404_start_hc(struct platform_device *dev)
        udelay(1000);
        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)
 {
-       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 */
 }
index 2769326da42e83f33575c6bf28348338d5ff7c8f..cd74bbdd007cef3e218dc649361e2e516c47f454 100644 (file)
@@ -327,7 +327,7 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
        }
        i2c_adap = i2c_get_adapter(2);
        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,
                                                   normal_i2c);
        i2c_put_adapter(i2c_adap);
@@ -411,7 +411,7 @@ out3:
 out2:
        clk_put(usb_clk);
 out1:
-       i2c_unregister_client(isp1301_i2c_client);
+       i2c_unregister_device(isp1301_i2c_client);
        isp1301_i2c_client = NULL;
 out_i2c_driver:
        i2c_del_driver(&isp1301_driver);
@@ -430,7 +430,7 @@ static int usb_hcd_pnx4008_remove(struct platform_device *pdev)
        pnx4008_unset_usb_bits();
        clk_disable(usb_clk);
        clk_put(usb_clk);
-       i2c_unregister_client(isp1301_i2c_client);
+       i2c_unregister_device(isp1301_i2c_client);
        isp1301_i2c_client = NULL;
        i2c_del_driver(&isp1301_driver);
 
index 68a301710297f6eeb32ec75538d17d1e12a14d92..103263c230cfd669ff4059909f03a7cae4e3c331 100644 (file)
@@ -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;
 
        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;
                goto err_rmr;
        }
 
        irq = irq_of_parse_and_map(dn, 0);
        if (irq == NO_IRQ) {
-               printk(KERN_ERR __FILE__ ": irq_of_parse_and_map failed\n");
+               printk(KERN_ERR "%s: irq_of_parse_and_map failed\n", __FILE__);
                rv = -EBUSY;
                goto err_irq;
        }
 
        hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
        if (!hcd->regs) {
-               printk(KERN_ERR __FILE__ ": ioremap failed\n");
+               printk(KERN_ERR "%s: ioremap failed\n", __FILE__);
                rv = -ENOMEM;
                goto err_ioremap;
        }
@@ -169,7 +169,7 @@ ohci_hcd_ppc_of_probe(struct of_device *op, const struct of_device_id *match)
                        } else
                                release_mem_region(res.start, 0x4);
                } 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);
@@ -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
        {
                .name = "usb",
index cd3398b675b2dea8c2402fd2178cee58c23a52e4..89e670e38c106b79f8851563728280e5e442e744 100644 (file)
@@ -41,14 +41,14 @@ static int usb_hcd_ppc_soc_probe(const struct hc_driver *driver,
 
        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (!res) {
-               pr_debug(__FILE__ ": no irq\n");
+               pr_debug("%s: no irq\n", __FILE__);
                return -ENODEV;
        }
        irq = res->start;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
-               pr_debug(__FILE__ ": no reg addr\n");
+               pr_debug("%s: no reg addr\n", __FILE__);
                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;
 
        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;
                goto err1;
        }
 
        hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
        if (!hcd->regs) {
-               pr_debug(__FILE__ ": ioremap failed\n");
+               pr_debug("%s: ioremap failed\n", __FILE__);
                retval = -ENOMEM;
                goto err2;
        }
index e4bbe8e188e4653355426294e511e92588085b9a..d8eb3bdafabb9287a5d98a77c8ee96c0ea4df339 100644 (file)
@@ -31,8 +31,8 @@ static void sa1111_start_hc(struct sa1111_dev *dev)
 {
        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
        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)
 {
        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.
index 5b22a4d1c9e491e3489e31ce3803623cec5c67c6..e11cc3aa4b82f2bd968d89e187f3a2c1ed53d40b 100644 (file)
@@ -51,6 +51,7 @@
 #include <asm/irq.h>
 #include <asm/system.h>
 #include <asm/byteorder.h>
+#include <asm/unaligned.h>
 
 #include "../core/hcd.h"
 #include "sl811.h"
@@ -1272,12 +1273,12 @@ sl811h_hub_control(
                sl811h_hub_descriptor(sl811, (struct usb_hub_descriptor *) buf);
                break;
        case GetHubStatus:
-               *(__le32 *) buf = cpu_to_le32(0);
+               put_unaligned_le32(0, buf);
                break;
        case GetPortStatus:
                if (wIndex != 1)
                        goto error;
-               *(__le32 *) buf = cpu_to_le32(sl811->port1);
+               put_unaligned_le32(sl811->port1, buf);
 
 #ifndef        VERBOSE
        if (*(u16*)(buf+2))     /* only if wPortChange is interesting */
index 99cd00fd3514c7f25abb0b42977e14c61edbb6ca..09197067fe6bc1032c4859fa557b5b15bb8be92c 100644 (file)
@@ -735,6 +735,7 @@ static void uhci_stop(struct usb_hcd *hcd)
                uhci_hc_died(uhci);
        uhci_scan_schedule(uhci);
        spin_unlock_irq(&uhci->lock);
+       synchronize_irq(hcd->irq);
 
        del_timer_sync(&uhci->fsbr_timer);
        release_uhci(uhci);
index 33128d52f21285ae04272e56659b6f800ea4bebd..105fa8b025bbb0375ae1fc543732507f4bfba80a 100644 (file)
@@ -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)
 {
        /* Fields are 32 bits wide, DMA addresses are in bytes */
index ecc131c3fe337a68788054dfc2dc695503b30a77..78c4edac1db14cf324cd90a039467d22f90ae53f 100644 (file)
@@ -101,12 +101,15 @@ static inline int xhci_find_next_cap_offset(void __iomem *base, int 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 */
                next = XHCI_HCC_EXT_CAPS(next);
-       else
+               ext_offset = 0;
+       } else {
                /* Find the next extended capability */
                next = XHCI_EXT_CAPS_NEXT(next);
+       }
+
        if (!next)
                return 0;
        /*
index 5e92c72df6420d025573850890d89319b12cd043..4cb69e0af83442230fc13448a3e31f5b144ebe86 100644 (file)
@@ -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).
         */
        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",
                                __func__, ep->desc.bEndpointAddress);
                return -ENOMEM;
@@ -1181,6 +1181,8 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
                ret = xhci_queue_evaluate_context(xhci, in_ctx->dma,
                                udev->slot_id);
        if (ret < 0) {
+               if (command)
+                       list_del(&command->cmd_list);
                spin_unlock_irqrestore(&xhci->lock, flags);
                xhci_dbg(xhci, "FIXME allocate a new ring segment\n");
                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);
        /* Install new rings and free or cache any old rings */
        for (i = 1; i < 31; ++i) {
-               int rings_cached;
-
                if (!virt_dev->eps[i].new_ring)
                        continue;
                /* Only cache or free the old ring if it exists.
                 * It may not if this is the first add of an endpoint.
                 */
                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].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");
 }
 
+/*
+ * 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
  * 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");
                return -EINVAL;
        }
-       config_cmd = xhci_alloc_command(xhci, true, mem_flags);
+       config_cmd = xhci_alloc_command(xhci, true, true, mem_flags);
        if (!config_cmd) {
                xhci_dbg(xhci, "Could not allocate xHCI command structure.\n");
                return -ENOMEM;
index eac5b53aa9e77c57fd1ffb09ac1fcac21cee2c9d..208b805b80eb0151d5d5a4e614db8a8fa9ab17eb 100644 (file)
@@ -129,6 +129,50 @@ static u32 xhci_port_state_to_neutral(u32 state)
        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,
                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;
        int retval = 0;
        u32 __iomem *addr;
-       char *port_change_bit;
 
        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);
                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";
+               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;
                default:
                        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;
        default:
 error:
index bffcef7a5545ec87dbdcc24cd0d43a45be401f60..49f7d72f8b1b0e5e936077024b3f9720d15178e0 100644 (file)
@@ -198,6 +198,31 @@ fail:
        return 0;
 }
 
+void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
+               struct xhci_virt_device *virt_dev,
+               unsigned int ep_index)
+{
+       int rings_cached;
+
+       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[ep_index].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[ep_index].ring);
+               xhci_dbg(xhci, "Ring cache full (%d rings), "
+                               "freeing ring\n",
+                               virt_dev->num_rings_cached);
+       }
+       virt_dev->eps[ep_index].ring = NULL;
+}
+
 /* Zero an endpoint ring (except for link TRBs) and move the enqueue and dequeue
  * pointers to the beginning of the ring.
  */
@@ -242,6 +267,8 @@ struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
 void xhci_free_container_ctx(struct xhci_hcd *xhci,
                             struct xhci_container_ctx *ctx)
 {
+       if (!ctx)
+               return;
        dma_pool_free(xhci->device_pool, ctx->bytes, ctx->dma);
        kfree(ctx);
 }
@@ -427,7 +454,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
        case USB_SPEED_LOW:
                slot_ctx->dev_info |= (u32) SLOT_SPEED_LS;
                break;
-       case USB_SPEED_VARIABLE:
+       case USB_SPEED_WIRELESS:
                xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
                return -EINVAL;
                break;
@@ -471,7 +498,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
        case USB_SPEED_LOW:
                ep0_ctx->ep_info2 |= MAX_PACKET(8);
                break;
-       case USB_SPEED_VARIABLE:
+       case USB_SPEED_WIRELESS:
                xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
                return -EINVAL;
                break;
@@ -819,7 +846,8 @@ static void scratchpad_free(struct xhci_hcd *xhci)
 }
 
 struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
-               bool allocate_completion, gfp_t mem_flags)
+               bool allocate_in_ctx, bool allocate_completion,
+               gfp_t mem_flags)
 {
        struct xhci_command *command;
 
@@ -827,11 +855,14 @@ struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
        if (!command)
                return NULL;
 
-       command->in_ctx =
-               xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT, mem_flags);
-       if (!command->in_ctx) {
-               kfree(command);
-               return NULL;
+       if (allocate_in_ctx) {
+               command->in_ctx =
+                       xhci_alloc_container_ctx(xhci, XHCI_CTX_TYPE_INPUT,
+                                       mem_flags);
+               if (!command->in_ctx) {
+                       kfree(command);
+                       return NULL;
+               }
        }
 
        if (allocate_completion) {
index e097008d6fb1afe9cf8269721b60265ac2115970..417d37aff8d7245d9ca09a1fd830a787e063b81f 100644 (file)
@@ -139,6 +139,7 @@ static const struct hc_driver xhci_pci_hc_driver = {
        .reset_bandwidth =      xhci_reset_bandwidth,
        .address_device =       xhci_address_device,
        .update_hub_device =    xhci_update_hub_device,
+       .reset_device =         xhci_reset_device,
 
        /*
         * scheduling support
index ee7bc7ecbc595c98985eeca9f7e9fcfb7e16f677..6ba841bca4a28f24db9a76f6808f87e08c599194 100644 (file)
@@ -953,6 +953,17 @@ bandwidth_change:
        case TRB_TYPE(TRB_RESET_EP):
                handle_reset_ep_completion(xhci, event, xhci->cmd_ring->dequeue);
                break;
+       case TRB_TYPE(TRB_RESET_DEV):
+               xhci_dbg(xhci, "Completed reset device command.\n");
+               slot_id = TRB_TO_SLOT_ID(
+                               xhci->cmd_ring->dequeue->generic.field[3]);
+               virt_dev = xhci->devs[slot_id];
+               if (virt_dev)
+                       handle_cmd_in_cmd_wait_list(xhci, virt_dev, event);
+               else
+                       xhci_warn(xhci, "Reset device command completion "
+                                       "for disabled slot %u\n", slot_id);
+               break;
        default:
                /* Skip over unknown commands on the event ring */
                xhci->error_bitmask |= 1 << 6;
@@ -1080,6 +1091,20 @@ static int xhci_requires_manual_halt_cleanup(struct xhci_hcd *xhci,
        return 0;
 }
 
+int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code)
+{
+       if (trb_comp_code >= 224 && trb_comp_code <= 255) {
+               /* Vendor defined "informational" completion code,
+                * treat as not-an-error.
+                */
+               xhci_dbg(xhci, "Vendor defined info completion code %u\n",
+                               trb_comp_code);
+               xhci_dbg(xhci, "Treating code as success.\n");
+               return 1;
+       }
+       return 0;
+}
+
 /*
  * If this function returns an error condition, it means it got a Transfer
  * event with a corrupted Slot ID, Endpoint ID, or TRB DMA address.
@@ -1196,13 +1221,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                status = -ENOSR;
                break;
        default:
-               if (trb_comp_code >= 224 && trb_comp_code <= 255) {
-                       /* Vendor defined "informational" completion code,
-                        * treat as not-an-error.
-                        */
-                       xhci_dbg(xhci, "Vendor defined info completion code %u\n",
-                                       trb_comp_code);
-                       xhci_dbg(xhci, "Treating code as success.\n");
+               if (xhci_is_vendor_info_code(xhci, trb_comp_code)) {
                        status = 0;
                        break;
                }
@@ -2181,6 +2200,14 @@ int xhci_queue_address_device(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
                        false);
 }
 
+/* Queue a reset device command TRB */
+int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id)
+{
+       return queue_command(xhci, 0, 0, 0,
+                       TRB_TYPE(TRB_RESET_DEV) | SLOT_ID_FOR_TRB(slot_id),
+                       false);
+}
+
 /* Queue a configure endpoint command TRB */
 int xhci_queue_configure_endpoint(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
                u32 slot_id, bool command_must_succeed)
index 877813505ef2044d062a1f66b8215b4a952aeda2..e5eb09b2f38ed690451995f5899fd75136bdcea7 100644 (file)
@@ -1210,6 +1210,8 @@ void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst);
 void xhci_dbg_cmd_ptrs(struct xhci_hcd *xhci);
 void xhci_dbg_ring_ptrs(struct xhci_hcd *xhci, struct xhci_ring *ring);
 void xhci_dbg_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int last_ep);
+char *xhci_get_slot_state(struct xhci_hcd *xhci,
+               struct xhci_container_ctx *ctx);
 
 /* xHCI memory management */
 void xhci_mem_cleanup(struct xhci_hcd *xhci);
@@ -1233,8 +1235,12 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev,
                struct usb_device *udev, struct usb_host_endpoint *ep,
                gfp_t mem_flags);
 void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring);
+void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
+               struct xhci_virt_device *virt_dev,
+               unsigned int ep_index);
 struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
-               bool allocate_completion, gfp_t mem_flags);
+               bool allocate_in_ctx, bool allocate_completion,
+               gfp_t mem_flags);
 void xhci_free_command(struct xhci_hcd *xhci,
                struct xhci_command *command);
 
@@ -1264,6 +1270,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status);
 int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep);
 int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev, struct usb_host_endpoint *ep);
 void xhci_endpoint_reset(struct usb_hcd *hcd, struct usb_host_endpoint *ep);
+int xhci_reset_device(struct usb_hcd *hcd, struct usb_device *udev);
 int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
 void xhci_reset_bandwidth(struct usb_hcd *hcd, struct usb_device *udev);
 
@@ -1272,6 +1279,7 @@ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg, union xhci_trb *trb);
 struct xhci_segment *trb_in_td(struct xhci_segment *start_seg,
                union xhci_trb *start_trb, union xhci_trb *end_trb,
                dma_addr_t suspect_dma);
+int xhci_is_vendor_info_code(struct xhci_hcd *xhci, unsigned int trb_comp_code);
 void xhci_ring_cmd_db(struct xhci_hcd *xhci);
 void *xhci_setup_one_noop(struct xhci_hcd *xhci);
 void xhci_handle_event(struct xhci_hcd *xhci);
@@ -1293,6 +1301,7 @@ int xhci_queue_evaluate_context(struct xhci_hcd *xhci, dma_addr_t in_ctx_ptr,
                u32 slot_id);
 int xhci_queue_reset_ep(struct xhci_hcd *xhci, int slot_id,
                unsigned int ep_index);
+int xhci_queue_reset_device(struct xhci_hcd *xhci, u32 slot_id);
 void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
                unsigned int slot_id, unsigned int ep_index,
                struct xhci_td *cur_td, struct xhci_dequeue_state *state);
index eca355dccf651215387cf76e7ef5951c4ed35f25..e192e8f7c5601cdc7eda7c4ac72a1e425729a46b 100644 (file)
@@ -967,7 +967,7 @@ static const struct file_operations mdc800_device_ops =
 
 
 
-static struct usb_device_id mdc800_table [] = {
+static const struct usb_device_id mdc800_table[] = {
        { USB_DEVICE(MDC800_VENDOR_ID, MDC800_PRODUCT_ID) },
        { }                                             /* Terminating entry */
 };
index 459a7287fe01972ceecd944a32cb85efdf297a3c..3a6bcd5fee09a6959faca5b33ce3aa58eb5bfa97 100644 (file)
@@ -155,7 +155,7 @@ static int mts_usb_probe(struct usb_interface *intf,
                         const struct usb_device_id *id);
 static void mts_usb_disconnect(struct usb_interface *intf);
 
-static struct usb_device_id mts_usb_ids [];
+static const struct usb_device_id mts_usb_ids[];
 
 static struct usb_driver mts_usb_driver = {
        .name =         "microtekX6",
@@ -656,7 +656,7 @@ static struct scsi_host_template mts_scsi_host_template = {
 /* The entries of microtek_table must correspond, line-by-line to
    the entries of mts_supported_products[]. */
 
-static struct usb_device_id mts_usb_ids [] =
+static const struct usb_device_id mts_usb_ids[] =
 {
        { USB_DEVICE(0x4ce, 0x0300) },
        { USB_DEVICE(0x5da, 0x0094) },
index abe3aa67ed0033d59a6735d9d61e3ec97529ad01..55660eaf947c2cae20fa894f2867dd1d5c12bda7 100644 (file)
@@ -87,17 +87,6 @@ config USB_LCD
          To compile this driver as a module, choose M here: the
          module will be called usblcd.
 
-config USB_BERRY_CHARGE
-       tristate "USB BlackBerry recharge support"
-       depends on USB
-       help
-         Say Y here if you want to connect a BlackBerry device to your
-         computer's USB port and have it automatically switch to "recharge"
-         mode.
-
-         To compile this driver as a module, choose M here: the
-         module will be called berry_charge.
-
 config USB_LED
        tristate "USB LED driver support"
        depends on USB
@@ -242,17 +231,3 @@ config USB_ISIGHTFW
          driver beforehand. Tools for doing so are available at
          http://bersace03.free.fr
 
-config USB_VST
-       tristate "USB VST driver"
-       depends on USB
-       help
-         This driver is intended for Vernier Software Technologies
-         bulk usb devices such as their Ocean-Optics spectrometers or
-         Labquest.
-         It is a bulk channel driver with configurable read and write
-         timeouts.
-
-         To compile this driver as a module, choose M here: the
-         module will be called vstusb.
-
-
index 0826aab8303fc1e0e1a9bf33f46ef7b7204a6b4f..717703e81425e9e874097025bfcaf4121718a629 100644 (file)
@@ -5,7 +5,6 @@
 
 obj-$(CONFIG_USB_ADUTUX)       += adutux.o
 obj-$(CONFIG_USB_APPLEDISPLAY) += appledisplay.o
-obj-$(CONFIG_USB_BERRY_CHARGE) += berry_charge.o
 obj-$(CONFIG_USB_CYPRESS_CY7C63)+= cypress_cy7c63.o
 obj-$(CONFIG_USB_CYTHERM)      += cytherm.o
 obj-$(CONFIG_USB_EMI26)                += emi26.o
@@ -23,7 +22,6 @@ obj-$(CONFIG_USB_TEST)                += usbtest.o
 obj-$(CONFIG_USB_TRANCEVIBRATOR)       += trancevibrator.o
 obj-$(CONFIG_USB_USS720)       += uss720.o
 obj-$(CONFIG_USB_SEVSEG)       += usbsevseg.o
-obj-$(CONFIG_USB_VST)          += vstusb.o
 
 obj-$(CONFIG_USB_SISUSBVGA)    += sisusbvga/
 
index 20352654201399d78fb7c265285c714694d261f9..d240de097c6211afd6ff2ef1399c1b2add9ca751 100644 (file)
@@ -38,7 +38,7 @@ static int debug = 1;
 #define dbg(lvl, format, arg...)                                       \
 do {                                                                   \
        if (debug >= lvl)                                               \
-               printk(KERN_DEBUG __FILE__ " : " format " \n", ## arg); \
+               printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg); \
 } while (0)
 
 
@@ -56,7 +56,7 @@ MODULE_PARM_DESC(debug, "Debug enabled or not");
 #define ADU_PRODUCT_ID 0x0064
 
 /* table of devices that work with this driver */
-static struct usb_device_id device_table [] = {
+static const struct usb_device_id device_table[] = {
        { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID) },          /* ADU100 */
        { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+20) },       /* ADU120 */
        { USB_DEVICE(ADU_VENDOR_ID, ADU_PRODUCT_ID+30) },       /* ADU130 */
@@ -132,8 +132,8 @@ static void adu_debug_data(int level, const char *function, int size,
        if (debug < level)
                return;
 
-       printk(KERN_DEBUG __FILE__": %s - length = %d, data = ",
-              function, size);
+       printk(KERN_DEBUG "%s: %s - length = %d, data = ",
+              __FILE__, function, size);
        for (i = 0; i < size; ++i)
                printk("%.2x ", data[i]);
        printk("\n");
index 1eb9e4162cc6a916a3ed8cce7641be7ffb2aa529..4d2952f1fb1370f86b7c13630ee7a096769f94e5 100644 (file)
@@ -57,7 +57,7 @@
        .bInterfaceProtocol = 0x00
 
 /* table of devices that work with this driver */
-static struct usb_device_id appledisplay_table [] = {
+static const struct usb_device_id appledisplay_table[] = {
        { APPLEDISPLAY_DEVICE(0x9218) },
        { APPLEDISPLAY_DEVICE(0x9219) },
        { APPLEDISPLAY_DEVICE(0x921c) },
@@ -179,7 +179,7 @@ static int appledisplay_bl_get_brightness(struct backlight_device *bd)
                return pdata->msgdata[1];
 }
 
-static struct backlight_ops appledisplay_bl_data = {
+static const struct backlight_ops appledisplay_bl_data = {
        .get_brightness = appledisplay_bl_get_brightness,
        .update_status  = appledisplay_bl_update_status,
 };
@@ -283,6 +283,7 @@ static int appledisplay_probe(struct usb_interface *iface,
                                                &appledisplay_bl_data);
        if (IS_ERR(pdata->bd)) {
                dev_err(&iface->dev, "Backlight registration failed\n");
+               retval = PTR_ERR(pdata->bd);
                goto error;
        }
 
diff --git a/drivers/usb/misc/berry_charge.c b/drivers/usb/misc/berry_charge.c
deleted file mode 100644 (file)
index c05a85b..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * USB BlackBerry charging module
- *
- * Copyright (C) 2007 Greg Kroah-Hartman <gregkh@suse.de>
- *
- *     This program is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation, version 2.
- *
- * Information on how to switch configs was taken by the bcharge.cc file
- * created by the barry.sf.net project.
- *
- * bcharge.cc has the following copyright:
- *     Copyright (C) 2006, Net Direct Inc. (http://www.netdirect.ca/)
- * and is released under the GPLv2.
- *
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/usb.h>
-
-#define RIM_VENDOR             0x0fca
-#define BLACKBERRY             0x0001
-#define BLACKBERRY_PEARL_DUAL   0x0004
-#define BLACKBERRY_PEARL        0x0006
-
-static int debug;
-static int pearl_dual_mode = 1;
-
-#ifdef dbg
-#undef dbg
-#endif
-#define dbg(dev, format, arg...)                               \
-       if (debug)                                              \
-               dev_printk(KERN_DEBUG , dev , format , ## arg)
-
-static struct usb_device_id id_table [] = {
-       { USB_DEVICE(RIM_VENDOR, BLACKBERRY) },
-       { USB_DEVICE(RIM_VENDOR, BLACKBERRY_PEARL) },
-       { USB_DEVICE(RIM_VENDOR, BLACKBERRY_PEARL_DUAL) },
-       { },                                    /* Terminating entry */
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-static int magic_charge(struct usb_device *udev)
-{
-       char *dummy_buffer = kzalloc(2, GFP_KERNEL);
-       int retval;
-
-       if (!dummy_buffer)
-               return -ENOMEM;
-
-       /* send two magic commands and then set the configuration.  The device
-        * will then reset itself with the new power usage and should start
-        * charging. */
-
-       /* Note, with testing, it only seems that the first message is really
-        * needed (at least for the 8700c), but to be safe, we emulate what
-        * other operating systems seem to be sending to their device.  We
-        * really need to get some specs for this device to be sure about what
-        * is going on here.
-        */
-       dbg(&udev->dev, "Sending first magic command\n");
-       retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-                                0xa5, 0xc0, 0, 1, dummy_buffer, 2, 100);
-       if (retval != 2) {
-               dev_err(&udev->dev, "First magic command failed: %d.\n",
-                       retval);
-               goto exit;
-       }
-
-       dbg(&udev->dev, "Sending second magic command\n");
-       retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-                                0xa2, 0x40, 0, 1, dummy_buffer, 0, 100);
-       if (retval != 0) {
-               dev_err(&udev->dev, "Second magic command failed: %d.\n",
-                       retval);
-               goto exit;
-       }
-
-       dbg(&udev->dev, "Calling set_configuration\n");
-       retval = usb_driver_set_configuration(udev, 1);
-       if (retval)
-               dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
-
-exit:
-       kfree(dummy_buffer);
-       return retval;
-}
-
-static int magic_dual_mode(struct usb_device *udev)
-{
-       char *dummy_buffer = kzalloc(2, GFP_KERNEL);
-       int retval;
-
-       if (!dummy_buffer)
-               return -ENOMEM;
-
-       /* send magic command so that the Blackberry Pearl device exposes
-        * two interfaces: both the USB mass-storage one and one which can
-        * be used for database access. */
-       dbg(&udev->dev, "Sending magic pearl command\n");
-       retval = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
-                                0xa9, 0xc0, 1, 1, dummy_buffer, 2, 100);
-       dbg(&udev->dev, "Magic pearl command returned %d\n", retval);
-
-       dbg(&udev->dev, "Calling set_configuration\n");
-       retval = usb_driver_set_configuration(udev, 1);
-       if (retval)
-               dev_err(&udev->dev, "Set Configuration failed :%d.\n", retval);
-
-       kfree(dummy_buffer);
-       return retval;
-}
-
-static int berry_probe(struct usb_interface *intf,
-                      const struct usb_device_id *id)
-{
-       struct usb_device *udev = interface_to_usbdev(intf);
-
-       if (udev->bus_mA < 500) {
-               dbg(&udev->dev, "Not enough power to charge available\n");
-               return -ENODEV;
-       }
-
-       dbg(&udev->dev, "Power is set to %dmA\n",
-           udev->actconfig->desc.bMaxPower * 2);
-
-       /* check the power usage so we don't try to enable something that is
-        * already enabled */
-       if ((udev->actconfig->desc.bMaxPower * 2) == 500) {
-               dbg(&udev->dev, "device is already charging, power is "
-                   "set to %dmA\n", udev->actconfig->desc.bMaxPower * 2);
-               return -ENODEV;
-       }
-
-       /* turn the power on */
-       magic_charge(udev);
-
-       if ((le16_to_cpu(udev->descriptor.idProduct) == BLACKBERRY_PEARL) &&
-           (pearl_dual_mode))
-               magic_dual_mode(udev);
-
-       /* we don't really want to bind to the device, userspace programs can
-        * handle the syncing just fine, so get outta here. */
-       return -ENODEV;
-}
-
-static void berry_disconnect(struct usb_interface *intf)
-{
-}
-
-static struct usb_driver berry_driver = {
-       .name =         "berry_charge",
-       .probe =        berry_probe,
-       .disconnect =   berry_disconnect,
-       .id_table =     id_table,
-};
-
-static int __init berry_init(void)
-{
-       return usb_register(&berry_driver);
-}
-
-static void __exit berry_exit(void)
-{
-       usb_deregister(&berry_driver);
-}
-
-module_init(berry_init);
-module_exit(berry_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@suse.de>");
-module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug enabled or not");
-module_param(pearl_dual_mode, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(pearl_dual_mode, "Change Blackberry Pearl to run in dual mode");
index 5720bfef6a389ada6709be2ffac3aca06a1d969a..1547d8cac5fb96fcae8f87b0085a63c277eb1320 100644 (file)
@@ -56,7 +56,7 @@
 
 
 /* table of devices that work with this driver */
-static struct usb_device_id cypress_table [] = {
+static const struct usb_device_id cypress_table[] = {
        { USB_DEVICE(CYPRESS_VENDOR_ID, CYPRESS_PRODUCT_ID) },
        { }
 };
index 4fb3c38b924b2fec1aad271da12f851e81f6e6e2..b9cbbbda824558f20802d18b28ae9151ce59a3d3 100644 (file)
@@ -27,7 +27,7 @@
 #define USB_SKEL_VENDOR_ID     0x04b4
 #define USB_SKEL_PRODUCT_ID    0x0002
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
        { }
 };
index 879a980ca8c4a1a0b37a892b4cfc333539c15a55..a6521c95f683255597fb72f4c8a32a4b2bdfae82 100644 (file)
@@ -245,7 +245,7 @@ wraperr:
        return err;
 }
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(EMI26_VENDOR_ID, EMI26_PRODUCT_ID) },
        { USB_DEVICE(EMI26_VENDOR_ID, EMI26B_PRODUCT_ID) },
        { }                                             /* Terminating entry */
index 59860b328534d893a8075f7cb2681a77f6fe69ce..fc15ad4c3139ca17432ced814bdc3204c559f56a 100644 (file)
@@ -259,7 +259,7 @@ wraperr:
        return err;
 }
 
-static __devinitdata struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] __devinitconst = {
        { USB_DEVICE(EMI62_VENDOR_ID, EMI62_PRODUCT_ID) },
        { }                                             /* Terminating entry */
 };
index 9d0675ed0d4c89e0acbf488dfd6beb7df9e9131c..1edb6d3618964ed160d6682d2ece2a77aeb10c99 100644 (file)
@@ -86,7 +86,7 @@ static struct list_head ftdi_static_list;
 #define USB_FTDI_ELAN_VENDOR_ID 0x0403
 #define USB_FTDI_ELAN_PRODUCT_ID 0xd6ea
 /* table of devices that work with this driver*/
-static struct usb_device_id ftdi_elan_table[] = {
+static const struct usb_device_id ftdi_elan_table[] = {
         {USB_DEVICE(USB_FTDI_ELAN_VENDOR_ID, USB_FTDI_ELAN_PRODUCT_ID)},
         { /* Terminating entry */ }
 };
@@ -623,9 +623,12 @@ static void ftdi_elan_status_work(struct work_struct *work)
 */
 static int ftdi_elan_open(struct inode *inode, struct file *file)
 {
-        int subminor = iminor(inode);
-        struct usb_interface *interface = usb_find_interface(&ftdi_elan_driver,
-                subminor);
+       int subminor;
+       struct usb_interface *interface;
+
+        subminor = iminor(inode);
+        interface = usb_find_interface(&ftdi_elan_driver, subminor);
+
         if (!interface) {
                 printk(KERN_ERR "can't find device for minor %d\n", subminor);
                 return -ENODEV;
index 1337a9ce80b9c8a66a546c646e24261ae6e73433..a54c3cb804ce4a5e6cf315aa03508ac3231ee0c8 100644 (file)
@@ -48,7 +48,7 @@
 #define ID_CHERRY  0x0010
 
 /* device ID table */
-static struct usb_device_id idmouse_table[] = {
+static const struct usb_device_id idmouse_table[] = {
        {USB_DEVICE(ID_SIEMENS, ID_IDMOUSE)}, /* Siemens ID Mouse (Professional) */
        {USB_DEVICE(ID_SIEMENS, ID_CHERRY )}, /* Cherry FingerTIP ID Board       */
        {}                                    /* terminating null entry          */
index e75bb87ee92b87f39d67b883bb22f4f77fce3a79..d3c8523638832f34c0d7fe5319232b1045df979d 100644 (file)
@@ -139,7 +139,7 @@ static int usb_set_report(struct usb_interface *intf, unsigned char type,
 /* driver registration */
 /*---------------------*/
 /* table of devices that work with this driver */
-static struct usb_device_id iowarrior_ids[] = {
+static const struct usb_device_id iowarrior_ids[] = {
        {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW40)},
        {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOW24)},
        {USB_DEVICE(USB_VENDOR_ID_CODEMERCS, USB_DEVICE_ID_CODEMERCS_IOWPV1)},
@@ -602,10 +602,12 @@ static int iowarrior_open(struct inode *inode, struct file *file)
 
        dbg("%s", __func__);
 
+       lock_kernel();
        subminor = iminor(inode);
 
        interface = usb_find_interface(&iowarrior_driver, subminor);
        if (!interface) {
+               unlock_kernel();
                err("%s - error, can't find device for minor %d", __func__,
                    subminor);
                return -ENODEV;
@@ -615,6 +617,7 @@ static int iowarrior_open(struct inode *inode, struct file *file)
        dev = usb_get_intfdata(interface);
        if (!dev) {
                mutex_unlock(&iowarrior_open_disc_lock);
+               unlock_kernel();
                return -ENODEV;
        }
 
@@ -641,6 +644,7 @@ static int iowarrior_open(struct inode *inode, struct file *file)
 
 out:
        mutex_unlock(&dev->mutex);
+       unlock_kernel();
        return retval;
 }
 
index b897f6554ecdd0e282fd4d5b0dfed072f041f3b7..06e990adc6cdd50e77657beeb5a690d7684ed224 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/errno.h>
 #include <linux/module.h>
 
-static struct usb_device_id id_table[] = {
+static const struct usb_device_id id_table[] = {
        {USB_DEVICE(0x05ac, 0x8300)},
        {},
 };
@@ -112,6 +112,8 @@ out:
        return ret;
 }
 
+MODULE_FIRMWARE("isight.fw");
+
 static void isight_firmware_disconnect(struct usb_interface *intf)
 {
 }
index 90f130126c10d605db2115ee6c16afe8329266cb..dd41d871004353b5e8bccba16b8899d4aa53aa5a 100644 (file)
@@ -69,7 +69,7 @@
 #endif
 
 /* table of devices that work with this driver */
-static struct usb_device_id ld_usb_table [] = {
+static const struct usb_device_id ld_usb_table[] = {
        { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_CASSY) },
        { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_POCKETCASSY) },
        { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MOBILECASSY) },
@@ -798,7 +798,7 @@ static int __init ld_usb_init(void)
        /* register this driver with the USB subsystem */
        retval = usb_register(&ld_usb_driver);
        if (retval)
-               err("usb_register failed for the "__FILE__" driver. Error number %d\n", retval);
+               err("usb_register failed for the %s driver. Error number %d\n", __FILE__, retval);
 
        return retval;
 }
index faa6d623de789ea5e6334e84651ba0675f852cf9..8547bf9e31752f6eb581011876f7b8ec3073883a 100644 (file)
 
 /* Use our own dbg macro */
 #undef dbg
-#define dbg(lvl, format, arg...) do { if (debug >= lvl) printk(KERN_DEBUG  __FILE__ ": " format "\n", ## arg); } while (0)
-
+#define dbg(lvl, format, arg...)                                       \
+do {                                                                   \
+       if (debug >= lvl)                                               \
+               printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg); \
+} while (0)
 
 /* Version Information */
 #define DRIVER_VERSION "v0.96"
@@ -192,7 +195,7 @@ struct tower_get_version_reply {
 
 
 /* table of devices that work with this driver */
-static struct usb_device_id tower_table [] = {
+static const struct usb_device_id tower_table[] = {
        { USB_DEVICE(LEGO_USB_TOWER_VENDOR_ID, LEGO_USB_TOWER_PRODUCT_ID) },
        { }                                     /* Terminating entry */
 };
@@ -302,7 +305,7 @@ static inline void lego_usb_tower_debug_data (int level, const char *function, i
        if (debug < level)
                return;
 
-       printk (KERN_DEBUG __FILE__": %s - length = %d, data = ", function, size);
+       printk (KERN_DEBUG "%s: %s - length = %d, data = ", __FILE__, function, size);
        for (i = 0; i < size; ++i) {
                printk ("%.2x ", data[i]);
        }
@@ -1055,7 +1058,7 @@ static int __init lego_usb_tower_init(void)
        /* register this driver with the USB subsystem */
        result = usb_register(&tower_driver);
        if (result < 0) {
-               err("usb_register failed for the "__FILE__" driver. Error number %d", result);
+               err("usb_register failed for the %s driver. Error number %d", __FILE__, result);
                retval = -1;
                goto exit;
        }
index 32d0199d0c3220a1c037856e5143bbd641b2cf38..a85771b1563d2c6151340b16da2319064da57cb4 100644 (file)
@@ -78,10 +78,13 @@ static int open_rio(struct inode *inode, struct file *file)
 {
        struct rio_usb_data *rio = &rio_instance;
 
+       /* against disconnect() */
+       lock_kernel();
        mutex_lock(&(rio->lock));
 
        if (rio->isopen || !rio->present) {
                mutex_unlock(&(rio->lock));
+               unlock_kernel();
                return -EBUSY;
        }
        rio->isopen = 1;
@@ -91,6 +94,7 @@ static int open_rio(struct inode *inode, struct file *file)
        mutex_unlock(&(rio->lock));
 
        dev_info(&rio->rio_dev->dev, "Rio opened.\n");
+       unlock_kernel();
 
        return 0;
 }
@@ -115,7 +119,6 @@ static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg)
        int retries;
        int retval=0;
 
-       lock_kernel();
        mutex_lock(&(rio->lock));
         /* Sanity check to make sure rio is connected, powered, etc */
         if (rio->present == 0 || rio->rio_dev == NULL) {
@@ -254,7 +257,6 @@ static long ioctl_rio(struct file *file, unsigned int cmd, unsigned long arg)
 
 err_out:
        mutex_unlock(&(rio->lock));
-       unlock_kernel();
        return retval;
 }
 
@@ -489,6 +491,7 @@ static void disconnect_rio(struct usb_interface *intf)
        struct rio_usb_data *rio = usb_get_intfdata (intf);
 
        usb_set_intfdata (intf, NULL);
+       lock_kernel();
        if (rio) {
                usb_deregister_dev(intf, &usb_rio_class);
 
@@ -498,6 +501,7 @@ static void disconnect_rio(struct usb_interface *intf)
                        /* better let it finish - the release will do whats needed */
                        rio->rio_dev = NULL;
                        mutex_unlock(&(rio->lock));
+                       unlock_kernel();
                        return;
                }
                kfree(rio->ibuf);
@@ -508,9 +512,10 @@ static void disconnect_rio(struct usb_interface *intf)
                rio->present = 0;
                mutex_unlock(&(rio->lock));
        }
+       unlock_kernel();
 }
 
-static struct usb_device_id rio_table [] = {
+static const struct usb_device_id rio_table[] = {
        { USB_DEVICE(0x0841, 1) },              /* Rio 500 */
        { }                                     /* Terminating entry */
 };
index 8b37a4b9839edcbc047258f391c73a8a16a82263..aae95a009bd57c39c49cc4bbe866d1ffc95aeeb7 100644 (file)
@@ -250,7 +250,7 @@ sisusb_bulkout_msg(struct sisusb_usb_data *sisusb, int index, unsigned int pipe,
        sisusb->urbstatus[index] |= SU_URB_BUSY;
 
        /* Submit URB */
-       retval = usb_submit_urb(urb, GFP_ATOMIC);
+       retval = usb_submit_urb(urb, GFP_KERNEL);
 
        /* If OK, and if timeout > 0, wait for completion */
        if ((retval == 0) && timeout) {
@@ -306,7 +306,7 @@ sisusb_bulkin_msg(struct sisusb_usb_data *sisusb, unsigned int pipe, void *data,
        urb->actual_length = 0;
 
        sisusb->completein = 0;
-       retval = usb_submit_urb(urb, GFP_ATOMIC);
+       retval = usb_submit_urb(urb, GFP_KERNEL);
        if (retval == 0) {
                wait_event_timeout(sisusb->wait_q, sisusb->completein, timeout);
                if (!sisusb->completein) {
@@ -2416,21 +2416,28 @@ sisusb_open(struct inode *inode, struct file *file)
        struct usb_interface *interface;
        int subminor = iminor(inode);
 
-       if (!(interface = usb_find_interface(&sisusb_driver, subminor)))
+       lock_kernel();
+       if (!(interface = usb_find_interface(&sisusb_driver, subminor))) {
+               unlock_kernel();
                return -ENODEV;
+       }
 
-       if (!(sisusb = usb_get_intfdata(interface)))
+       if (!(sisusb = usb_get_intfdata(interface))) {
+               unlock_kernel();
                return -ENODEV;
+       }
 
        mutex_lock(&sisusb->lock);
 
        if (!sisusb->present || !sisusb->ready) {
                mutex_unlock(&sisusb->lock);
+               unlock_kernel();
                return -ENODEV;
        }
 
        if (sisusb->isopen) {
                mutex_unlock(&sisusb->lock);
+               unlock_kernel();
                return -EBUSY;
        }
 
@@ -2439,11 +2446,13 @@ sisusb_open(struct inode *inode, struct file *file)
                        if (sisusb_init_gfxdevice(sisusb, 0)) {
                                mutex_unlock(&sisusb->lock);
                                dev_err(&sisusb->sisusb_dev->dev, "Failed to initialize device\n");
+                               unlock_kernel();
                                return -EIO;
                        }
                } else {
                        mutex_unlock(&sisusb->lock);
                        dev_err(&sisusb->sisusb_dev->dev, "Device not attached to USB 2.0 hub\n");
+                       unlock_kernel();
                        return -EIO;
                }
        }
@@ -2456,6 +2465,7 @@ sisusb_open(struct inode *inode, struct file *file)
        file->private_data = sisusb;
 
        mutex_unlock(&sisusb->lock);
+       unlock_kernel();
 
        return 0;
 }
@@ -3238,7 +3248,7 @@ static void sisusb_disconnect(struct usb_interface *intf)
        kref_put(&sisusb->kref, sisusb_delete);
 }
 
-static struct usb_device_id sisusb_table [] = {
+static const struct usb_device_id sisusb_table[] = {
        { USB_DEVICE(0x0711, 0x0550) },
        { USB_DEVICE(0x0711, 0x0900) },
        { USB_DEVICE(0x0711, 0x0901) },
index 2e14102955c5936def7394c9faea1306696f18bb..5da28eaee314c0e0ecdba8bed88f925e71a123ed 100644 (file)
@@ -33,7 +33,7 @@
 #define TRANCEVIBRATOR_VENDOR_ID       0x0b49  /* ASCII Corporation */
 #define TRANCEVIBRATOR_PRODUCT_ID      0x064f  /* Trance Vibrator */
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(TRANCEVIBRATOR_VENDOR_ID, TRANCEVIBRATOR_PRODUCT_ID) },
        { },
 };
index 4fb120357c5569cc7ab1bc5a90e83f1851910f54..90aede90553e112e69410a129e3bbbd2e2d29e6a 100644 (file)
@@ -30,7 +30,7 @@
 #define IOCTL_GET_DRV_VERSION  2
 
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { .idVendor = 0x10D2, .match_flags = USB_DEVICE_ID_MATCH_VENDOR, },
        { },
 };
@@ -74,10 +74,12 @@ static int lcd_open(struct inode *inode, struct file *file)
        struct usb_interface *interface;
        int subminor, r;
 
+       lock_kernel();
        subminor = iminor(inode);
 
        interface = usb_find_interface(&lcd_driver, subminor);
        if (!interface) {
+               unlock_kernel();
                err ("USBLCD: %s - error, can't find device for minor %d",
                     __func__, subminor);
                return -ENODEV;
@@ -87,6 +89,7 @@ static int lcd_open(struct inode *inode, struct file *file)
        dev = usb_get_intfdata(interface);
        if (!dev) {
                mutex_unlock(&open_disc_mutex);
+               unlock_kernel();
                return -ENODEV;
        }
 
@@ -98,11 +101,13 @@ static int lcd_open(struct inode *inode, struct file *file)
        r = usb_autopm_get_interface(interface);
        if (r < 0) {
                kref_put(&dev->kref, lcd_delete);
+               unlock_kernel();
                return r;
        }
 
        /* save our object in the file's private structure */
        file->private_data = dev;
+       unlock_kernel();
 
        return 0;
 }
index 06cb71942dc7ee87e52c56c1be0410d64a707be4..63da2c3c838fd0b6495d0429a870e3b1e035e9dd 100644 (file)
@@ -24,7 +24,7 @@
 #define PRODUCT_ID     0x1223
 
 /* table of devices that work with this driver */
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(VENDOR_ID, PRODUCT_ID) },
        { },
 };
index 3db255537e7913d2de5d0b03781fc20768af2a91..a9555cb901a1df27274d415255563242d74c178a 100644 (file)
@@ -27,7 +27,7 @@
 #define MAXLEN         6
 
 /* table of devices that work with this driver */
-static struct usb_device_id id_table[] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(VENDOR_ID, PRODUCT_ID) },
        { },
 };
index 3dab0c0b196f56a4f3c625b883d8064ffa900992..a21cce6f7403e723e42adad28524789ac807a4e4 100644 (file)
@@ -1580,10 +1580,6 @@ usbtest_ioctl (struct usb_interface *intf, unsigned int code, void *buf)
                return -ERESTARTSYS;
 
        /* FIXME: What if a system sleep starts while a test is running? */
-       if (!intf->is_active) {
-               mutex_unlock(&dev->lock);
-               return -EHOSTUNREACH;
-       }
 
        /* some devices, like ez-usb default devices, need a non-default
         * altsetting to have any active endpoints.  some tests change
@@ -2101,7 +2097,7 @@ static struct usbtest_info generic_info = {
 #endif
 
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
 
        /*-------------------------------------------------------------*/
 
index 9a6c27a01793ba2ff6111ede23e769ade617b64d..f56fed53f2dd202b8f6cc551488e3590f006af7a 100644 (file)
@@ -770,7 +770,7 @@ static void uss720_disconnect(struct usb_interface *intf)
 }
 
 /* table of cables that work through this driver */
-static struct usb_device_id uss720_table [] = {
+static const struct usb_device_id uss720_table[] = {
        { USB_DEVICE(0x047e, 0x1001) },
        { USB_DEVICE(0x0557, 0x2001) },
        { USB_DEVICE(0x0729, 0x1284) },
diff --git a/drivers/usb/misc/vstusb.c b/drivers/usb/misc/vstusb.c
deleted file mode 100644 (file)
index f26ea8d..0000000
+++ /dev/null
@@ -1,783 +0,0 @@
-/*****************************************************************************
- *  File: drivers/usb/misc/vstusb.c
- *
- *  Purpose: Support for the bulk USB Vernier Spectrophotometers
- *
- *  Author:     Johnnie Peters
- *              Axian Consulting
- *              Beaverton, OR, USA 97005
- *
- *  Modified by:     EQware Engineering, Inc.
- *                   Oregon City, OR, USA 97045
- *
- *  Copyright:  2007, 2008
- *              Vernier Software & Technology
- *              Beaverton, OR, USA 97005
- *
- *  Web:        www.vernier.com
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- *
- *****************************************************************************/
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-#include <linux/usb.h>
-
-#include <linux/usb/vstusb.h>
-
-#define DRIVER_VERSION "VST USB Driver Version 1.5"
-#define DRIVER_DESC "Vernier Software Technology Bulk USB Driver"
-
-#ifdef CONFIG_USB_DYNAMIC_MINORS
-       #define VSTUSB_MINOR_BASE       0
-#else
-       #define VSTUSB_MINOR_BASE       199
-#endif
-
-#define USB_VENDOR_OCEANOPTICS 0x2457
-#define USB_VENDOR_VERNIER     0x08F7  /* Vernier Software & Technology */
-
-#define USB_PRODUCT_USB2000    0x1002
-#define USB_PRODUCT_ADC1000_FW 0x1003  /* firmware download (renumerates) */
-#define USB_PRODUCT_ADC1000    0x1004
-#define USB_PRODUCT_HR2000_FW  0x1009  /* firmware download (renumerates) */
-#define USB_PRODUCT_HR2000     0x100A
-#define USB_PRODUCT_HR4000_FW  0x1011  /* firmware download (renumerates) */
-#define USB_PRODUCT_HR4000     0x1012
-#define USB_PRODUCT_USB650     0x1014  /* "Red Tide" */
-#define USB_PRODUCT_QE65000    0x1018
-#define USB_PRODUCT_USB4000    0x1022
-#define USB_PRODUCT_USB325     0x1024  /* "Vernier Spectrometer" */
-
-#define USB_PRODUCT_LABPRO     0x0001
-#define USB_PRODUCT_LABQUEST   0x0005
-
-#define VST_MAXBUFFER          (64*1024)
-
-static struct usb_device_id id_table[] = {
-       { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB2000)},
-       { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_HR4000)},
-       { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB650)},
-       { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB4000)},
-       { USB_DEVICE(USB_VENDOR_OCEANOPTICS, USB_PRODUCT_USB325)},
-       { USB_DEVICE(USB_VENDOR_VERNIER, USB_PRODUCT_LABQUEST)},
-       { USB_DEVICE(USB_VENDOR_VERNIER, USB_PRODUCT_LABPRO)},
-       {},
-};
-
-MODULE_DEVICE_TABLE(usb, id_table);
-
-struct vstusb_device {
-       struct kref                             kref;
-       struct mutex            lock;
-       struct usb_device       *usb_dev;
-       char                    present;
-       char                    isopen;
-       struct usb_anchor       submitted;
-       int                     rd_pipe;
-       int                     rd_timeout_ms;
-       int                     wr_pipe;
-       int                     wr_timeout_ms;
-};
-#define to_vst_dev(d) container_of(d, struct vstusb_device, kref)
-
-static struct usb_driver vstusb_driver;
-
-static void vstusb_delete(struct kref *kref)
-{
-       struct vstusb_device *vstdev = to_vst_dev(kref);
-
-       usb_put_dev(vstdev->usb_dev);
-       kfree(vstdev);
-}
-
-static int vstusb_open(struct inode *inode, struct file *file)
-{
-       struct vstusb_device *vstdev;
-       struct usb_interface *interface;
-
-       interface = usb_find_interface(&vstusb_driver, iminor(inode));
-
-       if (!interface) {
-               printk(KERN_ERR KBUILD_MODNAME
-                      ": %s - error, can't find device for minor %d\n",
-                      __func__, iminor(inode));
-               return -ENODEV;
-       }
-
-       vstdev = usb_get_intfdata(interface);
-
-       if (!vstdev)
-               return -ENODEV;
-
-       /* lock this device */
-       mutex_lock(&vstdev->lock);
-
-       /* can only open one time */
-       if ((!vstdev->present) || (vstdev->isopen)) {
-               mutex_unlock(&vstdev->lock);
-               return -EBUSY;
-       }
-
-       /* increment our usage count */
-       kref_get(&vstdev->kref);
-
-       vstdev->isopen = 1;
-
-       /* save device in the file's private structure */
-       file->private_data = vstdev;
-
-       dev_dbg(&vstdev->usb_dev->dev, "%s: opened\n", __func__);
-
-       mutex_unlock(&vstdev->lock);
-
-       return 0;
-}
-
-static int vstusb_release(struct inode *inode, struct file *file)
-{
-       struct vstusb_device *vstdev;
-
-       vstdev = file->private_data;
-
-       if (vstdev == NULL)
-               return -ENODEV;
-
-       mutex_lock(&vstdev->lock);
-
-       vstdev->isopen = 0;
-
-       dev_dbg(&vstdev->usb_dev->dev, "%s: released\n", __func__);
-
-       mutex_unlock(&vstdev->lock);
-
-       kref_put(&vstdev->kref, vstusb_delete);
-
-       return 0;
-}
-
-static void usb_api_blocking_completion(struct urb *urb)
-{
-       struct completion *completeit = urb->context;
-
-       complete(completeit);
-}
-
-static int vstusb_fill_and_send_urb(struct urb *urb,
-                                   struct usb_device *usb_dev,
-                                   unsigned int pipe, void *data,
-                                   unsigned int len, struct completion *done)
-{
-       struct usb_host_endpoint *ep;
-       struct usb_host_endpoint **hostep;
-       unsigned int pipend;
-
-       int status;
-
-       hostep = usb_pipein(pipe) ? usb_dev->ep_in : usb_dev->ep_out;
-       pipend = usb_pipeendpoint(pipe);
-       ep = hostep[pipend];
-
-       if (!ep || (len == 0))
-               return -EINVAL;
-
-       if ((ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
-           == USB_ENDPOINT_XFER_INT) {
-               pipe = (pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
-               usb_fill_int_urb(urb, usb_dev, pipe, data, len,
-                                (usb_complete_t)usb_api_blocking_completion,
-                                NULL, ep->desc.bInterval);
-       } else
-               usb_fill_bulk_urb(urb, usb_dev, pipe, data, len,
-                                 (usb_complete_t)usb_api_blocking_completion,
-                                 NULL);
-
-       init_completion(done);
-       urb->context = done;
-       urb->actual_length = 0;
-       status = usb_submit_urb(urb, GFP_KERNEL);
-
-       return status;
-}
-
-static int vstusb_complete_urb(struct urb *urb, struct completion *done,
-                              int timeout, int *actual_length)
-{
-       unsigned long expire;
-       int status;
-
-       expire = timeout ? msecs_to_jiffies(timeout) : MAX_SCHEDULE_TIMEOUT;
-       if (!wait_for_completion_interruptible_timeout(done, expire)) {
-               usb_kill_urb(urb);
-               status = urb->status == -ENOENT ? -ETIMEDOUT : urb->status;
-
-               dev_dbg(&urb->dev->dev,
-                       "%s timed out on ep%d%s len=%d/%d, urb status = %d\n",
-                       current->comm,
-                       usb_pipeendpoint(urb->pipe),
-                       usb_pipein(urb->pipe) ? "in" : "out",
-                       urb->actual_length,
-                       urb->transfer_buffer_length,
-                       urb->status);
-
-       } else {
-               if (signal_pending(current)) {
-                       /* if really an error */
-                       if (urb->status && !((urb->status == -ENOENT)     ||
-                                            (urb->status == -ECONNRESET) ||
-                                            (urb->status == -ESHUTDOWN))) {
-                               status = -EINTR;
-                               usb_kill_urb(urb);
-                       } else {
-                               status = 0;
-                       }
-
-                       dev_dbg(&urb->dev->dev,
-                               "%s: signal pending on ep%d%s len=%d/%d,"
-                               "urb status = %d\n",
-                               current->comm,
-                               usb_pipeendpoint(urb->pipe),
-                               usb_pipein(urb->pipe) ? "in" : "out",
-                               urb->actual_length,
-                               urb->transfer_buffer_length,
-                               urb->status);
-
-               } else {
-                       status = urb->status;
-               }
-       }
-
-       if (actual_length)
-               *actual_length = urb->actual_length;
-
-       return status;
-}
-
-static ssize_t vstusb_read(struct file *file, char __user *buffer,
-                          size_t count, loff_t *ppos)
-{
-       struct vstusb_device *vstdev;
-       int cnt = -1;
-       void *buf;
-       int retval = 0;
-
-       struct urb              *urb;
-       struct usb_device       *dev;
-       unsigned int            pipe;
-       int                     timeout;
-
-       DECLARE_COMPLETION_ONSTACK(done);
-
-       vstdev = file->private_data;
-
-       if (vstdev == NULL)
-               return -ENODEV;
-
-       /* verify that we actually want to read some data */
-       if ((count == 0) || (count > VST_MAXBUFFER))
-               return -EINVAL;
-
-       /* lock this object */
-       if (mutex_lock_interruptible(&vstdev->lock))
-               return -ERESTARTSYS;
-
-       /* anyone home */
-       if (!vstdev->present) {
-               mutex_unlock(&vstdev->lock);
-               printk(KERN_ERR KBUILD_MODNAME
-                      ": %s: device not present\n", __func__);
-               return -ENODEV;
-       }
-
-       /* pull out the necessary data */
-       dev =     vstdev->usb_dev;
-       pipe =    usb_rcvbulkpipe(dev, vstdev->rd_pipe);
-       timeout = vstdev->rd_timeout_ms;
-
-       buf = kmalloc(count, GFP_KERNEL);
-       if (buf == NULL) {
-               mutex_unlock(&vstdev->lock);
-               return -ENOMEM;
-       }
-
-       urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!urb) {
-               kfree(buf);
-               mutex_unlock(&vstdev->lock);
-               return -ENOMEM;
-       }
-
-       usb_anchor_urb(urb, &vstdev->submitted);
-       retval = vstusb_fill_and_send_urb(urb, dev, pipe, buf, count, &done);
-       mutex_unlock(&vstdev->lock);
-       if (retval) {
-               usb_unanchor_urb(urb);
-               dev_err(&dev->dev, "%s: error %d filling and sending urb %d\n",
-                       __func__, retval, pipe);
-               goto exit;
-       }
-
-       retval = vstusb_complete_urb(urb, &done, timeout, &cnt);
-       if (retval) {
-               dev_err(&dev->dev, "%s: error %d completing urb %d\n",
-                       __func__, retval, pipe);
-               goto exit;
-       }
-
-       if (copy_to_user(buffer, buf, cnt)) {
-               dev_err(&dev->dev, "%s: can't copy_to_user\n", __func__);
-               retval = -EFAULT;
-       } else {
-               retval = cnt;
-               dev_dbg(&dev->dev, "%s: read %d bytes from pipe %d\n",
-                       __func__, cnt, pipe);
-       }
-
-exit:
-       usb_free_urb(urb);
-       kfree(buf);
-       return retval;
-}
-
-static ssize_t vstusb_write(struct file *file, const char __user *buffer,
-                           size_t count, loff_t *ppos)
-{
-       struct vstusb_device *vstdev;
-       int cnt = -1;
-       void *buf;
-       int retval = 0;
-
-       struct urb              *urb;
-       struct usb_device       *dev;
-       unsigned int            pipe;
-       int                     timeout;
-
-       DECLARE_COMPLETION_ONSTACK(done);
-
-       vstdev = file->private_data;
-
-       if (vstdev == NULL)
-               return -ENODEV;
-
-       /* verify that we actually have some data to write */
-       if ((count == 0) || (count > VST_MAXBUFFER))
-               return retval;
-
-       /* lock this object */
-       if (mutex_lock_interruptible(&vstdev->lock))
-               return -ERESTARTSYS;
-
-       /* anyone home */
-       if (!vstdev->present) {
-               mutex_unlock(&vstdev->lock);
-               printk(KERN_ERR KBUILD_MODNAME
-                      ": %s: device not present\n", __func__);
-               return -ENODEV;
-       }
-
-       /* pull out the necessary data */
-       dev =     vstdev->usb_dev;
-       pipe =    usb_sndbulkpipe(dev, vstdev->wr_pipe);
-       timeout = vstdev->wr_timeout_ms;
-
-       buf = kmalloc(count, GFP_KERNEL);
-       if (buf == NULL) {
-               mutex_unlock(&vstdev->lock);
-               return -ENOMEM;
-       }
-
-       urb = usb_alloc_urb(0, GFP_KERNEL);
-       if (!urb) {
-               kfree(buf);
-               mutex_unlock(&vstdev->lock);
-               return -ENOMEM;
-       }
-
-       if (copy_from_user(buf, buffer, count)) {
-               mutex_unlock(&vstdev->lock);
-               dev_err(&dev->dev, "%s: can't copy_from_user\n", __func__);
-               retval = -EFAULT;
-               goto exit;
-       }
-
-       usb_anchor_urb(urb, &vstdev->submitted);
-       retval = vstusb_fill_and_send_urb(urb, dev, pipe, buf, count, &done);
-       mutex_unlock(&vstdev->lock);
-       if (retval) {
-               usb_unanchor_urb(urb);
-               dev_err(&dev->dev, "%s: error %d filling and sending urb %d\n",
-                       __func__, retval, pipe);
-               goto exit;
-       }
-
-       retval = vstusb_complete_urb(urb, &done, timeout, &cnt);
-       if (retval) {
-               dev_err(&dev->dev, "%s: error %d completing urb %d\n",
-                       __func__, retval, pipe);
-               goto exit;
-       } else {
-               retval = cnt;
-               dev_dbg(&dev->dev, "%s: sent %d bytes to pipe %d\n",
-                       __func__, cnt, pipe);
-       }
-
-exit:
-       usb_free_urb(urb);
-       kfree(buf);
-       return retval;
-}
-
-static long vstusb_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-       int retval = 0;
-       int cnt = -1;
-       void __user *data = (void __user *)arg;
-       struct vstusb_args usb_data;
-
-       struct vstusb_device *vstdev;
-       void *buffer = NULL; /* must be initialized. buffer is
-                             * referenced on exit but not all
-                             * ioctls allocate it */
-
-       struct urb              *urb = NULL; /* must be initialized. urb is
-                                             * referenced on exit but not all
-                                             * ioctls allocate it */
-       struct usb_device       *dev;
-       unsigned int            pipe;
-       int                     timeout;
-
-       DECLARE_COMPLETION_ONSTACK(done);
-
-       vstdev = file->private_data;
-
-       if (_IOC_TYPE(cmd) != VST_IOC_MAGIC) {
-               dev_warn(&vstdev->usb_dev->dev,
-                        "%s: ioctl command %x, bad ioctl magic %x, "
-                        "expected %x\n", __func__, cmd,
-                        _IOC_TYPE(cmd), VST_IOC_MAGIC);
-               return -EINVAL;
-       }
-
-       if (vstdev == NULL)
-               return -ENODEV;
-
-       if (copy_from_user(&usb_data, data, sizeof(struct vstusb_args))) {
-               dev_err(&vstdev->usb_dev->dev, "%s: can't copy_from_user\n",
-                       __func__);
-               return -EFAULT;
-       }
-
-       /* lock this object */
-       if (mutex_lock_interruptible(&vstdev->lock)) {
-               retval = -ERESTARTSYS;
-               goto exit;
-       }
-
-       /* anyone home */
-       if (!vstdev->present) {
-               mutex_unlock(&vstdev->lock);
-               dev_err(&vstdev->usb_dev->dev, "%s: device not present\n",
-                       __func__);
-               retval = -ENODEV;
-               goto exit;
-       }
-
-       /* pull out the necessary data */
-       dev = vstdev->usb_dev;
-
-       switch (cmd) {
-
-       case IOCTL_VSTUSB_CONFIG_RW:
-
-               vstdev->rd_pipe = usb_data.rd_pipe;
-               vstdev->rd_timeout_ms = usb_data.rd_timeout_ms;
-               vstdev->wr_pipe = usb_data.wr_pipe;
-               vstdev->wr_timeout_ms = usb_data.wr_timeout_ms;
-
-               mutex_unlock(&vstdev->lock);
-
-               dev_dbg(&dev->dev, "%s: setting pipes/timeouts, "
-                       "rdpipe = %d, rdtimeout = %d, "
-                       "wrpipe = %d, wrtimeout = %d\n", __func__,
-                       vstdev->rd_pipe, vstdev->rd_timeout_ms,
-                       vstdev->wr_pipe, vstdev->wr_timeout_ms);
-               break;
-
-       case IOCTL_VSTUSB_SEND_PIPE:
-
-               if ((usb_data.count == 0) || (usb_data.count > VST_MAXBUFFER)) {
-                       mutex_unlock(&vstdev->lock);
-                       retval = -EINVAL;
-                       goto exit;
-               }
-
-               buffer = kmalloc(usb_data.count, GFP_KERNEL);
-               if (buffer == NULL) {
-                       mutex_unlock(&vstdev->lock);
-                       retval = -ENOMEM;
-                       goto exit;
-               }
-
-               urb = usb_alloc_urb(0, GFP_KERNEL);
-               if (!urb) {
-                       mutex_unlock(&vstdev->lock);
-                       retval = -ENOMEM;
-                       goto exit;
-               }
-
-               timeout = usb_data.timeout_ms;
-
-               pipe = usb_sndbulkpipe(dev, usb_data.pipe);
-
-               if (copy_from_user(buffer, usb_data.buffer, usb_data.count)) {
-                       dev_err(&dev->dev, "%s: can't copy_from_user\n",
-                               __func__);
-                       mutex_unlock(&vstdev->lock);
-                       retval = -EFAULT;
-                       goto exit;
-               }
-
-               usb_anchor_urb(urb, &vstdev->submitted);
-               retval = vstusb_fill_and_send_urb(urb, dev, pipe, buffer,
-                                                 usb_data.count, &done);
-               mutex_unlock(&vstdev->lock);
-               if (retval) {
-                       usb_unanchor_urb(urb);
-                       dev_err(&dev->dev,
-                               "%s: error %d filling and sending urb %d\n",
-                               __func__, retval, pipe);
-                       goto exit;
-               }
-
-               retval = vstusb_complete_urb(urb, &done, timeout, &cnt);
-               if (retval) {
-                       dev_err(&dev->dev, "%s: error %d completing urb %d\n",
-                               __func__, retval, pipe);
-               }
-
-               break;
-       case IOCTL_VSTUSB_RECV_PIPE:
-
-               if ((usb_data.count == 0) || (usb_data.count > VST_MAXBUFFER)) {
-                       mutex_unlock(&vstdev->lock);
-                       retval = -EINVAL;
-                       goto exit;
-               }
-
-               buffer = kmalloc(usb_data.count, GFP_KERNEL);
-               if (buffer == NULL) {
-                       mutex_unlock(&vstdev->lock);
-                       retval = -ENOMEM;
-                       goto exit;
-               }
-
-               urb = usb_alloc_urb(0, GFP_KERNEL);
-               if (!urb) {
-                       mutex_unlock(&vstdev->lock);
-                       retval = -ENOMEM;
-                       goto exit;
-               }
-
-               timeout = usb_data.timeout_ms;
-
-               pipe = usb_rcvbulkpipe(dev, usb_data.pipe);
-
-               usb_anchor_urb(urb, &vstdev->submitted);
-               retval = vstusb_fill_and_send_urb(urb, dev, pipe, buffer,
-                                                 usb_data.count, &done);
-               mutex_unlock(&vstdev->lock);
-               if (retval) {
-                       usb_unanchor_urb(urb);
-                       dev_err(&dev->dev,
-                               "%s: error %d filling and sending urb %d\n",
-                               __func__, retval, pipe);
-                       goto exit;
-               }
-
-               retval = vstusb_complete_urb(urb, &done, timeout, &cnt);
-               if (retval) {
-                       dev_err(&dev->dev, "%s: error %d completing urb %d\n",
-                               __func__, retval, pipe);
-                       goto exit;
-               }
-
-               if (copy_to_user(usb_data.buffer, buffer, cnt)) {
-                       dev_err(&dev->dev, "%s: can't copy_to_user\n",
-                               __func__);
-                       retval = -EFAULT;
-                       goto exit;
-               }
-
-               usb_data.count = cnt;
-               if (copy_to_user(data, &usb_data, sizeof(struct vstusb_args))) {
-                       dev_err(&dev->dev, "%s: can't copy_to_user\n",
-                               __func__);
-                       retval = -EFAULT;
-               } else {
-                       dev_dbg(&dev->dev, "%s: recv %zd bytes from pipe %d\n",
-                               __func__, usb_data.count, usb_data.pipe);
-               }
-
-               break;
-
-       default:
-               mutex_unlock(&vstdev->lock);
-               dev_warn(&dev->dev, "ioctl_vstusb: invalid ioctl cmd %x\n",
-                        cmd);
-               return -EINVAL;
-               break;
-       }
-exit:
-       usb_free_urb(urb);
-       kfree(buffer);
-       return retval;
-}
-
-static const struct file_operations vstusb_fops = {
-       .owner =                THIS_MODULE,
-       .read =                 vstusb_read,
-       .write =                vstusb_write,
-       .unlocked_ioctl =       vstusb_ioctl,
-       .compat_ioctl =         vstusb_ioctl,
-       .open =                 vstusb_open,
-       .release =              vstusb_release,
-};
-
-static struct usb_class_driver usb_vstusb_class = {
-       .name =         "usb/vstusb%d",
-       .fops =         &vstusb_fops,
-       .minor_base =   VSTUSB_MINOR_BASE,
-};
-
-static int vstusb_probe(struct usb_interface *intf,
-                       const struct usb_device_id *id)
-{
-       struct usb_device *dev = interface_to_usbdev(intf);
-       struct vstusb_device *vstdev;
-       int i;
-       int retval = 0;
-
-       /* allocate memory for our device state and intialize it */
-
-       vstdev = kzalloc(sizeof(*vstdev), GFP_KERNEL);
-       if (vstdev == NULL)
-               return -ENOMEM;
-
-       /* must do usb_get_dev() prior to kref_init() since the kref_put()
-        * release function will do a usb_put_dev() */
-       usb_get_dev(dev);
-       kref_init(&vstdev->kref);
-       mutex_init(&vstdev->lock);
-
-       i = dev->descriptor.bcdDevice;
-
-       dev_dbg(&intf->dev, "Version %1d%1d.%1d%1d found at address %d\n",
-               (i & 0xF000) >> 12, (i & 0xF00) >> 8,
-               (i & 0xF0) >> 4, (i & 0xF), dev->devnum);
-
-       vstdev->present = 1;
-       vstdev->isopen = 0;
-       vstdev->usb_dev = dev;
-       init_usb_anchor(&vstdev->submitted);
-
-       usb_set_intfdata(intf, vstdev);
-       retval = usb_register_dev(intf, &usb_vstusb_class);
-       if (retval) {
-               dev_err(&intf->dev,
-                       "%s: Not able to get a minor for this device.\n",
-                       __func__);
-               usb_set_intfdata(intf, NULL);
-               kref_put(&vstdev->kref, vstusb_delete);
-               return retval;
-       }
-
-       /* let the user know what node this device is now attached to */
-       dev_info(&intf->dev,
-                "VST USB Device #%d now attached to major %d minor %d\n",
-                (intf->minor - VSTUSB_MINOR_BASE), USB_MAJOR, intf->minor);
-
-       dev_info(&intf->dev, "%s, %s\n", DRIVER_DESC, DRIVER_VERSION);
-
-       return retval;
-}
-
-static void vstusb_disconnect(struct usb_interface *intf)
-{
-       struct vstusb_device *vstdev = usb_get_intfdata(intf);
-
-       usb_deregister_dev(intf, &usb_vstusb_class);
-       usb_set_intfdata(intf, NULL);
-
-       if (vstdev) {
-
-               mutex_lock(&vstdev->lock);
-               vstdev->present = 0;
-
-               usb_kill_anchored_urbs(&vstdev->submitted);
-
-               mutex_unlock(&vstdev->lock);
-
-               kref_put(&vstdev->kref, vstusb_delete);
-       }
-
-}
-
-static int vstusb_suspend(struct usb_interface *intf, pm_message_t message)
-{
-       struct vstusb_device *vstdev = usb_get_intfdata(intf);
-       int time;
-       if (!vstdev)
-               return 0;
-
-       mutex_lock(&vstdev->lock);
-       time = usb_wait_anchor_empty_timeout(&vstdev->submitted, 1000);
-       if (!time)
-               usb_kill_anchored_urbs(&vstdev->submitted);
-       mutex_unlock(&vstdev->lock);
-
-       return 0;
-}
-
-static int vstusb_resume(struct usb_interface *intf)
-{
-       return 0;
-}
-
-static struct usb_driver vstusb_driver = {
-       .name =         "vstusb",
-       .probe =        vstusb_probe,
-       .disconnect =   vstusb_disconnect,
-       .suspend =      vstusb_suspend,
-       .resume =       vstusb_resume,
-       .id_table = id_table,
-};
-
-static int __init vstusb_init(void)
-{
-       int rc;
-
-       rc = usb_register(&vstusb_driver);
-       if (rc)
-               printk(KERN_ERR "%s: failed to register (%d)", __func__, rc);
-
-       return rc;
-}
-
-static void __exit vstusb_exit(void)
-{
-       usb_deregister(&vstusb_driver);
-}
-
-module_init(vstusb_init);
-module_exit(vstusb_exit);
-
-MODULE_AUTHOR("Dennis O'Brien/Stephen Ware");
-MODULE_DESCRIPTION(DRIVER_VERSION);
-MODULE_LICENSE("GPL");
index 385ec052016705386e4f10fa8bffc51a44dec9e9..6dd44bc1f5ff4cb98791691a077d344960894690 100644 (file)
@@ -460,8 +460,8 @@ static void mon_bin_event(struct mon_reader_bin *rp, struct urb *urb,
     char ev_type, int status)
 {
        const struct usb_endpoint_descriptor *epd = &urb->ep->desc;
-       unsigned long flags;
        struct timeval ts;
+       unsigned long flags;
        unsigned int urb_length;
        unsigned int offset;
        unsigned int length;
@@ -600,10 +600,13 @@ static void mon_bin_complete(void *data, struct urb *urb, int status)
 static void mon_bin_error(void *data, struct urb *urb, int error)
 {
        struct mon_reader_bin *rp = data;
+       struct timeval ts;
        unsigned long flags;
        unsigned int offset;
        struct mon_bin_hdr *ep;
 
+       do_gettimeofday(&ts);
+
        spin_lock_irqsave(&rp->b_lock, flags);
 
        offset = mon_buff_area_alloc(rp, PKT_SIZE);
@@ -623,6 +626,8 @@ static void mon_bin_error(void *data, struct urb *urb, int error)
        ep->devnum = urb->dev->devnum;
        ep->busnum = urb->dev->bus->busnum;
        ep->id = (unsigned long) urb;
+       ep->ts_sec = ts.tv_sec;
+       ep->ts_usec = ts.tv_usec;
        ep->status = error;
 
        ep->flag_setup = '-';
index 047568ff223db60743435effeaaf522b995d3e20..31c11888ec6a9e3bed63f56628761a98e193789d 100644 (file)
@@ -180,7 +180,7 @@ static inline unsigned int mon_get_timestamp(void)
        unsigned int stamp;
 
        do_gettimeofday(&tval);
-       stamp = tval.tv_sec & 0xFFFF;   /* 2^32 = 4294967296. Limit to 4096s. */
+       stamp = tval.tv_sec & 0xFFF   /* 2^32 = 4294967296. Limit to 4096s. */
        stamp = stamp * 1000000 + tval.tv_usec;
        return stamp;
 }
@@ -273,12 +273,12 @@ static void mon_text_error(void *data, struct urb *urb, int error)
 
        ep->type = 'E';
        ep->id = (unsigned long) urb;
-       ep->busnum = 0;
+       ep->busnum = urb->dev->bus->busnum;
        ep->devnum = urb->dev->devnum;
        ep->epnum = usb_endpoint_num(&urb->ep->desc);
        ep->xfertype = usb_endpoint_type(&urb->ep->desc);
        ep->is_in = usb_urb_dir_in(urb);
-       ep->tstamp = 0;
+       ep->tstamp = mon_get_timestamp();
        ep->length = 0;
        ep->status = error;
 
index ad26e656966510f84ef0244a7f57a56a3faa82c8..bcee1339d4fdfdbb0a53c7a96ddbdeceda360b85 100644 (file)
@@ -30,7 +30,6 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
        void __iomem *fifo = hw_ep->fifo;
        void __iomem *epio = hw_ep->regs;
        u8 epnum = hw_ep->epnum;
-       u16 dma_reg = 0;
 
        prefetch((u8 *)src);
 
@@ -42,15 +41,17 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
        dump_fifo_data(src, len);
 
        if (!ANOMALY_05000380 && epnum != 0) {
-               flush_dcache_range((unsigned int)src,
-                       (unsigned int)(src + len));
+               u16 dma_reg;
+
+               flush_dcache_range((unsigned long)src,
+                       (unsigned long)(src + len));
 
                /* Setup DMA address register */
-               dma_reg = (u16) ((u32) src & 0xFFFF);
+               dma_reg = (u32)src;
                bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg);
                SSYNC();
 
-               dma_reg = (u16) (((u32) src >> 16) & 0xFFFF);
+               dma_reg = (u32)src >> 16;
                bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg);
                SSYNC();
 
@@ -79,12 +80,9 @@ void musb_write_fifo(struct musb_hw_ep *hw_ep, u16 len, const u8 *src)
                SSYNC();
 
                if (unlikely((unsigned long)src & 0x01))
-                       outsw_8((unsigned long)fifo, src,
-                               len & 0x01 ? (len >> 1) + 1 : len >> 1);
+                       outsw_8((unsigned long)fifo, src, (len + 1) >> 1);
                else
-                       outsw((unsigned long)fifo, src,
-                               len & 0x01 ? (len >> 1) + 1 : len >> 1);
-
+                       outsw((unsigned long)fifo, src, (len + 1) >> 1);
        }
 }
 /*
@@ -94,19 +92,19 @@ void musb_read_fifo(struct musb_hw_ep *hw_ep, u16 len, u8 *dst)
 {
        void __iomem *fifo = hw_ep->fifo;
        u8 epnum = hw_ep->epnum;
-       u16 dma_reg = 0;
 
        if (ANOMALY_05000467 && epnum != 0) {
+               u16 dma_reg;
 
-               invalidate_dcache_range((unsigned int)dst,
-                       (unsigned int)(dst + len));
+               invalidate_dcache_range((unsigned long)dst,
+                       (unsigned long)(dst + len));
 
                /* Setup DMA address register */
-               dma_reg = (u16) ((u32) dst & 0xFFFF);
+               dma_reg = (u32)dst;
                bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_LOW), dma_reg);
                SSYNC();
 
-               dma_reg = (u16) (((u32) dst >> 16) & 0xFFFF);
+               dma_reg = (u32)dst >> 16;
                bfin_write16(USB_DMA_REG(epnum, USB_DMAx_ADDR_HIGH), dma_reg);
                SSYNC();
 
index a44a450c860d9e248c3c317d437c67abc4694a8f..3c69a76ec392fdd8574bd061e1e113df341175ad 100644 (file)
@@ -1191,8 +1191,13 @@ irqreturn_t cppi_interrupt(int irq, void *dev_id)
 
                bd = tx_ch->head;
 
+               /*
+                * If Head is null then this could mean that a abort interrupt
+                * that needs to be acknowledged.
+                */
                if (NULL == bd) {
                        DBG(1, "null BD\n");
+                       tx_ram->tx_complete = 0;
                        continue;
                }
 
@@ -1412,15 +1417,6 @@ static int cppi_channel_abort(struct dma_channel *channel)
 
        if (cppi_ch->transmit) {
                struct cppi_tx_stateram __iomem *tx_ram;
-               int                     enabled;
-
-               /* mask interrupts raised to signal teardown complete.  */
-               enabled = musb_readl(tibase, DAVINCI_TXCPPI_INTENAB_REG)
-                               & (1 << cppi_ch->index);
-               if (enabled)
-                       musb_writel(tibase, DAVINCI_TXCPPI_INTCLR_REG,
-                                       (1 << cppi_ch->index));
-
                /* REVISIT put timeouts on these controller handshakes */
 
                cppi_dump_tx(6, cppi_ch, " (teardown)");
@@ -1435,7 +1431,6 @@ static int cppi_channel_abort(struct dma_channel *channel)
                do {
                        value = musb_readl(&tx_ram->tx_complete, 0);
                } while (0xFFFFFFFC != value);
-               musb_writel(&tx_ram->tx_complete, 0, 0xFFFFFFFC);
 
                /* FIXME clean up the transfer state ... here?
                 * the completion routine should get called with
@@ -1448,23 +1443,15 @@ static int cppi_channel_abort(struct dma_channel *channel)
                musb_writew(regs, MUSB_TXCSR, value);
                musb_writew(regs, MUSB_TXCSR, value);
 
-               /* While we scrub the TX state RAM, ensure that we clean
-                * up any interrupt that's currently asserted:
+               /*
                 * 1. Write to completion Ptr value 0x1(bit 0 set)
                 *    (write back mode)
-                * 2. Write to completion Ptr value 0x0(bit 0 cleared)
-                *    (compare mode)
-                * Value written is compared(for bits 31:2) and when
-                * equal, interrupt is deasserted.
+                * 2. Wait for abort interrupt and then put the channel in
+                *    compare mode by writing 1 to the tx_complete register.
                 */
                cppi_reset_tx(tx_ram, 1);
-               musb_writel(&tx_ram->tx_complete, 0, 0);
-
-               /* re-enable interrupt */
-               if (enabled)
-                       musb_writel(tibase, DAVINCI_TXCPPI_INTENAB_REG,
-                                       (1 << cppi_ch->index));
-
+               cppi_ch->head = 0;
+               musb_writel(&tx_ram->tx_complete, 0, 1);
                cppi_dump_tx(5, cppi_ch, " (done teardown)");
 
                /* REVISIT tx side _should_ clean up the same way
index 738efd8063b5e201a1ef18b5e905de6c416634ab..b4bbf8f2c2381bb0f4de4d0042b85b2260a843d0 100644 (file)
@@ -557,6 +557,69 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
                handled = IRQ_HANDLED;
        }
 
+
+       if (int_usb & MUSB_INTR_SUSPEND) {
+               DBG(1, "SUSPEND (%s) devctl %02x power %02x\n",
+                               otg_state_string(musb), devctl, power);
+               handled = IRQ_HANDLED;
+
+               switch (musb->xceiv->state) {
+#ifdef CONFIG_USB_MUSB_OTG
+               case OTG_STATE_A_PERIPHERAL:
+                       /* We also come here if the cable is removed, since
+                        * this silicon doesn't report ID-no-longer-grounded.
+                        *
+                        * We depend on T(a_wait_bcon) to shut us down, and
+                        * hope users don't do anything dicey during this
+                        * undesired detour through A_WAIT_BCON.
+                        */
+                       musb_hnp_stop(musb);
+                       usb_hcd_resume_root_hub(musb_to_hcd(musb));
+                       musb_root_disconnect(musb);
+                       musb_platform_try_idle(musb, jiffies
+                                       + msecs_to_jiffies(musb->a_wait_bcon
+                                               ? : OTG_TIME_A_WAIT_BCON));
+
+                       break;
+#endif
+               case OTG_STATE_B_IDLE:
+                       if (!musb->is_active)
+                               break;
+               case OTG_STATE_B_PERIPHERAL:
+                       musb_g_suspend(musb);
+                       musb->is_active = is_otg_enabled(musb)
+                                       && musb->xceiv->gadget->b_hnp_enable;
+                       if (musb->is_active) {
+#ifdef CONFIG_USB_MUSB_OTG
+                               musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
+                               DBG(1, "HNP: Setting timer for b_ase0_brst\n");
+                               mod_timer(&musb->otg_timer, jiffies
+                                       + msecs_to_jiffies(
+                                                       OTG_TIME_B_ASE0_BRST));
+#endif
+                       }
+                       break;
+               case OTG_STATE_A_WAIT_BCON:
+                       if (musb->a_wait_bcon != 0)
+                               musb_platform_try_idle(musb, jiffies
+                                       + msecs_to_jiffies(musb->a_wait_bcon));
+                       break;
+               case OTG_STATE_A_HOST:
+                       musb->xceiv->state = OTG_STATE_A_SUSPEND;
+                       musb->is_active = is_otg_enabled(musb)
+                                       && musb->xceiv->host->b_hnp_enable;
+                       break;
+               case OTG_STATE_B_HOST:
+                       /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
+                       DBG(1, "REVISIT: SUSPEND as B_HOST\n");
+                       break;
+               default:
+                       /* "should not happen" */
+                       musb->is_active = 0;
+                       break;
+               }
+       }
+
        if (int_usb & MUSB_INTR_CONNECT) {
                struct usb_hcd *hcd = musb_to_hcd(musb);
 
@@ -625,10 +688,61 @@ b_host:
        }
 #endif /* CONFIG_USB_MUSB_HDRC_HCD */
 
+       if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) {
+               DBG(1, "DISCONNECT (%s) as %s, devctl %02x\n",
+                               otg_state_string(musb),
+                               MUSB_MODE(musb), devctl);
+               handled = IRQ_HANDLED;
+
+               switch (musb->xceiv->state) {
+#ifdef CONFIG_USB_MUSB_HDRC_HCD
+               case OTG_STATE_A_HOST:
+               case OTG_STATE_A_SUSPEND:
+                       usb_hcd_resume_root_hub(musb_to_hcd(musb));
+                       musb_root_disconnect(musb);
+                       if (musb->a_wait_bcon != 0 && is_otg_enabled(musb))
+                               musb_platform_try_idle(musb, jiffies
+                                       + msecs_to_jiffies(musb->a_wait_bcon));
+                       break;
+#endif /* HOST */
+#ifdef CONFIG_USB_MUSB_OTG
+               case OTG_STATE_B_HOST:
+                       /* REVISIT this behaves for "real disconnect"
+                        * cases; make sure the other transitions from
+                        * from B_HOST act right too.  The B_HOST code
+                        * in hnp_stop() is currently not used...
+                        */
+                       musb_root_disconnect(musb);
+                       musb_to_hcd(musb)->self.is_b_host = 0;
+                       musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
+                       MUSB_DEV_MODE(musb);
+                       musb_g_disconnect(musb);
+                       break;
+               case OTG_STATE_A_PERIPHERAL:
+                       musb_hnp_stop(musb);
+                       musb_root_disconnect(musb);
+                       /* FALLTHROUGH */
+               case OTG_STATE_B_WAIT_ACON:
+                       /* FALLTHROUGH */
+#endif /* OTG */
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+               case OTG_STATE_B_PERIPHERAL:
+               case OTG_STATE_B_IDLE:
+                       musb_g_disconnect(musb);
+                       break;
+#endif /* GADGET */
+               default:
+                       WARNING("unhandled DISCONNECT transition (%s)\n",
+                               otg_state_string(musb));
+                       break;
+               }
+       }
+
        /* mentor saves a bit: bus reset and babble share the same irq.
         * only host sees babble; only peripheral sees bus reset.
         */
        if (int_usb & MUSB_INTR_RESET) {
+               handled = IRQ_HANDLED;
                if (is_host_capable() && (devctl & MUSB_DEVCTL_HM) != 0) {
                        /*
                         * Looks like non-HS BABBLE can be ignored, but
@@ -641,7 +755,7 @@ b_host:
                                DBG(1, "BABBLE devctl: %02x\n", devctl);
                        else {
                                ERR("Stopping host session -- babble\n");
-                               musb_writeb(mbase, MUSB_DEVCTL, 0);
+                               musb_writeb(musb->mregs, MUSB_DEVCTL, 0);
                        }
                } else if (is_peripheral_capable()) {
                        DBG(1, "BUS RESET as %s\n", otg_state_string(musb));
@@ -686,29 +800,7 @@ b_host:
                                        otg_state_string(musb));
                        }
                }
-
-               handled = IRQ_HANDLED;
        }
-       schedule_work(&musb->irq_work);
-
-       return handled;
-}
-
-/*
- * Interrupt Service Routine to record USB "global" interrupts.
- * Since these do not happen often and signify things of
- * paramount importance, it seems OK to check them individually;
- * the order of the tests is specified in the manual
- *
- * @param musb instance pointer
- * @param int_usb register contents
- * @param devctl
- * @param power
- */
-static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
-                               u8 devctl, u8 power)
-{
-       irqreturn_t handled = IRQ_NONE;
 
 #if 0
 /* REVISIT ... this would be for multiplexing periodic endpoints, or
@@ -755,117 +847,7 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
        }
 #endif
 
-       if ((int_usb & MUSB_INTR_DISCONNECT) && !musb->ignore_disconnect) {
-               DBG(1, "DISCONNECT (%s) as %s, devctl %02x\n",
-                               otg_state_string(musb),
-                               MUSB_MODE(musb), devctl);
-               handled = IRQ_HANDLED;
-
-               switch (musb->xceiv->state) {
-#ifdef CONFIG_USB_MUSB_HDRC_HCD
-               case OTG_STATE_A_HOST:
-               case OTG_STATE_A_SUSPEND:
-                       usb_hcd_resume_root_hub(musb_to_hcd(musb));
-                       musb_root_disconnect(musb);
-                       if (musb->a_wait_bcon != 0 && is_otg_enabled(musb))
-                               musb_platform_try_idle(musb, jiffies
-                                       + msecs_to_jiffies(musb->a_wait_bcon));
-                       break;
-#endif /* HOST */
-#ifdef CONFIG_USB_MUSB_OTG
-               case OTG_STATE_B_HOST:
-                       /* REVISIT this behaves for "real disconnect"
-                        * cases; make sure the other transitions from
-                        * from B_HOST act right too.  The B_HOST code
-                        * in hnp_stop() is currently not used...
-                        */
-                       musb_root_disconnect(musb);
-                       musb_to_hcd(musb)->self.is_b_host = 0;
-                       musb->xceiv->state = OTG_STATE_B_PERIPHERAL;
-                       MUSB_DEV_MODE(musb);
-                       musb_g_disconnect(musb);
-                       break;
-               case OTG_STATE_A_PERIPHERAL:
-                       musb_hnp_stop(musb);
-                       musb_root_disconnect(musb);
-                       /* FALLTHROUGH */
-               case OTG_STATE_B_WAIT_ACON:
-                       /* FALLTHROUGH */
-#endif /* OTG */
-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
-               case OTG_STATE_B_PERIPHERAL:
-               case OTG_STATE_B_IDLE:
-                       musb_g_disconnect(musb);
-                       break;
-#endif /* GADGET */
-               default:
-                       WARNING("unhandled DISCONNECT transition (%s)\n",
-                               otg_state_string(musb));
-                       break;
-               }
-
-               schedule_work(&musb->irq_work);
-       }
-
-       if (int_usb & MUSB_INTR_SUSPEND) {
-               DBG(1, "SUSPEND (%s) devctl %02x power %02x\n",
-                               otg_state_string(musb), devctl, power);
-               handled = IRQ_HANDLED;
-
-               switch (musb->xceiv->state) {
-#ifdef CONFIG_USB_MUSB_OTG
-               case OTG_STATE_A_PERIPHERAL:
-                       /* We also come here if the cable is removed, since
-                        * this silicon doesn't report ID-no-longer-grounded.
-                        *
-                        * We depend on T(a_wait_bcon) to shut us down, and
-                        * hope users don't do anything dicey during this
-                        * undesired detour through A_WAIT_BCON.
-                        */
-                       musb_hnp_stop(musb);
-                       usb_hcd_resume_root_hub(musb_to_hcd(musb));
-                       musb_root_disconnect(musb);
-                       musb_platform_try_idle(musb, jiffies
-                                       + msecs_to_jiffies(musb->a_wait_bcon
-                                               ? : OTG_TIME_A_WAIT_BCON));
-                       break;
-#endif
-               case OTG_STATE_B_PERIPHERAL:
-                       musb_g_suspend(musb);
-                       musb->is_active = is_otg_enabled(musb)
-                                       && musb->xceiv->gadget->b_hnp_enable;
-                       if (musb->is_active) {
-#ifdef CONFIG_USB_MUSB_OTG
-                               musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
-                               DBG(1, "HNP: Setting timer for b_ase0_brst\n");
-                               mod_timer(&musb->otg_timer, jiffies
-                                       + msecs_to_jiffies(
-                                                       OTG_TIME_B_ASE0_BRST));
-#endif
-                       }
-                       break;
-               case OTG_STATE_A_WAIT_BCON:
-                       if (musb->a_wait_bcon != 0)
-                               musb_platform_try_idle(musb, jiffies
-                                       + msecs_to_jiffies(musb->a_wait_bcon));
-                       break;
-               case OTG_STATE_A_HOST:
-                       musb->xceiv->state = OTG_STATE_A_SUSPEND;
-                       musb->is_active = is_otg_enabled(musb)
-                                       && musb->xceiv->host->b_hnp_enable;
-                       break;
-               case OTG_STATE_B_HOST:
-                       /* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
-                       DBG(1, "REVISIT: SUSPEND as B_HOST\n");
-                       break;
-               default:
-                       /* "should not happen" */
-                       musb->is_active = 0;
-                       break;
-               }
-               schedule_work(&musb->irq_work);
-       }
-
+       schedule_work(&musb->irq_work);
 
        return handled;
 }
@@ -1095,6 +1077,36 @@ static struct fifo_cfg __initdata mode_4_cfg[] = {
 { .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, },
 };
 
+/* mode 5 - fits in 8KB */
+static struct fifo_cfg __initdata mode_5_cfg[] = {
+{ .hw_ep_num =  1, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  1, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  2, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  2, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  3, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  3, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  4, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  4, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  5, .style = FIFO_TX,   .maxpacket = 512, },
+{ .hw_ep_num =  5, .style = FIFO_RX,   .maxpacket = 512, },
+{ .hw_ep_num =  6, .style = FIFO_TX,   .maxpacket = 32, },
+{ .hw_ep_num =  6, .style = FIFO_RX,   .maxpacket = 32, },
+{ .hw_ep_num =  7, .style = FIFO_TX,   .maxpacket = 32, },
+{ .hw_ep_num =  7, .style = FIFO_RX,   .maxpacket = 32, },
+{ .hw_ep_num =  8, .style = FIFO_TX,   .maxpacket = 32, },
+{ .hw_ep_num =  8, .style = FIFO_RX,   .maxpacket = 32, },
+{ .hw_ep_num =  9, .style = FIFO_TX,   .maxpacket = 32, },
+{ .hw_ep_num =  9, .style = FIFO_RX,   .maxpacket = 32, },
+{ .hw_ep_num = 10, .style = FIFO_TX,   .maxpacket = 32, },
+{ .hw_ep_num = 10, .style = FIFO_RX,   .maxpacket = 32, },
+{ .hw_ep_num = 11, .style = FIFO_TX,   .maxpacket = 32, },
+{ .hw_ep_num = 11, .style = FIFO_RX,   .maxpacket = 32, },
+{ .hw_ep_num = 12, .style = FIFO_TX,   .maxpacket = 32, },
+{ .hw_ep_num = 12, .style = FIFO_RX,   .maxpacket = 32, },
+{ .hw_ep_num = 13, .style = FIFO_RXTX, .maxpacket = 512, },
+{ .hw_ep_num = 14, .style = FIFO_RXTX, .maxpacket = 1024, },
+{ .hw_ep_num = 15, .style = FIFO_RXTX, .maxpacket = 1024, },
+};
 
 /*
  * configure a fifo; for non-shared endpoints, this may be called
@@ -1210,6 +1222,10 @@ static int __init ep_config_from_table(struct musb *musb)
                cfg = mode_4_cfg;
                n = ARRAY_SIZE(mode_4_cfg);
                break;
+       case 5:
+               cfg = mode_5_cfg;
+               n = ARRAY_SIZE(mode_5_cfg);
+               break;
        }
 
        printk(KERN_DEBUG "%s: setup fifo_mode %d\n",
@@ -1314,9 +1330,6 @@ enum { MUSB_CONTROLLER_MHDRC, MUSB_CONTROLLER_HDRC, };
  */
 static int __init musb_core_init(u16 musb_type, struct musb *musb)
 {
-#ifdef MUSB_AHB_ID
-       u32 data;
-#endif
        u8 reg;
        char *type;
        char aInfo[90], aRevision[32], aDate[12];
@@ -1328,23 +1341,17 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
        reg = musb_read_configdata(mbase);
 
        strcpy(aInfo, (reg & MUSB_CONFIGDATA_UTMIDW) ? "UTMI-16" : "UTMI-8");
-       if (reg & MUSB_CONFIGDATA_DYNFIFO)
+       if (reg & MUSB_CONFIGDATA_DYNFIFO) {
                strcat(aInfo, ", dyn FIFOs");
+               musb->dyn_fifo = true;
+       }
        if (reg & MUSB_CONFIGDATA_MPRXE) {
                strcat(aInfo, ", bulk combine");
-#ifdef C_MP_RX
                musb->bulk_combine = true;
-#else
-               strcat(aInfo, " (X)");          /* no driver support */
-#endif
        }
        if (reg & MUSB_CONFIGDATA_MPTXE) {
                strcat(aInfo, ", bulk split");
-#ifdef C_MP_TX
                musb->bulk_split = true;
-#else
-               strcat(aInfo, " (X)");          /* no driver support */
-#endif
        }
        if (reg & MUSB_CONFIGDATA_HBRXE) {
                strcat(aInfo, ", HB-ISO Rx");
@@ -1360,20 +1367,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
        printk(KERN_DEBUG "%s: ConfigData=0x%02x (%s)\n",
                        musb_driver_name, reg, aInfo);
 
-#ifdef MUSB_AHB_ID
-       data = musb_readl(mbase, 0x404);
-       sprintf(aDate, "%04d-%02x-%02x", (data & 0xffff),
-               (data >> 16) & 0xff, (data >> 24) & 0xff);
-       /* FIXME ID2 and ID3 are unused */
-       data = musb_readl(mbase, 0x408);
-       printk(KERN_DEBUG "ID2=%lx\n", (long unsigned)data);
-       data = musb_readl(mbase, 0x40c);
-       printk(KERN_DEBUG "ID3=%lx\n", (long unsigned)data);
-       reg = musb_readb(mbase, 0x400);
-       musb_type = ('M' == reg) ? MUSB_CONTROLLER_MHDRC : MUSB_CONTROLLER_HDRC;
-#else
        aDate[0] = 0;
-#endif
        if (MUSB_CONTROLLER_MHDRC == musb_type) {
                musb->is_multipoint = 1;
                type = "M";
@@ -1404,21 +1398,10 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
        musb->nr_endpoints = 1;
        musb->epmask = 1;
 
-       if (reg & MUSB_CONFIGDATA_DYNFIFO) {
-               if (musb->config->dyn_fifo)
-                       status = ep_config_from_table(musb);
-               else {
-                       ERR("reconfigure software for Dynamic FIFOs\n");
-                       status = -ENODEV;
-               }
-       } else {
-               if (!musb->config->dyn_fifo)
-                       status = ep_config_from_hw(musb);
-               else {
-                       ERR("reconfigure software for static FIFOs\n");
-                       return -ENODEV;
-               }
-       }
+       if (musb->dyn_fifo)
+               status = ep_config_from_table(musb);
+       else
+               status = ep_config_from_hw(musb);
 
        if (status < 0)
                return status;
@@ -1587,11 +1570,6 @@ irqreturn_t musb_interrupt(struct musb *musb)
                ep_num++;
        }
 
-       /* finish handling "global" interrupts after handling fifos */
-       if (musb->int_usb)
-               retval |= musb_stage2_irq(musb,
-                               musb->int_usb, devctl, power);
-
        return retval;
 }
 
@@ -1696,7 +1674,7 @@ musb_vbus_store(struct device *dev, struct device_attribute *attr,
        unsigned long   val;
 
        if (sscanf(buf, "%lu", &val) < 1) {
-               printk(KERN_ERR "Invalid VBUS timeout ms value\n");
+               dev_err(dev, "Invalid VBUS timeout ms value\n");
                return -EINVAL;
        }
 
@@ -1746,7 +1724,7 @@ musb_srp_store(struct device *dev, struct device_attribute *attr,
 
        if (sscanf(buf, "%hu", &srp) != 1
                        || (srp != 1)) {
-               printk(KERN_ERR "SRP: Value must be 1\n");
+               dev_err(dev, "SRP: Value must be 1\n");
                return -EINVAL;
        }
 
@@ -1759,6 +1737,19 @@ static DEVICE_ATTR(srp, 0644, NULL, musb_srp_store);
 
 #endif /* CONFIG_USB_GADGET_MUSB_HDRC */
 
+static struct attribute *musb_attributes[] = {
+       &dev_attr_mode.attr,
+       &dev_attr_vbus.attr,
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
+       &dev_attr_srp.attr,
+#endif
+       NULL
+};
+
+static const struct attribute_group musb_attr_group = {
+       .attrs = musb_attributes,
+};
+
 #endif /* sysfs */
 
 /* Only used to provide driver mode change events */
@@ -1833,11 +1824,7 @@ static void musb_free(struct musb *musb)
         */
 
 #ifdef CONFIG_SYSFS
-       device_remove_file(musb->controller, &dev_attr_mode);
-       device_remove_file(musb->controller, &dev_attr_vbus);
-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
-       device_remove_file(musb->controller, &dev_attr_srp);
-#endif
+       sysfs_remove_group(&musb->controller->kobj, &musb_attr_group);
 #endif
 
 #ifdef CONFIG_USB_GADGET_MUSB_HDRC
@@ -2017,22 +2004,10 @@ bad_config:
                musb->irq_wake = 0;
        }
 
-       pr_info("%s: USB %s mode controller at %p using %s, IRQ %d\n",
-                       musb_driver_name,
-                       ({char *s;
-                       switch (musb->board_mode) {
-                       case MUSB_HOST:         s = "Host"; break;
-                       case MUSB_PERIPHERAL:   s = "Peripheral"; break;
-                       default:                s = "OTG"; break;
-                       }; s; }),
-                       ctrl,
-                       (is_dma_capable() && musb->dma_controller)
-                               ? "DMA" : "PIO",
-                       musb->nIrq);
-
        /* host side needs more setup */
        if (is_host_enabled(musb)) {
                struct usb_hcd  *hcd = musb_to_hcd(musb);
+               u8 busctl;
 
                otg_set_host(musb->xceiv, &hcd->self);
 
@@ -2040,6 +2015,13 @@ bad_config:
                        hcd->self.otg_port = 1;
                musb->xceiv->host = &hcd->self;
                hcd->power_budget = 2 * (plat->power ? : 250);
+
+               /* program PHY to use external vBus if required */
+               if (plat->extvbus) {
+                       busctl = musb_readb(musb->mregs, MUSB_ULPI_BUSCONTROL);
+                       busctl |= MUSB_ULPI_USE_EXTVBUS;
+                       musb_writeb(musb->mregs, MUSB_ULPI_BUSCONTROL, busctl);
+               }
        }
 
        /* For the host-only role, we can activate right away.
@@ -2079,26 +2061,26 @@ bad_config:
        }
 
 #ifdef CONFIG_SYSFS
-       status = device_create_file(dev, &dev_attr_mode);
-       status = device_create_file(dev, &dev_attr_vbus);
-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
-       status = device_create_file(dev, &dev_attr_srp);
-#endif /* CONFIG_USB_GADGET_MUSB_HDRC */
-       status = 0;
+       status = sysfs_create_group(&musb->controller->kobj, &musb_attr_group);
 #endif
        if (status)
                goto fail2;
 
+       dev_info(dev, "USB %s mode controller at %p using %s, IRQ %d\n",
+                       ({char *s;
+                        switch (musb->board_mode) {
+                        case MUSB_HOST:                s = "Host"; break;
+                        case MUSB_PERIPHERAL:  s = "Peripheral"; break;
+                        default:               s = "OTG"; break;
+                        }; s; }),
+                       ctrl,
+                       (is_dma_capable() && musb->dma_controller)
+                       ? "DMA" : "PIO",
+                       musb->nIrq);
+
        return 0;
 
 fail2:
-#ifdef CONFIG_SYSFS
-       device_remove_file(musb->controller, &dev_attr_mode);
-       device_remove_file(musb->controller, &dev_attr_vbus);
-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
-       device_remove_file(musb->controller, &dev_attr_srp);
-#endif
-#endif
        musb_platform_exit(musb);
 fail:
        dev_err(musb->controller,
@@ -2127,6 +2109,7 @@ static int __init musb_probe(struct platform_device *pdev)
 {
        struct device   *dev = &pdev->dev;
        int             irq = platform_get_irq(pdev, 0);
+       int             status;
        struct resource *iomem;
        void __iomem    *base;
 
@@ -2134,7 +2117,7 @@ static int __init musb_probe(struct platform_device *pdev)
        if (!iomem || irq == 0)
                return -ENODEV;
 
-       base = ioremap(iomem->start, iomem->end - iomem->start + 1);
+       base = ioremap(iomem->start, resource_size(iomem));
        if (!base) {
                dev_err(dev, "ioremap failed\n");
                return -ENOMEM;
@@ -2144,7 +2127,12 @@ static int __init musb_probe(struct platform_device *pdev)
        /* clobbered by use_dma=n */
        orig_dma_mask = dev->dma_mask;
 #endif
-       return musb_init_controller(dev, irq, base);
+
+       status = musb_init_controller(dev, irq, base);
+       if (status < 0)
+               iounmap(base);
+
+       return status;
 }
 
 static int __exit musb_remove(struct platform_device *pdev)
@@ -2173,6 +2161,148 @@ static int __exit musb_remove(struct platform_device *pdev)
 
 #ifdef CONFIG_PM
 
+static struct musb_context_registers musb_context;
+
+void musb_save_context(struct musb *musb)
+{
+       int i;
+       void __iomem *musb_base = musb->mregs;
+
+       if (is_host_enabled(musb)) {
+               musb_context.frame = musb_readw(musb_base, MUSB_FRAME);
+               musb_context.testmode = musb_readb(musb_base, MUSB_TESTMODE);
+       }
+       musb_context.power = musb_readb(musb_base, MUSB_POWER);
+       musb_context.intrtxe = musb_readw(musb_base, MUSB_INTRTXE);
+       musb_context.intrrxe = musb_readw(musb_base, MUSB_INTRRXE);
+       musb_context.intrusbe = musb_readb(musb_base, MUSB_INTRUSBE);
+       musb_context.index = musb_readb(musb_base, MUSB_INDEX);
+       musb_context.devctl = musb_readb(musb_base, MUSB_DEVCTL);
+
+       for (i = 0; i < MUSB_C_NUM_EPS; ++i) {
+               musb_writeb(musb_base, MUSB_INDEX, i);
+               musb_context.index_regs[i].txmaxp =
+                       musb_readw(musb_base, 0x10 + MUSB_TXMAXP);
+               musb_context.index_regs[i].txcsr =
+                       musb_readw(musb_base, 0x10 + MUSB_TXCSR);
+               musb_context.index_regs[i].rxmaxp =
+                       musb_readw(musb_base, 0x10 + MUSB_RXMAXP);
+               musb_context.index_regs[i].rxcsr =
+                       musb_readw(musb_base, 0x10 + MUSB_RXCSR);
+
+               if (musb->dyn_fifo) {
+                       musb_context.index_regs[i].txfifoadd =
+                                       musb_read_txfifoadd(musb_base);
+                       musb_context.index_regs[i].rxfifoadd =
+                                       musb_read_rxfifoadd(musb_base);
+                       musb_context.index_regs[i].txfifosz =
+                                       musb_read_txfifosz(musb_base);
+                       musb_context.index_regs[i].rxfifosz =
+                                       musb_read_rxfifosz(musb_base);
+               }
+               if (is_host_enabled(musb)) {
+                       musb_context.index_regs[i].txtype =
+                               musb_readb(musb_base, 0x10 + MUSB_TXTYPE);
+                       musb_context.index_regs[i].txinterval =
+                               musb_readb(musb_base, 0x10 + MUSB_TXINTERVAL);
+                       musb_context.index_regs[i].rxtype =
+                               musb_readb(musb_base, 0x10 + MUSB_RXTYPE);
+                       musb_context.index_regs[i].rxinterval =
+                               musb_readb(musb_base, 0x10 + MUSB_RXINTERVAL);
+
+                       musb_context.index_regs[i].txfunaddr =
+                               musb_read_txfunaddr(musb_base, i);
+                       musb_context.index_regs[i].txhubaddr =
+                               musb_read_txhubaddr(musb_base, i);
+                       musb_context.index_regs[i].txhubport =
+                               musb_read_txhubport(musb_base, i);
+
+                       musb_context.index_regs[i].rxfunaddr =
+                               musb_read_rxfunaddr(musb_base, i);
+                       musb_context.index_regs[i].rxhubaddr =
+                               musb_read_rxhubaddr(musb_base, i);
+                       musb_context.index_regs[i].rxhubport =
+                               musb_read_rxhubport(musb_base, i);
+               }
+       }
+
+       musb_writeb(musb_base, MUSB_INDEX, musb_context.index);
+
+       musb_platform_save_context(musb, &musb_context);
+}
+
+void musb_restore_context(struct musb *musb)
+{
+       int i;
+       void __iomem *musb_base = musb->mregs;
+       void __iomem *ep_target_regs;
+
+       musb_platform_restore_context(musb, &musb_context);
+
+       if (is_host_enabled(musb)) {
+               musb_writew(musb_base, MUSB_FRAME, musb_context.frame);
+               musb_writeb(musb_base, MUSB_TESTMODE, musb_context.testmode);
+       }
+       musb_writeb(musb_base, MUSB_POWER, musb_context.power);
+       musb_writew(musb_base, MUSB_INTRTXE, musb_context.intrtxe);
+       musb_writew(musb_base, MUSB_INTRRXE, musb_context.intrrxe);
+       musb_writeb(musb_base, MUSB_INTRUSBE, musb_context.intrusbe);
+       musb_writeb(musb_base, MUSB_DEVCTL, musb_context.devctl);
+
+       for (i = 0; i < MUSB_C_NUM_EPS; ++i) {
+               musb_writeb(musb_base, MUSB_INDEX, i);
+               musb_writew(musb_base, 0x10 + MUSB_TXMAXP,
+                       musb_context.index_regs[i].txmaxp);
+               musb_writew(musb_base, 0x10 + MUSB_TXCSR,
+                       musb_context.index_regs[i].txcsr);
+               musb_writew(musb_base, 0x10 + MUSB_RXMAXP,
+                       musb_context.index_regs[i].rxmaxp);
+               musb_writew(musb_base, 0x10 + MUSB_RXCSR,
+                       musb_context.index_regs[i].rxcsr);
+
+               if (musb->dyn_fifo) {
+                       musb_write_txfifosz(musb_base,
+                               musb_context.index_regs[i].txfifosz);
+                       musb_write_rxfifosz(musb_base,
+                               musb_context.index_regs[i].rxfifosz);
+                       musb_write_txfifoadd(musb_base,
+                               musb_context.index_regs[i].txfifoadd);
+                       musb_write_rxfifoadd(musb_base,
+                               musb_context.index_regs[i].rxfifoadd);
+               }
+
+               if (is_host_enabled(musb)) {
+                       musb_writeb(musb_base, 0x10 + MUSB_TXTYPE,
+                               musb_context.index_regs[i].txtype);
+                       musb_writeb(musb_base, 0x10 + MUSB_TXINTERVAL,
+                               musb_context.index_regs[i].txinterval);
+                       musb_writeb(musb_base, 0x10 + MUSB_RXTYPE,
+                               musb_context.index_regs[i].rxtype);
+                       musb_writeb(musb_base, 0x10 + MUSB_RXINTERVAL,
+
+                       musb_context.index_regs[i].rxinterval);
+                       musb_write_txfunaddr(musb_base, i,
+                               musb_context.index_regs[i].txfunaddr);
+                       musb_write_txhubaddr(musb_base, i,
+                               musb_context.index_regs[i].txhubaddr);
+                       musb_write_txhubport(musb_base, i,
+                               musb_context.index_regs[i].txhubport);
+
+                       ep_target_regs =
+                               musb_read_target_reg_base(i, musb_base);
+
+                       musb_write_rxfunaddr(ep_target_regs,
+                               musb_context.index_regs[i].rxfunaddr);
+                       musb_write_rxhubaddr(ep_target_regs,
+                               musb_context.index_regs[i].rxhubaddr);
+                       musb_write_rxhubport(ep_target_regs,
+                               musb_context.index_regs[i].rxhubport);
+               }
+       }
+
+       musb_writeb(musb_base, MUSB_INDEX, musb_context.index);
+}
+
 static int musb_suspend(struct device *dev)
 {
        struct platform_device *pdev = to_platform_device(dev);
@@ -2194,6 +2324,8 @@ static int musb_suspend(struct device *dev)
                 */
        }
 
+       musb_save_context(musb);
+
        if (musb->set_clock)
                musb->set_clock(musb->clock, 0);
        else
@@ -2215,6 +2347,8 @@ static int musb_resume_noirq(struct device *dev)
        else
                clk_enable(musb->clock);
 
+       musb_restore_context(musb);
+
        /* for static cmos like DaVinci, register values were preserved
         * unless for some reason the whole soc powered down or the USB
         * module got reset through the PSC (vs just being disabled).
index 5514c7ee85bd678917b13c0820ff1d05538541bd..d849fb81c131cb6cae9bcb3f9d7ce58020219c46 100644 (file)
@@ -52,6 +52,15 @@ struct musb;
 struct musb_hw_ep;
 struct musb_ep;
 
+/* Helper defines for struct musb->hwvers */
+#define MUSB_HWVERS_MAJOR(x)   ((x >> 10) & 0x1f)
+#define MUSB_HWVERS_MINOR(x)   (x & 0x3ff)
+#define MUSB_HWVERS_RC         0x8000
+#define MUSB_HWVERS_1300       0x52C
+#define MUSB_HWVERS_1400       0x590
+#define MUSB_HWVERS_1800       0x720
+#define MUSB_HWVERS_1900       0x784
+#define MUSB_HWVERS_2000       0x800
 
 #include "musb_debug.h"
 #include "musb_dma.h"
@@ -322,13 +331,6 @@ struct musb {
        struct clk              *clock;
        irqreturn_t             (*isr)(int, void *);
        struct work_struct      irq_work;
-#define MUSB_HWVERS_MAJOR(x)   ((x >> 10) & 0x1f)
-#define MUSB_HWVERS_MINOR(x)   (x & 0x3ff)
-#define MUSB_HWVERS_RC         0x8000
-#define MUSB_HWVERS_1300       0x52C
-#define MUSB_HWVERS_1400       0x590
-#define MUSB_HWVERS_1800       0x720
-#define MUSB_HWVERS_2000       0x800
        u16                     hwvers;
 
 /* this hub status bit is reserved by USB 2.0 and not seen by usbcore */
@@ -411,22 +413,15 @@ struct musb {
 
        unsigned                hb_iso_rx:1;    /* high bandwidth iso rx? */
        unsigned                hb_iso_tx:1;    /* high bandwidth iso tx? */
+       unsigned                dyn_fifo:1;     /* dynamic FIFO supported? */
 
-#ifdef C_MP_TX
-       unsigned bulk_split:1;
+       unsigned                bulk_split:1;
 #define        can_bulk_split(musb,type) \
-               (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_split)
-#else
-#define        can_bulk_split(musb, type)      0
-#endif
+       (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_split)
 
-#ifdef C_MP_RX
-       unsigned bulk_combine:1;
+       unsigned                bulk_combine:1;
 #define        can_bulk_combine(musb,type) \
-               (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_combine)
-#else
-#define        can_bulk_combine(musb, type)    0
-#endif
+       (((type) == USB_ENDPOINT_XFER_BULK) && (musb)->bulk_combine)
 
 #ifdef CONFIG_USB_GADGET_MUSB_HDRC
        /* is_suspended means USB B_PERIPHERAL suspend */
@@ -461,6 +456,45 @@ struct musb {
 #endif
 };
 
+#ifdef CONFIG_PM
+struct musb_csr_regs {
+       /* FIFO registers */
+       u16 txmaxp, txcsr, rxmaxp, rxcsr;
+       u16 rxfifoadd, txfifoadd;
+       u8 txtype, txinterval, rxtype, rxinterval;
+       u8 rxfifosz, txfifosz;
+       u8 txfunaddr, txhubaddr, txhubport;
+       u8 rxfunaddr, rxhubaddr, rxhubport;
+};
+
+struct musb_context_registers {
+
+#if defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP2430)
+       u32 otg_sysconfig, otg_forcestandby;
+#endif
+       u8 power;
+       u16 intrtxe, intrrxe;
+       u8 intrusbe;
+       u16 frame;
+       u8 index, testmode;
+
+       u8 devctl, misc;
+
+       struct musb_csr_regs index_regs[MUSB_C_NUM_EPS];
+};
+
+#if defined(CONFIG_ARCH_OMAP34XX) || defined(CONFIG_ARCH_OMAP2430)
+extern void musb_platform_save_context(struct musb *musb,
+               struct musb_context_registers *musb_context);
+extern void musb_platform_restore_context(struct musb *musb,
+               struct musb_context_registers *musb_context);
+#else
+#define musb_platform_save_context(m, x)       do {} while (0)
+#define musb_platform_restore_context(m, x)    do {} while (0)
+#endif
+
+#endif
+
 static inline void musb_set_vbus(struct musb *musb, int is_on)
 {
        musb->board_set_vbus(musb, is_on);
index cbcf14a236e6e3a19e80bfcd8e19af257ce5a727..a9f288cd70ed2817ce36fceb4a006888e79e5233 100644 (file)
@@ -895,7 +895,14 @@ static int musb_gadget_enable(struct usb_ep *ep,
                /* REVISIT if can_bulk_split(), use by updating "tmp";
                 * likewise high bandwidth periodic tx
                 */
-               musb_writew(regs, MUSB_TXMAXP, tmp);
+               /* Set TXMAXP with the FIFO size of the endpoint
+                * to disable double buffering mode. Currently, It seems that double
+                * buffering has problem if musb RTL revision number < 2.0.
+                */
+               if (musb->hwvers < MUSB_HWVERS_2000)
+                       musb_writew(regs, MUSB_TXMAXP, hw_ep->max_packet_sz_tx);
+               else
+                       musb_writew(regs, MUSB_TXMAXP, tmp);
 
                csr = MUSB_TXCSR_MODE | MUSB_TXCSR_CLRDATATOG;
                if (musb_readw(regs, MUSB_TXCSR)
@@ -925,7 +932,13 @@ static int musb_gadget_enable(struct usb_ep *ep,
                /* REVISIT if can_bulk_combine() use by updating "tmp"
                 * likewise high bandwidth periodic rx
                 */
-               musb_writew(regs, MUSB_RXMAXP, tmp);
+               /* Set RXMAXP with the FIFO size of the endpoint
+                * to disable double buffering mode.
+                */
+               if (musb->hwvers < MUSB_HWVERS_2000)
+                       musb_writew(regs, MUSB_RXMAXP, hw_ep->max_packet_sz_rx);
+               else
+                       musb_writew(regs, MUSB_RXMAXP, tmp);
 
                /* force shared fifo to OUT-only mode */
                if (hw_ep->is_shared_fifo) {
@@ -1697,8 +1710,7 @@ int usb_gadget_register_driver(struct usb_gadget_driver *driver)
                return -EINVAL;
 
        /* driver must be initialized to support peripheral mode */
-       if (!musb || !(musb->board_mode == MUSB_OTG
-                               || musb->board_mode != MUSB_OTG)) {
+       if (!musb) {
                DBG(1, "%s, no dev??\n", __func__);
                return -ENODEV;
        }
index 74c4c3698f1ebbff7511b85b78a1010a284eba4a..3421cf9858b5100ee3eddd2093af35aaf1dc7f25 100644 (file)
@@ -605,8 +605,14 @@ musb_rx_reinit(struct musb *musb, struct musb_qh *qh, struct musb_hw_ep *ep)
        musb_writeb(ep->regs, MUSB_RXTYPE, qh->type_reg);
        musb_writeb(ep->regs, MUSB_RXINTERVAL, qh->intv_reg);
        /* NOTE: bulk combining rewrites high bits of maxpacket */
-       musb_writew(ep->regs, MUSB_RXMAXP,
-                       qh->maxpacket | ((qh->hb_mult - 1) << 11));
+       /* Set RXMAXP with the FIFO size of the endpoint
+        * to disable double buffer mode.
+        */
+       if (musb->hwvers < MUSB_HWVERS_2000)
+               musb_writew(ep->regs, MUSB_RXMAXP, ep->max_packet_sz_rx);
+       else
+               musb_writew(ep->regs, MUSB_RXMAXP,
+                               qh->maxpacket | ((qh->hb_mult - 1) << 11));
 
        ep->rx_reinit = 0;
 }
@@ -1771,6 +1777,9 @@ static int musb_schedule(
        int                     best_end, epnum;
        struct musb_hw_ep       *hw_ep = NULL;
        struct list_head        *head = NULL;
+       u8                      toggle;
+       u8                      txtype;
+       struct urb              *urb = next_urb(qh);
 
        /* use fixed hardware for control and bulk */
        if (qh->type == USB_ENDPOINT_XFER_CONTROL) {
@@ -1809,6 +1818,27 @@ static int musb_schedule(
                diff -= (qh->maxpacket * qh->hb_mult);
 
                if (diff >= 0 && best_diff > diff) {
+
+                       /*
+                        * Mentor controller has a bug in that if we schedule
+                        * a BULK Tx transfer on an endpoint that had earlier
+                        * handled ISOC then the BULK transfer has to start on
+                        * a zero toggle.  If the BULK transfer starts on a 1
+                        * toggle then this transfer will fail as the mentor
+                        * controller starts the Bulk transfer on a 0 toggle
+                        * irrespective of the programming of the toggle bits
+                        * in the TXCSR register.  Check for this condition
+                        * while allocating the EP for a Tx Bulk transfer.  If
+                        * so skip this EP.
+                        */
+                       hw_ep = musb->endpoints + epnum;
+                       toggle = usb_gettoggle(urb->dev, qh->epnum, !is_in);
+                       txtype = (musb_readb(hw_ep->regs, MUSB_TXTYPE)
+                                       >> 4) & 0x3;
+                       if (!is_in && (qh->type == USB_ENDPOINT_XFER_BULK) &&
+                               toggle && (txtype == USB_ENDPOINT_XFER_ISOC))
+                               continue;
+
                        best_diff = diff;
                        best_end = epnum;
                }
index 473a94ef905f9f620b31480c29865b407d4d3cb9..292894a2c24711077df28529315c97f586e696fb 100644 (file)
 #define MUSB_DEVCTL_HR         0x02
 #define MUSB_DEVCTL_SESSION    0x01
 
+/* MUSB ULPI VBUSCONTROL */
+#define MUSB_ULPI_USE_EXTVBUS  0x01
+#define MUSB_ULPI_USE_EXTVBUSIND 0x02
+
 /* TESTMODE */
 #define MUSB_TEST_FORCE_HOST   0x80
 #define MUSB_TEST_FIFO_ACCESS  0x40
 
 /* REVISIT: vctrl/vstatus: optional vendor utmi+phy register at 0x68 */
 #define MUSB_HWVERS            0x6C    /* 8 bit */
+#define MUSB_ULPI_BUSCONTROL   0x70    /* 8 bit */
 
 #define MUSB_EPINFO            0x78    /* 8 bit */
 #define MUSB_RAMINFO           0x79    /* 8 bit */
@@ -321,6 +326,26 @@ static inline void  musb_write_rxfifoadd(void __iomem *mbase, u16 c_off)
        musb_writew(mbase, MUSB_RXFIFOADD, c_off);
 }
 
+static inline u8 musb_read_txfifosz(void __iomem *mbase)
+{
+       return musb_readb(mbase, MUSB_TXFIFOSZ);
+}
+
+static inline u16 musb_read_txfifoadd(void __iomem *mbase)
+{
+       return musb_readw(mbase, MUSB_TXFIFOADD);
+}
+
+static inline u8 musb_read_rxfifosz(void __iomem *mbase)
+{
+       return musb_readb(mbase, MUSB_RXFIFOSZ);
+}
+
+static inline u16  musb_read_rxfifoadd(void __iomem *mbase)
+{
+       return musb_readw(mbase, MUSB_RXFIFOADD);
+}
+
 static inline u8 musb_read_configdata(void __iomem *mbase)
 {
        musb_writeb(mbase, MUSB_INDEX, 0);
@@ -376,6 +401,36 @@ static inline void  musb_write_txhubport(void __iomem *mbase, u8 epnum,
                        qh_h_port_reg);
 }
 
+static inline u8 musb_read_rxfunaddr(void __iomem *mbase, u8 epnum)
+{
+       return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXFUNCADDR));
+}
+
+static inline u8 musb_read_rxhubaddr(void __iomem *mbase, u8 epnum)
+{
+       return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXHUBADDR));
+}
+
+static inline u8 musb_read_rxhubport(void __iomem *mbase, u8 epnum)
+{
+       return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_RXHUBPORT));
+}
+
+static inline u8  musb_read_txfunaddr(void __iomem *mbase, u8 epnum)
+{
+       return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXFUNCADDR));
+}
+
+static inline u8  musb_read_txhubaddr(void __iomem *mbase, u8 epnum)
+{
+       return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBADDR));
+}
+
+static inline u8  musb_read_txhubport(void __iomem *mbase, u8 epnum)
+{
+       return musb_readb(mbase, MUSB_BUSCTL_OFFSET(epnum, MUSB_TXHUBPORT));
+}
+
 #else /* CONFIG_BLACKFIN */
 
 #define USB_BASE               USB_FADDR
@@ -455,6 +510,22 @@ static inline void  musb_write_rxfifoadd(void __iomem *mbase, u16 c_off)
 {
 }
 
+static inline u8 musb_read_txfifosz(void __iomem *mbase)
+{
+}
+
+static inline u16 musb_read_txfifoadd(void __iomem *mbase)
+{
+}
+
+static inline u8 musb_read_rxfifosz(void __iomem *mbase)
+{
+}
+
+static inline u16  musb_read_rxfifoadd(void __iomem *mbase)
+{
+}
+
 static inline u8 musb_read_configdata(void __iomem *mbase)
 {
        return 0;
@@ -462,7 +533,11 @@ static inline u8 musb_read_configdata(void __iomem *mbase)
 
 static inline u16 musb_read_hwvers(void __iomem *mbase)
 {
-       return 0;
+       /*
+        * This register is invisible on Blackfin, actually the MUSB
+        * RTL version of Blackfin is 1.9, so just harcode its value.
+        */
+       return MUSB_HWVERS_1900;
 }
 
 static inline void __iomem *musb_read_target_reg_base(u8 i, void __iomem *mbase)
@@ -500,6 +575,30 @@ static inline void  musb_write_txhubport(void __iomem *mbase, u8 epnum,
 {
 }
 
+static inline u8 musb_read_rxfunaddr(void __iomem *mbase, u8 epnum)
+{
+}
+
+static inline u8 musb_read_rxhubaddr(void __iomem *mbase, u8 epnum)
+{
+}
+
+static inline u8 musb_read_rxhubport(void __iomem *mbase, u8 epnum)
+{
+}
+
+static inline u8  musb_read_txfunaddr(void __iomem *mbase, u8 epnum)
+{
+}
+
+static inline u8  musb_read_txhubaddr(void __iomem *mbase, u8 epnum)
+{
+}
+
+static inline void  musb_read_txhubport(void __iomem *mbase, u8 epnum)
+{
+}
+
 #endif /* CONFIG_BLACKFIN */
 
 #endif /* __MUSB_REGS_H__ */
index a237550f91bfdd17acd3f9ff40b1f124ce3b0e12..2fa7d5c00f313eadf7c83c061a9b0774c74279fa 100644 (file)
@@ -250,20 +250,39 @@ static irqreturn_t dma_controller_irq(int irq, void *private_data)
        u8 bchannel;
        u8 int_hsdma;
 
-       u32 addr;
+       u32 addr, count;
        u16 csr;
 
        spin_lock_irqsave(&musb->lock, flags);
 
        int_hsdma = musb_readb(mbase, MUSB_HSDMA_INTR);
-       if (!int_hsdma)
-               goto done;
 
 #ifdef CONFIG_BLACKFIN
        /* Clear DMA interrupt flags */
        musb_writeb(mbase, MUSB_HSDMA_INTR, int_hsdma);
 #endif
 
+       if (!int_hsdma) {
+               DBG(2, "spurious DMA irq\n");
+
+               for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) {
+                       musb_channel = (struct musb_dma_channel *)
+                                       &(controller->channel[bchannel]);
+                       channel = &musb_channel->channel;
+                       if (channel->status == MUSB_DMA_STATUS_BUSY) {
+                               count = musb_read_hsdma_count(mbase, bchannel);
+
+                               if (count == 0)
+                                       int_hsdma |= (1 << bchannel);
+                       }
+               }
+
+               DBG(2, "int_hsdma = 0x%x\n", int_hsdma);
+
+               if (!int_hsdma)
+                       goto done;
+       }
+
        for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) {
                if (int_hsdma & (1 << bchannel)) {
                        musb_channel = (struct musb_dma_channel *)
index 1299d92dc83f0174e03c7c6a2d039ca4d5305b1e..613f95a058f7c5ed9c9ed597ecd1949b0f9d1e74 100644 (file)
                    MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_ADDRESS), \
                    addr)
 
+#define musb_read_hsdma_count(mbase, bchannel) \
+       musb_readl(mbase,       \
+                  MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT))
+
 #define musb_write_hsdma_count(mbase, bchannel, len) \
        musb_writel(mbase, \
                    MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT), \
@@ -96,6 +100,19 @@ static inline void musb_write_hsdma_addr(void __iomem *mbase,
                ((u16)(((u32) dma_addr >> 16) & 0xFFFF)));
 }
 
+static inline u32 musb_read_hsdma_count(void __iomem *mbase, u8 bchannel)
+{
+       u32 count = musb_readw(mbase,
+               MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_HIGH));
+
+       count = count << 16;
+
+       count |= musb_readw(mbase,
+               MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT_LOW));
+
+       return count;
+}
+
 static inline void musb_write_hsdma_count(void __iomem *mbase,
                                u8 bchannel, u32 len)
 {
index 83beeac5e7bf3ba55982e1c8feab9e7f0c3e0011..3fe16867b5a87f0338f861f1b37901eb3ad15a7f 100644 (file)
@@ -220,7 +220,7 @@ int __init musb_platform_init(struct musb *musb)
 
        musb_platform_resume(musb);
 
-       l = omap_readl(OTG_SYSCONFIG);
+       l = musb_readl(musb->mregs, OTG_SYSCONFIG);
        l &= ~ENABLEWAKEUP;     /* disable wakeup */
        l &= ~NOSTDBY;          /* remove possible nostdby */
        l |= SMARTSTDBY;        /* enable smart standby */
@@ -233,17 +233,19 @@ int __init musb_platform_init(struct musb *musb)
         */
        if (!cpu_is_omap3430())
                l |= AUTOIDLE;          /* enable auto idle */
-       omap_writel(l, OTG_SYSCONFIG);
+       musb_writel(musb->mregs, OTG_SYSCONFIG, l);
 
-       l = omap_readl(OTG_INTERFSEL);
+       l = musb_readl(musb->mregs, OTG_INTERFSEL);
        l |= ULPI_12PIN;
-       omap_writel(l, OTG_INTERFSEL);
+       musb_writel(musb->mregs, OTG_INTERFSEL, l);
 
        pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
                        "sysstatus 0x%x, intrfsel 0x%x, simenable  0x%x\n",
-                       omap_readl(OTG_REVISION), omap_readl(OTG_SYSCONFIG),
-                       omap_readl(OTG_SYSSTATUS), omap_readl(OTG_INTERFSEL),
-                       omap_readl(OTG_SIMENABLE));
+                       musb_readl(musb->mregs, OTG_REVISION),
+                       musb_readl(musb->mregs, OTG_SYSCONFIG),
+                       musb_readl(musb->mregs, OTG_SYSSTATUS),
+                       musb_readl(musb->mregs, OTG_INTERFSEL),
+                       musb_readl(musb->mregs, OTG_SIMENABLE));
 
        omap_vbus_power(musb, musb->board_mode == MUSB_HOST, 1);
 
@@ -255,6 +257,22 @@ int __init musb_platform_init(struct musb *musb)
        return 0;
 }
 
+#ifdef CONFIG_PM
+void musb_platform_save_context(struct musb *musb,
+               struct musb_context_registers *musb_context)
+{
+       musb_context->otg_sysconfig = musb_readl(musb->mregs, OTG_SYSCONFIG);
+       musb_context->otg_forcestandby = musb_readl(musb->mregs, OTG_FORCESTDBY);
+}
+
+void musb_platform_restore_context(struct musb *musb,
+               struct musb_context_registers *musb_context)
+{
+       musb_writel(musb->mregs, OTG_SYSCONFIG, musb_context->otg_sysconfig);
+       musb_writel(musb->mregs, OTG_FORCESTDBY, musb_context->otg_forcestandby);
+}
+#endif
+
 int musb_platform_suspend(struct musb *musb)
 {
        u32 l;
@@ -263,13 +281,13 @@ int musb_platform_suspend(struct musb *musb)
                return 0;
 
        /* in any role */
-       l = omap_readl(OTG_FORCESTDBY);
+       l = musb_readl(musb->mregs, OTG_FORCESTDBY);
        l |= ENABLEFORCE;       /* enable MSTANDBY */
-       omap_writel(l, OTG_FORCESTDBY);
+       musb_writel(musb->mregs, OTG_FORCESTDBY, l);
 
-       l = omap_readl(OTG_SYSCONFIG);
+       l = musb_readl(musb->mregs, OTG_SYSCONFIG);
        l |= ENABLEWAKEUP;      /* enable wakeup */
-       omap_writel(l, OTG_SYSCONFIG);
+       musb_writel(musb->mregs, OTG_SYSCONFIG, l);
 
        otg_set_suspend(musb->xceiv, 1);
 
@@ -295,13 +313,13 @@ static int musb_platform_resume(struct musb *musb)
        else
                clk_enable(musb->clock);
 
-       l = omap_readl(OTG_SYSCONFIG);
+       l = musb_readl(musb->mregs, OTG_SYSCONFIG);
        l &= ~ENABLEWAKEUP;     /* disable wakeup */
-       omap_writel(l, OTG_SYSCONFIG);
+       musb_writel(musb->mregs, OTG_SYSCONFIG, l);
 
-       l = omap_readl(OTG_FORCESTDBY);
+       l = musb_readl(musb->mregs, OTG_FORCESTDBY);
        l &= ~ENABLEFORCE;      /* disable MSTANDBY */
-       omap_writel(l, OTG_FORCESTDBY);
+       musb_writel(musb->mregs, OTG_FORCESTDBY, l);
 
        return 0;
 }
index fbede7798aedbab2a32db1e45780a0aea0b30483..40b3c02ae9f0812f0d6cba75dab78a39b41f6c40 100644 (file)
 #ifndef __MUSB_OMAP243X_H__
 #define __MUSB_OMAP243X_H__
 
-#if defined(CONFIG_ARCH_OMAP2430) || defined(CONFIG_ARCH_OMAP3430)
-#include <mach/hardware.h>
 #include <plat/usb.h>
 
 /*
  * OMAP2430-specific definitions
  */
 
-#define MENTOR_BASE_OFFSET     0
-#if    defined(CONFIG_ARCH_OMAP2430)
-#define        OMAP_HSOTG_BASE         (OMAP243X_HS_BASE)
-#elif  defined(CONFIG_ARCH_OMAP3430)
-#define        OMAP_HSOTG_BASE         (OMAP34XX_HSUSB_OTG_BASE)
-#endif
-#define OMAP_HSOTG(offset)     (OMAP_HSOTG_BASE + 0x400 + (offset))
-#define OTG_REVISION           OMAP_HSOTG(0x0)
-#define OTG_SYSCONFIG          OMAP_HSOTG(0x4)
+#define OTG_REVISION           0x400
+
+#define OTG_SYSCONFIG          0x404
 #      define  MIDLEMODE       12      /* bit position */
 #      define  FORCESTDBY              (0 << MIDLEMODE)
 #      define  NOSTDBY                 (1 << MIDLEMODE)
 #      define  SMARTSTDBY              (2 << MIDLEMODE)
+
 #      define  SIDLEMODE               3       /* bit position */
 #      define  FORCEIDLE               (0 << SIDLEMODE)
 #      define  NOIDLE                  (1 << SIDLEMODE)
 #      define  SMARTIDLE               (2 << SIDLEMODE)
+
 #      define  ENABLEWAKEUP            (1 << 2)
 #      define  SOFTRST                 (1 << 1)
 #      define  AUTOIDLE                (1 << 0)
-#define OTG_SYSSTATUS          OMAP_HSOTG(0x8)
+
+#define OTG_SYSSTATUS          0x408
 #      define  RESETDONE               (1 << 0)
-#define OTG_INTERFSEL          OMAP_HSOTG(0xc)
+
+#define OTG_INTERFSEL          0x40c
 #      define  EXTCP                   (1 << 2)
-#      define  PHYSEL          0       /* bit position */
+#      define  PHYSEL                  0       /* bit position */
 #      define  UTMI_8BIT               (0 << PHYSEL)
 #      define  ULPI_12PIN              (1 << PHYSEL)
 #      define  ULPI_8PIN               (2 << PHYSEL)
-#define OTG_SIMENABLE          OMAP_HSOTG(0x10)
+
+#define OTG_SIMENABLE          0x410
 #      define  TM1                     (1 << 0)
-#define OTG_FORCESTDBY         OMAP_HSOTG(0x14)
-#      define  ENABLEFORCE             (1 << 0)
 
-#endif /* CONFIG_ARCH_OMAP2430 */
+#define OTG_FORCESTDBY         0x414
+#      define  ENABLEFORCE             (1 << 0)
 
 #endif /* __MUSB_OMAP243X_H__ */
index 88b587c703e96cfea7ce2149190cdecb1003ba42..ab776a8d98cad99897a7c01f0a02cc78ba1b4dc2 100644 (file)
@@ -1118,7 +1118,7 @@ int __init musb_platform_init(struct musb *musb)
        }
        musb->sync = mem->start;
 
-       sync = ioremap(mem->start, mem->end - mem->start + 1);
+       sync = ioremap(mem->start, resource_size(mem));
        if (!sync) {
                pr_debug("ioremap for sync failed\n");
                ret = -ENOMEM;
index e13c77052e5e966a4f3dd45cc827f55289c12d92..1c868096bd6fb2697adff17fe018d5ec4400b11a 100644 (file)
@@ -648,7 +648,7 @@ void dma_controller_destroy(struct dma_controller *c)
                }
        }
 
-       if (!tusb_dma->multichannel && tusb_dma && tusb_dma->ch >= 0)
+       if (tusb_dma && !tusb_dma->multichannel && tusb_dma->ch >= 0)
                omap_free_dma(tusb_dma->ch);
 
        kfree(tusb_dma);
index 2be9f2fa41f91b87d6f794b57ca0c7c39cd522f1..3e4e9f434d78d31f6f6699c0e507a1e6e09e91a7 100644 (file)
@@ -36,7 +36,7 @@
 #include <linux/i2c/twl.h>
 #include <linux/regulator/consumer.h>
 #include <linux/err.h>
-
+#include <linux/notifier.h>
 
 /* Register defines */
 
 #define PMBR1                          0x0D
 #define GPIO_USB_4PIN_ULPI_2430C       (3 << 0)
 
-
-
-enum linkstat {
-       USB_LINK_UNKNOWN = 0,
-       USB_LINK_NONE,
-       USB_LINK_VBUS,
-       USB_LINK_ID,
-};
-
 struct twl4030_usb {
        struct otg_transceiver  otg;
        struct device           *dev;
@@ -347,10 +338,10 @@ twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
 
 /*-------------------------------------------------------------------------*/
 
-static enum linkstat twl4030_usb_linkstat(struct twl4030_usb *twl)
+static enum usb_xceiv_events twl4030_usb_linkstat(struct twl4030_usb *twl)
 {
        int     status;
-       int     linkstat = USB_LINK_UNKNOWN;
+       int     linkstat = USB_EVENT_NONE;
 
        /*
         * For ID/VBUS sensing, see manual section 15.4.8 ...
@@ -368,11 +359,11 @@ static enum linkstat twl4030_usb_linkstat(struct twl4030_usb *twl)
                dev_err(twl->dev, "USB link status err %d\n", status);
        else if (status & (BIT(7) | BIT(2))) {
                if (status & BIT(2))
-                       linkstat = USB_LINK_ID;
+                       linkstat = USB_EVENT_ID;
                else
-                       linkstat = USB_LINK_VBUS;
+                       linkstat = USB_EVENT_VBUS;
        } else
-               linkstat = USB_LINK_NONE;
+               linkstat = USB_EVENT_NONE;
 
        dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n",
                        status, status, linkstat);
@@ -383,7 +374,7 @@ static enum linkstat twl4030_usb_linkstat(struct twl4030_usb *twl)
 
        spin_lock_irq(&twl->lock);
        twl->linkstat = linkstat;
-       if (linkstat == USB_LINK_ID) {
+       if (linkstat == USB_EVENT_ID) {
                twl->otg.default_a = true;
                twl->otg.state = OTG_STATE_A_IDLE;
        } else {
@@ -564,7 +555,7 @@ static ssize_t twl4030_usb_vbus_show(struct device *dev,
 
        spin_lock_irqsave(&twl->lock, flags);
        ret = sprintf(buf, "%s\n",
-                       (twl->linkstat == USB_LINK_VBUS) ? "on" : "off");
+                       (twl->linkstat == USB_EVENT_VBUS) ? "on" : "off");
        spin_unlock_irqrestore(&twl->lock, flags);
 
        return ret;
@@ -576,17 +567,8 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
        struct twl4030_usb *twl = _twl;
        int status;
 
-#ifdef CONFIG_LOCKDEP
-       /* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
-        * we don't want and can't tolerate.  Although it might be
-        * friendlier not to borrow this thread context...
-        */
-       local_irq_enable();
-#endif
-
        status = twl4030_usb_linkstat(twl);
-       if (status != USB_LINK_UNKNOWN) {
-
+       if (status >= 0) {
                /* FIXME add a set_power() method so that B-devices can
                 * configure the charger appropriately.  It's not always
                 * correct to consume VBUS power, and how much current to
@@ -598,12 +580,13 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
                 * USB_LINK_VBUS state.  musb_hdrc won't care until it
                 * starts to handle softconnect right.
                 */
-               if (status == USB_LINK_NONE)
+               if (status == USB_EVENT_NONE)
                        twl4030_phy_suspend(twl, 0);
                else
                        twl4030_phy_resume(twl);
 
-               twl4030charger_usb_en(status == USB_LINK_VBUS);
+               blocking_notifier_call_chain(&twl->otg.notifier, status,
+                               twl->otg.gadget);
        }
        sysfs_notify(&twl->dev->kobj, NULL, "vbus");
 
@@ -693,6 +676,8 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev)
        if (device_create_file(&pdev->dev, &dev_attr_vbus))
                dev_warn(&pdev->dev, "could not create sysfs file\n");
 
+       BLOCKING_INIT_NOTIFIER_HEAD(&twl->otg.notifier);
+
        /* Our job is to use irqs and status from the power module
         * to keep the transceiver disabled when nothing's connected.
         *
@@ -702,7 +687,7 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev)
         * need both handles, otherwise just one suffices.
         */
        twl->irq_enabled = true;
-       status = request_irq(twl->irq, twl4030_usb_irq,
+       status = request_threaded_irq(twl->irq, NULL, twl4030_usb_irq,
                        IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
                        "twl4030_usb", twl);
        if (status < 0) {
index c480ea4c19f28797a79b1a5ad4fb11701f537dc9..c78b255e3f831ee7cd086c6053f7728915062783 100644 (file)
@@ -472,6 +472,17 @@ config USB_SERIAL_OTI6858
          To compile this driver as a module, choose M here: the
          module will be called oti6858.
 
+config USB_SERIAL_QCAUX
+       tristate "USB Qualcomm Auxiliary Serial Port Driver"
+       ---help---
+         Say Y here if you want to use the auxiliary serial ports provided
+         by many modems based on Qualcomm chipsets.  These ports often use
+         a proprietary protocol called DM and cannot be used for AT- or
+         PPP-based communication.
+
+         To compile this driver as a module, choose M here: the
+         module will be called moto_modem.  If unsure, choose N.
+
 config USB_SERIAL_QUALCOMM
        tristate "USB Qualcomm Serial modem"
        help
@@ -600,6 +611,14 @@ config USB_SERIAL_OPTICON
          To compile this driver as a module, choose M here: the
          module will be called opticon.
 
+config USB_SERIAL_VIVOPAY_SERIAL
+        tristate "USB ViVOpay serial interface driver"
+        help
+          Say Y here if you want to use a ViVOtech ViVOpay USB device.
+
+          To compile this driver as a module, choose M here: the
+          module will be called vivopay-serial.
+
 config USB_SERIAL_DEBUG
        tristate "USB Debugging Device"
        help
index 66619beb6cc0578b591c2e961e1e71f5306ca09a..83c9e431a56805fb3d3c33c812b2cdf5e27c71b2 100644 (file)
@@ -45,6 +45,7 @@ obj-$(CONFIG_USB_SERIAL_OPTICON)              += opticon.o
 obj-$(CONFIG_USB_SERIAL_OPTION)                        += option.o
 obj-$(CONFIG_USB_SERIAL_OTI6858)               += oti6858.o
 obj-$(CONFIG_USB_SERIAL_PL2303)                        += pl2303.o
+obj-$(CONFIG_USB_SERIAL_QCAUX)                 += qcaux.o
 obj-$(CONFIG_USB_SERIAL_QUALCOMM)              += qcserial.o
 obj-$(CONFIG_USB_SERIAL_SAFE)                  += safe_serial.o
 obj-$(CONFIG_USB_SERIAL_SIEMENS_MPI)           += siemens_mpi.o
@@ -55,4 +56,5 @@ obj-$(CONFIG_USB_SERIAL_TI)                   += ti_usb_3410_5052.o
 obj-$(CONFIG_USB_SERIAL_VISOR)                 += visor.o
 obj-$(CONFIG_USB_SERIAL_WHITEHEAT)             += whiteheat.o
 obj-$(CONFIG_USB_SERIAL_XIRCOM)                        += keyspan_pda.o
+obj-$(CONFIG_USB_SERIAL_VIVOPAY_SERIAL)        += vivopay-serial.o
 
index b10ac840941137a8516da829a9832b0ace64a665..365db1097bfdbdca5761fff631a8b37b6f280c10 100644 (file)
@@ -78,7 +78,7 @@ static int debug;
 #define DRIVER_DESC "AIRcable USB Driver"
 
 /* ID table that will be registered with USB core */
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(AIRCABLE_VID, AIRCABLE_USB_PID) },
        { },
 };
@@ -468,10 +468,6 @@ static void aircable_read_bulk_callback(struct urb *urb)
 
        if (status) {
                dbg("%s - urb status = %d", __func__, status);
-               if (!port->port.count) {
-                       dbg("%s - port is closed, exiting.", __func__);
-                       return;
-               }
                if (status == -EPROTO) {
                        dbg("%s - caught -EPROTO, resubmitting the urb",
                            __func__);
@@ -530,23 +526,19 @@ static void aircable_read_bulk_callback(struct urb *urb)
        }
        tty_kref_put(tty);
 
-       /* Schedule the next read _if_ we are still open */
-       if (port->port.count) {
-               usb_fill_bulk_urb(port->read_urb, port->serial->dev,
-                                 usb_rcvbulkpipe(port->serial->dev,
-                                         port->bulk_in_endpointAddress),
-                                 port->read_urb->transfer_buffer,
-                                 port->read_urb->transfer_buffer_length,
-                                 aircable_read_bulk_callback, port);
-
-               result = usb_submit_urb(urb, GFP_ATOMIC);
-               if (result)
-                       dev_err(&urb->dev->dev,
-                               "%s - failed resubmitting read urb, error %d\n",
-                               __func__, result);
-       }
-
-       return;
+       /* Schedule the next read */
+       usb_fill_bulk_urb(port->read_urb, port->serial->dev,
+                         usb_rcvbulkpipe(port->serial->dev,
+                                 port->bulk_in_endpointAddress),
+                         port->read_urb->transfer_buffer,
+                         port->read_urb->transfer_buffer_length,
+                         aircable_read_bulk_callback, port);
+
+       result = usb_submit_urb(urb, GFP_ATOMIC);
+       if (result && result != -EPERM)
+               dev_err(&urb->dev->dev,
+                       "%s - failed resubmitting read urb, error %d\n",
+                       __func__, result);
 }
 
 /* Based on ftdi_sio.c throttle */
index a9c2dec8e3fb66ce7233e8185c8d08fb4a2cedad..547c9448c28c345fd2f90966e3410b8e7949f2d3 100644 (file)
@@ -50,7 +50,7 @@ static int debug;
 /* usb timeout of 1 second */
 #define ARK_TIMEOUT (1*HZ)
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x6547, 0x0232) },
        { USB_DEVICE(0x18ec, 0x3118) },         /* USB to IrDA adapter */
        { },
@@ -733,7 +733,6 @@ static void ark3116_read_bulk_callback(struct urb *urb)
 
                tty = tty_port_tty_get(&port->port);
                if (tty) {
-                       tty_buffer_request_room(tty, urb->actual_length + 1);
                        /* overrun is special, not associated with a char */
                        if (unlikely(lsr & UART_LSR_OE))
                                tty_insert_flip_char(tty, 0, TTY_OVERRUN);
index a0467bc616270b51920d16d1e684ad2693454749..1295e44e3f1ce9382c5c2dc138b230ccca2d9ddd 100644 (file)
@@ -103,7 +103,7 @@ static int  belkin_sa_tiocmset(struct tty_struct *tty, struct file *file,
                                        unsigned int set, unsigned int clear);
 
 
-static struct usb_device_id id_table_combined [] = {
+static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(BELKIN_SA_VID, BELKIN_SA_PID) },
        { USB_DEVICE(BELKIN_OLD_VID, BELKIN_OLD_PID) },
        { USB_DEVICE(PERACOM_VID, PERACOM_PID) },
index 59eff721fcc5bb1e3374b1bfd098b0a67b558ddc..9f4fed1968b52ae64e9c58f0132fd5571efde772 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 #include <linux/serial.h>
+#include <asm/unaligned.h>
 
 #define DEFAULT_BAUD_RATE 9600
 #define DEFAULT_TIMEOUT   1000
@@ -70,7 +71,7 @@
 
 static int debug;
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x4348, 0x5523) },
        { USB_DEVICE(0x1a86, 0x7523) },
        { },
@@ -392,16 +393,22 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state)
        struct usb_serial_port *port = tty->driver_data;
        int r;
        uint16_t reg_contents;
-       uint8_t break_reg[2];
+       uint8_t *break_reg;
 
        dbg("%s()", __func__);
 
+       break_reg = kmalloc(2, GFP_KERNEL);
+       if (!break_reg) {
+               dev_err(&port->dev, "%s - kmalloc failed\n", __func__);
+               return;
+       }
+
        r = ch341_control_in(port->serial->dev, CH341_REQ_READ_REG,
-                       ch341_break_reg, 0, break_reg, sizeof(break_reg));
+                       ch341_break_reg, 0, break_reg, 2);
        if (r < 0) {
-               printk(KERN_WARNING "%s: USB control read error whilst getting"
-                               " break register contents.\n", __FILE__);
-               return;
+               dev_err(&port->dev, "%s - USB control read error (%d)\n",
+                               __func__, r);
+               goto out;
        }
        dbg("%s - initial ch341 break register contents - reg1: %x, reg2: %x",
                        __func__, break_reg[0], break_reg[1]);
@@ -416,12 +423,14 @@ static void ch341_break_ctl(struct tty_struct *tty, int break_state)
        }
        dbg("%s - New ch341 break register contents - reg1: %x, reg2: %x",
                        __func__, break_reg[0], break_reg[1]);
-       reg_contents = (uint16_t)break_reg[0] | ((uint16_t)break_reg[1] << 8);
+       reg_contents = get_unaligned_le16(break_reg);
        r = ch341_control_out(port->serial->dev, CH341_REQ_WRITE_REG,
                        ch341_break_reg, reg_contents);
        if (r < 0)
-               printk(KERN_WARNING "%s: USB control write error whilst setting"
-                               " break register contents.\n", __FILE__);
+               dev_err(&port->dev, "%s - USB control write error (%d)\n",
+                               __func__, r);
+out:
+       kfree(break_reg);
 }
 
 static int ch341_tiocmset(struct tty_struct *tty, struct file *file,
index bd254ec97d14be6d9b9e4db7e64bfbbca1f7d14c..507382b0a9ed1d377330344c62024fbd8e661d9d 100644 (file)
@@ -55,7 +55,7 @@ static int cp210x_carrier_raised(struct usb_serial_port *p);
 
 static int debug;
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x0471, 0x066A) }, /* AKTAKOM ACE-1001 cable */
        { USB_DEVICE(0x0489, 0xE000) }, /* Pirelli Broadband S.p.A, DP-L10 SIP/GSM Mobile */
        { USB_DEVICE(0x0745, 0x1000) }, /* CipherLab USB CCD Barcode Scanner 1000 */
@@ -91,11 +91,12 @@ static struct usb_device_id id_table [] = {
        { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
        { USB_DEVICE(0x10C4, 0x81E2) }, /* Lipowsky Industrie Elektronik GmbH, Baby-LIN */
        { USB_DEVICE(0x10C4, 0x81E7) }, /* Aerocomm Radio */
+       { USB_DEVICE(0x10C4, 0x81E8) }, /* Zephyr Bioharness */
        { USB_DEVICE(0x10C4, 0x81F2) }, /* C1007 HF band RFID controller */
        { USB_DEVICE(0x10C4, 0x8218) }, /* Lipowsky Industrie Elektronik GmbH, HARP-1 */
        { USB_DEVICE(0x10C4, 0x822B) }, /* Modem EDGE(GSM) Comander 2 */
        { USB_DEVICE(0x10C4, 0x826B) }, /* Cygnal Integrated Products, Inc., Fasttrax GPS demostration module */
-       { USB_DEVICE(0x10c4, 0x8293) }, /* Telegesys ETRX2USB */
+       { USB_DEVICE(0x10C4, 0x8293) }, /* Telegesys ETRX2USB */
        { USB_DEVICE(0x10C4, 0x82F9) }, /* Procyon AVS */
        { USB_DEVICE(0x10C4, 0x8341) }, /* Siemens MC35PU GPRS Modem */
        { USB_DEVICE(0x10C4, 0x8382) }, /* Cygnal Integrated Products, Inc. */
@@ -612,7 +613,7 @@ static void cp210x_set_termios(struct tty_struct *tty,
                                baud);
                if (cp210x_set_config_single(port, CP210X_SET_BAUDDIV,
                                        ((BAUD_RATE_GEN_FREQ + baud/2) / baud))) {
-                       dbg("Baud rate requested not supported by device\n");
+                       dbg("Baud rate requested not supported by device");
                        baud = tty_termios_baud_rate(old_termios);
                }
        }
index b0f6402a91ca57423769c16a8e0690896958fafa..f744ab7a3b19fb098d185a02545d8fa6987260a1 100644 (file)
@@ -70,7 +70,7 @@ static void cyberjack_read_int_callback(struct urb *urb);
 static void cyberjack_read_bulk_callback(struct urb *urb);
 static void cyberjack_write_bulk_callback(struct urb *urb);
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(CYBERJACK_VENDOR_ID, CYBERJACK_PRODUCT_ID) },
        { }                     /* Terminating entry */
 };
@@ -391,11 +391,10 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
 
        tty = tty_port_tty_get(&port->port);
        if (!tty) {
-               dbg("%s - ignoring since device not open\n", __func__);
+               dbg("%s - ignoring since device not open", __func__);
                return;
        }
        if (urb->actual_length) {
-               tty_buffer_request_room(tty, urb->actual_length);
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
        }
index a591ebec0f89c0af5d0ece8c3e9685fbe3d80d4f..baf74b44e6ed801c3941c8984c15c554e89a44fd 100644 (file)
 #include <linux/serial.h>
 #include <linux/delay.h>
 #include <linux/uaccess.h>
+#include <asm/unaligned.h>
 
 #include "cypress_m8.h"
 
 
-#ifdef CONFIG_USB_SERIAL_DEBUG
-       static int debug = 1;
-#else
-       static int debug;
-#endif
+static int debug;
 static int stats;
 static int interval;
+static int unstable_bauds;
 
 /*
  * Version Information
@@ -89,24 +87,24 @@ static int interval;
 #define CYPRESS_BUF_SIZE       1024
 #define CYPRESS_CLOSING_WAIT   (30*HZ)
 
-static struct usb_device_id id_table_earthmate [] = {
+static const struct usb_device_id id_table_earthmate[] = {
        { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) },
        { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) },
        { }                                             /* Terminating entry */
 };
 
-static struct usb_device_id id_table_cyphidcomrs232 [] = {
+static const struct usb_device_id id_table_cyphidcomrs232[] = {
        { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
        { USB_DEVICE(VENDOR_ID_POWERCOM, PRODUCT_ID_UPS) },
        { }                                             /* Terminating entry */
 };
 
-static struct usb_device_id id_table_nokiaca42v2 [] = {
+static const struct usb_device_id id_table_nokiaca42v2[] = {
        { USB_DEVICE(VENDOR_ID_DAZZLE, PRODUCT_ID_CA42) },
        { }                                             /* Terminating entry */
 };
 
-static struct usb_device_id id_table_combined [] = {
+static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB) },
        { USB_DEVICE(VENDOR_ID_DELORME, PRODUCT_ID_EARTHMATEUSB_LT20) },
        { USB_DEVICE(VENDOR_ID_CYPRESS, PRODUCT_ID_CYPHIDCOM) },
@@ -295,6 +293,9 @@ static int analyze_baud_rate(struct usb_serial_port *port, speed_t new_rate)
        struct cypress_private *priv;
        priv = usb_get_serial_port_data(port);
 
+       if (unstable_bauds)
+               return new_rate;
+
        /*
         * The general purpose firmware for the Cypress M8 allows for
         * a maximum speed of 57600bps (I have no idea whether DeLorme
@@ -344,7 +345,8 @@ static int cypress_serial_control(struct tty_struct *tty,
 {
        int new_baudrate = 0, retval = 0, tries = 0;
        struct cypress_private *priv;
-       __u8 feature_buffer[5];
+       u8 *feature_buffer;
+       const unsigned int feature_len = 5;
        unsigned long flags;
 
        dbg("%s", __func__);
@@ -354,17 +356,18 @@ static int cypress_serial_control(struct tty_struct *tty,
        if (!priv->comm_is_ok)
                return -ENODEV;
 
+       feature_buffer = kcalloc(feature_len, sizeof(u8), GFP_KERNEL);
+       if (!feature_buffer)
+               return -ENOMEM;
+
        switch (cypress_request_type) {
        case CYPRESS_SET_CONFIG:
-               new_baudrate = priv->baud_rate;
                /* 0 means 'Hang up' so doesn't change the true bit rate */
-               if (baud_rate == 0)
-                       new_baudrate = priv->baud_rate;
-               /* Change of speed ? */
-               else if (baud_rate != priv->baud_rate) {
+               new_baudrate = priv->baud_rate;
+               if (baud_rate && baud_rate != priv->baud_rate) {
                        dbg("%s - baud rate is changing", __func__);
                        retval = analyze_baud_rate(port, baud_rate);
-                       if (retval >=  0) {
+                       if (retval >= 0) {
                                new_baudrate = retval;
                                dbg("%s - New baud rate set to %d",
                                    __func__, new_baudrate);
@@ -373,9 +376,8 @@ static int cypress_serial_control(struct tty_struct *tty,
                dbg("%s - baud rate is being sent as %d",
                                        __func__, new_baudrate);
 
-               memset(feature_buffer, 0, sizeof(feature_buffer));
                /* fill the feature_buffer with new configuration */
-               *((u_int32_t *)feature_buffer) = new_baudrate;
+               put_unaligned_le32(new_baudrate, feature_buffer);
                feature_buffer[4] |= data_bits;   /* assign data bits in 2 bit space ( max 3 ) */
                /* 1 bit gap */
                feature_buffer[4] |= (stop_bits << 3);   /* assign stop bits in 1 bit space */
@@ -397,15 +399,15 @@ static int cypress_serial_control(struct tty_struct *tty,
                                        HID_REQ_SET_REPORT,
                                        USB_DIR_OUT | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
                                        0x0300, 0, feature_buffer,
-                                       sizeof(feature_buffer), 500);
+                                       feature_len, 500);
 
                        if (tries++ >= 3)
                                break;
 
-               } while (retval != sizeof(feature_buffer) &&
+               } while (retval != feature_len &&
                         retval != -ENODEV);
 
-               if (retval != sizeof(feature_buffer)) {
+               if (retval != feature_len) {
                        dev_err(&port->dev, "%s - failed sending serial "
                                "line settings - %d\n", __func__, retval);
                        cypress_set_dead(port);
@@ -425,43 +427,42 @@ static int cypress_serial_control(struct tty_struct *tty,
                        /* Not implemented for this device,
                           and if we try to do it we're likely
                           to crash the hardware. */
-                       return -ENOTTY;
+                       retval = -ENOTTY;
+                       goto out;
                }
                dbg("%s - retreiving serial line settings", __func__);
-               /* set initial values in feature buffer */
-               memset(feature_buffer, 0, sizeof(feature_buffer));
-
                do {
                        retval = usb_control_msg(port->serial->dev,
                                        usb_rcvctrlpipe(port->serial->dev, 0),
                                        HID_REQ_GET_REPORT,
                                        USB_DIR_IN | USB_RECIP_INTERFACE | USB_TYPE_CLASS,
                                        0x0300, 0, feature_buffer,
-                                       sizeof(feature_buffer), 500);
+                                       feature_len, 500);
 
                        if (tries++ >= 3)
                                break;
-               } while (retval != sizeof(feature_buffer)
+               } while (retval != feature_len
                                                && retval != -ENODEV);
 
-               if (retval != sizeof(feature_buffer)) {
+               if (retval != feature_len) {
                        dev_err(&port->dev, "%s - failed to retrieve serial "
                                "line settings - %d\n", __func__, retval);
                        cypress_set_dead(port);
-                       return retval;
+                       goto out;
                } else {
                        spin_lock_irqsave(&priv->lock, flags);
                        /* store the config in one byte, and later
                           use bit masks to check values */
                        priv->current_config = feature_buffer[4];
-                       priv->baud_rate = *((u_int32_t *)feature_buffer);
+                       priv->baud_rate = get_unaligned_le32(feature_buffer);
                        spin_unlock_irqrestore(&priv->lock, flags);
                }
        }
        spin_lock_irqsave(&priv->lock, flags);
        ++priv->cmd_count;
        spin_unlock_irqrestore(&priv->lock, flags);
-
+out:
+       kfree(feature_buffer);
        return retval;
 } /* cypress_serial_control */
 
@@ -690,7 +691,6 @@ static void cypress_dtr_rts(struct usb_serial_port *port, int on)
 {
        struct cypress_private *priv = usb_get_serial_port_data(port);
        /* drop dtr and rts */
-       priv = usb_get_serial_port_data(port);
        spin_lock_irq(&priv->lock);
        if (on == 0)
                priv->line_control = 0;
@@ -1307,13 +1307,9 @@ static void cypress_read_int_callback(struct urb *urb)
                spin_unlock_irqrestore(&priv->lock, flags);
 
        /* process read if there is data other than line status */
-       if (tty && (bytes > i)) {
-               bytes = tty_buffer_request_room(tty, bytes);
-               for (; i < bytes ; ++i) {
-                       dbg("pushing byte number %d - %d - %c", i, data[i],
-                                       data[i]);
-                       tty_insert_flip_char(tty, data[i], tty_flag);
-               }
+       if (tty && bytes > i) {
+               tty_insert_flip_string_fixed_flag(tty, data + i,
+                               bytes - i, tty_flag);
                tty_flip_buffer_push(tty);
        }
 
@@ -1325,9 +1321,9 @@ static void cypress_read_int_callback(struct urb *urb)
 continue_read:
        tty_kref_put(tty);
 
-       /* Continue trying to always read... unless the port has closed. */
+       /* Continue trying to always read */
 
-       if (port->port.count > 0 && priv->comm_is_ok) {
+       if (priv->comm_is_ok) {
                usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
                                usb_rcvintpipe(port->serial->dev,
                                        port->interrupt_in_endpointAddress),
@@ -1336,7 +1332,7 @@ continue_read:
                                cypress_read_int_callback, port,
                                priv->read_urb_interval);
                result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
-               if (result) {
+               if (result && result != -EPERM) {
                        dev_err(&urb->dev->dev, "%s - failed resubmitting "
                                        "read urb, error %d\n", __func__,
                                        result);
@@ -1650,3 +1646,5 @@ module_param(stats, bool, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(stats, "Enable statistics or not");
 module_param(interval, int, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(interval, "Overrides interrupt interval");
+module_param(unstable_bauds, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(unstable_bauds, "Allow unstable baud rates");
index 68e80be6b9e1888dbc82b7c8cc6584a9f7abddb7..68b0aa5e516c2deb0036790a61ff2a7e1039e19a 100644 (file)
@@ -470,18 +470,18 @@ static int digi_read_oob_callback(struct urb *urb);
 
 static int debug;
 
-static struct usb_device_id id_table_combined [] = {
+static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) },
        { USB_DEVICE(DIGI_VENDOR_ID, DIGI_4_ID) },
        { }                                             /* Terminating entry */
 };
 
-static struct usb_device_id id_table_2 [] = {
+static const struct usb_device_id id_table_2[] = {
        { USB_DEVICE(DIGI_VENDOR_ID, DIGI_2_ID) },
        { }                                             /* Terminating entry */
 };
 
-static struct usb_device_id id_table_4 [] = {
+static const struct usb_device_id id_table_4[] = {
        { USB_DEVICE(DIGI_VENDOR_ID, DIGI_4_ID) },
        { }                                             /* Terminating entry */
 };
@@ -1262,10 +1262,10 @@ static void digi_write_bulk_callback(struct urb *urb)
                return;
        }
 
-       /* try to send any buffered data on this port, if it is open */
+       /* try to send any buffered data on this port */
        spin_lock(&priv->dp_port_lock);
        priv->dp_write_urb_in_use = 0;
-       if (port->port.count && priv->dp_out_buf_len > 0) {
+       if (priv->dp_out_buf_len > 0) {
                *((unsigned char *)(port->write_urb->transfer_buffer))
                        = (unsigned char)DIGI_CMD_SEND_DATA;
                *((unsigned char *)(port->write_urb->transfer_buffer) + 1)
@@ -1288,7 +1288,7 @@ static void digi_write_bulk_callback(struct urb *urb)
        schedule_work(&priv->dp_wakeup_work);
 
        spin_unlock(&priv->dp_port_lock);
-       if (ret)
+       if (ret && ret != -EPERM)
                dev_err(&port->dev,
                        "%s: usb_submit_urb failed, ret=%d, port=%d\n",
                        __func__, ret, priv->dp_port_num);
@@ -1353,8 +1353,7 @@ static int digi_open(struct tty_struct *tty, struct usb_serial_port *port)
        struct digi_port *priv = usb_get_serial_port_data(port);
        struct ktermios not_termios;
 
-       dbg("digi_open: TOP: port=%d, open_count=%d",
-               priv->dp_port_num, port->port.count);
+       dbg("digi_open: TOP: port=%d", priv->dp_port_num);
 
        /* be sure the device is started up */
        if (digi_startup_device(port->serial) != 0)
@@ -1393,8 +1392,7 @@ static void digi_close(struct usb_serial_port *port)
        unsigned char buf[32];
        struct digi_port *priv = usb_get_serial_port_data(port);
 
-       dbg("digi_close: TOP: port=%d, open_count=%d",
-               priv->dp_port_num, port->port.count);
+       dbg("digi_close: TOP: port=%d", priv->dp_port_num);
 
        mutex_lock(&port->serial->disc_mutex);
        /* if disconnected, just clear flags */
@@ -1629,7 +1627,7 @@ static void digi_read_bulk_callback(struct urb *urb)
        /* continue read */
        urb->dev = port->serial->dev;
        ret = usb_submit_urb(urb, GFP_ATOMIC);
-       if (ret != 0) {
+       if (ret != 0 && ret != -EPERM) {
                dev_err(&port->dev,
                        "%s: failed resubmitting urb, ret=%d, port=%d\n",
                        __func__, ret, priv->dp_port_num);
@@ -1658,12 +1656,11 @@ static int digi_read_inb_callback(struct urb *urb)
        int port_status = ((unsigned char *)urb->transfer_buffer)[2];
        unsigned char *data = ((unsigned char *)urb->transfer_buffer) + 3;
        int flag, throttled;
-       int i;
        int status = urb->status;
 
        /* do not process callbacks on closed ports */
        /* but do continue the read chain */
-       if (port->port.count == 0)
+       if (urb->status == -ENOENT)
                return 0;
 
        /* short/multiple packet check */
@@ -1705,17 +1702,9 @@ static int digi_read_inb_callback(struct urb *urb)
 
                /* data length is len-1 (one byte of len is port_status) */
                --len;
-
-               len = tty_buffer_request_room(tty, len);
                if (len > 0) {
-                       /* Hot path */
-                       if (flag == TTY_NORMAL)
-                               tty_insert_flip_string(tty, data, len);
-                       else {
-                               for (i = 0; i < len; i++)
-                                       tty_insert_flip_char(tty,
-                                                               data[i], flag);
-                       }
+                       tty_insert_flip_string_fixed_flag(tty, data, len,
+                                                                       flag);
                        tty_flip_buffer_push(tty);
                }
        }
@@ -1776,8 +1765,7 @@ static int digi_read_oob_callback(struct urb *urb)
 
                tty = tty_port_tty_get(&port->port);
                rts = 0;
-               if (port->port.count)
-                       rts = tty->termios->c_cflag & CRTSCTS;
+               rts = tty->termios->c_cflag & CRTSCTS;
                
                if (opcode == DIGI_CMD_READ_INPUT_SIGNALS) {
                        spin_lock(&priv->dp_port_lock);
index 7dd0e3eadbe64ce3fab049ed2af23e1ba7e424f4..5f740a1eacab7958e3964c7a76d9369e08535d57 100644 (file)
@@ -93,7 +93,7 @@ static void empeg_init_termios(struct tty_struct *tty);
 static void empeg_write_bulk_callback(struct urb *urb);
 static void empeg_read_bulk_callback(struct urb *urb);
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(EMPEG_VENDOR_ID, EMPEG_PRODUCT_ID) },
        { }                                     /* Terminating entry */
 };
@@ -346,7 +346,6 @@ static void empeg_read_bulk_callback(struct urb *urb)
        tty = tty_port_tty_get(&port->port);
 
        if (urb->actual_length) {
-               tty_buffer_request_room(tty, urb->actual_length);
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
                bytes_in += urb->actual_length;
index 7638828e7317787bbd8905f426032c3dbbaa2dce..6af0dfa5f5ac22e31a0fc9d70c8996ba33cbe53a 100644 (file)
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/slab.h>
-#include <linux/smp_lock.h>
 #include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/mutex.h>
 #include <linux/uaccess.h>
 #include <linux/usb.h>
 #include <linux/serial.h>
@@ -88,10 +88,10 @@ struct ftdi_private {
 
        unsigned int latency;           /* latency setting in use */
        spinlock_t tx_lock;     /* spinlock for transmit state */
-       unsigned long tx_bytes;
        unsigned long tx_outstanding_bytes;
        unsigned long tx_outstanding_urbs;
        unsigned short max_packet_size;
+       struct mutex cfg_lock; /* Avoid mess by parallel calls of config ioctl() */
 };
 
 /* struct ftdi_sio_quirk is used by devices requiring special attention. */
@@ -614,6 +614,7 @@ static struct usb_device_id id_table_combined [] = {
        { USB_DEVICE(FTDI_VID, FTDI_OCEANIC_PID) },
        { USB_DEVICE(TTI_VID, TTI_QL355P_PID) },
        { USB_DEVICE(FTDI_VID, FTDI_RM_CANVIEW_PID) },
+       { USB_DEVICE(CONTEC_VID, CONTEC_COM1USBH_PID) },
        { USB_DEVICE(BANDB_VID, BANDB_USOTL4_PID) },
        { USB_DEVICE(BANDB_VID, BANDB_USTL4_PID) },
        { USB_DEVICE(BANDB_VID, BANDB_USO9ML2_PID) },
@@ -737,6 +738,10 @@ static struct usb_device_id id_table_combined [] = {
                .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
        { USB_DEVICE(FTDI_VID, HAMEG_HO820_PID) },
        { USB_DEVICE(FTDI_VID, HAMEG_HO870_PID) },
+       { USB_DEVICE(FTDI_VID, MJSG_GENERIC_PID) },
+       { USB_DEVICE(FTDI_VID, MJSG_SR_RADIO_PID) },
+       { USB_DEVICE(FTDI_VID, MJSG_HD_RADIO_PID) },
+       { USB_DEVICE(FTDI_VID, MJSG_XM_RADIO_PID) },
        { },                                    /* Optional parameter entry */
        { }                                     /* Terminating entry */
 };
@@ -812,7 +817,7 @@ static struct usb_serial_driver ftdi_sio_device = {
                .name =         "ftdi_sio",
        },
        .description =          "FTDI USB Serial Device",
-       .usb_driver =           &ftdi_driver ,
+       .usb_driver =           &ftdi_driver,
        .id_table =             id_table_combined,
        .num_ports =            1,
        .probe =                ftdi_sio_probe,
@@ -828,8 +833,8 @@ static struct usb_serial_driver ftdi_sio_device = {
        .chars_in_buffer =      ftdi_chars_in_buffer,
        .read_bulk_callback =   ftdi_read_bulk_callback,
        .write_bulk_callback =  ftdi_write_bulk_callback,
-       .tiocmget =             ftdi_tiocmget,
-       .tiocmset =             ftdi_tiocmset,
+       .tiocmget =             ftdi_tiocmget,
+       .tiocmset =             ftdi_tiocmset,
        .ioctl =                ftdi_ioctl,
        .set_termios =          ftdi_set_termios,
        .break_ctl =            ftdi_break_ctl,
@@ -935,7 +940,6 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set,
                                                        unsigned int clear)
 {
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       char *buf;
        unsigned urb_value;
        int rv;
 
@@ -944,10 +948,6 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set,
                return 0;       /* no change */
        }
 
-       buf = kmalloc(1, GFP_NOIO);
-       if (!buf)
-               return -ENOMEM;
-
        clear &= ~set;  /* 'set' takes precedence over 'clear' */
        urb_value = 0;
        if (clear & TIOCM_DTR)
@@ -963,9 +963,7 @@ static int update_mctrl(struct usb_serial_port *port, unsigned int set,
                               FTDI_SIO_SET_MODEM_CTRL_REQUEST,
                               FTDI_SIO_SET_MODEM_CTRL_REQUEST_TYPE,
                               urb_value, priv->interface,
-                              buf, 0, WDR_TIMEOUT);
-
-       kfree(buf);
+                              NULL, 0, WDR_TIMEOUT);
        if (rv < 0) {
                dbg("%s Error from MODEM_CTRL urb: DTR %s, RTS %s",
                                __func__,
@@ -1124,16 +1122,11 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty,
 static int change_speed(struct tty_struct *tty, struct usb_serial_port *port)
 {
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       char *buf;
        __u16 urb_value;
        __u16 urb_index;
        __u32 urb_index_value;
        int rv;
 
-       buf = kmalloc(1, GFP_NOIO);
-       if (!buf)
-               return -ENOMEM;
-
        urb_index_value = get_ftdi_divisor(tty, port);
        urb_value = (__u16)urb_index_value;
        urb_index = (__u16)(urb_index_value >> 16);
@@ -1146,9 +1139,7 @@ static int change_speed(struct tty_struct *tty, struct usb_serial_port *port)
                            FTDI_SIO_SET_BAUDRATE_REQUEST,
                            FTDI_SIO_SET_BAUDRATE_REQUEST_TYPE,
                            urb_value, urb_index,
-                           buf, 0, WDR_SHORT_TIMEOUT);
-
-       kfree(buf);
+                           NULL, 0, WDR_SHORT_TIMEOUT);
        return rv;
 }
 
@@ -1156,8 +1147,7 @@ static int write_latency_timer(struct usb_serial_port *port)
 {
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        struct usb_device *udev = port->serial->dev;
-       char buf[1];
-       int rv = 0;
+       int rv;
        int l = priv->latency;
 
        if (priv->flags & ASYNC_LOW_LATENCY)
@@ -1170,8 +1160,7 @@ static int write_latency_timer(struct usb_serial_port *port)
                             FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
                             FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
                             l, priv->interface,
-                            buf, 0, WDR_TIMEOUT);
-
+                            NULL, 0, WDR_TIMEOUT);
        if (rv < 0)
                dev_err(&port->dev, "Unable to write latency timer: %i\n", rv);
        return rv;
@@ -1181,24 +1170,29 @@ static int read_latency_timer(struct usb_serial_port *port)
 {
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        struct usb_device *udev = port->serial->dev;
-       unsigned short latency = 0;
-       int rv = 0;
-
+       unsigned char *buf;
+       int rv;
 
        dbg("%s", __func__);
 
+       buf = kmalloc(1, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+
        rv = usb_control_msg(udev,
                             usb_rcvctrlpipe(udev, 0),
                             FTDI_SIO_GET_LATENCY_TIMER_REQUEST,
                             FTDI_SIO_GET_LATENCY_TIMER_REQUEST_TYPE,
                             0, priv->interface,
-                            (char *) &latency, 1, WDR_TIMEOUT);
-
-       if (rv < 0) {
+                            buf, 1, WDR_TIMEOUT);
+       if (rv < 0)
                dev_err(&port->dev, "Unable to read latency timer: %i\n", rv);
-               return -EIO;
-       }
-       return latency;
+       else
+               priv->latency = buf[0];
+
+       kfree(buf);
+
+       return rv;
 }
 
 static int get_serial_info(struct usb_serial_port *port,
@@ -1229,7 +1223,7 @@ static int set_serial_info(struct tty_struct *tty,
        if (copy_from_user(&new_serial, newinfo, sizeof(new_serial)))
                return -EFAULT;
 
-       lock_kernel();
+       mutex_lock(&priv->cfg_lock);
        old_priv = *priv;
 
        /* Do error checking and permission checking */
@@ -1237,7 +1231,7 @@ static int set_serial_info(struct tty_struct *tty,
        if (!capable(CAP_SYS_ADMIN)) {
                if (((new_serial.flags & ~ASYNC_USR_MASK) !=
                     (priv->flags & ~ASYNC_USR_MASK))) {
-                       unlock_kernel();
+                       mutex_unlock(&priv->cfg_lock);
                        return -EPERM;
                }
                priv->flags = ((priv->flags & ~ASYNC_USR_MASK) |
@@ -1248,7 +1242,7 @@ static int set_serial_info(struct tty_struct *tty,
 
        if ((new_serial.baud_base != priv->baud_base) &&
            (new_serial.baud_base < 9600)) {
-               unlock_kernel();
+               mutex_unlock(&priv->cfg_lock);
                return -EINVAL;
        }
 
@@ -1278,11 +1272,11 @@ check_and_exit:
             (priv->flags & ASYNC_SPD_MASK)) ||
            (((priv->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) &&
             (old_priv.custom_divisor != priv->custom_divisor))) {
-               unlock_kernel();
+               mutex_unlock(&priv->cfg_lock);
                change_speed(tty, port);
        }
        else
-               unlock_kernel();
+               mutex_unlock(&priv->cfg_lock);
        return 0;
 
 } /* set_serial_info */
@@ -1338,20 +1332,20 @@ static void ftdi_determine_type(struct usb_serial_port *port)
                                        __func__);
                }
        } else if (version < 0x200) {
-               /* Old device.  Assume its the original SIO. */
+               /* Old device.  Assume it's the original SIO. */
                priv->chip_type = SIO;
                priv->baud_base = 12000000 / 16;
                priv->write_offset = 1;
        } else if (version < 0x400) {
-               /* Assume its an FT8U232AM (or FT8U245AM) */
+               /* Assume it's an FT8U232AM (or FT8U245AM) */
                /* (It might be a BM because of the iSerialNumber bug,
                 * but it will still work as an AM device.) */
                priv->chip_type = FT8U232AM;
        } else if (version < 0x600) {
-               /* Assume its an FT232BM (or FT245BM) */
+               /* Assume it's an FT232BM (or FT245BM) */
                priv->chip_type = FT232BM;
        } else {
-               /* Assume its an FT232R  */
+               /* Assume it's an FT232R */
                priv->chip_type = FT232RL;
        }
        dev_info(&udev->dev, "Detected %s\n", ftdi_chip_name[priv->chip_type]);
@@ -1371,7 +1365,7 @@ static void ftdi_set_max_packet_size(struct usb_serial_port *port)
        struct usb_endpoint_descriptor *ep_desc = &interface->cur_altsetting->endpoint[1].desc;
 
        unsigned num_endpoints;
-       int i = 0;
+       int i;
 
        num_endpoints = interface->cur_altsetting->desc.bNumEndpoints;
        dev_info(&udev->dev, "Number of endpoints %d\n", num_endpoints);
@@ -1423,7 +1417,7 @@ static ssize_t store_latency_timer(struct device *dev,
        struct usb_serial_port *port = to_usb_serial_port(dev);
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        int v = simple_strtoul(valbuf, NULL, 10);
-       int rv = 0;
+       int rv;
 
        priv->latency = v;
        rv = write_latency_timer(port);
@@ -1440,9 +1434,8 @@ static ssize_t store_event_char(struct device *dev,
        struct usb_serial_port *port = to_usb_serial_port(dev);
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        struct usb_device *udev = port->serial->dev;
-       char buf[1];
        int v = simple_strtoul(valbuf, NULL, 10);
-       int rv = 0;
+       int rv;
 
        dbg("%s: setting event char = %i", __func__, v);
 
@@ -1451,8 +1444,7 @@ static ssize_t store_event_char(struct device *dev,
                             FTDI_SIO_SET_EVENT_CHAR_REQUEST,
                             FTDI_SIO_SET_EVENT_CHAR_REQUEST_TYPE,
                             v, priv->interface,
-                            buf, 0, WDR_TIMEOUT);
-
+                            NULL, 0, WDR_TIMEOUT);
        if (rv < 0) {
                dbg("Unable to write event character: %i", rv);
                return -EIO;
@@ -1551,9 +1543,9 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
 
        kref_init(&priv->kref);
        spin_lock_init(&priv->tx_lock);
+       mutex_init(&priv->cfg_lock);
        init_waitqueue_head(&priv->delta_msr_wait);
-       /* This will push the characters through immediately rather
-          than queue a task to deliver them */
+
        priv->flags = ASYNC_LOW_LATENCY;
 
        if (quirk && quirk->port_probe)
@@ -1585,7 +1577,8 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
 
        ftdi_determine_type(port);
        ftdi_set_max_packet_size(port);
-       read_latency_timer(port);
+       if (read_latency_timer(port) < 0)
+               priv->latency = 16;
        create_sysfs_attrs(port);
        return 0;
 }
@@ -1630,8 +1623,6 @@ static int ftdi_NDI_device_setup(struct usb_serial *serial)
 {
        struct usb_device *udev = serial->dev;
        int latency = ndi_latency_timer;
-       int rv = 0;
-       char buf[1];
 
        if (latency == 0)
                latency = 1;
@@ -1641,10 +1632,11 @@ static int ftdi_NDI_device_setup(struct usb_serial *serial)
        dbg("%s setting NDI device latency to %d", __func__, latency);
        dev_info(&udev->dev, "NDI device with a latency value of %d", latency);
 
-       rv = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+       /* FIXME: errors are not returned */
+       usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
                                FTDI_SIO_SET_LATENCY_TIMER_REQUEST,
                                FTDI_SIO_SET_LATENCY_TIMER_REQUEST_TYPE,
-                               latency, 0, buf, 0, WDR_TIMEOUT);
+                               latency, 0, NULL, 0, WDR_TIMEOUT);
        return 0;
 }
 
@@ -1720,7 +1712,7 @@ static int ftdi_submit_read_urb(struct usb_serial_port *port, gfp_t mem_flags)
                           urb->transfer_buffer_length,
                           ftdi_read_bulk_callback, port);
        result = usb_submit_urb(urb, mem_flags);
-       if (result)
+       if (result && result != -EPERM)
                dev_err(&port->dev,
                        "%s - failed submitting read urb, error %d\n",
                                                        __func__, result);
@@ -1732,16 +1724,10 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
        struct usb_device *dev = port->serial->dev;
        struct ftdi_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
-
-       int result = 0;
-       char buf[1]; /* Needed for the usb_control_msg I think */
+       int result;
 
        dbg("%s", __func__);
 
-       spin_lock_irqsave(&priv->tx_lock, flags);
-       priv->tx_bytes = 0;
-       spin_unlock_irqrestore(&priv->tx_lock, flags);
-
        write_latency_timer(port);
 
        /* No error checking for this (will get errors later anyway) */
@@ -1749,7 +1735,7 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
        usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
                        FTDI_SIO_RESET_REQUEST, FTDI_SIO_RESET_REQUEST_TYPE,
                        FTDI_SIO_RESET_SIO,
-                       priv->interface, buf, 0, WDR_TIMEOUT);
+                       priv->interface, NULL, 0, WDR_TIMEOUT);
 
        /* Termios defaults are set by usb_serial_init. We don't change
           port->tty->termios - this would lose speed settings, etc.
@@ -1777,7 +1763,6 @@ static int ftdi_open(struct tty_struct *tty, struct usb_serial_port *port)
 static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
 {
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       char buf[1];
 
        mutex_lock(&port->serial->disc_mutex);
        if (!port->serial->disconnected) {
@@ -1786,7 +1771,7 @@ static void ftdi_dtr_rts(struct usb_serial_port *port, int on)
                            usb_sndctrlpipe(port->serial->dev, 0),
                            FTDI_SIO_SET_FLOW_CTRL_REQUEST,
                            FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
-                           0, priv->interface, buf, 0,
+                           0, priv->interface, NULL, 0,
                            WDR_TIMEOUT) < 0) {
                            dev_err(&port->dev, "error from flowcontrol urb\n");
                }
@@ -1847,7 +1832,7 @@ static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
        spin_lock_irqsave(&priv->tx_lock, flags);
        if (priv->tx_outstanding_urbs > URB_UPPER_LIMIT) {
                spin_unlock_irqrestore(&priv->tx_lock, flags);
-               dbg("%s - write limit hit\n", __func__);
+               dbg("%s - write limit hit", __func__);
                return 0;
        }
        priv->tx_outstanding_urbs++;
@@ -1927,7 +1912,6 @@ static int ftdi_write(struct tty_struct *tty, struct usb_serial_port *port,
        } else {
                spin_lock_irqsave(&priv->tx_lock, flags);
                priv->tx_outstanding_bytes += count;
-               priv->tx_bytes += count;
                spin_unlock_irqrestore(&priv->tx_lock, flags);
        }
 
@@ -2154,8 +2138,7 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state)
 {
        struct usb_serial_port *port = tty->driver_data;
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       __u16 urb_value = 0;
-       char buf[1];
+       __u16 urb_value;
 
        /* break_state = -1 to turn on break, and 0 to turn off break */
        /* see drivers/char/tty_io.c to see it used */
@@ -2171,7 +2154,7 @@ static void ftdi_break_ctl(struct tty_struct *tty, int break_state)
                        FTDI_SIO_SET_DATA_REQUEST,
                        FTDI_SIO_SET_DATA_REQUEST_TYPE,
                        urb_value , priv->interface,
-                       buf, 0, WDR_TIMEOUT) < 0) {
+                       NULL, 0, WDR_TIMEOUT) < 0) {
                dev_err(&port->dev, "%s FAILED to enable/disable break state "
                        "(state was %d)\n", __func__, break_state);
        }
@@ -2195,7 +2178,6 @@ static void ftdi_set_termios(struct tty_struct *tty,
        struct ktermios *termios = tty->termios;
        unsigned int cflag = termios->c_cflag;
        __u16 urb_value; /* will hold the new flags */
-       char buf[1]; /* Perhaps I should dynamically alloc this? */
 
        /* Added for xon/xoff support */
        unsigned int iflag = termios->c_iflag;
@@ -2246,12 +2228,10 @@ static void ftdi_set_termios(struct tty_struct *tty,
        }
        if (cflag & CSIZE) {
                switch (cflag & CSIZE) {
-               case CS5: urb_value |= 5; dbg("Setting CS5"); break;
-               case CS6: urb_value |= 6; dbg("Setting CS6"); break;
                case CS7: urb_value |= 7; dbg("Setting CS7"); break;
                case CS8: urb_value |= 8; dbg("Setting CS8"); break;
                default:
-                       dev_err(&port->dev, "CSIZE was set but not CS5-CS8\n");
+                       dev_err(&port->dev, "CSIZE was set but not CS7-CS8\n");
                }
        }
 
@@ -2263,7 +2243,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
                            FTDI_SIO_SET_DATA_REQUEST,
                            FTDI_SIO_SET_DATA_REQUEST_TYPE,
                            urb_value , priv->interface,
-                           buf, 0, WDR_SHORT_TIMEOUT) < 0) {
+                           NULL, 0, WDR_SHORT_TIMEOUT) < 0) {
                dev_err(&port->dev, "%s FAILED to set "
                        "databits/stopbits/parity\n", __func__);
        }
@@ -2275,7 +2255,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST,
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
                                    0, priv->interface,
-                                   buf, 0, WDR_TIMEOUT) < 0) {
+                                   NULL, 0, WDR_TIMEOUT) < 0) {
                        dev_err(&port->dev,
                                "%s error from disable flowcontrol urb\n",
                                __func__);
@@ -2301,7 +2281,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST,
                                    FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
                                    0 , (FTDI_SIO_RTS_CTS_HS | priv->interface),
-                                   buf, 0, WDR_TIMEOUT) < 0) {
+                                   NULL, 0, WDR_TIMEOUT) < 0) {
                        dev_err(&port->dev,
                                "urb failed to set to rts/cts flow control\n");
                }
@@ -2333,7 +2313,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
                                            FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
                                            urb_value , (FTDI_SIO_XON_XOFF_HS
                                                         | priv->interface),
-                                           buf, 0, WDR_TIMEOUT) < 0) {
+                                           NULL, 0, WDR_TIMEOUT) < 0) {
                                dev_err(&port->dev, "urb failed to set to "
                                        "xon/xoff flow control\n");
                        }
@@ -2347,7 +2327,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
                                            FTDI_SIO_SET_FLOW_CTRL_REQUEST,
                                            FTDI_SIO_SET_FLOW_CTRL_REQUEST_TYPE,
                                            0, priv->interface,
-                                           buf, 0, WDR_TIMEOUT) < 0) {
+                                           NULL, 0, WDR_TIMEOUT) < 0) {
                                dev_err(&port->dev,
                                        "urb failed to clear flow control\n");
                        }
@@ -2361,21 +2341,22 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
 {
        struct usb_serial_port *port = tty->driver_data;
        struct ftdi_private *priv = usb_get_serial_port_data(port);
-       unsigned char buf[2];
+       unsigned char *buf;
+       int len;
        int ret;
 
        dbg("%s TIOCMGET", __func__);
+
+       buf = kmalloc(2, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
+       /*
+        * The 8U232AM returns a two byte value (the SIO a 1 byte value) in
+        * the same format as the data returned from the in point.
+        */
        switch (priv->chip_type) {
        case SIO:
-               /* Request the status from the device */
-               ret = usb_control_msg(port->serial->dev,
-                          usb_rcvctrlpipe(port->serial->dev, 0),
-                          FTDI_SIO_GET_MODEM_STATUS_REQUEST,
-                          FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
-                          0, 0,
-                          buf, 1, WDR_TIMEOUT);
-               if (ret < 0)
-                       return ret;
+               len = 1;
                break;
        case FT8U232AM:
        case FT232BM:
@@ -2383,27 +2364,30 @@ static int ftdi_tiocmget(struct tty_struct *tty, struct file *file)
        case FT232RL:
        case FT2232H:
        case FT4232H:
-               /* the 8U232AM returns a two byte value (the sio is a 1 byte
-                  value) - in the same format as the data returned from the in
-                  point */
-               ret = usb_control_msg(port->serial->dev,
-                                  usb_rcvctrlpipe(port->serial->dev, 0),
-                                  FTDI_SIO_GET_MODEM_STATUS_REQUEST,
-                                  FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
-                                  0, priv->interface,
-                                  buf, 2, WDR_TIMEOUT);
-               if (ret < 0)
-                       return ret;
+               len = 2;
                break;
        default:
-               return -EFAULT;
+               ret = -EFAULT;
+               goto out;
        }
 
-       return  (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
+       ret = usb_control_msg(port->serial->dev,
+                       usb_rcvctrlpipe(port->serial->dev, 0),
+                       FTDI_SIO_GET_MODEM_STATUS_REQUEST,
+                       FTDI_SIO_GET_MODEM_STATUS_REQUEST_TYPE,
+                       0, priv->interface,
+                       buf, len, WDR_TIMEOUT);
+       if (ret < 0)
+               goto out;
+
+       ret = (buf[0] & FTDI_SIO_DSR_MASK ? TIOCM_DSR : 0) |
                (buf[0] & FTDI_SIO_CTS_MASK ? TIOCM_CTS : 0) |
                (buf[0]  & FTDI_SIO_RI_MASK  ? TIOCM_RI  : 0) |
                (buf[0]  & FTDI_SIO_RLSD_MASK ? TIOCM_CD  : 0) |
                priv->last_dtr_rts;
+out:
+       kfree(buf);
+       return ret;
 }
 
 static int ftdi_tiocmset(struct tty_struct *tty, struct file *file,
@@ -2508,8 +2492,7 @@ void ftdi_unthrottle(struct tty_struct *tty)
        port->throttled = port->throttle_req = 0;
        spin_unlock_irqrestore(&port->lock, flags);
 
-       /* Resubmit urb if throttled and open. */
-       if (was_throttled && test_bit(ASYNCB_INITIALIZED, &port->port.flags))
+       if (was_throttled)
                ftdi_submit_read_urb(port, GFP_KERNEL);
 }
 
index b0e0d64f822e27b9bcf0c076d34e67ddecdebea5..ff9bf80327a300634487aa885114eb3c3cba0496 100644 (file)
 #define FTDI_SIO_SET_FLOW_CTRL 2 /* Set flow control register */
 #define FTDI_SIO_SET_BAUD_RATE 3 /* Set baud rate */
 #define FTDI_SIO_SET_DATA      4 /* Set the data characteristics of the port */
-#define FTDI_SIO_GET_MODEM_STATUS      5 /* Retrieve current value of modern status register */
+#define FTDI_SIO_GET_MODEM_STATUS      5 /* Retrieve current value of modem status register */
 #define FTDI_SIO_SET_EVENT_CHAR        6 /* Set the event character */
 #define FTDI_SIO_SET_ERROR_CHAR        7 /* Set the error character */
 #define FTDI_SIO_SET_LATENCY_TIMER     9 /* Set the latency timer */
 #define FTDI_SIO_GET_LATENCY_TIMER     10 /* Get the latency timer */
 
-/* Interface indicies for FT2232, FT2232H and FT4232H devices*/
+/* Interface indices for FT2232, FT2232H and FT4232H devices */
 #define INTERFACE_A            1
 #define INTERFACE_B            2
 #define INTERFACE_C            3
@@ -270,7 +270,7 @@ typedef enum {
  *   BmRequestType:  0100 0000b
  *   bRequest:       FTDI_SIO_SET_FLOW_CTRL
  *   wValue:         Xoff/Xon
- *   wIndex:         Protocol/Port - hIndex is protocl / lIndex is port
+ *   wIndex:         Protocol/Port - hIndex is protocol / lIndex is port
  *   wLength:        0
  *   Data:           None
  *
index c8951aeed98379d93d3793a70440eb426ffb2286..0727e198503e5b402af505b2e5ef286937f325b5 100644 (file)
@@ -22,7 +22,7 @@
 #define FTDI_8U232AM_ALT_PID 0x6006 /* FTDI's alternate PID for above */
 #define FTDI_8U2232C_PID 0x6010 /* Dual channel device */
 #define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */
-#define FTDI_SIO_PID   0x8372  /* Product Id SIO application of 8U100AX  */
+#define FTDI_SIO_PID   0x8372  /* Product Id SIO application of 8U100AX */
 #define FTDI_232RL_PID  0xFBFA  /* Product ID for FT232RL */
 
 
@@ -49,7 +49,7 @@
 #define LMI_LM3S_DEVEL_BOARD_PID       0xbcd8
 #define LMI_LM3S_EVAL_BOARD_PID                0xbcd9
 
-#define FTDI_TURTELIZER_PID    0xBDC8 /* JTAG/RS-232 adapter by egnite GmBH */
+#define FTDI_TURTELIZER_PID    0xBDC8 /* JTAG/RS-232 adapter by egnite GmbH */
 
 /* OpenDCC (www.opendcc.de) product id */
 #define FTDI_OPENDCC_PID       0xBFD8
 #define FTDI_ELV_TFD128_PID    0xE0EC  /* ELV Temperatur-Feuchte-Datenlogger TFD 128 */
 #define FTDI_ELV_FM3RX_PID     0xE0ED  /* ELV Messwertuebertragung FM3 RX */
 #define FTDI_ELV_WS777_PID     0xE0EE  /* Conrad WS 777 */
-#define FTDI_ELV_EM1010PC_PID  0xE0EF  /* Engery monitor EM 1010 PC */
+#define FTDI_ELV_EM1010PC_PID  0xE0EF  /* Energy monitor EM 1010 PC */
 #define FTDI_ELV_CSI8_PID      0xE0F0  /* Computer-Schalt-Interface (CSI 8) */
 #define FTDI_ELV_EM1000DL_PID  0xE0F1  /* PC-Datenlogger fuer Energiemonitor (EM 1000 DL) */
 #define FTDI_ELV_PCK100_PID    0xE0F2  /* PC-Kabeltester (PCK 100) */
  * drivers, or possibly the Comedi drivers in some cases. */
 #define FTDI_ELV_CLI7000_PID   0xFB59  /* Computer-Light-Interface (CLI 7000) */
 #define FTDI_ELV_PPS7330_PID   0xFB5C  /* Processor-Power-Supply (PPS 7330) */
-#define FTDI_ELV_TFM100_PID    0xFB5D  /* Temperartur-Feuchte Messgeraet (TFM 100) */
-#define FTDI_ELV_UDF77_PID     0xFB5E  /* USB DCF Funkurh (UDF 77) */
+#define FTDI_ELV_TFM100_PID    0xFB5D  /* Temperatur-Feuchte-Messgeraet (TFM 100) */
+#define FTDI_ELV_UDF77_PID     0xFB5E  /* USB DCF Funkuhr (UDF 77) */
 #define FTDI_ELV_UIO88_PID     0xFB5F  /* USB-I/O Interface (UIO 88) */
 
 /*
 
 /*
  * 4N-GALAXY.DE PIDs for CAN-USB, USB-RS232, USB-RS422, USB-RS485,
- * USB-TTY activ, USB-TTY passiv.  Some PIDs are used by several devices
+ * USB-TTY aktiv, USB-TTY passiv.  Some PIDs are used by several devices
  * and I'm not entirely sure which are used by which.
  */
 #define FTDI_4N_GALAXY_DE_1_PID        0xF3C0
  * Linx Technologies product ids
  */
 #define LINX_SDMUSBQSS_PID     0xF448  /* Linx SDM-USB-QS-S */
-#define LINX_MASTERDEVEL2_PID   0xF449   /* Linx Master Development 2.0 */
-#define LINX_FUTURE_0_PID   0xF44A   /* Linx future device */
-#define LINX_FUTURE_1_PID   0xF44B   /* Linx future device */
-#define LINX_FUTURE_2_PID   0xF44C   /* Linx future device */
+#define LINX_MASTERDEVEL2_PID   0xF449 /* Linx Master Development 2.0 */
+#define LINX_FUTURE_0_PID   0xF44A     /* Linx future device */
+#define LINX_FUTURE_1_PID   0xF44B     /* Linx future device */
+#define LINX_FUTURE_2_PID   0xF44C     /* Linx future device */
 
 /*
  * Oceanic product ids
 #define RATOC_VENDOR_ID                0x0584
 #define RATOC_PRODUCT_ID_USB60F        0xb020
 
+/*
+ * Contec products (http://www.contec.com)
+ * Submitted by Daniel Sangorrin
+ */
+#define CONTEC_VID             0x06CE  /* Vendor ID */
+#define CONTEC_COM1USBH_PID    0x8311  /* COM-1(USB)H */
+
 /*
  * Definitions for B&B Electronics products.
  */
 #define FALCOM_TWIST_PID       0x0001  /* Falcom Twist USB GPRS modem */
 #define FALCOM_SAMBA_PID       0x0005  /* Falcom Samba USB GPRS modem */
 
-/* Larsen and Brusgaard AltiTrack/USBtrack  */
+/* Larsen and Brusgaard AltiTrack/USBtrack */
 #define LARSENBRUSGAARD_VID            0x0FD8
 #define LB_ALTITRACK_PID               0x0001
 
 #define ALTI2_N3_PID   0x6001  /* Neptune 3 */
 
 /*
- * Dresden Elektronic Sensor Terminal Board
+ * Dresden Elektronik Sensor Terminal Board
  */
 #define DE_VID                 0x1cf1 /* Vendor ID */
 #define STB_PID                        0x0001 /* Sensor Terminal Board */
 #define EVO_8U232AM_PID        0x02FF  /* Evolution robotics RCM2 (FT232AM)*/
 #define EVO_HYBRID_PID         0x0302  /* Evolution robotics RCM4 PID (FT232BM)*/
 #define EVO_RCM4_PID           0x0303  /* Evolution robotics RCM4 PID */
+
+/*
+ * MJS Gadgets HD Radio / XM Radio / Sirius Radio interfaces (using VID 0x0403)
+ */
+#define MJSG_GENERIC_PID       0x9378
+#define MJSG_SR_RADIO_PID      0x9379
+#define MJSG_XM_RADIO_PID      0x937A
+#define MJSG_HD_RADIO_PID      0x937C
index d30f736d2cc51a604b095e333f09d7b1201bd859..e21ce9ddfc631d824e38e9e27dd1e053a2677a11 100644 (file)
@@ -18,7 +18,7 @@
 
 static int debug;
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x1404, 0xcddc) },
        { },
 };
index 5ac900e5a50edbb3a44418271fa900272f882ad8..a42b29a695b2a6995a4e331197bc1a2c35a0fa36 100644 (file)
@@ -210,7 +210,7 @@ static unsigned char const PRIVATE_REQ[]
 
 
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        /* the same device id seems to be used by all
           usb enabled GPS devices */
        { USB_DEVICE(GARMIN_VENDOR_ID, 3) },
@@ -271,7 +271,6 @@ static void send_to_tty(struct usb_serial_port *port,
                usb_serial_debug_data(debug, &port->dev,
                                        __func__, actual_length, data);
 
-               tty_buffer_request_room(tty, actual_length);
                tty_insert_flip_string(tty, data, actual_length);
                tty_flip_buffer_push(tty);
        }
index 83443d6306d60e03f5b60ea0f9c4b70ae01f292b..89fac36684c56d83caa67e9426c723e3cfb00009 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/usb/serial.h>
 #include <linux/uaccess.h>
 #include <linux/kfifo.h>
+#include <linux/serial.h>
 
 static int debug;
 
@@ -41,7 +42,7 @@ static struct usb_device_id generic_device_ids[2]; /* Initially all zeroes. */
 
 /* we want to look at all devices, as the vendor/product id can change
  * depending on the command line argument */
-static struct usb_device_id generic_serial_ids[] = {
+static const struct usb_device_id generic_serial_ids[] = {
        {.driver_info = 42},
        {}
 };
@@ -194,7 +195,7 @@ static int usb_serial_multi_urb_write(struct tty_struct *tty,
                if (port->urbs_in_flight >
                    port->serial->type->max_in_flight_urbs) {
                        spin_unlock_irqrestore(&port->lock, flags);
-                       dbg("%s - write limit hit\n", __func__);
+                       dbg("%s - write limit hit", __func__);
                        return bwrite;
                }
                port->tx_bytes_flight += towrite;
@@ -585,7 +586,7 @@ int usb_serial_generic_resume(struct usb_serial *serial)
 
        for (i = 0; i < serial->num_ports; i++) {
                port = serial->port[i];
-               if (!port->port.count)
+               if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
                        continue;
 
                if (port->read_urb) {
index 431329275133169eb6f0c3ca06f472aee5e54530..809379159b0e67e21a16db13bb0f556b4e7be19a 100644 (file)
@@ -29,7 +29,7 @@
 #define HP_VENDOR_ID 0x03f0
 #define HP49GP_PRODUCT_ID 0x0121
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(HP_VENDOR_ID, HP49GP_PRODUCT_ID) },
        { }                                     /* Terminating entry */
 };
index b97960ac92f2762bbe4938ddc1d76812fd726864..3ef8df0ef888e9d99849953d275dfe81a6f6b47b 100644 (file)
@@ -364,42 +364,6 @@ static void update_edgeport_E2PROM(struct edgeport_serial *edge_serial)
        release_firmware(fw);
 }
 
-
-/************************************************************************
- *                                                                     *
- *  Get string descriptor from device                                  *
- *                                                                     *
- ************************************************************************/
-static int get_string(struct usb_device *dev, int Id, char *string, int buflen)
-{
-       struct usb_string_descriptor StringDesc;
-       struct usb_string_descriptor *pStringDesc;
-
-       dbg("%s - USB String ID = %d", __func__, Id);
-
-       if (!usb_get_descriptor(dev, USB_DT_STRING, Id,
-                                       &StringDesc, sizeof(StringDesc)))
-               return 0;
-
-       pStringDesc = kmalloc(StringDesc.bLength, GFP_KERNEL);
-       if (!pStringDesc)
-               return 0;
-
-       if (!usb_get_descriptor(dev, USB_DT_STRING, Id,
-                                       pStringDesc, StringDesc.bLength)) {
-               kfree(pStringDesc);
-               return 0;
-       }
-
-       unicode_to_ascii(string, buflen,
-                               pStringDesc->wData, pStringDesc->bLength/2);
-
-       kfree(pStringDesc);
-       dbg("%s - USB String %s", __func__, string);
-       return strlen(string);
-}
-
-
 #if 0
 /************************************************************************
  *
@@ -2007,7 +1971,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial,
                        return;
 
                case IOSP_EXT_STATUS_RX_CHECK_RSP:
-                       dbg("%s ========== Port %u CHECK_RSP Sequence = %02x =============\n", __func__, edge_serial->rxPort, byte3);
+                       dbg("%s ========== Port %u CHECK_RSP Sequence = %02x =============", __func__, edge_serial->rxPort, byte3);
                        /* Port->RxCheckRsp = true; */
                        return;
                }
@@ -2075,7 +2039,7 @@ static void process_rcvd_status(struct edgeport_serial *edge_serial,
                break;
 
        default:
-               dbg("%s - Unrecognized IOSP status code %u\n", __func__, code);
+               dbg("%s - Unrecognized IOSP status code %u", __func__, code);
                break;
        }
        return;
@@ -2091,18 +2055,13 @@ static void edge_tty_recv(struct device *dev, struct tty_struct *tty,
 {
        int cnt;
 
-       do {
-               cnt = tty_buffer_request_room(tty, length);
-               if (cnt < length) {
-                       dev_err(dev, "%s - dropping data, %d bytes lost\n",
-                                       __func__, length - cnt);
-                       if (cnt == 0)
-                               break;
-               }
-               tty_insert_flip_string(tty, data, cnt);
-               data += cnt;
-               length -= cnt;
-       } while (length > 0);
+       cnt = tty_insert_flip_string(tty, data, length);
+       if (cnt < length) {
+               dev_err(dev, "%s - dropping data, %d bytes lost\n",
+                               __func__, length - cnt);
+       }
+       data += cnt;
+       length -= cnt;
 
        tty_flip_buffer_push(tty);
 }
@@ -2530,7 +2489,7 @@ static int calc_baud_rate_divisor(int baudrate, int *divisor)
 
                *divisor = custom;
 
-               dbg("%s - Baud %d = %d\n", __func__, baudrate, custom);
+               dbg("%s - Baud %d = %d", __func__, baudrate, custom);
                return 0;
        }
 
@@ -2915,7 +2874,7 @@ static void load_application_firmware(struct edgeport_serial *edge_serial)
                        break;
 
                case EDGE_DOWNLOAD_FILE_NONE:
-                       dbg     ("No download file specified, skipping download\n");
+                       dbg("No download file specified, skipping download");
                        return;
 
                default:
@@ -2997,10 +2956,12 @@ static int edge_startup(struct usb_serial *serial)
        usb_set_serial_data(serial, edge_serial);
 
        /* get the name for the device from the device */
-       i = get_string(dev, dev->descriptor.iManufacturer,
+       i = usb_string(dev, dev->descriptor.iManufacturer,
            &edge_serial->name[0], MAX_NAME_LEN+1);
+       if (i < 0)
+               i = 0;
        edge_serial->name[i++] = ' ';
-       get_string(dev, dev->descriptor.iProduct,
+       usb_string(dev, dev->descriptor.iProduct,
            &edge_serial->name[i], MAX_NAME_LEN+2 - i);
 
        dev_info(&serial->dev->dev, "%s detected\n", edge_serial->name);
index 9241d314751324f65cb430ece19b6e6db373c72c..feb56a4ca7990c9315b728b40e142a84c17654f5 100644 (file)
@@ -14,7 +14,7 @@
 #ifndef IO_TABLES_H
 #define IO_TABLES_H
 
-static struct usb_device_id edgeport_2port_id_table [] = {
+static const struct usb_device_id edgeport_2port_id_table[] = {
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_2I) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_421) },
@@ -23,7 +23,7 @@ static struct usb_device_id edgeport_2port_id_table [] = {
        { }
 };
 
-static struct usb_device_id edgeport_4port_id_table [] = {
+static const struct usb_device_id edgeport_4port_id_table[] = {
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_RAPIDPORT_4) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4T) },
@@ -37,7 +37,7 @@ static struct usb_device_id edgeport_4port_id_table [] = {
        { }
 };
 
-static struct usb_device_id edgeport_8port_id_table [] = {
+static const struct usb_device_id edgeport_8port_id_table[] = {
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_16_DUAL_CPU) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_8I) },
@@ -47,7 +47,7 @@ static struct usb_device_id edgeport_8port_id_table [] = {
        { }
 };
 
-static struct usb_device_id Epic_port_id_table [] = {
+static const struct usb_device_id Epic_port_id_table[] = {
        { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0202) },
        { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0203) },
        { USB_DEVICE(USB_VENDOR_ID_NCR, NCR_DEVICE_ID_EPIC_0310) },
@@ -60,7 +60,7 @@ static struct usb_device_id Epic_port_id_table [] = {
 };
 
 /* Devices that this driver supports */
-static struct usb_device_id id_table_combined [] = {
+static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_RAPIDPORT_4) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_EDGEPORT_4T) },
index d4cc0f7af400d0133653e4e0515b25a131e2a37f..aa876f71f228e4f8bf053e66fc331aca593f7b54 100644 (file)
@@ -134,7 +134,7 @@ struct edgeport_serial {
 
 
 /* Devices that this driver supports */
-static struct usb_device_id edgeport_1port_id_table [] = {
+static const struct usb_device_id edgeport_1port_id_table[] = {
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I) },
@@ -154,7 +154,7 @@ static struct usb_device_id edgeport_1port_id_table [] = {
        { }
 };
 
-static struct usb_device_id edgeport_2port_id_table [] = {
+static const struct usb_device_id edgeport_2port_id_table[] = {
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2C) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_2I) },
@@ -177,7 +177,7 @@ static struct usb_device_id edgeport_2port_id_table [] = {
 };
 
 /* Devices that this driver supports */
-static struct usb_device_id id_table_combined [] = {
+static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_EDGEPORT_1) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1) },
        { USB_DEVICE(USB_VENDOR_ID_ION, ION_DEVICE_ID_TI_TI3410_EDGEPORT_1I) },
@@ -413,11 +413,18 @@ static int write_boot_mem(struct edgeport_serial *serial,
 {
        int status = 0;
        int i;
-       __u8 temp;
+       u8 *temp;
 
        /* Must do a read before write */
        if (!serial->TiReadI2C) {
-               status = read_boot_mem(serial, 0, 1, &temp);
+               temp = kmalloc(1, GFP_KERNEL);
+               if (!temp) {
+                       dev_err(&serial->serial->dev->dev,
+                                       "%s - out of memory\n", __func__);
+                       return -ENOMEM;
+               }
+               status = read_boot_mem(serial, 0, 1, temp);
+               kfree(temp);
                if (status)
                        return status;
        }
@@ -935,37 +942,47 @@ static int build_i2c_fw_hdr(__u8 *header, struct device *dev)
 static int i2c_type_bootmode(struct edgeport_serial *serial)
 {
        int status;
-       __u8 data;
+       u8 *data;
+
+       data = kmalloc(1, GFP_KERNEL);
+       if (!data) {
+               dev_err(&serial->serial->dev->dev,
+                               "%s - out of memory\n", __func__);
+               return -ENOMEM;
+       }
 
        /* Try to read type 2 */
        status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ,
-                               DTK_ADDR_SPACE_I2C_TYPE_II, 0, &data, 0x01);
+                               DTK_ADDR_SPACE_I2C_TYPE_II, 0, data, 0x01);
        if (status)
                dbg("%s - read 2 status error = %d", __func__, status);
        else
-               dbg("%s - read 2 data = 0x%x", __func__, data);
-       if ((!status) && (data == UMP5152 || data == UMP3410)) {
+               dbg("%s - read 2 data = 0x%x", __func__, *data);
+       if ((!status) && (*data == UMP5152 || *data == UMP3410)) {
                dbg("%s - ROM_TYPE_II", __func__);
                serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
-               return 0;
+               goto out;
        }
 
        /* Try to read type 3 */
        status = ti_vread_sync(serial->serial->dev, UMPC_MEMORY_READ,
-                               DTK_ADDR_SPACE_I2C_TYPE_III, 0, &data, 0x01);
+                               DTK_ADDR_SPACE_I2C_TYPE_III, 0, data, 0x01);
        if (status)
                dbg("%s - read 3 status error = %d", __func__, status);
        else
-               dbg("%s - read 2 data = 0x%x", __func__, data);
-       if ((!status) && (data == UMP5152 || data == UMP3410)) {
+               dbg("%s - read 2 data = 0x%x", __func__, *data);
+       if ((!status) && (*data == UMP5152 || *data == UMP3410)) {
                dbg("%s - ROM_TYPE_III", __func__);
                serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_III;
-               return 0;
+               goto out;
        }
 
        dbg("%s - Unknown", __func__);
        serial->TI_I2C_Type = DTK_ADDR_SPACE_I2C_TYPE_II;
-       return -ENODEV;
+       status = -ENODEV;
+out:
+       kfree(data);
+       return status;
 }
 
 static int bulk_xfer(struct usb_serial *serial, void *buffer,
@@ -1113,7 +1130,7 @@ static int download_fw(struct edgeport_serial *serial)
                                I2C_DESC_TYPE_FIRMWARE_BASIC, rom_desc);
                if (start_address != 0) {
                        struct ti_i2c_firmware_rec *firmware_version;
-                       __u8 record;
+                       u8 *record;
 
                        dbg("%s - Found Type FIRMWARE (Type 2) record",
                                                                __func__);
@@ -1165,6 +1182,15 @@ static int download_fw(struct edgeport_serial *serial)
                                    OperationalMajorVersion,
                                    OperationalMinorVersion);
 
+                               record = kmalloc(1, GFP_KERNEL);
+                               if (!record) {
+                                       dev_err(dev, "%s - out of memory.\n",
+                                                       __func__);
+                                       kfree(firmware_version);
+                                       kfree(rom_desc);
+                                       kfree(ti_manuf_desc);
+                                       return -ENOMEM;
+                               }
                                /* In order to update the I2C firmware we must
                                 * change the type 2 record to type 0xF2. This
                                 * will force the UMP to come up in Boot Mode.
@@ -1177,13 +1203,14 @@ static int download_fw(struct edgeport_serial *serial)
                                 * firmware will update the record type from
                                 * 0xf2 to 0x02.
                                 */
-                               record = I2C_DESC_TYPE_FIRMWARE_BLANK;
+                               *record = I2C_DESC_TYPE_FIRMWARE_BLANK;
 
                                /* Change the I2C Firmware record type to
                                   0xf2 to trigger an update */
                                status = write_rom(serial, start_address,
-                                               sizeof(record), &record);
+                                               sizeof(*record), record);
                                if (status) {
+                                       kfree(record);
                                        kfree(firmware_version);
                                        kfree(rom_desc);
                                        kfree(ti_manuf_desc);
@@ -1196,19 +1223,21 @@ static int download_fw(struct edgeport_serial *serial)
                                 */
                                status = read_rom(serial,
                                                        start_address,
-                                                       sizeof(record),
-                                                       &record);
+                                                       sizeof(*record),
+                                                       record);
                                if (status) {
+                                       kfree(record);
                                        kfree(firmware_version);
                                        kfree(rom_desc);
                                        kfree(ti_manuf_desc);
                                        return status;
                                }
 
-                               if (record != I2C_DESC_TYPE_FIRMWARE_BLANK) {
+                               if (*record != I2C_DESC_TYPE_FIRMWARE_BLANK) {
                                        dev_err(dev,
                                                "%s - error resetting device\n",
                                                __func__);
+                                       kfree(record);
                                        kfree(firmware_version);
                                        kfree(rom_desc);
                                        kfree(ti_manuf_desc);
@@ -1226,6 +1255,7 @@ static int download_fw(struct edgeport_serial *serial)
                                                __func__, status);
 
                                /* return an error on purpose. */
+                               kfree(record);
                                kfree(firmware_version);
                                kfree(rom_desc);
                                kfree(ti_manuf_desc);
@@ -1686,7 +1716,7 @@ static void edge_interrupt_callback(struct urb *urb)
        case TIUMP_INTERRUPT_CODE_MSR:  /* MSR */
                /* Copy MSR from UMP */
                msr = data[1];
-               dbg("%s - ===== Port %u MSR Status = %02x ======\n",
+               dbg("%s - ===== Port %u MSR Status = %02x ======",
                     __func__, port_number, msr);
                handle_new_msr(edge_port, msr);
                break;
@@ -1790,7 +1820,6 @@ static void edge_tty_recv(struct device *dev, struct tty_struct *tty,
 {
        int queued;
 
-       tty_buffer_request_room(tty, length);
        queued = tty_insert_flip_string(tty, data, length);
        if (queued < length)
                dev_err(dev, "%s - dropping data, %d bytes lost\n",
index d6231c38813e41d7b3072312907fcb33067de2d4..3fea9298eb15bef43fbc95010d73948ddb0c7490 100644 (file)
@@ -747,7 +747,6 @@ static void ipaq_read_bulk_callback(struct urb *urb)
 
        tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
-               tty_buffer_request_room(tty, urb->actual_length);
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
                bytes_in += urb->actual_length;
index 727d323f092aaa25436109a2382a33a243f1eec8..e1d07840cee66c65c2cb62feb5497bf27491cf82 100644 (file)
@@ -134,7 +134,7 @@ enum {
 
 #define IPW_WANTS_TO_SEND      0x30
 
-static struct usb_device_id usb_ipw_ids[] = {
+static const struct usb_device_id usb_ipw_ids[] = {
        { USB_DEVICE(IPW_VID, IPW_PID) },
        { },
 };
@@ -172,7 +172,6 @@ static void ipw_read_bulk_callback(struct urb *urb)
 
        tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
-               tty_buffer_request_room(tty, urb->actual_length);
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
        }
index 95d8d26b9a44de53501d02ddd02f4d7e8c07fa1d..4a0f51974232cd21b8c673c23659ca5a454c92d1 100644 (file)
@@ -100,7 +100,7 @@ static u8 ir_baud;
 static u8 ir_xbof;
 static u8 ir_add_bof;
 
-static struct usb_device_id ir_id_table[] = {
+static const struct usb_device_id ir_id_table[] = {
        { USB_DEVICE(0x050f, 0x0180) },         /* KC Technology, KC-180 */
        { USB_DEVICE(0x08e9, 0x0100) },         /* XTNDAccess */
        { USB_DEVICE(0x09c4, 0x0011) },         /* ACTiSys ACT-IR2000U */
@@ -445,11 +445,6 @@ static void ir_read_bulk_callback(struct urb *urb)
 
        dbg("%s - port %d", __func__, port->number);
 
-       if (!port->port.count) {
-               dbg("%s - port closed.", __func__);
-               return;
-       }
-
        switch (status) {
        case 0: /* Successful */
                /*
@@ -462,10 +457,8 @@ static void ir_read_bulk_callback(struct urb *urb)
                usb_serial_debug_data(debug, &port->dev, __func__,
                                                urb->actual_length, data);
                tty = tty_port_tty_get(&port->port);
-               if (tty_buffer_request_room(tty, urb->actual_length - 1)) {
-                       tty_insert_flip_string(tty, data+1, urb->actual_length - 1);
-                       tty_flip_buffer_push(tty);
-               }
+               tty_insert_flip_string(tty, data+1, urb->actual_length - 1);
+               tty_flip_buffer_push(tty);
                tty_kref_put(tty);
 
                /*
index e6e02b178d2bbef5df8c27967061b7e0b1587ed4..43f13cf2f016ccf9254655572a22bf5f7d6f15c6 100644 (file)
@@ -43,7 +43,7 @@ static int debug;
 #define DRIVER_VERSION "v0.11"
 #define DRIVER_DESC "Infinity USB Unlimited Phoenix driver"
 
-static struct usb_device_id id_table[] = {
+static const struct usb_device_id id_table[] = {
        {USB_DEVICE(IUU_USB_VENDOR_ID, IUU_USB_PRODUCT_ID)},
        {}                      /* Terminating entry */
 };
index f8c4b07033ffb6666c4e636e4dad9b52767709a2..297163c3c6100a84106fb26e9f68ca28c3a73802 100644 (file)
@@ -464,13 +464,9 @@ static void        usa26_indat_callback(struct urb *urb)
 
        /* Resubmit urb so we continue receiving */
        urb->dev = port->serial->dev;
-       if (port->port.count) {
-               err = usb_submit_urb(urb, GFP_ATOMIC);
-               if (err != 0)
-                       dbg("%s - resubmit read urb failed. (%d)",
-                                       __func__, err);
-       }
-       return;
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err != 0)
+               dbg("%s - resubmit read urb failed. (%d)", __func__, err);
 }
 
 /* Outdat handling is common for all devices */
@@ -483,8 +479,7 @@ static void usa2x_outdat_callback(struct urb *urb)
        p_priv = usb_get_serial_port_data(port);
        dbg("%s - urb %d", __func__, urb == p_priv->out_urbs[1]);
 
-       if (port->port.count)
-               usb_serial_port_softint(port);
+       usb_serial_port_softint(port);
 }
 
 static void    usa26_inack_callback(struct urb *urb)
@@ -615,12 +610,10 @@ static void usa28_indat_callback(struct urb *urb)
 
                /* Resubmit urb so we continue receiving */
                urb->dev = port->serial->dev;
-               if (port->port.count) {
-                       err = usb_submit_urb(urb, GFP_ATOMIC);
-                       if (err != 0)
-                               dbg("%s - resubmit read urb failed. (%d)",
-                                                               __func__, err);
-               }
+               err = usb_submit_urb(urb, GFP_ATOMIC);
+               if (err != 0)
+                       dbg("%s - resubmit read urb failed. (%d)",
+                                                       __func__, err);
                p_priv->in_flip ^= 1;
 
                urb = p_priv->in_urbs[p_priv->in_flip];
@@ -856,12 +849,9 @@ static void        usa49_indat_callback(struct urb *urb)
 
        /* Resubmit urb so we continue receiving */
        urb->dev = port->serial->dev;
-       if (port->port.count) {
-               err = usb_submit_urb(urb, GFP_ATOMIC);
-               if (err != 0)
-                       dbg("%s - resubmit read urb failed. (%d)",
-                                                       __func__, err);
-       }
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err != 0)
+               dbg("%s - resubmit read urb failed. (%d)", __func__, err);
 }
 
 static void usa49wg_indat_callback(struct urb *urb)
@@ -904,11 +894,7 @@ static void usa49wg_indat_callback(struct urb *urb)
                                /* no error on any byte */
                                i++;
                                for (x = 1; x < len ; ++x)
-                                       if (port->port.count)
-                                               tty_insert_flip_char(tty,
-                                                               data[i++], 0);
-                                       else
-                                               i++;
+                                       tty_insert_flip_char(tty, data[i++], 0);
                        } else {
                                /*
                                 * some bytes had errors, every byte has status
@@ -922,14 +908,12 @@ static void usa49wg_indat_callback(struct urb *urb)
                                        if (stat & RXERROR_PARITY)
                                                flag |= TTY_PARITY;
                                        /* XXX should handle break (0x10) */
-                                       if (port->port.count)
-                                               tty_insert_flip_char(tty,
+                                       tty_insert_flip_char(tty,
                                                        data[i+1], flag);
                                        i += 2;
                                }
                        }
-                       if (port->port.count)
-                               tty_flip_buffer_push(tty);
+                       tty_flip_buffer_push(tty);
                        tty_kref_put(tty);
                }
        }
@@ -1013,13 +997,9 @@ static void usa90_indat_callback(struct urb *urb)
 
        /* Resubmit urb so we continue receiving */
        urb->dev = port->serial->dev;
-       if (port->port.count) {
-               err = usb_submit_urb(urb, GFP_ATOMIC);
-               if (err != 0)
-                       dbg("%s - resubmit read urb failed. (%d)",
-                                                       __func__, err);
-       }
-       return;
+       err = usb_submit_urb(urb, GFP_ATOMIC);
+       if (err != 0)
+               dbg("%s - resubmit read urb failed. (%d)", __func__, err);
 }
 
 
@@ -2418,8 +2398,7 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial,
                msg.portEnabled = 0;
        /* Sending intermediate configs */
        else {
-               if (port->port.count)
-                       msg.portEnabled = 1;
+               msg.portEnabled = 1;
                msg.txBreak = (p_priv->break_on);
        }
 
index 30771e5b397381e2b543e5eca3d4192fdc8a10bb..bf3297ddd186220374b38d43e408e7708b5005d4 100644 (file)
@@ -456,7 +456,7 @@ static const struct keyspan_device_details *keyspan_devices[] = {
        NULL,
 };
 
-static struct usb_device_id keyspan_ids_combined[] = {
+static const struct usb_device_id keyspan_ids_combined[] = {
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) },
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) },
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19w_pre_product_id) },
@@ -497,7 +497,7 @@ static struct usb_driver keyspan_driver = {
 };
 
 /* usb_device_id table for the pre-firmware download keyspan devices */
-static struct usb_device_id keyspan_pre_ids[] = {
+static const struct usb_device_id keyspan_pre_ids[] = {
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_pre_product_id) },
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_pre_product_id) },
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_pre_product_id) },
@@ -513,7 +513,7 @@ static struct usb_device_id keyspan_pre_ids[] = {
        { } /* Terminating entry */
 };
 
-static struct usb_device_id keyspan_1port_ids[] = {
+static const struct usb_device_id keyspan_1port_ids[] = {
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa18x_product_id) },
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19_product_id) },
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa19qi_product_id) },
@@ -524,7 +524,7 @@ static struct usb_device_id keyspan_1port_ids[] = {
        { } /* Terminating entry */
 };
 
-static struct usb_device_id keyspan_2port_ids[] = {
+static const struct usb_device_id keyspan_2port_ids[] = {
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28_product_id) },
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28x_product_id) },
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa28xa_product_id) },
@@ -532,7 +532,7 @@ static struct usb_device_id keyspan_2port_ids[] = {
        { } /* Terminating entry */
 };
 
-static struct usb_device_id keyspan_4port_ids[] = {
+static const struct usb_device_id keyspan_4port_ids[] = {
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49w_product_id) },
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wlc_product_id)},
        { USB_DEVICE(KEYSPAN_VENDOR_ID, keyspan_usa49wg_product_id)},
index 84f08e968e0b3e250562e4401dd801accc9e50cb..185fe9a7d4e05f277bd1293343aa0f80394d8835 100644 (file)
@@ -125,7 +125,7 @@ struct keyspan_pda_private {
 #define ENTREGRA_VENDOR_ID             0x1645
 #define ENTREGRA_FAKE_ID               0x8093
 
-static struct usb_device_id id_table_combined [] = {
+static const struct usb_device_id id_table_combined[] = {
 #ifdef KEYSPAN
        { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_FAKE_ID) },
 #endif
@@ -147,20 +147,20 @@ static struct usb_driver keyspan_pda_driver = {
        .no_dynamic_id =        1,
 };
 
-static struct usb_device_id id_table_std [] = {
+static const struct usb_device_id id_table_std[] = {
        { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_ID) },
        { }                                             /* Terminating entry */
 };
 
 #ifdef KEYSPAN
-static struct usb_device_id id_table_fake [] = {
+static const struct usb_device_id id_table_fake[] = {
        { USB_DEVICE(KEYSPAN_VENDOR_ID, KEYSPAN_PDA_FAKE_ID) },
        { }                                             /* Terminating entry */
 };
 #endif
 
 #ifdef XIRCOM
-static struct usb_device_id id_table_fake_xircom [] = {
+static const struct usb_device_id id_table_fake_xircom[] = {
        { USB_DEVICE(XIRCOM_VENDOR_ID, XIRCOM_FAKE_ID) },
        { USB_DEVICE(ENTREGRA_VENDOR_ID, ENTREGRA_FAKE_ID) },
        { }
@@ -429,13 +429,20 @@ static int keyspan_pda_get_modem_info(struct usb_serial *serial,
                                      unsigned char *value)
 {
        int rc;
-       unsigned char data;
+       u8 *data;
+
+       data = kmalloc(1, GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
        rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
                             3, /* get pins */
                             USB_TYPE_VENDOR|USB_RECIP_INTERFACE|USB_DIR_IN,
-                            0, 0, &data, 1, 2000);
+                            0, 0, data, 1, 2000);
        if (rc >= 0)
-               *value = data;
+               *value = *data;
+
+       kfree(data);
        return rc;
 }
 
@@ -543,7 +550,14 @@ static int keyspan_pda_write(struct tty_struct *tty,
           device how much room it really has.  This is done only on
           scheduler time, since usb_control_msg() sleeps. */
        if (count > priv->tx_room && !in_interrupt()) {
-               unsigned char room;
+               u8 *room;
+
+               room = kmalloc(1, GFP_KERNEL);
+               if (!room) {
+                       rc = -ENOMEM;
+                       goto exit;
+               }
+
                rc = usb_control_msg(serial->dev,
                                     usb_rcvctrlpipe(serial->dev, 0),
                                     6, /* write_room */
@@ -551,9 +565,14 @@ static int keyspan_pda_write(struct tty_struct *tty,
                                     | USB_DIR_IN,
                                     0, /* value: 0 means "remaining room" */
                                     0, /* index */
-                                    &room,
+                                    room,
                                     1,
                                     2000);
+               if (rc > 0) {
+                       dbg(" roomquery says %d", *room);
+                       priv->tx_room = *room;
+               }
+               kfree(room);
                if (rc < 0) {
                        dbg(" roomquery failed");
                        goto exit;
@@ -563,8 +582,6 @@ static int keyspan_pda_write(struct tty_struct *tty,
                        rc = -EIO; /* device didn't return any data */
                        goto exit;
                }
-               dbg(" roomquery says %d", room);
-               priv->tx_room = room;
        }
        if (count > priv->tx_room) {
                /* we're about to completely fill the Tx buffer, so
@@ -684,18 +701,22 @@ static int keyspan_pda_open(struct tty_struct *tty,
                                        struct usb_serial_port *port)
 {
        struct usb_serial *serial = port->serial;
-       unsigned char room;
+       u8 *room;
        int rc = 0;
        struct keyspan_pda_private *priv;
 
        /* find out how much room is in the Tx ring */
+       room = kmalloc(1, GFP_KERNEL);
+       if (!room)
+               return -ENOMEM;
+
        rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
                             6, /* write_room */
                             USB_TYPE_VENDOR | USB_RECIP_INTERFACE
                             | USB_DIR_IN,
                             0, /* value */
                             0, /* index */
-                            &room,
+                            room,
                             1,
                             2000);
        if (rc < 0) {
@@ -708,8 +729,8 @@ static int keyspan_pda_open(struct tty_struct *tty,
                goto error;
        }
        priv = usb_get_serial_port_data(port);
-       priv->tx_room = room;
-       priv->tx_throttled = room ? 0 : 1;
+       priv->tx_room = *room;
+       priv->tx_throttled = *room ? 0 : 1;
 
        /*Start reading from the device*/
        port->interrupt_in_urb->dev = serial->dev;
@@ -718,8 +739,8 @@ static int keyspan_pda_open(struct tty_struct *tty,
                dbg("%s - usb_submit_urb(read int) failed", __func__);
                goto error;
        }
-
 error:
+       kfree(room);
        return rc;
 }
 static void keyspan_pda_close(struct usb_serial_port *port)
index 3a7873806f465aaf02a41213df7c2d41e5f866f1..8eef91ba4b1c5021c2ecad2725e028ad4ce7dd73 100644 (file)
@@ -94,7 +94,7 @@ static int  klsi_105_tiocmset(struct tty_struct *tty, struct file *file,
 /*
  * All of the device info needed for the KLSI converters.
  */
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(PALMCONNECT_VID, PALMCONNECT_PID) },
        { USB_DEVICE(KLSI_VID, KLSI_KL5KUSB105D_PID) },
        { }             /* Terminating entry */
@@ -212,10 +212,19 @@ static int klsi_105_get_line_state(struct usb_serial_port *port,
                                   unsigned long *line_state_p)
 {
        int rc;
-       __u8 status_buf[KLSI_STATUSBUF_LEN] = { -1, -1};
+       u8 *status_buf;
        __u16 status;
 
        dev_info(&port->serial->dev->dev, "sending SIO Poll request\n");
+
+       status_buf = kmalloc(KLSI_STATUSBUF_LEN, GFP_KERNEL);
+       if (!status_buf) {
+               dev_err(&port->dev, "%s - out of memory for status buffer.\n",
+                               __func__);
+               return -ENOMEM;
+       }
+       status_buf[0] = 0xff;
+       status_buf[1] = 0xff;
        rc = usb_control_msg(port->serial->dev,
                             usb_rcvctrlpipe(port->serial->dev, 0),
                             KL5KUSB105A_SIO_POLL,
@@ -236,6 +245,8 @@ static int klsi_105_get_line_state(struct usb_serial_port *port,
 
                *line_state_p = klsi_105_status2linestate(status);
        }
+
+       kfree(status_buf);
        return rc;
 }
 
@@ -364,7 +375,7 @@ static int  klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
        int rc;
        int i;
        unsigned long line_state;
-       struct klsi_105_port_settings cfg;
+       struct klsi_105_port_settings *cfg;
        unsigned long flags;
 
        dbg("%s port %d", __func__, port->number);
@@ -376,12 +387,18 @@ static int  klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
         * Then read the modem line control and store values in
         * priv->line_state.
         */
-       cfg.pktlen   = 5;
-       cfg.baudrate = kl5kusb105a_sio_b9600;
-       cfg.databits = kl5kusb105a_dtb_8;
-       cfg.unknown1 = 0;
-       cfg.unknown2 = 1;
-       klsi_105_chg_port_settings(port, &cfg);
+       cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
+       if (!cfg) {
+               dev_err(&port->dev, "%s - out of memory for config buffer.\n",
+                               __func__);
+               return -ENOMEM;
+       }
+       cfg->pktlen   = 5;
+       cfg->baudrate = kl5kusb105a_sio_b9600;
+       cfg->databits = kl5kusb105a_dtb_8;
+       cfg->unknown1 = 0;
+       cfg->unknown2 = 1;
+       klsi_105_chg_port_settings(port, cfg);
 
        /* set up termios structure */
        spin_lock_irqsave(&priv->lock, flags);
@@ -391,11 +408,11 @@ static int  klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
        priv->termios.c_lflag = tty->termios->c_lflag;
        for (i = 0; i < NCCS; i++)
                priv->termios.c_cc[i] = tty->termios->c_cc[i];
-       priv->cfg.pktlen   = cfg.pktlen;
-       priv->cfg.baudrate = cfg.baudrate;
-       priv->cfg.databits = cfg.databits;
-       priv->cfg.unknown1 = cfg.unknown1;
-       priv->cfg.unknown2 = cfg.unknown2;
+       priv->cfg.pktlen   = cfg->pktlen;
+       priv->cfg.baudrate = cfg->baudrate;
+       priv->cfg.databits = cfg->databits;
+       priv->cfg.unknown1 = cfg->unknown1;
+       priv->cfg.unknown2 = cfg->unknown2;
        spin_unlock_irqrestore(&priv->lock, flags);
 
        /* READ_ON and urb submission */
@@ -441,6 +458,7 @@ static int  klsi_105_open(struct tty_struct *tty, struct usb_serial_port *port)
                retval = rc;
 
 exit:
+       kfree(cfg);
        return retval;
 } /* klsi_105_open */
 
@@ -681,7 +699,6 @@ static void klsi_105_read_bulk_callback(struct urb *urb)
                        bytes_sent = urb->actual_length - 2;
                }
 
-               tty_buffer_request_room(tty, bytes_sent);
                tty_insert_flip_string(tty, data + 2, bytes_sent);
                tty_flip_buffer_push(tty);
                tty_kref_put(tty);
@@ -714,10 +731,17 @@ static void klsi_105_set_termios(struct tty_struct *tty,
        unsigned int old_iflag = old_termios->c_iflag;
        unsigned int cflag = tty->termios->c_cflag;
        unsigned int old_cflag = old_termios->c_cflag;
-       struct klsi_105_port_settings cfg;
+       struct klsi_105_port_settings *cfg;
        unsigned long flags;
        speed_t baud;
 
+       cfg = kmalloc(sizeof(*cfg), GFP_KERNEL);
+       if (!cfg) {
+               dev_err(&port->dev, "%s - out of memory for config buffer.\n",
+                               __func__);
+               return;
+       }
+
        /* lock while we are modifying the settings */
        spin_lock_irqsave(&priv->lock, flags);
 
@@ -793,11 +817,11 @@ static void klsi_105_set_termios(struct tty_struct *tty,
                case CS5:
                        dbg("%s - 5 bits/byte not supported", __func__);
                        spin_unlock_irqrestore(&priv->lock, flags);
-                       return ;
+                       goto err;
                case CS6:
                        dbg("%s - 6 bits/byte not supported", __func__);
                        spin_unlock_irqrestore(&priv->lock, flags);
-                       return ;
+                       goto err;
                case CS7:
                        priv->cfg.databits = kl5kusb105a_dtb_7;
                        break;
@@ -856,11 +880,13 @@ static void klsi_105_set_termios(struct tty_struct *tty,
 #endif
                ;
        }
-       memcpy(&cfg, &priv->cfg, sizeof(cfg));
+       memcpy(cfg, &priv->cfg, sizeof(*cfg));
        spin_unlock_irqrestore(&priv->lock, flags);
 
        /* now commit changes to device */
-       klsi_105_chg_port_settings(port, &cfg);
+       klsi_105_chg_port_settings(port, cfg);
+err:
+       kfree(cfg);
 } /* klsi_105_set_termios */
 
 
index 45ea694b3ae6a4900d0a04810ef9a8b149ad7c32..c113a2a0e10c529e198dcd9e6b7de868e27cddba 100644 (file)
@@ -86,7 +86,7 @@ static void kobil_set_termios(struct tty_struct *tty,
                        struct usb_serial_port *port, struct ktermios *old);
 static void kobil_init_termios(struct tty_struct *tty);
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_B_PRODUCT_ID) },
        { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_ADAPTER_K_PRODUCT_ID) },
        { USB_DEVICE(KOBIL_VENDOR_ID, KOBIL_USBTWIN_PRODUCT_ID) },
@@ -388,7 +388,6 @@ static void kobil_read_int_callback(struct urb *urb)
                */
                /* END DEBUG */
 
-               tty_buffer_request_room(tty, urb->actual_length);
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
        }
@@ -624,7 +623,6 @@ static void kobil_set_termios(struct tty_struct *tty,
        unsigned short urb_val = 0;
        int c_cflag = tty->termios->c_cflag;
        speed_t speed;
-       void *settings;
 
        priv = usb_get_serial_port_data(port);
        if (priv->device_type == KOBIL_USBTWIN_PRODUCT_ID ||
@@ -647,25 +645,13 @@ static void kobil_set_termios(struct tty_struct *tty,
        }
        urb_val |= (c_cflag & CSTOPB) ? SUSBCR_SPASB_2StopBits :
                                                        SUSBCR_SPASB_1StopBit;
-
-       settings = kzalloc(50, GFP_KERNEL);
-       if (!settings)
-               return;
-
-       sprintf(settings, "%d ", speed);
-
        if (c_cflag & PARENB) {
-               if  (c_cflag & PARODD) {
+               if  (c_cflag & PARODD)
                        urb_val |= SUSBCR_SPASB_OddParity;
-                       strcat(settings, "Odd Parity");
-               } else {
+               else
                        urb_val |= SUSBCR_SPASB_EvenParity;
-                       strcat(settings, "Even Parity");
-               }
-       } else {
+       } else
                urb_val |= SUSBCR_SPASB_NoParity;
-               strcat(settings, "No Parity");
-       }
        tty->termios->c_cflag &= ~CMSPAR;
        tty_encode_baud_rate(tty, speed, speed);
 
@@ -675,11 +661,10 @@ static void kobil_set_termios(struct tty_struct *tty,
                  USB_TYPE_VENDOR | USB_RECIP_ENDPOINT | USB_DIR_OUT,
                  urb_val,
                  0,
-                 settings,
+                 NULL,
                  0,
                  KOBIL_TIMEOUT
                );
-       kfree(settings);
 }
 
 static int kobil_ioctl(struct tty_struct *tty, struct file *file,
index cd009cb280a50b29d80a50610f8303a4badbd9af..2849f8c320157e483504962b3ec16b13a0a4bd45 100644 (file)
@@ -75,6 +75,7 @@
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/uaccess.h>
+#include <asm/unaligned.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 #include "mct_u232.h"
@@ -110,7 +111,7 @@ static void mct_u232_unthrottle(struct tty_struct *tty);
 /*
  * All of the device info needed for the MCT USB-RS232 converter.
  */
-static struct usb_device_id id_table_combined [] = {
+static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(MCT_U232_VID, MCT_U232_PID) },
        { USB_DEVICE(MCT_U232_VID, MCT_U232_SITECOM_PID) },
        { USB_DEVICE(MCT_U232_VID, MCT_U232_DU_H3SP_PID) },
@@ -231,19 +232,22 @@ static int mct_u232_calculate_baud_rate(struct usb_serial *serial,
 static int mct_u232_set_baud_rate(struct tty_struct *tty,
        struct usb_serial *serial, struct usb_serial_port *port, speed_t value)
 {
-       __le32 divisor;
+       unsigned int divisor;
        int rc;
-       unsigned char zero_byte = 0;
+       unsigned char *buf;
        unsigned char cts_enable_byte = 0;
        speed_t speed;
 
-       divisor = cpu_to_le32(mct_u232_calculate_baud_rate(serial, value,
-                                                               &speed));
+       buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
 
+       divisor = mct_u232_calculate_baud_rate(serial, value, &speed);
+       put_unaligned_le32(cpu_to_le32(divisor), buf);
        rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
                                MCT_U232_SET_BAUD_RATE_REQUEST,
                                MCT_U232_SET_REQUEST_TYPE,
-                               0, 0, &divisor, MCT_U232_SET_BAUD_RATE_SIZE,
+                               0, 0, buf, MCT_U232_SET_BAUD_RATE_SIZE,
                                WDR_TIMEOUT);
        if (rc < 0)     /*FIXME: What value speed results */
                dev_err(&port->dev, "Set BAUD RATE %d failed (error = %d)\n",
@@ -269,10 +273,11 @@ static int mct_u232_set_baud_rate(struct tty_struct *tty,
           a device which is not asserting 'CTS'.
        */
 
+       buf[0] = 0;
        rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
                                MCT_U232_SET_UNKNOWN1_REQUEST,
                                MCT_U232_SET_REQUEST_TYPE,
-                               0, 0, &zero_byte, MCT_U232_SET_UNKNOWN1_SIZE,
+                               0, 0, buf, MCT_U232_SET_UNKNOWN1_SIZE,
                                WDR_TIMEOUT);
        if (rc < 0)
                dev_err(&port->dev, "Sending USB device request code %d "
@@ -284,30 +289,40 @@ static int mct_u232_set_baud_rate(struct tty_struct *tty,
 
        dbg("set_baud_rate: send second control message, data = %02X",
                                                        cts_enable_byte);
+       buf[0] = cts_enable_byte;
        rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
                        MCT_U232_SET_CTS_REQUEST,
                        MCT_U232_SET_REQUEST_TYPE,
-                       0, 0, &cts_enable_byte, MCT_U232_SET_CTS_SIZE,
+                       0, 0, buf, MCT_U232_SET_CTS_SIZE,
                        WDR_TIMEOUT);
        if (rc < 0)
                dev_err(&port->dev, "Sending USB device request code %d "
                        "failed (error = %d)\n", MCT_U232_SET_CTS_REQUEST, rc);
 
+       kfree(buf);
        return rc;
 } /* mct_u232_set_baud_rate */
 
 static int mct_u232_set_line_ctrl(struct usb_serial *serial, unsigned char lcr)
 {
        int rc;
+       unsigned char *buf;
+
+       buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
+
+       buf[0] = lcr;
        rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
                        MCT_U232_SET_LINE_CTRL_REQUEST,
                        MCT_U232_SET_REQUEST_TYPE,
-                       0, 0, &lcr, MCT_U232_SET_LINE_CTRL_SIZE,
+                       0, 0, buf, MCT_U232_SET_LINE_CTRL_SIZE,
                        WDR_TIMEOUT);
        if (rc < 0)
                dev_err(&serial->dev->dev,
                        "Set LINE CTRL 0x%x failed (error = %d)\n", lcr, rc);
        dbg("set_line_ctrl: 0x%x", lcr);
+       kfree(buf);
        return rc;
 } /* mct_u232_set_line_ctrl */
 
@@ -315,23 +330,31 @@ static int mct_u232_set_modem_ctrl(struct usb_serial *serial,
                                   unsigned int control_state)
 {
        int rc;
-       unsigned char mcr = MCT_U232_MCR_NONE;
+       unsigned char mcr;
+       unsigned char *buf;
+
+       buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL);
+       if (buf == NULL)
+               return -ENOMEM;
 
+       mcr = MCT_U232_MCR_NONE;
        if (control_state & TIOCM_DTR)
                mcr |= MCT_U232_MCR_DTR;
        if (control_state & TIOCM_RTS)
                mcr |= MCT_U232_MCR_RTS;
 
+       buf[0] = mcr;
        rc = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
                        MCT_U232_SET_MODEM_CTRL_REQUEST,
                        MCT_U232_SET_REQUEST_TYPE,
-                       0, 0, &mcr, MCT_U232_SET_MODEM_CTRL_SIZE,
+                       0, 0, buf, MCT_U232_SET_MODEM_CTRL_SIZE,
                        WDR_TIMEOUT);
        if (rc < 0)
                dev_err(&serial->dev->dev,
                        "Set MODEM CTRL 0x%x failed (error = %d)\n", mcr, rc);
        dbg("set_modem_ctrl: state=0x%x ==> mcr=0x%x", control_state, mcr);
 
+       kfree(buf);
        return rc;
 } /* mct_u232_set_modem_ctrl */
 
@@ -339,17 +362,27 @@ static int mct_u232_get_modem_stat(struct usb_serial *serial,
                                                unsigned char *msr)
 {
        int rc;
+       unsigned char *buf;
+
+       buf = kmalloc(MCT_U232_MAX_SIZE, GFP_KERNEL);
+       if (buf == NULL) {
+               *msr = 0;
+               return -ENOMEM;
+       }
        rc = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
                        MCT_U232_GET_MODEM_STAT_REQUEST,
                        MCT_U232_GET_REQUEST_TYPE,
-                       0, 0, msr, MCT_U232_GET_MODEM_STAT_SIZE,
+                       0, 0, buf, MCT_U232_GET_MODEM_STAT_SIZE,
                        WDR_TIMEOUT);
        if (rc < 0) {
                dev_err(&serial->dev->dev,
                        "Get MODEM STATus failed (error = %d)\n", rc);
                *msr = 0;
+       } else {
+               *msr = buf[0];
        }
        dbg("get_modem_stat: 0x%x", *msr);
+       kfree(buf);
        return rc;
 } /* mct_u232_get_modem_stat */
 
index 07b6bec31dc898a2e6f9fcccc5ff1ab654b328c6..7417d5ce1e23918145f3ff0ad1e185f7233b9dda 100644 (file)
@@ -73,6 +73,8 @@
 #define MCT_U232_SET_CTS_REQUEST   12
 #define MCT_U232_SET_CTS_SIZE       1
 
+#define MCT_U232_MAX_SIZE              4       /* of MCT_XXX_SIZE */
+
 /*
  * Baud rate (divisor)
  * Actually, there are two of them, MCT website calls them "Philips solution"
index 763e32a44be02eb790c0c7f66ed25e0bae947f19..0d47f2c4d59f21b80b0f9f1540af9fac422009cf 100644 (file)
@@ -81,12 +81,15 @@ struct moschip_serial {
 
 static int debug;
 
+static struct usb_serial_driver moschip7720_2port_driver;
+
 #define USB_VENDOR_ID_MOSCHIP          0x9710
 #define MOSCHIP_DEVICE_ID_7720         0x7720
 #define MOSCHIP_DEVICE_ID_7715         0x7715
 
-static struct usb_device_id moschip_port_id_table[] = {
+static const struct usb_device_id moschip_port_id_table[] = {
        { USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7720) },
+       { USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7715) },
        { } /* terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, moschip_port_id_table);
@@ -106,7 +109,7 @@ static void mos7720_interrupt_callback(struct urb *urb)
        __u8 sp1;
        __u8 sp2;
 
-       dbg("%s", " : Entering\n");
+       dbg(" : Entering");
 
        switch (status) {
        case 0:
@@ -185,6 +188,75 @@ exit:
        return;
 }
 
+/*
+ * mos7715_interrupt_callback
+ *     this is the 7715's callback function for when we have received data on
+ *     the interrupt endpoint.
+ */
+static void mos7715_interrupt_callback(struct urb *urb)
+{
+       int result;
+       int length;
+       int status = urb->status;
+       __u8 *data;
+       __u8 iir;
+
+       switch (status) {
+       case 0:
+               /* success */
+               break;
+       case -ECONNRESET:
+       case -ENOENT:
+       case -ESHUTDOWN:
+               /* this urb is terminated, clean up */
+               dbg("%s - urb shutting down with status: %d", __func__,
+                   status);
+               return;
+       default:
+               dbg("%s - nonzero urb status received: %d", __func__,
+                   status);
+               goto exit;
+       }
+
+       length = urb->actual_length;
+       data = urb->transfer_buffer;
+
+       /* Structure of data from 7715 device:
+        * Byte 1: IIR serial Port
+        * Byte 2: unused
+        * Byte 2: DSR parallel port
+        * Byte 4: FIFO status for both */
+
+       if (unlikely(length != 4)) {
+               dbg("Wrong data !!!");
+               return;
+       }
+
+       iir = data[0];
+       if (!(iir & 0x01)) {    /* serial port interrupt pending */
+               switch (iir & 0x0f) {
+               case SERIAL_IIR_RLS:
+                       dbg("Serial Port: Receiver status error or address "
+                           "bit detected in 9-bit mode\n");
+                       break;
+               case SERIAL_IIR_CTI:
+                       dbg("Serial Port: Receiver time out");
+                       break;
+               case SERIAL_IIR_MS:
+                       dbg("Serial Port: Modem status change");
+                       break;
+               }
+       }
+
+exit:
+       result = usb_submit_urb(urb, GFP_ATOMIC);
+       if (result)
+               dev_err(&urb->dev->dev,
+                       "%s - Error %d submitting control urb\n",
+                       __func__, result);
+       return;
+}
+
 /*
  * mos7720_bulk_in_callback
  *     this is the callback function for when we have received data on the
@@ -206,7 +278,7 @@ static void mos7720_bulk_in_callback(struct urb *urb)
 
        mos7720_port = urb->context;
        if (!mos7720_port) {
-               dbg("%s", "NULL mos7720_port pointer \n");
+               dbg("NULL mos7720_port pointer");
                return ;
        }
 
@@ -218,7 +290,6 @@ static void mos7720_bulk_in_callback(struct urb *urb)
 
        tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
-               tty_buffer_request_room(tty, urb->actual_length);
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
        }
@@ -275,17 +346,15 @@ static void mos7720_bulk_out_data_callback(struct urb *urb)
  *     this function will be used for sending command to device
  */
 static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value,
-                       __u16 index, void *data)
+                       __u16 index, u8 *data)
 {
        int status;
-       unsigned int pipe;
+       u8 *buf;
        u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
-       __u8 requesttype;
-       __u16 size = 0x0000;
 
        if (value < MOS_MAX_PORT) {
                if (product == MOSCHIP_DEVICE_ID_7715)
-                       value = value*0x100+0x100;
+                       value = 0x0200; /* identifies the 7715's serial port */
                else
                        value = value*0x100+0x200;
        } else {
@@ -298,27 +367,58 @@ static int send_mos_cmd(struct usb_serial *serial, __u8 request, __u16 value,
        }
 
        if (request == MOS_WRITE) {
-               request = (__u8)MOS_WRITE;
-               requesttype = (__u8)0x40;
-               value  = value + (__u16)*((unsigned char *)data);
-               data = NULL;
-               pipe = usb_sndctrlpipe(serial->dev, 0);
+               value = value + *data;
+               status = usb_control_msg(serial->dev,
+                               usb_sndctrlpipe(serial->dev, 0), MOS_WRITE,
+                               0x40, value, index, NULL, 0, MOS_WDR_TIMEOUT);
        } else {
-               request = (__u8)MOS_READ;
-               requesttype = (__u8)0xC0;
-               size = 0x01;
-               pipe = usb_rcvctrlpipe(serial->dev, 0);
+               buf = kmalloc(1, GFP_KERNEL);
+               if (!buf) {
+                       status = -ENOMEM;
+                       goto out;
+               }
+               status = usb_control_msg(serial->dev,
+                               usb_rcvctrlpipe(serial->dev, 0), MOS_READ,
+                               0xc0, value, index, buf, 1, MOS_WDR_TIMEOUT);
+               *data = *buf;
+               kfree(buf);
        }
-
-       status = usb_control_msg(serial->dev, pipe, request, requesttype,
-                                value, index, data, size, MOS_WDR_TIMEOUT);
-
+out:
        if (status < 0)
-               dbg("Command Write failed Value %x index %x\n", value, index);
+               dbg("Command Write failed Value %x index %x", value, index);
 
        return status;
 }
 
+
+/*
+ * mos77xx_probe
+ *     this function installs the appropriate read interrupt endpoint callback
+ *     depending on whether the device is a 7720 or 7715, thus avoiding costly
+ *     run-time checks in the high-frequency callback routine itself.
+ */
+static int mos77xx_probe(struct usb_serial *serial,
+                        const struct usb_device_id *id)
+{
+       if (id->idProduct == MOSCHIP_DEVICE_ID_7715)
+               moschip7720_2port_driver.read_int_callback =
+                       mos7715_interrupt_callback;
+       else
+               moschip7720_2port_driver.read_int_callback =
+                       mos7720_interrupt_callback;
+
+       return 0;
+}
+
+static int mos77xx_calc_num_ports(struct usb_serial *serial)
+{
+       u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
+       if (product == MOSCHIP_DEVICE_ID_7715)
+               return 1;
+
+       return 2;
+}
+
 static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
        struct usb_serial *serial;
@@ -390,7 +490,7 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)
          */
        port_number = port->number - port->serial->minor;
        send_mos_cmd(port->serial, MOS_READ, port_number, UART_LSR, &data);
-       dbg("SS::%p LSR:%x\n", mos7720_port, data);
+       dbg("SS::%p LSR:%x", mos7720_port, data);
 
        dbg("Check:Sending Command ..........");
 
@@ -729,7 +829,7 @@ static void mos7720_throttle(struct tty_struct *tty)
        struct moschip_port *mos7720_port;
        int status;
 
-       dbg("%s- port %d\n", __func__, port->number);
+       dbg("%s- port %d", __func__, port->number);
 
        mos7720_port = usb_get_serial_port_data(port);
 
@@ -1208,7 +1308,7 @@ static void mos7720_set_termios(struct tty_struct *tty,
                return;
        }
 
-       dbg("%s\n", "setting termios - ASPIRE");
+       dbg("setting termios - ASPIRE");
 
        cflag = tty->termios->c_cflag;
 
@@ -1226,7 +1326,7 @@ static void mos7720_set_termios(struct tty_struct *tty,
        change_port_settings(tty, mos7720_port, old_termios);
 
        if (!port->read_urb) {
-               dbg("%s", "URB KILLED !!!!!\n");
+               dbg("URB KILLED !!!!!");
                return;
        }
 
@@ -1495,6 +1595,7 @@ static int mos7720_startup(struct usb_serial *serial)
        struct usb_device *dev;
        int i;
        char data;
+       u16 product = le16_to_cpu(serial->dev->descriptor.idProduct);
 
        dbg("%s: Entering ..........", __func__);
 
@@ -1514,6 +1615,29 @@ static int mos7720_startup(struct usb_serial *serial)
 
        usb_set_serial_data(serial, mos7720_serial);
 
+       /*
+        * The 7715 uses the first bulk in/out endpoint pair for the parallel
+        * port, and the second for the serial port.  Because the usbserial core
+        * assumes both pairs are serial ports, we must engage in a bit of
+        * subterfuge and swap the pointers for ports 0 and 1 in order to make
+        * port 0 point to the serial port.  However, both moschip devices use a
+        * single interrupt-in endpoint for both ports (as mentioned a little
+        * further down), and this endpoint was assigned to port 0.  So after
+        * the swap, we must copy the interrupt endpoint elements from port 1
+        * (as newly assigned) to port 0, and null out port 1 pointers.
+        */
+       if (product == MOSCHIP_DEVICE_ID_7715) {
+               struct usb_serial_port *tmp = serial->port[0];
+               serial->port[0] = serial->port[1];
+               serial->port[1] = tmp;
+               serial->port[0]->interrupt_in_urb = tmp->interrupt_in_urb;
+               serial->port[0]->interrupt_in_buffer = tmp->interrupt_in_buffer;
+               serial->port[0]->interrupt_in_endpointAddress =
+                       tmp->interrupt_in_endpointAddress;
+               serial->port[1]->interrupt_in_urb = NULL;
+               serial->port[1]->interrupt_in_buffer = NULL;
+       }
+
        /* we set up the pointers to the endpoints in the mos7720_open *
         * function, as the structures aren't created yet.             */
 
@@ -1529,7 +1653,7 @@ static int mos7720_startup(struct usb_serial *serial)
 
                /* Initialize all port interrupt end point to port 0 int
                 * endpoint.  Our device has only one interrupt endpoint
-                * comman to all ports */
+                * common to all ports */
                serial->port[i]->interrupt_in_endpointAddress =
                                serial->port[0]->interrupt_in_endpointAddress;
 
@@ -1584,11 +1708,12 @@ static struct usb_serial_driver moschip7720_2port_driver = {
        .description            = "Moschip 2 port adapter",
        .usb_driver             = &usb_driver,
        .id_table               = moschip_port_id_table,
-       .num_ports              = 2,
+       .calc_num_ports         = mos77xx_calc_num_ports,
        .open                   = mos7720_open,
        .close                  = mos7720_close,
        .throttle               = mos7720_throttle,
        .unthrottle             = mos7720_unthrottle,
+       .probe                  = mos77xx_probe,
        .attach                 = mos7720_startup,
        .release                = mos7720_release,
        .ioctl                  = mos7720_ioctl,
@@ -1600,7 +1725,7 @@ static struct usb_serial_driver moschip7720_2port_driver = {
        .chars_in_buffer        = mos7720_chars_in_buffer,
        .break_ctl              = mos7720_break,
        .read_bulk_callback     = mos7720_bulk_in_callback,
-       .read_int_callback      = mos7720_interrupt_callback,
+       .read_int_callback      = NULL  /* dynamically assigned in probe() */
 };
 
 static int __init moschip7720_init(void)
index 2cfe2451ed97a349e8be147abd7c3dc80178a9d3..2fda1c0182b74848259f563a3ccfa38731c209f9 100644 (file)
 #define URB_TRANSFER_BUFFER_SIZE        32     /* URB Size  */
 
 
-static struct usb_device_id moschip_port_id_table[] = {
+static const struct usb_device_id moschip_port_id_table[] = {
        {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
        {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
        {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)},
@@ -198,7 +198,7 @@ static struct usb_device_id moschip_port_id_table[] = {
        {}                      /* terminating entry */
 };
 
-static __devinitdata struct usb_device_id moschip_id_table_combined[] = {
+static const struct usb_device_id moschip_id_table_combined[] __devinitconst = {
        {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7840)},
        {USB_DEVICE(USB_VENDOR_ID_MOSCHIP, MOSCHIP_DEVICE_ID_7820)},
        {USB_DEVICE(USB_VENDOR_ID_BANDB, BANDB_DEVICE_ID_USO9ML2_2)},
@@ -283,12 +283,19 @@ static int mos7840_get_reg_sync(struct usb_serial_port *port, __u16 reg,
 {
        struct usb_device *dev = port->serial->dev;
        int ret = 0;
+       u8 *buf;
+
+       buf = kmalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
 
        ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
-                             MCS_RD_RTYPE, 0, reg, val, VENDOR_READ_LENGTH,
+                             MCS_RD_RTYPE, 0, reg, buf, VENDOR_READ_LENGTH,
                              MOS_WDR_TIMEOUT);
+       *val = buf[0];
        dbg("mos7840_get_reg_sync offset is %x, return val %x", reg, *val);
-       *val = (*val) & 0x00ff;
+
+       kfree(buf);
        return ret;
 }
 
@@ -341,6 +348,11 @@ static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg,
        struct usb_device *dev = port->serial->dev;
        int ret = 0;
        __u16 Wval;
+       u8 *buf;
+
+       buf = kmalloc(VENDOR_READ_LENGTH, GFP_KERNEL);
+       if (!buf)
+               return -ENOMEM;
 
        /* dbg("application number is %4x",
            (((__u16)port->number - (__u16)(port->serial->minor))+1)<<8); */
@@ -364,9 +376,11 @@ static int mos7840_get_uart_reg(struct usb_serial_port *port, __u16 reg,
                }
        }
        ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), MCS_RDREQ,
-                             MCS_RD_RTYPE, Wval, reg, val, VENDOR_READ_LENGTH,
+                             MCS_RD_RTYPE, Wval, reg, buf, VENDOR_READ_LENGTH,
                              MOS_WDR_TIMEOUT);
-       *val = (*val) & 0x00ff;
+       *val = buf[0];
+
+       kfree(buf);
        return ret;
 }
 
@@ -750,7 +764,6 @@ static void mos7840_bulk_in_callback(struct urb *urb)
        if (urb->actual_length) {
                tty = tty_port_tty_get(&mos7840_port->port->port);
                if (tty) {
-                       tty_buffer_request_room(tty, urb->actual_length);
                        tty_insert_flip_string(tty, data, urb->actual_length);
                        dbg(" %s ", data);
                        tty_flip_buffer_push(tty);
index 99bd00f5188aeb1b76904e4c4edac767223a1645..cf1718394e18e3079452104948caf233292490c4 100644 (file)
@@ -21,7 +21,7 @@
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x05c6, 0x3197) }, /* unknown Motorola phone */
        { USB_DEVICE(0x0c44, 0x0022) }, /* unknown Mororola phone */
        { USB_DEVICE(0x22b8, 0x2a64) }, /* Motorola KRZR K1m */
index 5ceaa4c6be0901de3cbe2305ae3775904fec701c..04a6cbbed2c0f1de6837d9b3d611a3f543e18e97 100644 (file)
@@ -22,7 +22,7 @@
 
 static int debug;
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x0a99, 0x0001) }, /* Talon Technology device */
        { },
 };
@@ -66,7 +66,6 @@ static void navman_read_int_callback(struct urb *urb)
 
        tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
-               tty_buffer_request_room(tty, urb->actual_length);
                tty_insert_flip_string(tty, data, urb->actual_length);
                tty_flip_buffer_push(tty);
        }
index 062265038bf0cd57ec11972af1aafdfed8899aa4..89c724c0ac0a9cb3a9747f632973f5e0980677f6 100644 (file)
@@ -75,7 +75,7 @@ static void omninet_disconnect(struct usb_serial *serial);
 static void omninet_release(struct usb_serial *serial);
 static int omninet_attach(struct usb_serial *serial);
 
-static struct usb_device_id id_table[] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(ZYXEL_VENDOR_ID, ZYXEL_OMNINET_ID) },
        { USB_DEVICE(ZYXEL_VENDOR_ID, BT_IGNITIONPRO_ID) },
        { }                                             /* Terminating entry */
@@ -218,8 +218,8 @@ static void omninet_read_bulk_callback(struct urb *urb)
 
        if (debug && header->oh_xxx != 0x30) {
                if (urb->actual_length) {
-                       printk(KERN_DEBUG __FILE__
-                                       ": omninet_read %d: ", header->oh_len);
+                       printk(KERN_DEBUG "%s: omninet_read %d: ",
+                              __FILE__, header->oh_len);
                        for (i = 0; i < (header->oh_len +
                                                OMNINET_HEADERLEN); i++)
                                printk("%.2x ", data[i]);
@@ -332,7 +332,7 @@ static void omninet_write_bulk_callback(struct urb *urb)
        struct usb_serial_port  *port   =  urb->context;
        int status = urb->status;
 
-       dbg("%s - port %0x\n", __func__, port->number);
+       dbg("%s - port %0x", __func__, port->number);
 
        port->write_urb_busy = 0;
        if (status) {
index 4cdb975caa89a96a897451ba57203e97968a7bdc..f37476e22684af0663b46e41d4431692834d741b 100644 (file)
@@ -22,7 +22,7 @@
 
 static int debug;
 
-static struct usb_device_id id_table[] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x065a, 0x0009) },
        { },
 };
@@ -55,7 +55,6 @@ static void opticon_bulk_callback(struct urb *urb)
        int status = urb->status;
        struct tty_struct *tty;
        int result;
-       int available_room = 0;
        int data_length;
 
        dbg("%s - port %d", __func__, port->number);
@@ -96,13 +95,9 @@ static void opticon_bulk_callback(struct urb *urb)
                        /* real data, send it to the tty layer */
                        tty = tty_port_tty_get(&port->port);
                        if (tty) {
-                               available_room = tty_buffer_request_room(tty,
-                                                               data_length);
-                               if (available_room) {
-                                       tty_insert_flip_string(tty, data,
-                                                              available_room);
-                                       tty_flip_buffer_push(tty);
-                               }
+                               tty_insert_flip_string(tty, data,
+                                                              data_length);
+                               tty_flip_buffer_push(tty);
                                tty_kref_put(tty);
                        }
                } else {
@@ -217,7 +212,7 @@ static int opticon_write(struct tty_struct *tty, struct usb_serial_port *port,
        spin_lock_irqsave(&priv->lock, flags);
        if (priv->outstanding_urbs > URB_UPPER_LIMIT) {
                spin_unlock_irqrestore(&priv->lock, flags);
-               dbg("%s - write limit hit\n", __func__);
+               dbg("%s - write limit hit", __func__);
                return 0;
        }
        priv->outstanding_urbs++;
@@ -288,7 +283,7 @@ static int opticon_write_room(struct tty_struct *tty)
        spin_lock_irqsave(&priv->lock, flags);
        if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) {
                spin_unlock_irqrestore(&priv->lock, flags);
-               dbg("%s - write limit hit\n", __func__);
+               dbg("%s - write limit hit", __func__);
                return 0;
        }
        spin_unlock_irqrestore(&priv->lock, flags);
index 6e94a6711f08c28f3e3aeb6ca0ac2f1cfa0d3a7f..847b805d63a3b7444b554462efb4c78dc4581fba 100644 (file)
@@ -336,15 +336,42 @@ static int  option_resume(struct usb_serial *serial);
 #define AIRPLUS_VENDOR_ID                      0x1011
 #define AIRPLUS_PRODUCT_MCD650                 0x3198
 
+/* Longcheer/Longsung vendor ID; makes whitelabel devices that
+ * many other vendors like 4G Systems, Alcatel, ChinaBird,
+ * Mobidata, etc sell under their own brand names.
+ */
+#define LONGCHEER_VENDOR_ID                    0x1c9e
+
 /* 4G Systems products */
-#define FOUR_G_SYSTEMS_VENDOR_ID               0x1c9e
+/* This is the 4G XS Stick W14 a.k.a. Mobilcom Debitel Surf-Stick *
+ * It seems to contain a Qualcomm QSC6240/6290 chipset            */
 #define FOUR_G_SYSTEMS_PRODUCT_W14             0x9603
 
 /* Haier products */
 #define HAIER_VENDOR_ID                                0x201e
 #define HAIER_PRODUCT_CE100                    0x2009
 
-static struct usb_device_id option_ids[] = {
+/* some devices interfaces need special handling due to a number of reasons */
+enum option_blacklist_reason {
+               OPTION_BLACKLIST_NONE = 0,
+               OPTION_BLACKLIST_SENDSETUP = 1,
+               OPTION_BLACKLIST_RESERVED_IF = 2
+};
+
+struct option_blacklist_info {
+       const u32 infolen;      /* number of interface numbers on blacklist */
+       const u8  *ifaceinfo;   /* pointer to the array holding the numbers */
+       enum option_blacklist_reason reason;
+};
+
+static const u8 four_g_w14_no_sendsetup[] = { 0, 1 };
+static const struct option_blacklist_info four_g_w14_blacklist = {
+       .infolen = ARRAY_SIZE(four_g_w14_no_sendsetup),
+       .ifaceinfo = four_g_w14_no_sendsetup,
+       .reason = OPTION_BLACKLIST_SENDSETUP
+};
+
+static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA) },
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_RICOLA_LIGHT) },
@@ -644,7 +671,9 @@ static struct usb_device_id option_ids[] = {
        { USB_DEVICE(ALCATEL_VENDOR_ID, ALCATEL_PRODUCT_X060S) },
        { USB_DEVICE(AIRPLUS_VENDOR_ID, AIRPLUS_PRODUCT_MCD650) },
        { USB_DEVICE(TLAYTECH_VENDOR_ID, TLAYTECH_PRODUCT_TEU800) },
-       { USB_DEVICE(FOUR_G_SYSTEMS_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14) },
+       { USB_DEVICE(LONGCHEER_VENDOR_ID, FOUR_G_SYSTEMS_PRODUCT_W14),
+         .driver_info = (kernel_ulong_t)&four_g_w14_blacklist
+       },
        { USB_DEVICE(HAIER_VENDOR_ID, HAIER_PRODUCT_CE100) },
        { } /* Terminating entry */
 };
@@ -709,6 +738,7 @@ struct option_intf_private {
        spinlock_t susp_lock;
        unsigned int suspended:1;
        int in_flight;
+       struct option_blacklist_info *blacklist_info;
 };
 
 struct option_port_private {
@@ -778,9 +808,27 @@ static int option_probe(struct usb_serial *serial,
        if (!data)
                return -ENOMEM;
        spin_lock_init(&data->susp_lock);
+       data->blacklist_info = (struct option_blacklist_info*) id->driver_info;
        return 0;
 }
 
+static enum option_blacklist_reason is_blacklisted(const u8 ifnum,
+                               const struct option_blacklist_info *blacklist)
+{
+       const u8  *info;
+       int i;
+
+       if (blacklist) {
+               info = blacklist->ifaceinfo;
+
+               for (i = 0; i < blacklist->infolen; i++) {
+                       if (info[i] == ifnum)
+                               return blacklist->reason;
+               }
+       }
+       return OPTION_BLACKLIST_NONE;
+}
+
 static void option_set_termios(struct tty_struct *tty,
                struct usb_serial_port *port, struct ktermios *old_termios)
 {
@@ -921,7 +969,6 @@ static void option_indat_callback(struct urb *urb)
        } else {
                tty = tty_port_tty_get(&port->port);
                if (urb->actual_length) {
-                       tty_buffer_request_room(tty, urb->actual_length);
                        tty_insert_flip_string(tty, data, urb->actual_length);
                        tty_flip_buffer_push(tty);
                } else 
@@ -929,9 +976,9 @@ static void option_indat_callback(struct urb *urb)
                tty_kref_put(tty);
 
                /* Resubmit urb so we continue receiving */
-               if (port->port.count && status != -ESHUTDOWN) {
+               if (status != -ESHUTDOWN) {
                        err = usb_submit_urb(urb, GFP_ATOMIC);
-                       if (err)
+                       if (err && err != -EPERM)
                                printk(KERN_ERR "%s: resubmit read urb failed. "
                                        "(%d)", __func__, err);
                        else
@@ -985,7 +1032,7 @@ static void option_instat_callback(struct urb *urb)
                                (struct usb_ctrlrequest *)urb->transfer_buffer;
 
                if (!req_pkt) {
-                       dbg("%s: NULL req_pkt\n", __func__);
+                       dbg("%s: NULL req_pkt", __func__);
                        return;
                }
                if ((req_pkt->bRequestType == 0xA1) &&
@@ -1211,11 +1258,19 @@ static void option_setup_urbs(struct usb_serial *serial)
 static int option_send_setup(struct usb_serial_port *port)
 {
        struct usb_serial *serial = port->serial;
+       struct option_intf_private *intfdata =
+               (struct option_intf_private *) serial->private;
        struct option_port_private *portdata;
        int ifNum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
        int val = 0;
        dbg("%s", __func__);
 
+       if (is_blacklisted(ifNum, intfdata->blacklist_info) ==
+                                               OPTION_BLACKLIST_SENDSETUP) {
+               dbg("No send_setup on blacklisted interface #%d\n", ifNum);
+               return -EIO;
+       }
+
        portdata = usb_get_serial_port_data(port);
 
        if (portdata->dtr_state)
@@ -1401,7 +1456,7 @@ static int option_resume(struct usb_serial *serial)
        for (i = 0; i < serial->num_ports; i++) {
                port = serial->port[i];
                if (!port->interrupt_in_urb) {
-                       dbg("%s: No interrupt URB for port %d\n", __func__, i);
+                       dbg("%s: No interrupt URB for port %d", __func__, i);
                        continue;
                }
                err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
index c644e26394b47360e1a1d52c684d59d16f16d609..deeacdea05dbc882b8b7e972b5b85b8e56208e8d 100644 (file)
@@ -58,7 +58,7 @@
 #define OTI6858_AUTHOR "Tomasz Michal Lukaszewski <FIXME@FIXME>"
 #define OTI6858_VERSION "0.1"
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(OTI6858_VENDOR_ID, OTI6858_PRODUCT_ID) },
        { }
 };
@@ -302,7 +302,7 @@ void send_data(struct work_struct *work)
        struct usb_serial_port *port = priv->port;
        int count = 0, result;
        unsigned long flags;
-       unsigned char allow;
+       u8 *allow;
 
        dbg("%s(port = %d)", __func__, port->number);
 
@@ -321,13 +321,20 @@ void send_data(struct work_struct *work)
                count = port->bulk_out_size;
 
        if (count != 0) {
+               allow = kmalloc(1, GFP_KERNEL);
+               if (!allow) {
+                       dev_err(&port->dev, "%s(): kmalloc failed\n",
+                                       __func__);
+                       return;
+               }
                result = usb_control_msg(port->serial->dev,
                                usb_rcvctrlpipe(port->serial->dev, 0),
                                OTI6858_REQ_T_CHECK_TXBUFF,
                                OTI6858_REQ_CHECK_TXBUFF,
-                               count, 0, &allow, 1, 100);
-               if (result != 1 || allow != 0)
+                               count, 0, allow, 1, 100);
+               if (result != 1 || *allow != 0)
                        count = 0;
+               kfree(allow);
        }
 
        if (count == 0) {
@@ -578,9 +585,6 @@ static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port)
        usb_clear_halt(serial->dev, port->write_urb->pipe);
        usb_clear_halt(serial->dev, port->read_urb->pipe);
 
-       if (port->port.count != 1)
-               return 0;
-
        buf = kmalloc(OTI6858_CTRL_PKT_SIZE, GFP_KERNEL);
        if (buf == NULL) {
                dev_err(&port->dev, "%s(): out of memory!\n", __func__);
@@ -927,10 +931,6 @@ static void oti6858_read_bulk_callback(struct urb *urb)
        spin_unlock_irqrestore(&priv->lock, flags);
 
        if (status != 0) {
-               if (!port->port.count) {
-                       dbg("%s(): port is closed, exiting", __func__);
-                       return;
-               }
                /*
                if (status == -EPROTO) {
                        * PL2303 mysteriously fails with -EPROTO reschedule
@@ -954,14 +954,12 @@ static void oti6858_read_bulk_callback(struct urb *urb)
        }
        tty_kref_put(tty);
 
-       /* schedule the interrupt urb if we are still open */
-       if (port->port.count != 0) {
-               port->interrupt_in_urb->dev = port->serial->dev;
-               result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
-               if (result != 0) {
-                       dev_err(&port->dev, "%s(): usb_submit_urb() failed,"
-                                       " error %d\n", __func__, result);
-               }
+       /* schedule the interrupt urb */
+       port->interrupt_in_urb->dev = port->serial->dev;
+       result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
+       if (result != 0 && result != -EPERM) {
+               dev_err(&port->dev, "%s(): usb_submit_urb() failed,"
+                               " error %d\n", __func__, result);
        }
 }
 
index 9ec1a49e23622a6787d93ec3280f62ce14aac93e..73d5f346d3e07659ad585f89f1c3b93b97d6aba9 100644 (file)
@@ -50,7 +50,7 @@ struct pl2303_buf {
        char            *buf_put;
 };
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID) },
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_RSAQ2) },
        { USB_DEVICE(PL2303_VENDOR_ID, PL2303_PRODUCT_ID_DCU11) },
@@ -451,7 +451,6 @@ static void pl2303_send(struct usb_serial_port *port)
                              port->write_urb->transfer_buffer);
 
        port->write_urb->transfer_buffer_length = count;
-       port->write_urb->dev = port->serial->dev;
        result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
        if (result) {
                dev_err(&port->dev, "%s - failed submitting write urb,"
@@ -769,7 +768,6 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
                pl2303_set_termios(tty, port, &tmp_termios);
 
        dbg("%s - submitting read urb", __func__);
-       port->read_urb->dev = serial->dev;
        result = usb_submit_urb(port->read_urb, GFP_KERNEL);
        if (result) {
                dev_err(&port->dev, "%s - failed submitting read urb,"
@@ -779,7 +777,6 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
        }
 
        dbg("%s - submitting interrupt urb", __func__);
-       port->interrupt_in_urb->dev = serial->dev;
        result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
        if (result) {
                dev_err(&port->dev, "%s - failed submitting interrupt urb,"
@@ -895,10 +892,23 @@ static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
 static int pl2303_ioctl(struct tty_struct *tty, struct file *file,
                        unsigned int cmd, unsigned long arg)
 {
+       struct serial_struct ser;
        struct usb_serial_port *port = tty->driver_data;
        dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
 
        switch (cmd) {
+       case TIOCGSERIAL:
+               memset(&ser, 0, sizeof ser);
+               ser.type = PORT_16654;
+               ser.line = port->serial->minor;
+               ser.port = port->number;
+               ser.baud_base = 460800;
+
+               if (copy_to_user((void __user *)arg, &ser, sizeof ser))
+                       return -EFAULT;
+
+               return 0;
+
        case TIOCMIWAIT:
                dbg("%s (%d) TIOCMIWAIT", __func__,  port->number);
                return wait_modem_info(port, arg);
@@ -1042,7 +1052,6 @@ static void pl2303_push_data(struct tty_struct *tty,
                tty_flag = TTY_FRAME;
        dbg("%s - tty_flag = %d", __func__, tty_flag);
 
-       tty_buffer_request_room(tty, urb->actual_length + 1);
        /* overrun is special, not associated with a char */
        if (line_status & UART_OVERRUN_ERROR)
                tty_insert_flip_char(tty, 0, TTY_OVERRUN);
@@ -1072,16 +1081,11 @@ static void pl2303_read_bulk_callback(struct urb *urb)
 
        if (status) {
                dbg("%s - urb status = %d", __func__, status);
-               if (!port->port.count) {
-                       dbg("%s - port is closed, exiting.", __func__);
-                       return;
-               }
                if (status == -EPROTO) {
                        /* PL2303 mysteriously fails with -EPROTO reschedule
                         * the read */
                        dbg("%s - caught -EPROTO, resubmitting the urb",
                            __func__);
-                       urb->dev = port->serial->dev;
                        result = usb_submit_urb(urb, GFP_ATOMIC);
                        if (result)
                                dev_err(&urb->dev->dev, "%s - failed"
@@ -1108,15 +1112,10 @@ static void pl2303_read_bulk_callback(struct urb *urb)
        }
        tty_kref_put(tty);
        /* Schedule the next read _if_ we are still open */
-       if (port->port.count) {
-               urb->dev = port->serial->dev;
-               result = usb_submit_urb(urb, GFP_ATOMIC);
-               if (result)
-                       dev_err(&urb->dev->dev, "%s - failed resubmitting"
-                               " read urb, error %d\n", __func__, result);
-       }
-
-       return;
+       result = usb_submit_urb(urb, GFP_ATOMIC);
+       if (result && result != -EPERM)
+               dev_err(&urb->dev->dev, "%s - failed resubmitting"
+                       " read urb, error %d\n", __func__, result);
 }
 
 static void pl2303_write_bulk_callback(struct urb *urb)
@@ -1146,7 +1145,6 @@ static void pl2303_write_bulk_callback(struct urb *urb)
                dbg("%s - nonzero write bulk status received: %d", __func__,
                    status);
                port->write_urb->transfer_buffer_length = 1;
-               port->write_urb->dev = port->serial->dev;
                result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
                if (result)
                        dev_err(&urb->dev->dev, "%s - failed resubmitting write"
diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c
new file mode 100644 (file)
index 0000000..0b93620
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ * Qualcomm USB Auxiliary Serial Port driver
+ *
+ * Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
+ * Copyright (C) 2010 Dan Williams <dcbw@redhat.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ * Devices listed here usually provide a CDC ACM port on which normal modem
+ * AT commands and PPP can be used.  But when that port is in-use by PPP it
+ * cannot be used simultaneously for status or signal strength.  Instead, the
+ * ports here can be queried for that information using the Qualcomm DM
+ * protocol.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+/* NOTE: for now, only use this driver for devices that provide a CDC-ACM port
+ * for normal AT commands, but also provide secondary USB interfaces for the
+ * QCDM-capable ports.  Devices that do not provide a CDC-ACM port should
+ * probably be driven by option.ko.
+ */
+
+/* UTStarcom/Pantech/Curitel devices */
+#define UTSTARCOM_VENDOR_ID                    0x106c
+#define UTSTARCOM_PRODUCT_PC5740               0x3701
+#define UTSTARCOM_PRODUCT_PC5750               0x3702 /* aka Pantech PX-500 */
+#define UTSTARCOM_PRODUCT_UM150                        0x3711
+#define UTSTARCOM_PRODUCT_UM175_V1             0x3712
+#define UTSTARCOM_PRODUCT_UM175_V2             0x3714
+#define UTSTARCOM_PRODUCT_UM175_ALLTEL         0x3715
+
+/* CMOTECH devices */
+#define CMOTECH_VENDOR_ID                      0x16d8
+#define CMOTECH_PRODUCT_CDU550                 0x5553
+#define CMOTECH_PRODUCT_CDX650                 0x6512
+
+static struct usb_device_id id_table[] = {
+       { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_PC5740, 0xff, 0x00, 0x00) },
+       { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_PC5750, 0xff, 0x00, 0x00) },
+       { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_UM150, 0xff, 0x00, 0x00) },
+       { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_UM175_V1, 0xff, 0x00, 0x00) },
+       { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_UM175_V2, 0xff, 0x00, 0x00) },
+       { USB_DEVICE_AND_INTERFACE_INFO(UTSTARCOM_VENDOR_ID, UTSTARCOM_PRODUCT_UM175_ALLTEL, 0xff, 0x00, 0x00) },
+       { USB_DEVICE_AND_INTERFACE_INFO(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDU550, 0xff, 0xff, 0x00) },
+       { USB_DEVICE_AND_INTERFACE_INFO(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_CDX650, 0xff, 0xff, 0x00) },
+       { },
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver qcaux_driver = {
+       .name =         "qcaux",
+       .probe =        usb_serial_probe,
+       .disconnect =   usb_serial_disconnect,
+       .id_table =     id_table,
+       .no_dynamic_id =        1,
+};
+
+static struct usb_serial_driver qcaux_device = {
+       .driver = {
+               .owner =        THIS_MODULE,
+               .name =         "qcaux",
+       },
+       .id_table =             id_table,
+       .num_ports =            1,
+};
+
+static int __init qcaux_init(void)
+{
+       int retval;
+
+       retval = usb_serial_register(&qcaux_device);
+       if (retval)
+               return retval;
+       retval = usb_register(&qcaux_driver);
+       if (retval)
+               usb_serial_deregister(&qcaux_device);
+       return retval;
+}
+
+static void __exit qcaux_exit(void)
+{
+       usb_deregister(&qcaux_driver);
+       usb_serial_deregister(&qcaux_device);
+}
+
+module_init(qcaux_init);
+module_exit(qcaux_exit);
+MODULE_LICENSE("GPL");
index 7528b8d57f1cc9048001244f780524b8cca17690..310ff6ec65678d1c38da316cfdb4fe8a06936c52 100644 (file)
@@ -21,7 +21,7 @@
 
 static int debug;
 
-static struct usb_device_id id_table[] = {
+static const struct usb_device_id id_table[] = {
        {USB_DEVICE(0x05c6, 0x9211)},   /* Acer Gobi QDL device */
        {USB_DEVICE(0x05c6, 0x9212)},   /* Acer Gobi Modem Device */
        {USB_DEVICE(0x03f0, 0x1f1d)},   /* HP un2400 Gobi Modem Device */
index 951ea0c6ba7705e58f8e0c9d7966c696487624f1..cb8195cabfde82d0ce0cb9c16c5e441100ca1757 100644 (file)
@@ -22,7 +22,7 @@
 #define DRIVER_DESC "Driver for Siemens USB/MPI adapter"
 
 
-static struct usb_device_id id_table[] = {
+static const struct usb_device_id id_table[] = {
        /* Vendor and product id for 6ES7-972-0CB20-0XA0 */
        { USB_DEVICE(0x908, 0x0004) },
        { },
index 3eb6143bb6468135fe45f64af73b41a1a12f7845..34e6f894cba9c422769c4607d49d2fd8081b7747 100644 (file)
@@ -226,7 +226,7 @@ static const struct sierra_iface_info direct_ip_interface_blacklist = {
        .ifaceinfo = direct_ip_non_serial_ifaces,
 };
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x0F3D, 0x0112) }, /* Airprime/Sierra PC 5220 */
        { USB_DEVICE(0x03F0, 0x1B1D) }, /* HP ev2200 a.k.a MC5720 */
        { USB_DEVICE(0x03F0, 0x1E1D) }, /* HP hs2300 a.k.a MC8775 */
@@ -304,16 +304,6 @@ static struct usb_device_id id_table [] = {
 };
 MODULE_DEVICE_TABLE(usb, id_table);
 
-static struct usb_driver sierra_driver = {
-       .name       = "sierra",
-       .probe      = usb_serial_probe,
-       .disconnect = usb_serial_disconnect,
-       .suspend    = usb_serial_suspend,
-       .resume     = usb_serial_resume,
-       .id_table   = id_table,
-       .no_dynamic_id =        1,
-       .supports_autosuspend = 1,
-};
 
 struct sierra_port_private {
        spinlock_t lock;        /* lock the structure */
@@ -477,7 +467,7 @@ static void sierra_outdat_callback(struct urb *urb)
 static int sierra_write(struct tty_struct *tty, struct usb_serial_port *port,
                                        const unsigned char *buf, int count)
 {
-       struct sierra_port_private *portdata = usb_get_serial_port_data(port);
+       struct sierra_port_private *portdata;
        struct sierra_intf_private *intfdata;
        struct usb_serial *serial = port->serial;
        unsigned long flags;
@@ -604,14 +594,15 @@ static void sierra_indat_callback(struct urb *urb)
        } else {
                if (urb->actual_length) {
                        tty = tty_port_tty_get(&port->port);
-
-                       tty_buffer_request_room(tty, urb->actual_length);
-                       tty_insert_flip_string(tty, data, urb->actual_length);
-                       tty_flip_buffer_push(tty);
-
-                       tty_kref_put(tty);
-                       usb_serial_debug_data(debug, &port->dev, __func__,
-                               urb->actual_length, data);
+                       if (tty) {
+                               tty_insert_flip_string(tty, data,
+                                       urb->actual_length);
+                               tty_flip_buffer_push(tty);
+
+                               tty_kref_put(tty);
+                               usb_serial_debug_data(debug, &port->dev,
+                                       __func__, urb->actual_length, data);
+                       }
                } else {
                        dev_dbg(&port->dev, "%s: empty read urb"
                                " received\n", __func__);
@@ -619,10 +610,10 @@ static void sierra_indat_callback(struct urb *urb)
        }
 
        /* Resubmit urb so we continue receiving */
-       if (port->port.count && status != -ESHUTDOWN && status != -EPERM) {
+       if (status != -ESHUTDOWN && status != -EPERM) {
                usb_mark_last_busy(port->serial->dev);
                err = usb_submit_urb(urb, GFP_ATOMIC);
-               if (err)
+               if (err && err != -EPERM)
                        dev_err(&port->dev, "resubmit read urb failed."
                                "(%d)\n", err);
        }
@@ -681,11 +672,11 @@ static void sierra_instat_callback(struct urb *urb)
                dev_dbg(&port->dev, "%s: error %d\n", __func__, status);
 
        /* Resubmit urb so we continue receiving IRQ data */
-       if (port->port.count && status != -ESHUTDOWN && status != -ENOENT) {
+       if (status != -ESHUTDOWN && status != -ENOENT) {
                usb_mark_last_busy(serial->dev);
                urb->dev = serial->dev;
                err = usb_submit_urb(urb, GFP_ATOMIC);
-               if (err)
+               if (err && err != -EPERM)
                        dev_err(&port->dev, "%s: resubmit intr urb "
                                "failed. (%d)\n", __func__, err);
        }
@@ -1061,11 +1052,31 @@ static int sierra_resume(struct usb_serial *serial)
 
        return ec ? -EIO : 0;
 }
+
+static int sierra_reset_resume(struct usb_interface *intf)
+{
+       struct usb_serial *serial = usb_get_intfdata(intf);
+       dev_err(&serial->dev->dev, "%s\n", __func__);
+       return usb_serial_resume(intf);
+}
 #else
 #define sierra_suspend NULL
 #define sierra_resume NULL
+#define sierra_reset_resume NULL
 #endif
 
+static struct usb_driver sierra_driver = {
+       .name       = "sierra",
+       .probe      = usb_serial_probe,
+       .disconnect = usb_serial_disconnect,
+       .suspend    = usb_serial_suspend,
+       .resume     = usb_serial_resume,
+       .reset_resume = sierra_reset_resume,
+       .id_table   = id_table,
+       .no_dynamic_id =        1,
+       .supports_autosuspend = 1,
+};
+
 static struct usb_serial_driver sierra_device = {
        .driver = {
                .owner =        THIS_MODULE,
index 1e58220403d1f7f466425d77c1d3ccf124fa993a..5d39191e7244bb0f645ca5b124da4deaba9ac97d 100644 (file)
@@ -45,7 +45,7 @@ static int debug;
 #define SPCP8x5_835_VID                0x04fc
 #define SPCP8x5_835_PID                0x0231
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(SPCP8x5_PHILIPS_VID , SPCP8x5_PHILIPS_PID)},
        { USB_DEVICE(SPCP8x5_INTERMATIC_VID, SPCP8x5_INTERMATIC_PID)},
        { USB_DEVICE(SPCP8x5_835_VID, SPCP8x5_835_PID)},
@@ -609,7 +609,7 @@ static void spcp8x5_set_termios(struct tty_struct *tty,
        if (i < 0)
                dev_err(&port->dev, "Set UART format %#x failed (error = %d)\n",
                        uartdata, i);
-       dbg("0x21:0x40:0:0  %d\n", i);
+       dbg("0x21:0x40:0:0  %d", i);
 
        if (cflag & CRTSCTS) {
                /* enable hardware flow control */
@@ -677,7 +677,6 @@ static void spcp8x5_read_bulk_callback(struct urb *urb)
        struct tty_struct *tty;
        unsigned char *data = urb->transfer_buffer;
        unsigned long flags;
-       int i;
        int result = urb->status;
        u8 status;
        char tty_flag;
@@ -687,8 +686,6 @@ static void spcp8x5_read_bulk_callback(struct urb *urb)
 
        /* check the urb status */
        if (result) {
-               if (!port->port.count)
-                       return;
                if (result == -EPROTO) {
                        /* spcp8x5 mysteriously fails with -EPROTO */
                        /* reschedule the read */
@@ -726,26 +723,20 @@ static void spcp8x5_read_bulk_callback(struct urb *urb)
 
        tty = tty_port_tty_get(&port->port);
        if (tty && urb->actual_length) {
-               tty_buffer_request_room(tty, urb->actual_length + 1);
                /* overrun is special, not associated with a char */
                if (status & UART_OVERRUN_ERROR)
                        tty_insert_flip_char(tty, 0, TTY_OVERRUN);
-               for (i = 0; i < urb->actual_length; ++i)
-                       tty_insert_flip_char(tty, data[i], tty_flag);
+               tty_insert_flip_string_fixed_flag(tty, data,
+                                               urb->actual_length, tty_flag);
                tty_flip_buffer_push(tty);
        }
        tty_kref_put(tty);
 
-       /* Schedule the next read _if_ we are still open */
-       if (port->port.count) {
-               urb->dev = port->serial->dev;
-               result = usb_submit_urb(urb , GFP_ATOMIC);
-               if (result)
-                       dev_dbg(&port->dev, "failed submitting read urb %d\n",
-                               result);
-       }
-
-       return;
+       /* Schedule the next read */
+       urb->dev = port->serial->dev;
+       result = usb_submit_urb(urb , GFP_ATOMIC);
+       if (result)
+               dev_dbg(&port->dev, "failed submitting read urb %d\n", result);
 }
 
 /* get data from ring buffer and then write to usb bus */
index b282c0f2d8e565101bd17a7f0f37e220b9b17e6d..72398888858ffb95ed24943033d41b5f2ebe4ca0 100644 (file)
@@ -21,7 +21,7 @@
 
 static int debug;
 
-static struct usb_device_id id_table[] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x05e0, 0x0600) },
        { },
 };
@@ -51,7 +51,6 @@ static void symbol_int_callback(struct urb *urb)
        int status = urb->status;
        struct tty_struct *tty;
        int result;
-       int available_room = 0;
        int data_length;
 
        dbg("%s - port %d", __func__, port->number);
@@ -89,13 +88,8 @@ static void symbol_int_callback(struct urb *urb)
                 */
                tty = tty_port_tty_get(&port->port);
                if (tty) {
-                       available_room = tty_buffer_request_room(tty,
-                                                       data_length);
-                       if (available_room) {
-                               tty_insert_flip_string(tty, &data[1],
-                                                      available_room);
-                               tty_flip_buffer_push(tty);
-                       }
+                       tty_insert_flip_string(tty, &data[1], data_length);
+                       tty_flip_buffer_push(tty);
                        tty_kref_put(tty);
                }
        } else {
index 1e9dc882169826ff742e5c199b4a11098f97411c..0afe5c71c17e6e4c687c3b2f5ac816857146087f 100644 (file)
@@ -1271,14 +1271,13 @@ static void ti_recv(struct device *dev, struct tty_struct *tty,
        int cnt;
 
        do {
-               cnt = tty_buffer_request_room(tty, length);
+               cnt = tty_insert_flip_string(tty, data, length);
                if (cnt < length) {
                        dev_err(dev, "%s - dropping data, %d bytes lost\n",
                                                __func__, length - cnt);
                        if (cnt == 0)
                                break;
                }
-               tty_insert_flip_string(tty, data, cnt);
                tty_flip_buffer_push(tty);
                data += cnt;
                length -= cnt;
index 33c85f7084f879593b3f47e2833c2776bda97486..3873660d821776cab0d2950633cd17169b728643 100644 (file)
@@ -358,10 +358,6 @@ static int serial_write(struct tty_struct *tty, const unsigned char *buf,
 
        dbg("%s - port %d, %d byte(s)", __func__, port->number, count);
 
-       /* count is managed under the mutex lock for the tty so cannot
-          drop to zero until after the last close completes */
-       WARN_ON(!port->port.count);
-
        /* pass on to the driver specific version of this function */
        retval = port->serial->type->write(tty, port, buf, count);
 
@@ -373,7 +369,6 @@ static int serial_write_room(struct tty_struct *tty)
 {
        struct usb_serial_port *port = tty->driver_data;
        dbg("%s - port %d", __func__, port->number);
-       WARN_ON(!port->port.count);
        /* pass on to the driver specific version of this function */
        return port->serial->type->write_room(tty);
 }
@@ -381,7 +376,7 @@ static int serial_write_room(struct tty_struct *tty)
 static int serial_chars_in_buffer(struct tty_struct *tty)
 {
        struct usb_serial_port *port = tty->driver_data;
-       dbg("%s = port %d", __func__, port->number);
+       dbg("%s - port %d", __func__, port->number);
 
        /* if the device was unplugged then any remaining characters
           fell out of the connector ;) */
@@ -396,7 +391,6 @@ static void serial_throttle(struct tty_struct *tty)
        struct usb_serial_port *port = tty->driver_data;
        dbg("%s - port %d", __func__, port->number);
 
-       WARN_ON(!port->port.count);
        /* pass on to the driver specific version of this function */
        if (port->serial->type->throttle)
                port->serial->type->throttle(tty);
@@ -407,7 +401,6 @@ static void serial_unthrottle(struct tty_struct *tty)
        struct usb_serial_port *port = tty->driver_data;
        dbg("%s - port %d", __func__, port->number);
 
-       WARN_ON(!port->port.count);
        /* pass on to the driver specific version of this function */
        if (port->serial->type->unthrottle)
                port->serial->type->unthrottle(tty);
@@ -421,8 +414,6 @@ static int serial_ioctl(struct tty_struct *tty, struct file *file,
 
        dbg("%s - port %d, cmd 0x%.4x", __func__, port->number, cmd);
 
-       WARN_ON(!port->port.count);
-
        /* pass on to the driver specific version of this function
           if it is available */
        if (port->serial->type->ioctl) {
@@ -437,7 +428,6 @@ static void serial_set_termios(struct tty_struct *tty, struct ktermios *old)
        struct usb_serial_port *port = tty->driver_data;
        dbg("%s - port %d", __func__, port->number);
 
-       WARN_ON(!port->port.count);
        /* pass on to the driver specific version of this function
           if it is available */
        if (port->serial->type->set_termios)
@@ -452,7 +442,6 @@ static int serial_break(struct tty_struct *tty, int break_state)
 
        dbg("%s - port %d", __func__, port->number);
 
-       WARN_ON(!port->port.count);
        /* pass on to the driver specific version of this function
           if it is available */
        if (port->serial->type->break_ctl)
@@ -513,7 +502,6 @@ static int serial_tiocmget(struct tty_struct *tty, struct file *file)
 
        dbg("%s - port %d", __func__, port->number);
 
-       WARN_ON(!port->port.count);
        if (port->serial->type->tiocmget)
                return port->serial->type->tiocmget(tty, file);
        return -EINVAL;
@@ -526,7 +514,6 @@ static int serial_tiocmset(struct tty_struct *tty, struct file *file,
 
        dbg("%s - port %d", __func__, port->number);
 
-       WARN_ON(!port->port.count);
        if (port->serial->type->tiocmset)
                return port->serial->type->tiocmset(tty, file, set, clear);
        return -EINVAL;
index 7b5bfc4edd3d4668e2c6f25f76d287b70a20017f..252cc2d993b2992b7bbb7480f76c3760800322f3 100644 (file)
@@ -29,7 +29,7 @@ static char USB_DEBUG_BRK[USB_DEBUG_BRK_SIZE] = {
        0xff,
 };
 
-static struct usb_device_id id_table [] = {
+static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x0525, 0x127a) },
        { },
 };
index ad1f9232292d264506b16cb5b5bd8a625dc2e88d..094942707c7d6591afab24d006cc8d0d1d1de097 100644 (file)
@@ -368,7 +368,7 @@ static int visor_write(struct tty_struct *tty, struct usb_serial_port *port,
        spin_lock_irqsave(&priv->lock, flags);
        if (priv->outstanding_urbs > URB_UPPER_LIMIT) {
                spin_unlock_irqrestore(&priv->lock, flags);
-               dbg("%s - write limit hit\n", __func__);
+               dbg("%s - write limit hit", __func__);
                return 0;
        }
        priv->outstanding_urbs++;
@@ -446,7 +446,7 @@ static int visor_write_room(struct tty_struct *tty)
        spin_lock_irqsave(&priv->lock, flags);
        if (priv->outstanding_urbs > URB_UPPER_LIMIT * 2 / 3) {
                spin_unlock_irqrestore(&priv->lock, flags);
-               dbg("%s - write limit hit\n", __func__);
+               dbg("%s - write limit hit", __func__);
                return 0;
        }
        spin_unlock_irqrestore(&priv->lock, flags);
@@ -503,13 +503,9 @@ static void visor_read_bulk_callback(struct urb *urb)
        if (urb->actual_length) {
                tty = tty_port_tty_get(&port->port);
                if (tty) {
-                       available_room = tty_buffer_request_room(tty,
-                                                       urb->actual_length);
-                       if (available_room) {
-                               tty_insert_flip_string(tty, data,
-                                                       available_room);
-                               tty_flip_buffer_push(tty);
-                       }
+                       tty_insert_flip_string(tty, data,
+                                               urb->actual_length);
+                       tty_flip_buffer_push(tty);
                        tty_kref_put(tty);
                }
                spin_lock(&priv->lock);
@@ -807,10 +803,14 @@ static int clie_3_5_startup(struct usb_serial *serial)
 {
        struct device *dev = &serial->dev->dev;
        int result;
-       u8 data;
+       u8 *data;
 
        dbg("%s", __func__);
 
+       data = kmalloc(1, GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+
        /*
         * Note that PEG-300 series devices expect the following two calls.
         */
@@ -818,36 +818,42 @@ static int clie_3_5_startup(struct usb_serial *serial)
        /* get the config number */
        result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
                                  USB_REQ_GET_CONFIGURATION, USB_DIR_IN,
-                                 0, 0, &data, 1, 3000);
+                                 0, 0, data, 1, 3000);
        if (result < 0) {
                dev_err(dev, "%s: get config number failed: %d\n",
                                                        __func__, result);
-               return result;
+               goto out;
        }
        if (result != 1) {
                dev_err(dev, "%s: get config number bad return length: %d\n",
                                                        __func__, result);
-               return -EIO;
+               result = -EIO;
+               goto out;
        }
 
        /* get the interface number */
        result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
                                  USB_REQ_GET_INTERFACE,
                                  USB_DIR_IN | USB_RECIP_INTERFACE,
-                                 0, 0, &data, 1, 3000);
+                                 0, 0, data, 1, 3000);
        if (result < 0) {
                dev_err(dev, "%s: get interface number failed: %d\n",
                                                        __func__, result);
-               return result;
+               goto out;
        }
        if (result != 1) {
                dev_err(dev,
                        "%s: get interface number bad return length: %d\n",
                                                        __func__, result);
-               return -EIO;
+               result = -EIO;
+               goto out;
        }
 
-       return generic_startup(serial);
+       result = generic_startup(serial);
+out:
+       kfree(data);
+
+       return result;
 }
 
 static int treo_attach(struct usb_serial *serial)
diff --git a/drivers/usb/serial/vivopay-serial.c b/drivers/usb/serial/vivopay-serial.c
new file mode 100644 (file)
index 0000000..f719d00
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2001-2005 Greg Kroah-Hartman (greg@kroah.com)
+ * Copyright (C) 2009 Outpost Embedded, LLC
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+
+#define DRIVER_VERSION "v1.0"
+#define DRIVER_DESC "ViVOpay USB Serial Driver"
+
+#define VIVOPAY_VENDOR_ID 0x1d5f
+
+
+static struct usb_device_id id_table [] = {
+       /* ViVOpay 8800 */
+       { USB_DEVICE(VIVOPAY_VENDOR_ID, 0x1004) },
+       { },
+};
+
+MODULE_DEVICE_TABLE(usb, id_table);
+
+static struct usb_driver vivopay_serial_driver = {
+       .name =                 "vivopay-serial",
+       .probe =                usb_serial_probe,
+       .disconnect =           usb_serial_disconnect,
+       .id_table =             id_table,
+       .no_dynamic_id =        1,
+};
+
+static struct usb_serial_driver vivopay_serial_device = {
+       .driver = {
+               .owner =        THIS_MODULE,
+               .name =         "vivopay-serial",
+       },
+       .id_table =             id_table,
+       .usb_driver =           &vivopay_serial_driver,
+       .num_ports =            1,
+};
+
+static int __init vivopay_serial_init(void)
+{
+       int retval;
+       retval = usb_serial_register(&vivopay_serial_device);
+       if (retval)
+               goto failed_usb_serial_register;
+       retval = usb_register(&vivopay_serial_driver);
+       if (retval)
+               goto failed_usb_register;
+       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+           DRIVER_DESC "\n");
+       return 0;
+failed_usb_register:
+       usb_serial_deregister(&vivopay_serial_device);
+failed_usb_serial_register:
+       return retval;
+}
+
+static void __exit vivopay_serial_exit(void)
+{
+       usb_deregister(&vivopay_serial_driver);
+       usb_serial_deregister(&vivopay_serial_device);
+}
+
+module_init(vivopay_serial_init);
+module_exit(vivopay_serial_exit);
+
+MODULE_AUTHOR("Forest Bond <forest.bond@outpostembedded.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
index 1093d2eb046ad06a02e4082fe0c1656fc953f332..12ed8209ca72aa594d1c33179db89a63c238298b 100644 (file)
@@ -111,17 +111,17 @@ static int debug;
    separate ID tables, and then a third table that combines them
    just for the purpose of exporting the autoloading information.
 */
-static struct usb_device_id id_table_std [] = {
+static const struct usb_device_id id_table_std[] = {
        { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_WHITE_HEAT_ID) },
        { }                                             /* Terminating entry */
 };
 
-static struct usb_device_id id_table_prerenumeration [] = {
+static const struct usb_device_id id_table_prerenumeration[] = {
        { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_FAKE_WHITE_HEAT_ID) },
        { }                                             /* Terminating entry */
 };
 
-static struct usb_device_id id_table_combined [] = {
+static const struct usb_device_id id_table_combined[] = {
        { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_WHITE_HEAT_ID) },
        { USB_DEVICE(CONNECT_TECH_VENDOR_ID, CONNECT_TECH_FAKE_WHITE_HEAT_ID) },
        { }                                             /* Terminating entry */
@@ -1492,21 +1492,9 @@ static void rx_data_softint(struct work_struct *work)
                wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
                urb = wrap->urb;
 
-               if (tty && urb->actual_length) {
-                       int len = tty_buffer_request_room(tty,
-                                                       urb->actual_length);
-                       /* This stuff can go away now I suspect */
-                       if (unlikely(len < urb->actual_length)) {
-                               spin_lock_irqsave(&info->lock, flags);
-                               list_add(tmp, &info->rx_urb_q);
-                               spin_unlock_irqrestore(&info->lock, flags);
-                               tty_flip_buffer_push(tty);
-                               schedule_work(&info->rx_work);
-                               goto out;
-                       }
-                       tty_insert_flip_string(tty, urb->transfer_buffer, len);
-                       sent += len;
-               }
+               if (tty && urb->actual_length)
+                       sent += tty_insert_flip_string(tty,
+                               urb->transfer_buffer, urb->actual_length);
 
                urb->dev = port->serial->dev;
                result = usb_submit_urb(urb, GFP_ATOMIC);
index 80e65f29921cbed01c80406dddbe838feac5d11a..198bb3ed95b280de8839e8182fd8650196f3ff10 100644 (file)
@@ -202,7 +202,7 @@ static int onetouch_connect_input(struct us_data *ss)
                goto fail1;
 
        onetouch->data = usb_buffer_alloc(udev, ONETOUCH_PKT_LEN,
-                                         GFP_ATOMIC, &onetouch->data_dma);
+                                         GFP_KERNEL, &onetouch->data_dma);
        if (!onetouch->data)
                goto fail1;
 
index aadc16b5eed79c8d6ee0801c948c3172f1e4a6e9..4cc035562cc2e0669e588d4a376ad9bf1c25b032 100644 (file)
@@ -133,7 +133,7 @@ static int slave_configure(struct scsi_device *sdev)
 
                if (us->fflags & US_FL_MAX_SECTORS_MIN)
                        max_sectors = PAGE_CACHE_SIZE >> 9;
-               if (queue_max_sectors(sdev->request_queue) > max_sectors)
+               if (queue_max_hw_sectors(sdev->request_queue) > max_sectors)
                        blk_queue_max_hw_sectors(sdev->request_queue,
                                              max_sectors);
        } else if (sdev->type == TYPE_TAPE) {
@@ -484,7 +484,7 @@ static ssize_t show_max_sectors(struct device *dev, struct device_attribute *att
 {
        struct scsi_device *sdev = to_scsi_device(dev);
 
-       return sprintf(buf, "%u\n", queue_max_sectors(sdev->request_queue));
+       return sprintf(buf, "%u\n", queue_max_hw_sectors(sdev->request_queue));
 }
 
 /* Input routine for the sysfs max_sectors file */
@@ -494,9 +494,9 @@ static ssize_t store_max_sectors(struct device *dev, struct device_attribute *at
        struct scsi_device *sdev = to_scsi_device(dev);
        unsigned short ms;
 
-       if (sscanf(buf, "%hu", &ms) > 0 && ms <= SCSI_DEFAULT_MAX_SECTORS) {
+       if (sscanf(buf, "%hu", &ms) > 0) {
                blk_queue_max_hw_sectors(sdev->request_queue, ms);
-               return strlen(buf);
+               return count;
        }
        return -EINVAL; 
 }
@@ -539,7 +539,7 @@ struct scsi_host_template usb_stor_host_template = {
        .slave_configure =              slave_configure,
 
        /* lots of sg segments can be handled */
-       .sg_tablesize =                 SG_ALL,
+       .sg_tablesize =                 SCSI_MAX_SG_CHAIN_SEGMENTS,
 
        /* limit the total size of a transfer to 120 KB */
        .max_sectors =                  240,
index b62a28814ebeaec12d0a1989c433f0c067572ce9..bd3f415893d81f3ffd76d77cd6fe64f8739035ba 100644 (file)
@@ -1628,10 +1628,10 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
                return USB_STOR_TRANSPORT_ERROR;
        }
 
-       if ( (result = usbat_multiple_write(us, 
-                       registers, data, 7)) != USB_STOR_TRANSPORT_GOOD) {
+       result = usbat_multiple_write(us, registers, data, 7);
+
+       if (result != USB_STOR_TRANSPORT_GOOD)
                return result;
-       }
 
        /*
         * Write the 12-byte command header.
@@ -1643,12 +1643,11 @@ static int usbat_hp8200e_transport(struct scsi_cmnd *srb, struct us_data *us)
         * AT SPEED 4 IS UNRELIABLE!!!
         */
 
-       if ((result = usbat_write_block(us,
-                       USBAT_ATA, srb->cmnd, 12,
-                               (srb->cmnd[0]==GPCMD_BLANK ? 75 : 10), 0) !=
-                            USB_STOR_TRANSPORT_GOOD)) {
+       result = usbat_write_block(us, USBAT_ATA, srb->cmnd, 12,
+                                  srb->cmnd[0] == GPCMD_BLANK ? 75 : 10, 0);
+
+       if (result != USB_STOR_TRANSPORT_GOOD)
                return result;
-       }
 
        /* If there is response data to be read in then do it here. */
 
index cc313d16d727d0dc827627835d380249f638ab9c..468038126e5eb00ba5180585a8923575103be9d0 100644 (file)
@@ -47,6 +47,8 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 
+#include <linux/usb/quirks.h>
+
 #include <scsi/scsi.h>
 #include <scsi/scsi_eh.h>
 #include <scsi/scsi_device.h>
@@ -1297,6 +1299,10 @@ int usb_stor_port_reset(struct us_data *us)
 {
        int result;
 
+       /*for these devices we must use the class specific method */
+       if (us->pusb_dev->quirks & USB_QUIRK_RESET_MORPHS)
+               return -EPERM;
+
        result = usb_lock_device_for_reset(us->pusb_dev, us->pusb_intf);
        if (result < 0)
                US_DEBUGP("unable to lock device for reset: %d\n", result);
index 49575fba37560424fa6959f827577089995be580..98b549b1cab25f0799c8846aaa43edc98e4c8cc7 100644 (file)
@@ -1147,8 +1147,8 @@ UNUSUAL_DEV( 0x0af0, 0x7401, 0x0000, 0x0000,
                0 ),
 
 /* Reported by Jan Dumon <j.dumon@option.com>
- * This device (wrongly) has a vendor-specific device descriptor.
- * The entry is needed so usb-storage can bind to it's mass-storage
+ * These devices (wrongly) have a vendor-specific device descriptor.
+ * These entries are needed so usb-storage can bind to their mass-storage
  * interface as an interface driver */
 UNUSUAL_DEV( 0x0af0, 0x7501, 0x0000, 0x0000,
                "Option",
@@ -1156,6 +1156,90 @@ UNUSUAL_DEV( 0x0af0, 0x7501, 0x0000, 0x0000,
                US_SC_DEVICE, US_PR_DEVICE, NULL,
                0 ),
 
+UNUSUAL_DEV( 0x0af0, 0x7701, 0x0000, 0x0000,
+               "Option",
+               "GI 0451 SD-Card",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x7706, 0x0000, 0x0000,
+               "Option",
+               "GI 0451 SD-Card",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x7901, 0x0000, 0x0000,
+               "Option",
+               "GI 0452 SD-Card",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x7A01, 0x0000, 0x0000,
+               "Option",
+               "GI 0461 SD-Card",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x7A05, 0x0000, 0x0000,
+               "Option",
+               "GI 0461 SD-Card",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x8300, 0x0000, 0x0000,
+               "Option",
+               "GI 033x SD-Card",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x8302, 0x0000, 0x0000,
+               "Option",
+               "GI 033x SD-Card",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               0 ),
+
+UNUSUAL_DEV( 0x0af0, 0x8304, 0x0000, 0x0000,
+               "Option",
+               "GI 033x SD-Card",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xc100, 0x0000, 0x0000,
+               "Option",
+               "GI 070x SD-Card",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xd057, 0x0000, 0x0000,
+               "Option",
+               "GI 1505 SD-Card",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xd058, 0x0000, 0x0000,
+               "Option",
+               "GI 1509 SD-Card",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xd157, 0x0000, 0x0000,
+               "Option",
+               "GI 1515 SD-Card",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xd257, 0x0000, 0x0000,
+               "Option",
+               "GI 1215 SD-Card",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               0 ),
+
+UNUSUAL_DEV( 0x0af0, 0xd357, 0x0000, 0x0000,
+               "Option",
+               "GI 1505 SD-Card",
+               US_SC_DEVICE, US_PR_DEVICE, NULL,
+               0 ),
+
 /* Reported by Ben Efros <ben@pc-doctor.com> */
 UNUSUAL_DEV( 0x0bc2, 0x3010, 0x0000, 0x0000,
                "Seagate",
index b1e579c5c97cbb90bc19be3619d41aaee1f8e6f4..61522787f39cdd4f2fbfd99d7467be4c62757031 100644 (file)
@@ -28,7 +28,7 @@
 #define USB_SKEL_PRODUCT_ID    0xfff0
 
 /* table of devices that work with this driver */
-static struct usb_device_id skel_table[] = {
+static const struct usb_device_id skel_table[] = {
        { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
        { }                                     /* Terminating entry */
 };
index 25eae405f62252bd9cffef3c4dba28ab100ad1de..51a8e0d5789d0da9654e13dca6e6ab53290d51cc 100644 (file)
@@ -641,7 +641,7 @@ static void cbaf_disconnect(struct usb_interface *iface)
        kzfree(cbaf);
 }
 
-static struct usb_device_id cbaf_id_table[] = {
+static const struct usb_device_id cbaf_id_table[] = {
        { USB_INTERFACE_INFO(0xef, 0x03, 0x01), },
        { },
 };
index dced419f7abac944a2f13f2cb661b8de31fbc632..1c918286159cd683f71916c891ba9cd7d6f5753e 100644 (file)
@@ -868,7 +868,7 @@ static struct usb_wireless_cap_descriptor wusb_cap_descr_default = {
  * reference that we'll drop.
  *
  * First we need to determine if the device is a WUSB device (else we
- * ignore it). For that we use the speed setting (USB_SPEED_VARIABLE)
+ * ignore it). For that we use the speed setting (USB_SPEED_WIRELESS)
  * [FIXME: maybe we'd need something more definitive]. If so, we track
  * it's usb_busd and from there, the WUSB HC.
  *
index 3b52161e6e9cd8d5af017879f78613eb11f7b729..2d827397e30b2dbddd121342a8899d9e028b0867 100644 (file)
@@ -263,7 +263,7 @@ int wusbhc_chid_set(struct wusbhc *wusbhc, const struct wusb_ckhdid *chid)
 {
        int result = 0;
 
-       if (memcmp(chid, &wusb_ckhdid_zero, sizeof(chid)) == 0)
+       if (memcmp(chid, &wusb_ckhdid_zero, sizeof(*chid)) == 0)
                chid = NULL;
 
        mutex_lock(&wusbhc->mutex);
index eb677cf56106cc17dfc1f05873c9478e93813935..9239d033a0a3a94f503d11682bf6324a53179bd8 100644 (file)
@@ -2,8 +2,8 @@
 #define _LINUX_TTY_FLIP_H
 
 extern int tty_buffer_request_room(struct tty_struct *tty, size_t size);
-extern int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, size_t size);
 extern int tty_insert_flip_string_flags(struct tty_struct *tty, const unsigned char *chars, const char *flags, size_t size);
+extern int tty_insert_flip_string_fixed_flag(struct tty_struct *tty, const unsigned char *chars, char flag, size_t size);
 extern int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size);
 extern int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size);
 void tty_schedule_flip(struct tty_struct *tty);
@@ -20,4 +20,9 @@ static inline int tty_insert_flip_char(struct tty_struct *tty,
        return tty_insert_flip_string_flags(tty, &ch, &flag, 1);
 }
 
+static inline int tty_insert_flip_string(struct tty_struct *tty, const unsigned char *chars, size_t size)
+{
+       return tty_insert_flip_string_fixed_flag(tty, chars, TTY_NORMAL, size);
+}
+
 #endif /* _LINUX_TTY_FLIP_H */
index 332eaea610217aab63378e27daf8afe3720b6a6c..3492abf82e75907210bc1acfff6e960811f5a1e8 100644 (file)
@@ -122,7 +122,6 @@ enum usb_interface_condition {
  *     number from the USB core by calling usb_register_dev().
  * @condition: binding state of the interface: not bound, binding
  *     (in probe()), bound to a driver, or unbinding (in disconnect())
- * @is_active: flag set when the interface is bound and not suspended.
  * @sysfs_files_created: sysfs attributes exist
  * @ep_devs_created: endpoint child pseudo-devices exist
  * @unregistering: flag set when the interface is being unregistered
@@ -135,8 +134,7 @@ enum usb_interface_condition {
  * @dev: driver model's view of this device
  * @usb_dev: if an interface is bound to the USB major, this will point
  *     to the sysfs representation for that device.
- * @pm_usage_cnt: PM usage counter for this interface; autosuspend is not
- *     allowed unless the counter is 0.
+ * @pm_usage_cnt: PM usage counter for this interface
  * @reset_ws: Used for scheduling resets from atomic context.
  * @reset_running: set to 1 if the interface is currently running a
  *      queued reset so that usb_cancel_queued_reset() doesn't try to
@@ -184,7 +182,6 @@ struct usb_interface {
        int minor;                      /* minor number this interface is
                                         * bound to */
        enum usb_interface_condition condition;         /* state of binding */
-       unsigned is_active:1;           /* the interface is not suspended */
        unsigned sysfs_files_created:1; /* the sysfs attributes exist */
        unsigned ep_devs_created:1;     /* endpoint "devices" exist */
        unsigned unregistering:1;       /* unregistration is in progress */
@@ -401,7 +398,6 @@ struct usb_tt;
  * @portnum: parent port number (origin 1)
  * @level: number of USB hub ancestors
  * @can_submit: URBs may be submitted
- * @discon_suspended: disconnected while suspended
  * @persist_enabled:  USB_PERSIST enabled for this device
  * @have_langid: whether string_langid is valid
  * @authorized: policy has said we can use it;
@@ -421,20 +417,15 @@ struct usb_tt;
  * @usbfs_dentry: usbfs dentry entry for the device
  * @maxchild: number of ports if hub
  * @children: child devices - USB devices that are attached to this hub
- * @pm_usage_cnt: usage counter for autosuspend
  * @quirks: quirks of the whole device
  * @urbnum: number of URBs submitted for the whole device
  * @active_duration: total time device is not suspended
- * @autosuspend: for delayed autosuspends
- * @autoresume: for autoresumes requested while in_interrupt
- * @pm_mutex: protects PM operations
  * @last_busy: time of last use
  * @autosuspend_delay: in jiffies
  * @connect_time: time device was first connected
  * @do_remote_wakeup:  remote wakeup should be enabled
  * @reset_resume: needs reset instead of resume
  * @autosuspend_disabled: autosuspend disabled by the user
- * @skip_sys_resume: skip the next system resume
  * @wusb_dev: if this is a Wireless USB device, link to the WUSB
  *     specific data for the device.
  * @slot_id: Slot ID assigned by xHCI
@@ -475,7 +466,6 @@ struct usb_device {
        u8 level;
 
        unsigned can_submit:1;
-       unsigned discon_suspended:1;
        unsigned persist_enabled:1;
        unsigned have_langid:1;
        unsigned authorized:1;
@@ -499,17 +489,12 @@ struct usb_device {
        int maxchild;
        struct usb_device *children[USB_MAXCHILDREN];
 
-       int pm_usage_cnt;
        u32 quirks;
        atomic_t urbnum;
 
        unsigned long active_duration;
 
 #ifdef CONFIG_PM
-       struct delayed_work autosuspend;
-       struct work_struct autoresume;
-       struct mutex pm_mutex;
-
        unsigned long last_busy;
        int autosuspend_delay;
        unsigned long connect_time;
@@ -517,7 +502,6 @@ struct usb_device {
        unsigned do_remote_wakeup:1;
        unsigned reset_resume:1;
        unsigned autosuspend_disabled:1;
-       unsigned skip_sys_resume:1;
 #endif
        struct wusb_dev *wusb_dev;
        int slot_id;
@@ -542,21 +526,15 @@ extern struct usb_device *usb_find_device(u16 vendor_id, u16 product_id);
 
 /* USB autosuspend and autoresume */
 #ifdef CONFIG_USB_SUSPEND
+extern int usb_enable_autosuspend(struct usb_device *udev);
+extern int usb_disable_autosuspend(struct usb_device *udev);
+
 extern int usb_autopm_get_interface(struct usb_interface *intf);
 extern void usb_autopm_put_interface(struct usb_interface *intf);
 extern int usb_autopm_get_interface_async(struct usb_interface *intf);
 extern void usb_autopm_put_interface_async(struct usb_interface *intf);
-
-static inline void usb_autopm_get_interface_no_resume(
-               struct usb_interface *intf)
-{
-       atomic_inc(&intf->pm_usage_cnt);
-}
-static inline void usb_autopm_put_interface_no_suspend(
-               struct usb_interface *intf)
-{
-       atomic_dec(&intf->pm_usage_cnt);
-}
+extern void usb_autopm_get_interface_no_resume(struct usb_interface *intf);
+extern void usb_autopm_put_interface_no_suspend(struct usb_interface *intf);
 
 static inline void usb_mark_last_busy(struct usb_device *udev)
 {
@@ -565,6 +543,11 @@ static inline void usb_mark_last_busy(struct usb_device *udev)
 
 #else
 
+static inline int usb_enable_autosuspend(struct usb_device *udev)
+{ return 0; }
+static inline int usb_disable_autosuspend(struct usb_device *udev)
+{ return 0; }
+
 static inline int usb_autopm_get_interface(struct usb_interface *intf)
 { return 0; }
 static inline int usb_autopm_get_interface_async(struct usb_interface *intf)
@@ -1583,14 +1566,18 @@ extern void usb_register_notify(struct notifier_block *nb);
 extern void usb_unregister_notify(struct notifier_block *nb);
 
 #ifdef DEBUG
-#define dbg(format, arg...) printk(KERN_DEBUG "%s: " format "\n" , \
-       __FILE__ , ## arg)
+#define dbg(format, arg...)                                            \
+       printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg)
 #else
-#define dbg(format, arg...) do {} while (0)
+#define dbg(format, arg...)                                            \
+do {                                                                   \
+       if (0)                                                          \
+               printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg); \
+} while (0)
 #endif
 
-#define err(format, arg...) printk(KERN_ERR KBUILD_MODNAME ": " \
-       format "\n" , ## arg)
+#define err(format, arg...)                                    \
+       printk(KERN_ERR KBUILD_MODNAME ": " format "\n", ##arg)
 
 /* debugfs stuff */
 extern struct dentry *usb_debug_root;
index 54c446309a2afb7d2cb8ed80298d48d61530fee9..29fd73b0bffc97bb56528a2f7fa4194def8623c6 100644 (file)
@@ -5,4 +5,3 @@ header-y += gadgetfs.h
 header-y += midi.h
 header-y += g_printer.h
 header-y += tmc.h
-header-y += vstusb.h
index 6311fa2d9f824248351aab69e0ad624a36b4cc55..baf41c8616e930e959d456e28e8cdfac0306e00a 100644 (file)
@@ -15,6 +15,7 @@ struct usba_ep_data {
 
 struct usba_platform_data {
        int                     vbus_pin;
+       int                     vbus_pin_inverted;
        int                     num_ep;
        struct usba_ep_data     ep[0];
 };
index 94012e649d86ce18f0a5dedc2511abeead1f46d6..e58369ff8168b7a81058efa3b060a807284ff73f 100644 (file)
@@ -775,7 +775,7 @@ enum usb_device_speed {
        USB_SPEED_UNKNOWN = 0,                  /* enumerating */
        USB_SPEED_LOW, USB_SPEED_FULL,          /* usb 1.1 */
        USB_SPEED_HIGH,                         /* usb 2.0 */
-       USB_SPEED_VARIABLE,                     /* wireless (usb 2.5) */
+       USB_SPEED_WIRELESS,                     /* wireless (usb 2.5) */
        USB_SPEED_SUPER,                        /* usb 3.0 */
 };
 
index 5dc2f227a0f1591bc5a8dd1165a3218da2901a62..7acef0234c0ec800c0beef24fe9cc98ce43beafc 100644 (file)
@@ -30,26 +30,26 @@ struct musb_hdrc_eps_bits {
 struct musb_hdrc_config {
        /* MUSB configuration-specific details */
        unsigned        multipoint:1;   /* multipoint device */
-       unsigned        dyn_fifo:1;     /* supports dynamic fifo sizing */
-       unsigned        soft_con:1;     /* soft connect required */
-       unsigned        utm_16:1;       /* utm data witdh is 16 bits */
+       unsigned        dyn_fifo:1 __deprecated; /* supports dynamic fifo sizing */
+       unsigned        soft_con:1 __deprecated; /* soft connect required */
+       unsigned        utm_16:1 __deprecated; /* utm data witdh is 16 bits */
        unsigned        big_endian:1;   /* true if CPU uses big-endian */
        unsigned        mult_bulk_tx:1; /* Tx ep required for multbulk pkts */
        unsigned        mult_bulk_rx:1; /* Rx ep required for multbulk pkts */
        unsigned        high_iso_tx:1;  /* Tx ep required for HB iso */
        unsigned        high_iso_rx:1;  /* Rx ep required for HD iso */
-       unsigned        dma:1;          /* supports DMA */
-       unsigned        vendor_req:1;   /* vendor registers required */
+       unsigned        dma:1 __deprecated; /* supports DMA */
+       unsigned        vendor_req:1 __deprecated; /* vendor registers required */
 
        u8              num_eps;        /* number of endpoints _with_ ep0 */
-       u8              dma_channels;   /* number of dma channels */
+       u8              dma_channels __deprecated; /* number of dma channels */
        u8              dyn_fifo_size;  /* dynamic size in bytes */
-       u8              vendor_ctrl;    /* vendor control reg width */
-       u8              vendor_stat;    /* vendor status reg witdh */
-       u8              dma_req_chan;   /* bitmask for required dma channels */
+       u8              vendor_ctrl __deprecated; /* vendor control reg width */
+       u8              vendor_stat __deprecated; /* vendor status reg witdh */
+       u8              dma_req_chan __deprecated; /* bitmask for required dma channels */
        u8              ram_bits;       /* ram address size */
 
-       struct musb_hdrc_eps_bits *eps_bits;
+       struct musb_hdrc_eps_bits *eps_bits __deprecated;
 #ifdef CONFIG_BLACKFIN
         /* A GPIO controlling VRSEL in Blackfin */
         unsigned int    gpio_vrsel;
@@ -76,6 +76,9 @@ struct musb_hdrc_platform_data {
        /* (HOST or OTG) msec/2 after VBUS on till power good */
        u8              potpgt;
 
+       /* (HOST or OTG) program PHY for external Vbus */
+       unsigned        extvbus:1;
+
        /* Power the device on or off */
        int             (*set_power)(int state);
 
index fef0972c814672ec04f8b3d60b269a2d9ad8f46b..f8302d036a7674e33109bf8fce16d67325d2d17a 100644 (file)
@@ -9,6 +9,8 @@
 #ifndef __LINUX_USB_OTG_H
 #define __LINUX_USB_OTG_H
 
+#include <linux/notifier.h>
+
 /* OTG defines lots of enumeration states before device reset */
 enum usb_otg_state {
        OTG_STATE_UNDEFINED = 0,
@@ -33,6 +35,14 @@ enum usb_otg_state {
        OTG_STATE_A_VBUS_ERR,
 };
 
+enum usb_xceiv_events {
+       USB_EVENT_NONE,         /* no events or cable disconnected */
+       USB_EVENT_VBUS,         /* vbus valid event */
+       USB_EVENT_ID,           /* id was grounded */
+       USB_EVENT_CHARGER,      /* usb dedicated charger */
+       USB_EVENT_ENUMERATED,   /* gadget driver enumerated */
+};
+
 #define USB_OTG_PULLUP_ID              (1 << 0)
 #define USB_OTG_PULLDOWN_DP            (1 << 1)
 #define USB_OTG_PULLDOWN_DM            (1 << 2)
@@ -70,6 +80,9 @@ struct otg_transceiver {
        struct otg_io_access_ops        *io_ops;
        void __iomem                    *io_priv;
 
+       /* for notification of usb_xceiv_events */
+       struct blocking_notifier_head   notifier;
+
        /* to pass extra port status to the root hub */
        u16                     port_status;
        u16                     port_change;
@@ -213,6 +226,18 @@ otg_start_srp(struct otg_transceiver *otg)
        return otg->start_srp(otg);
 }
 
+/* notifiers */
+static inline int
+otg_register_notifier(struct otg_transceiver *otg, struct notifier_block *nb)
+{
+       return blocking_notifier_chain_register(&otg->notifier, nb);
+}
+
+static inline void
+otg_unregister_notifier(struct otg_transceiver *otg, struct notifier_block *nb)
+{
+       blocking_notifier_chain_unregister(&otg->notifier, nb);
+}
 
 /* for OTG controller drivers (and maybe other stuff) */
 extern int usb_bus_start_enum(struct usb_bus *bus, unsigned port_num);
index 2526f3bbd273e522e1ff77b2ba404c87d9a5a56a..0a555dd131fcdc24db1b8debe89f641fcc5b20bb 100644 (file)
@@ -19,4 +19,7 @@
 /* device can't handle its Configuration or Interface strings */
 #define USB_QUIRK_CONFIG_INTF_STRINGS  0x00000008
 
+/*device will morph if reset, don't use reset for handling errors */
+#define USB_QUIRK_RESET_MORPHS         0x00000010
+
 #endif /* __LINUX_USB_QUIRKS_H */
index 1819396ed5015df55d335934e1b2cff8fff4da0f..0a458b86193365d9113f49abc360faf00b2b2519 100644 (file)
@@ -351,14 +351,11 @@ static inline void usb_serial_debug_data(int debug,
 
 /* Use our own dbg macro */
 #undef dbg
-#define dbg(format, arg...) \
-       do { \
-               if (debug) \
-                       printk(KERN_DEBUG "%s: " format "\n" , __FILE__ , \
-                               ## arg); \
-       } while (0)
-
-
+#define dbg(format, arg...)                                            \
+do {                                                                   \
+       if (debug)                                                      \
+               printk(KERN_DEBUG "%s: " format "\n", __FILE__, ##arg); \
+} while (0)
 
 #endif /* __LINUX_USB_SERIAL_H */
 
diff --git a/include/linux/usb/vstusb.h b/include/linux/usb/vstusb.h
deleted file mode 100644 (file)
index 1cfac67..0000000
+++ /dev/null
@@ -1,71 +0,0 @@
-/*****************************************************************************
- *  File: drivers/usb/misc/vstusb.h
- *
- *  Purpose: Support for the bulk USB Vernier Spectrophotometers
- *
- *  Author:     EQware Engineering, Inc.
- *              Oregon City, OR, USA 97045
- *
- *  Copyright:  2007, 2008
- *              Vernier Software & Technology
- *              Beaverton, OR, USA 97005
- *
- *  Web:        www.vernier.com
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
- *
- *****************************************************************************/
-/*****************************************************************************
- *
- *  The vstusb module is a standard usb 'client' driver running on top of the
- *  standard usb host controller stack.
- *
- *  In general, vstusb supports standard bulk usb pipes.  It supports multiple
- *  devices and multiple pipes per device.
- *
- *  The vstusb driver supports two interfaces:
- *  1 - ioctl SEND_PIPE/RECV_PIPE - a general bulk write/read msg
- *     interface to any pipe with timeout support;
- *  2 - standard read/write with ioctl config - offers standard read/write
- *     interface with ioctl configured pipes and timeouts.
- *
- *  Both interfaces can be signal from other process and will abort its i/o
- *  operation.
- *
- *  A timeout of 0 means NO timeout.  The user can still terminate the read via
- *  signal.
- *
- *  If using multiple threads with this driver, the user should ensure that
- *  any reads, writes, or ioctls are complete before closing the device.
- *  Changing read/write timeouts or pipes takes effect on next read/write.
- *
- *****************************************************************************/
-
-struct vstusb_args {
-       union {
-               /* this struct is used for IOCTL_VSTUSB_SEND_PIPE,      *
-                * IOCTL_VSTUSB_RECV_PIPE, and read()/write() fops      */
-               struct {
-                       void __user     *buffer;
-                       size_t          count;
-                       unsigned int    timeout_ms;
-                       int             pipe;
-               };
-
-               /* this one is used for IOCTL_VSTUSB_CONFIG_RW          */
-               struct {
-                       int rd_pipe;
-                       int rd_timeout_ms;
-                       int wr_pipe;
-                       int wr_timeout_ms;
-               };
-       };
-};
-
-#define VST_IOC_MAGIC 'L'
-#define VST_IOC_FIRST 0x20
-#define IOCTL_VSTUSB_SEND_PIPE _IO(VST_IOC_MAGIC, VST_IOC_FIRST)
-#define IOCTL_VSTUSB_RECV_PIPE _IO(VST_IOC_MAGIC, VST_IOC_FIRST + 1)
-#define IOCTL_VSTUSB_CONFIG_RW _IO(VST_IOC_MAGIC, VST_IOC_FIRST + 2)