Merge branch 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 9 Jan 2012 20:09:47 +0000 (12:09 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 9 Jan 2012 20:09:47 +0000 (12:09 -0800)
* 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (232 commits)
  USB: Add USB-ID for Multiplex RC serial adapter to cp210x.c
  xhci: Clean up 32-bit build warnings.
  USB: update documentation for usbmon
  usb: usb-storage doesn't support dynamic id currently, the patch disables the feature to fix an oops
  drivers/usb/class/cdc-acm.c: clear dangling pointer
  drivers/usb/dwc3/dwc3-pci.c: introduce missing kfree
  drivers/usb/host/isp1760-if.c: introduce missing kfree
  usb: option: add ZD Incorporated HSPA modem
  usb: ch9: fix up MaxStreams helper
  USB: usb-skeleton.c: cleanup open_count
  USB: usb-skeleton.c: fix open/disconnect race
  xhci: Properly handle COMP_2ND_BW_ERR
  USB: remove dead code from suspend/resume path
  USB: add quirk for another camera
  drivers: usb: wusbcore: Fix dependency for USB_WUSB
  xhci: Better debugging for critical host errors.
  xhci: Be less verbose during URB cancellation.
  xhci: Remove debugging about ring structure allocation.
  xhci: Remove debugging about toggling cycle bits.
  xhci: Remove debugging for individual transfers.
  ...

203 files changed:
Documentation/ABI/testing/sysfs-bus-usb
Documentation/feature-removal-schedule.txt
Documentation/kernel-parameters.txt
Documentation/usb/usbmon.txt
arch/arm/mach-omap2/board-n8x0.c
arch/arm/mach-s3c2416/mach-smdk2416.c
arch/arm/plat-samsung/devs.c
arch/arm/plat-samsung/include/plat/udc.h
drivers/hv/hv_kvp.c
drivers/usb/Makefile
drivers/usb/c67x00/c67x00-drv.c
drivers/usb/c67x00/c67x00-hcd.c
drivers/usb/class/cdc-acm.c
drivers/usb/class/cdc-acm.h
drivers/usb/core/devio.c
drivers/usb/core/driver.c
drivers/usb/core/hcd-pci.c
drivers/usb/core/hcd.c
drivers/usb/core/hub.c
drivers/usb/core/quirks.c
drivers/usb/core/usb.h
drivers/usb/dwc3/Kconfig
drivers/usb/dwc3/Makefile
drivers/usb/dwc3/core.c
drivers/usb/dwc3/core.h
drivers/usb/dwc3/debugfs.c
drivers/usb/dwc3/dwc3-omap.c
drivers/usb/dwc3/dwc3-pci.c
drivers/usb/dwc3/ep0.c
drivers/usb/dwc3/gadget.c
drivers/usb/dwc3/gadget.h
drivers/usb/dwc3/host.c [new file with mode: 0644]
drivers/usb/dwc3/io.h
drivers/usb/gadget/Kconfig
drivers/usb/gadget/Makefile
drivers/usb/gadget/amd5536udc.c
drivers/usb/gadget/at91_udc.c
drivers/usb/gadget/atmel_usba_udc.c
drivers/usb/gadget/ci13xxx_udc.c
drivers/usb/gadget/ci13xxx_udc.h
drivers/usb/gadget/composite.c
drivers/usb/gadget/dbgp.c
drivers/usb/gadget/dummy_hcd.c
drivers/usb/gadget/epautoconf.c
drivers/usb/gadget/f_fs.c
drivers/usb/gadget/f_mass_storage.c
drivers/usb/gadget/file_storage.c
drivers/usb/gadget/fsl_qe_udc.c
drivers/usb/gadget/fsl_udc_core.c
drivers/usb/gadget/fusb300_udc.c
drivers/usb/gadget/goku_udc.c
drivers/usb/gadget/imx_udc.c
drivers/usb/gadget/inode.c
drivers/usb/gadget/langwell_udc.c
drivers/usb/gadget/m66592-udc.c
drivers/usb/gadget/mv_udc.h
drivers/usb/gadget/mv_udc_core.c
drivers/usb/gadget/net2272.c
drivers/usb/gadget/net2280.c
drivers/usb/gadget/omap_udc.c
drivers/usb/gadget/pch_udc.c
drivers/usb/gadget/printer.c
drivers/usb/gadget/pxa25x_udc.c
drivers/usb/gadget/pxa27x_udc.c
drivers/usb/gadget/r8a66597-udc.c
drivers/usb/gadget/s3c-hsotg.c
drivers/usb/gadget/s3c-hsudc.c
drivers/usb/gadget/s3c2410_udc.c
drivers/usb/gadget/udc-core.c
drivers/usb/gadget/usbstring.c
drivers/usb/host/Kconfig
drivers/usb/host/ehci-au1xxx.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-mv.c [new file with mode: 0644]
drivers/usb/host/ehci-octeon.c
drivers/usb/host/ehci-omap.c
drivers/usb/host/ehci-ps3.c
drivers/usb/host/ehci-pxa168.c
drivers/usb/host/ehci-q.c
drivers/usb/host/ehci-s5p.c
drivers/usb/host/ehci-vt8500.c
drivers/usb/host/ehci-w90x900.c
drivers/usb/host/ehci-xls.c
drivers/usb/host/fhci-hcd.c
drivers/usb/host/fsl-mph-dr-of.c
drivers/usb/host/hwa-hc.c
drivers/usb/host/imx21-hcd.c
drivers/usb/host/isp1760-hcd.c
drivers/usb/host/isp1760-if.c
drivers/usb/host/ohci-au1xxx.c
drivers/usb/host/ohci-dbg.c
drivers/usb/host/ohci-ep93xx.c
drivers/usb/host/ohci-hcd.c
drivers/usb/host/ohci-hub.c
drivers/usb/host/ohci-omap.c
drivers/usb/host/ohci-pci.c
drivers/usb/host/ohci-pxa27x.c
drivers/usb/host/ohci-q.c
drivers/usb/host/ohci-s3c2410.c
drivers/usb/host/ohci-sh.c
drivers/usb/host/ohci-sm501.c
drivers/usb/host/ohci-spear.c
drivers/usb/host/ohci-tmio.c
drivers/usb/host/ohci-xls.c
drivers/usb/host/ohci.h
drivers/usb/host/oxu210hp-hcd.c
drivers/usb/host/uhci-q.c
drivers/usb/host/whci/qset.c
drivers/usb/host/xhci-hub.c
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci-ring.c
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h
drivers/usb/misc/isight_firmware.c
drivers/usb/misc/usbtest.c
drivers/usb/musb/Kconfig
drivers/usb/musb/Makefile
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_core.h
drivers/usb/musb/musb_debug.h
drivers/usb/musb/musb_debugfs.c
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musb_gadget_ep0.c
drivers/usb/musb/musb_io.h
drivers/usb/musb/omap2430.c
drivers/usb/musb/tusb6010.c
drivers/usb/musb/ux500_dma.c
drivers/usb/otg/Kconfig
drivers/usb/otg/Makefile
drivers/usb/otg/fsl_otg.c
drivers/usb/otg/mv_otg.c [new file with mode: 0644]
drivers/usb/otg/mv_otg.h [new file with mode: 0644]
drivers/usb/renesas_usbhs/common.c
drivers/usb/renesas_usbhs/common.h
drivers/usb/renesas_usbhs/fifo.c
drivers/usb/renesas_usbhs/fifo.h
drivers/usb/renesas_usbhs/mod.c
drivers/usb/renesas_usbhs/mod_gadget.c
drivers/usb/renesas_usbhs/mod_host.c
drivers/usb/renesas_usbhs/pipe.c
drivers/usb/renesas_usbhs/pipe.h
drivers/usb/serial/ChangeLog.history [deleted file]
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/ftdi_sio.c
drivers/usb/serial/garmin_gps.c
drivers/usb/serial/generic.c
drivers/usb/serial/io_edgeport.c
drivers/usb/serial/io_ti.c
drivers/usb/serial/ipaq.c
drivers/usb/serial/ir-usb.c
drivers/usb/serial/iuu_phoenix.c
drivers/usb/serial/keyspan.c
drivers/usb/serial/keyspan_pda.c
drivers/usb/serial/kobil_sct.c
drivers/usb/serial/mct_u232.c
drivers/usb/serial/mos7720.c
drivers/usb/serial/mos7840.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/sierra.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/whiteheat.c
drivers/usb/storage/alauda.c
drivers/usb/storage/cypress_atacb.c
drivers/usb/storage/datafab.c
drivers/usb/storage/ene_ub6250.c
drivers/usb/storage/freecom.c
drivers/usb/storage/isd200.c
drivers/usb/storage/jumpshot.c
drivers/usb/storage/karma.c
drivers/usb/storage/onetouch.c
drivers/usb/storage/realtek_cr.c
drivers/usb/storage/sddr09.c
drivers/usb/storage/sddr55.c
drivers/usb/storage/shuttle_usbat.c
drivers/usb/storage/usb.c
drivers/usb/usb-skeleton.c
drivers/usb/wusbcore/Kconfig
drivers/usb/wusbcore/security.c
drivers/uwb/est.c
fs/fat/namei_vfat.c
fs/nls/nls_base.c
include/linux/nls.h
include/linux/platform_data/mv_usb.h
include/linux/platform_data/s3c-hsudc.h [new file with mode: 0644]
include/linux/usb.h
include/linux/usb/ch11.h
include/linux/usb/ch9.h
include/linux/usb/gadget.h
include/linux/usb/hcd.h
include/linux/usb/renesas_usbhs.h
include/linux/usb/serial.h

index e647378..b4f5487 100644 (file)
@@ -119,6 +119,31 @@ Description:
                Write a 1 to force the device to disconnect
                (equivalent to unplugging a wired USB device).
 
+What:          /sys/bus/usb/drivers/.../new_id
+Date:          October 2011
+Contact:       linux-usb@vger.kernel.org
+Description:
+               Writing a device ID to this file will attempt to
+               dynamically add a new device ID to a USB device driver.
+               This may allow the driver to support more hardware than
+               was included in the driver's static device ID support
+               table at compile time. The format for the device ID is:
+               idVendor idProduct bInterfaceClass.
+               The vendor ID and device ID fields are required, the
+               interface class is optional.
+               Upon successfully adding an ID, the driver will probe
+               for the device and attempt to bind to it.  For example:
+               # echo "8086 10f5" > /sys/bus/usb/drivers/foo/new_id
+
+What:          /sys/bus/usb-serial/drivers/.../new_id
+Date:          October 2011
+Contact:       linux-usb@vger.kernel.org
+Description:
+               For serial USB drivers, this attribute appears under the
+               extra bus folder "usb-serial" in sysfs; apart from that
+               difference, all descriptions from the entry
+               "/sys/bus/usb/drivers/.../new_id" apply.
+
 What:          /sys/bus/usb/drivers/.../remove_id
 Date:          November 2009
 Contact:       CHENG Renquan <rqcheng@smu.edu.sg>
index a1e7f3e..284b442 100644 (file)
@@ -523,6 +523,20 @@ Why:    In 3.0, we can now autodetect internal 3G device and already have
        information log when acer-wmi initial.
 Who:    Lee, Chun-Yi <jlee@novell.com>
 
+---------------------------
+
+What:  /sys/devices/platform/_UDC_/udc/_UDC_/is_dualspeed file and
+       is_dualspeed line in /sys/devices/platform/ci13xxx_*/udc/device file.
+When:  3.8
+Why:   The is_dualspeed file is superseded by maximum_speed in the same
+       directory and is_dualspeed line in device file is superseded by
+       max_speed line in the same file.
+
+       The maximum_speed/max_speed specifies maximum speed supported by UDC.
+       To check if dualspeeed is supported, check if the value is >= 3.
+       Various possible speeds are defined in <linux/usb/ch9.h>.
+Who:   Michal Nazarewicz <mina86@mina86.com>
+
 ----------------------------
 
 What:  The XFS nodelaylog mount option
index e229769..7b2e5c5 100644 (file)
@@ -2637,6 +2637,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        [USB] Start with the old device initialization
                        scheme (default 0 = off).
 
+       usbcore.usbfs_memory_mb=
+                       [USB] Memory limit (in MB) for buffers allocated by
+                       usbfs (default = 16, 0 = max = 2047).
+
        usbcore.use_both_schemes=
                        [USB] Try the other device initialization scheme
                        if the first one fails (default 1 = enabled).
index a4efa04..5335fa8 100644 (file)
@@ -47,10 +47,11 @@ This allows to filter away annoying devices that talk continuously.
 
 2. Find which bus connects to the desired device
 
-Run "cat /proc/bus/usb/devices", and find the T-line which corresponds to
-the device. Usually you do it by looking for the vendor string. If you have
-many similar devices, unplug one and compare two /proc/bus/usb/devices outputs.
-The T-line will have a bus number. Example:
+Run "cat /sys/kernel/debug/usb/devices", and find the T-line which corresponds
+to the device. Usually you do it by looking for the vendor string. If you have
+many similar devices, unplug one and compare the two
+/sys/kernel/debug/usb/devices outputs. The T-line will have a bus number.
+Example:
 
 T:  Bus=03 Lev=01 Prnt=01 Port=00 Cnt=01 Dev#=  2 Spd=12  MxCh= 0
 D:  Ver= 1.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS= 8 #Cfgs=  1
@@ -58,7 +59,10 @@ P:  Vendor=0557 ProdID=2004 Rev= 1.00
 S:  Manufacturer=ATEN
 S:  Product=UC100KM V2.00
 
-Bus=03 means it's bus 3.
+"Bus=03" means it's bus 3. Alternatively, you can look at the output from
+"lsusb" and get the bus number from the appropriate line. Example:
+
+Bus 003 Device 002: ID 0557:2004 ATEN UC100KM V2.00
 
 3. Start 'cat'
 
index cef2cf1..72d76ed 100644 (file)
@@ -46,7 +46,7 @@ static struct device *mmc_device;
 #define TUSB6010_GPIO_ENABLE   0
 #define TUSB6010_DMACHAN       0x3f
 
-#ifdef CONFIG_USB_MUSB_TUSB6010
+#if defined(CONFIG_USB_MUSB_TUSB6010) || defined(CONFIG_USB_MUSB_TUSB6010_MODULE)
 /*
  * Enable or disable power to TUSB6010. When enabling, turn on 3.3 V and
  * 1.5 V voltage regulators of PM companion chip. Companion chip will then
index 66b7173..eebe1e7 100644 (file)
@@ -50,6 +50,7 @@
 #include <plat/nand.h>
 #include <plat/sdhci.h>
 #include <plat/udc.h>
+#include <linux/platform_data/s3c-hsudc.h>
 
 #include <plat/regs-fb-v4.h>
 #include <plat/fb.h>
index 4ca8b57..92b4c02 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/mmc/host.h>
 #include <linux/ioport.h>
+#include <linux/platform_data/s3c-hsudc.h>
 
 #include <asm/irq.h>
 #include <asm/pmu.h>
index 8c22d58..de8e228 100644 (file)
@@ -37,20 +37,7 @@ struct s3c2410_udc_mach_info {
 
 extern void __init s3c24xx_udc_set_platdata(struct s3c2410_udc_mach_info *);
 
-/**
- * s3c24xx_hsudc_platdata - Platform data for USB High-Speed gadget controller.
- * @epnum: Number of endpoints to be instantiated by the controller driver.
- * @gpio_init: Platform specific USB related GPIO initialization.
- * @gpio_uninit: Platform specific USB releted GPIO uninitialzation.
- *
- * Representation of platform data for the S3C24XX USB 2.0 High Speed gadget
- * controllers.
- */
-struct s3c24xx_hsudc_platdata {
-       unsigned int    epnum;
-       void            (*gpio_init)(void);
-       void            (*gpio_uninit)(void);
-};
+struct s3c24xx_hsudc_platdata;
 
 extern void __init s3c24xx_hsudc_set_platdata(struct s3c24xx_hsudc_platdata *pd);
 
index 89f5244..0e8343f 100644 (file)
@@ -212,11 +212,13 @@ kvp_respond_to_host(char *key, char *value, int error)
         * The windows host expects the key/value pair to be encoded
         * in utf16.
         */
-       keylen = utf8s_to_utf16s(key_name, strlen(key_name),
-                               (wchar_t *)kvp_data->data.key);
+       keylen = utf8s_to_utf16s(key_name, strlen(key_name), UTF16_HOST_ENDIAN,
+                               (wchar_t *) kvp_data->data.key,
+                               HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2);
        kvp_data->data.key_size = 2*(keylen + 1); /* utf16 encoding */
-       valuelen = utf8s_to_utf16s(value, strlen(value),
-                               (wchar_t *)kvp_data->data.value);
+       valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN,
+                               (wchar_t *) kvp_data->data.value,
+                               HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2);
        kvp_data->data.value_size = 2*(valuelen + 1); /* utf16 encoding */
 
        kvp_data->data.value_type = REG_SZ; /* all our values are strings */
index 75eca76..53a7bc0 100644 (file)
@@ -6,6 +6,8 @@
 
 obj-$(CONFIG_USB)              += core/
 
+obj-$(CONFIG_USB_OTG_UTILS)    += otg/
+
 obj-$(CONFIG_USB_DWC3)         += dwc3/
 
 obj-$(CONFIG_USB_MON)          += mon/
@@ -51,7 +53,6 @@ obj-$(CONFIG_USB_SPEEDTOUCH)  += atm/
 
 obj-$(CONFIG_USB_MUSB_HDRC)    += musb/
 obj-$(CONFIG_USB_RENESAS_USBHS)        += renesas_usbhs/
-obj-$(CONFIG_USB_OTG_UTILS)    += otg/
 obj-$(CONFIG_USB_GADGET)       += gadget/
 
 obj-$(CONFIG_USB_COMMON)       += usb-common.o
index 57ae44c..6f3b6e2 100644 (file)
@@ -225,21 +225,10 @@ static struct platform_driver c67x00_driver = {
                .name = "c67x00",
        },
 };
-MODULE_ALIAS("platform:c67x00");
-
-static int __init c67x00_init(void)
-{
-       return platform_driver_register(&c67x00_driver);
-}
 
-static void __exit c67x00_exit(void)
-{
-       platform_driver_unregister(&c67x00_driver);
-}
-
-module_init(c67x00_init);
-module_exit(c67x00_exit);
+module_platform_driver(c67x00_driver);
 
 MODULE_AUTHOR("Peter Korsgaard, Jan Veldeman, Grant Likely");
 MODULE_DESCRIPTION("Cypress C67X00 USB Controller Driver");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:c67x00");
index d3e1356..75e47b8 100644 (file)
@@ -271,7 +271,6 @@ static void c67x00_hcd_irq(struct c67x00_sie *sie, u16 int_status, u16 msg)
        if (int_status & SOFEOP_FLG(sie->sie_num)) {
                c67x00_ll_usb_clear_status(sie, SOF_EOP_IRQ_FLG);
                c67x00_sched_kick(c67x00);
-               set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
        }
 }
 
index a8078d0..9543b19 100644 (file)
@@ -58,12 +58,62 @@ static struct usb_driver acm_driver;
 static struct tty_driver *acm_tty_driver;
 static struct acm *acm_table[ACM_TTY_MINORS];
 
-static DEFINE_MUTEX(open_mutex);
+static DEFINE_MUTEX(acm_table_lock);
 
-#define ACM_READY(acm) (acm && acm->dev && acm->port.count)
+/*
+ * acm_table accessors
+ */
 
-static const struct tty_port_operations acm_port_ops = {
-};
+/*
+ * Look up an ACM structure by index. If found and not disconnected, increment
+ * its refcount and return it with its mutex held.
+ */
+static struct acm *acm_get_by_index(unsigned index)
+{
+       struct acm *acm;
+
+       mutex_lock(&acm_table_lock);
+       acm = acm_table[index];
+       if (acm) {
+               mutex_lock(&acm->mutex);
+               if (acm->disconnected) {
+                       mutex_unlock(&acm->mutex);
+                       acm = NULL;
+               } else {
+                       tty_port_get(&acm->port);
+                       mutex_unlock(&acm->mutex);
+               }
+       }
+       mutex_unlock(&acm_table_lock);
+       return acm;
+}
+
+/*
+ * Try to find an available minor number and if found, associate it with 'acm'.
+ */
+static int acm_alloc_minor(struct acm *acm)
+{
+       int minor;
+
+       mutex_lock(&acm_table_lock);
+       for (minor = 0; minor < ACM_TTY_MINORS; minor++) {
+               if (!acm_table[minor]) {
+                       acm_table[minor] = acm;
+                       break;
+               }
+       }
+       mutex_unlock(&acm_table_lock);
+
+       return minor;
+}
+
+/* Release the minor number associated with 'acm'.  */
+static void acm_release_minor(struct acm *acm)
+{
+       mutex_lock(&acm_table_lock);
+       acm_table[acm->minor] = NULL;
+       mutex_unlock(&acm_table_lock);
+}
 
 /*
  * Functions for ACM control messages.
@@ -267,9 +317,6 @@ static void acm_ctrl_irq(struct urb *urb)
                goto exit;
        }
 
-       if (!ACM_READY(acm))
-               goto exit;
-
        usb_mark_last_busy(acm->dev);
 
        data = (unsigned char *)(dr + 1);
@@ -429,8 +476,7 @@ static void acm_write_bulk(struct urb *urb)
        spin_lock_irqsave(&acm->write_lock, flags);
        acm_write_done(acm, wb);
        spin_unlock_irqrestore(&acm->write_lock, flags);
-       if (ACM_READY(acm))
-               schedule_work(&acm->work);
+       schedule_work(&acm->work);
 }
 
 static void acm_softint(struct work_struct *work)
@@ -440,8 +486,6 @@ static void acm_softint(struct work_struct *work)
 
        dev_vdbg(&acm->data->dev, "%s\n", __func__);
 
-       if (!ACM_READY(acm))
-               return;
        tty = tty_port_tty_get(&acm->port);
        if (!tty)
                return;
@@ -453,93 +497,122 @@ static void acm_softint(struct work_struct *work)
  * TTY handlers
  */
 
-static int acm_tty_open(struct tty_struct *tty, struct file *filp)
+static int acm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
 {
        struct acm *acm;
-       int rv = -ENODEV;
-
-       mutex_lock(&open_mutex);
+       int retval;
 
-       acm = acm_table[tty->index];
-       if (!acm || !acm->dev)
-               goto out;
-       else
-               rv = 0;
+       dev_dbg(tty->dev, "%s\n", __func__);
 
-       dev_dbg(&acm->control->dev, "%s\n", __func__);
+       acm = acm_get_by_index(tty->index);
+       if (!acm)
+               return -ENODEV;
 
-       set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
+       retval = tty_init_termios(tty);
+       if (retval)
+               goto error_init_termios;
 
        tty->driver_data = acm;
-       tty_port_tty_set(&acm->port, tty);
 
-       if (usb_autopm_get_interface(acm->control) < 0)
-               goto early_bail;
-       else
-               acm->control->needs_remote_wakeup = 1;
+       /* Final install (we use the default method) */
+       tty_driver_kref_get(driver);
+       tty->count++;
+       driver->ttys[tty->index] = tty;
+
+       return 0;
+
+error_init_termios:
+       tty_port_put(&acm->port);
+       return retval;
+}
+
+static int acm_tty_open(struct tty_struct *tty, struct file *filp)
+{
+       struct acm *acm = tty->driver_data;
+
+       dev_dbg(tty->dev, "%s\n", __func__);
+
+       return tty_port_open(&acm->port, tty, filp);
+}
+
+static int acm_port_activate(struct tty_port *port, struct tty_struct *tty)
+{
+       struct acm *acm = container_of(port, struct acm, port);
+       int retval = -ENODEV;
+
+       dev_dbg(&acm->control->dev, "%s\n", __func__);
 
        mutex_lock(&acm->mutex);
-       if (acm->port.count++) {
-               mutex_unlock(&acm->mutex);
-               usb_autopm_put_interface(acm->control);
-               goto out;
-       }
+       if (acm->disconnected)
+               goto disconnected;
+
+       retval = usb_autopm_get_interface(acm->control);
+       if (retval)
+               goto error_get_interface;
+
+       /*
+        * FIXME: Why do we need this? Allocating 64K of physically contiguous
+        * memory is really nasty...
+        */
+       set_bit(TTY_NO_WRITE_SPLIT, &tty->flags);
+       acm->control->needs_remote_wakeup = 1;
 
        acm->ctrlurb->dev = acm->dev;
        if (usb_submit_urb(acm->ctrlurb, GFP_KERNEL)) {
                dev_err(&acm->control->dev,
                        "%s - usb_submit_urb(ctrl irq) failed\n", __func__);
-               goto bail_out;
+               goto error_submit_urb;
        }
 
-       if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) &&
+       acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS;
+       if (acm_set_control(acm, acm->ctrlout) < 0 &&
            (acm->ctrl_caps & USB_CDC_CAP_LINE))
-               goto bail_out;
+               goto error_set_control;
 
        usb_autopm_put_interface(acm->control);
 
        if (acm_submit_read_urbs(acm, GFP_KERNEL))
-               goto bail_out;
-
-       set_bit(ASYNCB_INITIALIZED, &acm->port.flags);
-       rv = tty_port_block_til_ready(&acm->port, tty, filp);
+               goto error_submit_read_urbs;
 
        mutex_unlock(&acm->mutex);
-out:
-       mutex_unlock(&open_mutex);
-       return rv;
 
-bail_out:
-       acm->port.count--;
-       mutex_unlock(&acm->mutex);
+       return 0;
+
+error_submit_read_urbs:
+       acm->ctrlout = 0;
+       acm_set_control(acm, acm->ctrlout);
+error_set_control:
+       usb_kill_urb(acm->ctrlurb);
+error_submit_urb:
        usb_autopm_put_interface(acm->control);
-early_bail:
-       mutex_unlock(&open_mutex);
-       tty_port_tty_set(&acm->port, NULL);
-       return -EIO;
+error_get_interface:
+disconnected:
+       mutex_unlock(&acm->mutex);
+       return retval;
 }
 
-static void acm_tty_unregister(struct acm *acm)
+static void acm_port_destruct(struct tty_port *port)
 {
-       int i;
+       struct acm *acm = container_of(port, struct acm, port);
+
+       dev_dbg(&acm->control->dev, "%s\n", __func__);
 
        tty_unregister_device(acm_tty_driver, acm->minor);
+       acm_release_minor(acm);
        usb_put_intf(acm->control);
-       acm_table[acm->minor] = NULL;
-       usb_free_urb(acm->ctrlurb);
-       for (i = 0; i < ACM_NW; i++)
-               usb_free_urb(acm->wb[i].urb);
-       for (i = 0; i < acm->rx_buflimit; i++)
-               usb_free_urb(acm->read_urbs[i]);
        kfree(acm->country_codes);
        kfree(acm);
 }
 
-static void acm_port_down(struct acm *acm)
+static void acm_port_shutdown(struct tty_port *port)
 {
+       struct acm *acm = container_of(port, struct acm, port);
        int i;
 
-       if (acm->dev) {
+       dev_dbg(&acm->control->dev, "%s\n", __func__);
+
+       mutex_lock(&acm->mutex);
+       if (!acm->disconnected) {
                usb_autopm_get_interface(acm->control);
                acm_set_control(acm, acm->ctrlout = 0);
                usb_kill_urb(acm->ctrlurb);
@@ -550,40 +623,28 @@ static void acm_port_down(struct acm *acm)
                acm->control->needs_remote_wakeup = 0;
                usb_autopm_put_interface(acm->control);
        }
+       mutex_unlock(&acm->mutex);
+}
+
+static void acm_tty_cleanup(struct tty_struct *tty)
+{
+       struct acm *acm = tty->driver_data;
+       dev_dbg(&acm->control->dev, "%s\n", __func__);
+       tty_port_put(&acm->port);
 }
 
 static void acm_tty_hangup(struct tty_struct *tty)
 {
        struct acm *acm = tty->driver_data;
+       dev_dbg(&acm->control->dev, "%s\n", __func__);
        tty_port_hangup(&acm->port);
-       mutex_lock(&open_mutex);
-       acm_port_down(acm);
-       mutex_unlock(&open_mutex);
 }
 
 static void acm_tty_close(struct tty_struct *tty, struct file *filp)
 {
        struct acm *acm = tty->driver_data;
-
-       /* Perform the closing process and see if we need to do the hardware
-          shutdown */
-       if (!acm)
-               return;
-
-       mutex_lock(&open_mutex);
-       if (tty_port_close_start(&acm->port, tty, filp) == 0) {
-               if (!acm->dev) {
-                       tty_port_tty_set(&acm->port, NULL);
-                       acm_tty_unregister(acm);
-                       tty->driver_data = NULL;
-               }
-               mutex_unlock(&open_mutex);
-               return;
-       }
-       acm_port_down(acm);
-       tty_port_close_end(&acm->port, tty);
-       tty_port_tty_set(&acm->port, NULL);
-       mutex_unlock(&open_mutex);
+       dev_dbg(&acm->control->dev, "%s\n", __func__);
+       tty_port_close(&acm->port, tty, filp);
 }
 
 static int acm_tty_write(struct tty_struct *tty,
@@ -595,8 +656,6 @@ static int acm_tty_write(struct tty_struct *tty,
        int wbn;
        struct acm_wb *wb;
 
-       if (!ACM_READY(acm))
-               return -EINVAL;
        if (!count)
                return 0;
 
@@ -625,8 +684,6 @@ static int acm_tty_write(struct tty_struct *tty,
 static int acm_tty_write_room(struct tty_struct *tty)
 {
        struct acm *acm = tty->driver_data;
-       if (!ACM_READY(acm))
-               return -EINVAL;
        /*
         * Do not let the line discipline to know that we have a reserve,
         * or it might get too enthusiastic.
@@ -637,7 +694,11 @@ static int acm_tty_write_room(struct tty_struct *tty)
 static int acm_tty_chars_in_buffer(struct tty_struct *tty)
 {
        struct acm *acm = tty->driver_data;
-       if (!ACM_READY(acm))
+       /*
+        * if the device was unplugged then any remaining characters fell out
+        * of the connector ;)
+        */
+       if (acm->disconnected)
                return 0;
        /*
         * This is inaccurate (overcounts), but it works.
@@ -649,9 +710,6 @@ static void acm_tty_throttle(struct tty_struct *tty)
 {
        struct acm *acm = tty->driver_data;
 
-       if (!ACM_READY(acm))
-               return;
-
        spin_lock_irq(&acm->read_lock);
        acm->throttle_req = 1;
        spin_unlock_irq(&acm->read_lock);
@@ -662,9 +720,6 @@ static void acm_tty_unthrottle(struct tty_struct *tty)
        struct acm *acm = tty->driver_data;
        unsigned int was_throttled;
 
-       if (!ACM_READY(acm))
-               return;
-
        spin_lock_irq(&acm->read_lock);
        was_throttled = acm->throttled;
        acm->throttled = 0;
@@ -679,8 +734,7 @@ static int acm_tty_break_ctl(struct tty_struct *tty, int state)
 {
        struct acm *acm = tty->driver_data;
        int retval;
-       if (!ACM_READY(acm))
-               return -EINVAL;
+
        retval = acm_send_break(acm, state ? 0xffff : 0);
        if (retval < 0)
                dev_dbg(&acm->control->dev, "%s - send break failed\n",
@@ -692,9 +746,6 @@ static int acm_tty_tiocmget(struct tty_struct *tty)
 {
        struct acm *acm = tty->driver_data;
 
-       if (!ACM_READY(acm))
-               return -EINVAL;
-
        return (acm->ctrlout & ACM_CTRL_DTR ? TIOCM_DTR : 0) |
               (acm->ctrlout & ACM_CTRL_RTS ? TIOCM_RTS : 0) |
               (acm->ctrlin  & ACM_CTRL_DSR ? TIOCM_DSR : 0) |
@@ -709,9 +760,6 @@ static int acm_tty_tiocmset(struct tty_struct *tty,
        struct acm *acm = tty->driver_data;
        unsigned int newctrl;
 
-       if (!ACM_READY(acm))
-               return -EINVAL;
-
        newctrl = acm->ctrlout;
        set = (set & TIOCM_DTR ? ACM_CTRL_DTR : 0) |
                                        (set & TIOCM_RTS ? ACM_CTRL_RTS : 0);
@@ -728,11 +776,6 @@ static int acm_tty_tiocmset(struct tty_struct *tty,
 static int acm_tty_ioctl(struct tty_struct *tty,
                                        unsigned int cmd, unsigned long arg)
 {
-       struct acm *acm = tty->driver_data;
-
-       if (!ACM_READY(acm))
-               return -EINVAL;
-
        return -ENOIOCTLCMD;
 }
 
@@ -756,9 +799,6 @@ static void acm_tty_set_termios(struct tty_struct *tty,
        struct usb_cdc_line_coding newline;
        int newctrl = acm->ctrlout;
 
-       if (!ACM_READY(acm))
-               return;
-
        newline.dwDTERate = cpu_to_le32(tty_get_baud_rate(tty));
        newline.bCharFormat = termios->c_cflag & CSTOPB ? 2 : 0;
        newline.bParityType = termios->c_cflag & PARENB ?
@@ -788,6 +828,12 @@ static void acm_tty_set_termios(struct tty_struct *tty,
        }
 }
 
+static const struct tty_port_operations acm_port_ops = {
+       .shutdown = acm_port_shutdown,
+       .activate = acm_port_activate,
+       .destruct = acm_port_destruct,
+};
+
 /*
  * USB probe and disconnect routines.
  */
@@ -1047,12 +1093,6 @@ skip_normal_probe:
        }
 made_compressed_probe:
        dev_dbg(&intf->dev, "interfaces are valid\n");
-       for (minor = 0; minor < ACM_TTY_MINORS && acm_table[minor]; minor++);
-
-       if (minor == ACM_TTY_MINORS) {
-               dev_err(&intf->dev, "no more free acm devices\n");
-               return -ENODEV;
-       }
 
        acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
        if (acm == NULL) {
@@ -1060,6 +1100,13 @@ made_compressed_probe:
                goto alloc_fail;
        }
 
+       minor = acm_alloc_minor(acm);
+       if (minor == ACM_TTY_MINORS) {
+               dev_err(&intf->dev, "no more free acm devices\n");
+               kfree(acm);
+               return -ENODEV;
+       }
+
        ctrlsize = usb_endpoint_maxp(epctrl);
        readsize = usb_endpoint_maxp(epread) *
                                (quirks == SINGLE_RX_URB ? 1 : 2);
@@ -1183,6 +1230,8 @@ made_compressed_probe:
                i = device_create_file(&intf->dev, &dev_attr_wCountryCodes);
                if (i < 0) {
                        kfree(acm->country_codes);
+                       acm->country_codes = NULL;
+                       acm->country_code_size = 0;
                        goto skip_countries;
                }
 
@@ -1191,6 +1240,8 @@ made_compressed_probe:
                if (i < 0) {
                        device_remove_file(&intf->dev, &dev_attr_wCountryCodes);
                        kfree(acm->country_codes);
+                       acm->country_codes = NULL;
+                       acm->country_code_size = 0;
                        goto skip_countries;
                }
        }
@@ -1218,8 +1269,6 @@ skip_countries:
        usb_get_intf(control_interface);
        tty_register_device(acm_tty_driver, minor, &control_interface->dev);
 
-       acm_table[minor] = acm;
-
        return 0;
 alloc_fail7:
        for (i = 0; i < ACM_NW; i++)
@@ -1234,6 +1283,7 @@ alloc_fail5:
 alloc_fail4:
        usb_free_coherent(usb_dev, ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
 alloc_fail2:
+       acm_release_minor(acm);
        kfree(acm);
 alloc_fail:
        return -ENOMEM;
@@ -1259,12 +1309,16 @@ static void acm_disconnect(struct usb_interface *intf)
        struct acm *acm = usb_get_intfdata(intf);
        struct usb_device *usb_dev = interface_to_usbdev(intf);
        struct tty_struct *tty;
+       int i;
+
+       dev_dbg(&intf->dev, "%s\n", __func__);
 
        /* sibling interface is already cleaning up */
        if (!acm)
                return;
 
-       mutex_lock(&open_mutex);
+       mutex_lock(&acm->mutex);
+       acm->disconnected = true;
        if (acm->country_codes) {
                device_remove_file(&acm->control->dev,
                                &dev_attr_wCountryCodes);
@@ -1272,33 +1326,32 @@ static void acm_disconnect(struct usb_interface *intf)
                                &dev_attr_iCountryCodeRelDate);
        }
        device_remove_file(&acm->control->dev, &dev_attr_bmCapabilities);
-       acm->dev = NULL;
        usb_set_intfdata(acm->control, NULL);
        usb_set_intfdata(acm->data, NULL);
+       mutex_unlock(&acm->mutex);
+
+       tty = tty_port_tty_get(&acm->port);
+       if (tty) {
+               tty_vhangup(tty);
+               tty_kref_put(tty);
+       }
 
        stop_data_traffic(acm);
 
+       usb_free_urb(acm->ctrlurb);
+       for (i = 0; i < ACM_NW; i++)
+               usb_free_urb(acm->wb[i].urb);
+       for (i = 0; i < acm->rx_buflimit; i++)
+               usb_free_urb(acm->read_urbs[i]);
        acm_write_buffers_free(acm);
-       usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer,
-                         acm->ctrl_dma);
+       usb_free_coherent(usb_dev, acm->ctrlsize, acm->ctrl_buffer, acm->ctrl_dma);
        acm_read_buffers_free(acm);
 
        if (!acm->combined_interfaces)
                usb_driver_release_interface(&acm_driver, intf == acm->control ?
                                        acm->data : acm->control);
 
-       if (acm->port.count == 0) {
-               acm_tty_unregister(acm);
-               mutex_unlock(&open_mutex);
-               return;
-       }
-
-       mutex_unlock(&open_mutex);
-       tty = tty_port_tty_get(&acm->port);
-       if (tty) {
-               tty_hangup(tty);
-               tty_kref_put(tty);
-       }
+       tty_port_put(&acm->port);
 }
 
 #ifdef CONFIG_PM
@@ -1325,16 +1378,10 @@ static int acm_suspend(struct usb_interface *intf, pm_message_t message)
 
        if (cnt)
                return 0;
-       /*
-       we treat opened interfaces differently,
-       we must guard against open
-       */
-       mutex_lock(&acm->mutex);
 
-       if (acm->port.count)
+       if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags))
                stop_data_traffic(acm);
 
-       mutex_unlock(&acm->mutex);
        return 0;
 }
 
@@ -1353,8 +1400,7 @@ static int acm_resume(struct usb_interface *intf)
        if (cnt)
                return 0;
 
-       mutex_lock(&acm->mutex);
-       if (acm->port.count) {
+       if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
                rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO);
 
                spin_lock_irq(&acm->write_lock);
@@ -1378,7 +1424,6 @@ static int acm_resume(struct usb_interface *intf)
        }
 
 err_out:
-       mutex_unlock(&acm->mutex);
        return rv;
 }
 
@@ -1387,15 +1432,14 @@ 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) {
+       if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) {
                tty = tty_port_tty_get(&acm->port);
                if (tty) {
                        tty_hangup(tty);
                        tty_kref_put(tty);
                }
        }
-       mutex_unlock(&acm->mutex);
+
        return acm_resume(intf);
 }
 
@@ -1604,8 +1648,10 @@ static struct usb_driver acm_driver = {
  */
 
 static const struct tty_operations acm_ops = {
+       .install =              acm_tty_install,
        .open =                 acm_tty_open,
        .close =                acm_tty_close,
+       .cleanup =              acm_tty_cleanup,
        .hangup =               acm_tty_hangup,
        .write =                acm_tty_write,
        .write_room =           acm_tty_write_room,
index ca7937f..35ef887 100644 (file)
@@ -101,6 +101,7 @@ struct acm {
        int transmitting;
        spinlock_t write_lock;
        struct mutex mutex;
+       bool disconnected;
        struct usb_cdc_line_coding line;                /* bits, stop, parity */
        struct work_struct work;                        /* work queue entry for line discipline waking up */
        unsigned int ctrlin;                            /* input control lines (DCD, DSR, RI, break, overruns) */
index e3beaf2..3af5e2d 100644 (file)
@@ -86,6 +86,7 @@ struct async {
        void __user *userbuffer;
        void __user *userurb;
        struct urb *urb;
+       unsigned int mem_usage;
        int status;
        u32 secid;
        u8 bulk_addr;
@@ -108,8 +109,44 @@ enum snoop_when {
 
 #define USB_DEVICE_DEV         MKDEV(USB_DEVICE_MAJOR, 0)
 
-#define        MAX_USBFS_BUFFER_SIZE   16384
+/* Limit on the total amount of memory we can allocate for transfers */
+static unsigned usbfs_memory_mb = 16;
+module_param(usbfs_memory_mb, uint, 0644);
+MODULE_PARM_DESC(usbfs_memory_mb,
+               "maximum MB allowed for usbfs buffers (0 = no limit)");
 
+/* Hard limit, necessary to avoid aithmetic overflow */
+#define USBFS_XFER_MAX         (UINT_MAX / 2 - 1000000)
+
+static atomic_t usbfs_memory_usage;    /* Total memory currently allocated */
+
+/* Check whether it's okay to allocate more memory for a transfer */
+static int usbfs_increase_memory_usage(unsigned amount)
+{
+       unsigned lim;
+
+       /*
+        * Convert usbfs_memory_mb to bytes, avoiding overflows.
+        * 0 means use the hard limit (effectively unlimited).
+        */
+       lim = ACCESS_ONCE(usbfs_memory_mb);
+       if (lim == 0 || lim > (USBFS_XFER_MAX >> 20))
+               lim = USBFS_XFER_MAX;
+       else
+               lim <<= 20;
+
+       atomic_add(amount, &usbfs_memory_usage);
+       if (atomic_read(&usbfs_memory_usage) <= lim)
+               return 0;
+       atomic_sub(amount, &usbfs_memory_usage);
+       return -ENOMEM;
+}
+
+/* Memory for a transfer is being deallocated */
+static void usbfs_decrease_memory_usage(unsigned amount)
+{
+       atomic_sub(amount, &usbfs_memory_usage);
+}
 
 static int connected(struct dev_state *ps)
 {
@@ -249,10 +286,12 @@ static struct async *alloc_async(unsigned int numisoframes)
 static void free_async(struct async *as)
 {
        put_pid(as->pid);
-       put_cred(as->cred);
+       if (as->cred)
+               put_cred(as->cred);
        kfree(as->urb->transfer_buffer);
        kfree(as->urb->setup_packet);
        usb_free_urb(as->urb);
+       usbfs_decrease_memory_usage(as->mem_usage);
        kfree(as);
 }
 
@@ -792,9 +831,15 @@ static int proc_control(struct dev_state *ps, void __user *arg)
        wLength = ctrl.wLength;         /* To suppress 64k PAGE_SIZE warning */
        if (wLength > PAGE_SIZE)
                return -EINVAL;
+       ret = usbfs_increase_memory_usage(PAGE_SIZE + sizeof(struct urb) +
+                       sizeof(struct usb_ctrlrequest));
+       if (ret)
+               return ret;
        tbuf = (unsigned char *)__get_free_page(GFP_KERNEL);
-       if (!tbuf)
-               return -ENOMEM;
+       if (!tbuf) {
+               ret = -ENOMEM;
+               goto done;
+       }
        tmo = ctrl.timeout;
        snoop(&dev->dev, "control urb: bRequestType=%02x "
                "bRequest=%02x wValue=%04x "
@@ -806,8 +851,8 @@ static int proc_control(struct dev_state *ps, void __user *arg)
        if (ctrl.bRequestType & 0x80) {
                if (ctrl.wLength && !access_ok(VERIFY_WRITE, ctrl.data,
                                               ctrl.wLength)) {
-                       free_page((unsigned long)tbuf);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto done;
                }
                pipe = usb_rcvctrlpipe(dev, 0);
                snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, NULL, 0);
@@ -821,15 +866,15 @@ static int proc_control(struct dev_state *ps, void __user *arg)
                          tbuf, max(i, 0));
                if ((i > 0) && ctrl.wLength) {
                        if (copy_to_user(ctrl.data, tbuf, i)) {
-                               free_page((unsigned long)tbuf);
-                               return -EFAULT;
+                               ret = -EFAULT;
+                               goto done;
                        }
                }
        } else {
                if (ctrl.wLength) {
                        if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) {
-                               free_page((unsigned long)tbuf);
-                               return -EFAULT;
+                               ret = -EFAULT;
+                               goto done;
                        }
                }
                pipe = usb_sndctrlpipe(dev, 0);
@@ -843,14 +888,18 @@ static int proc_control(struct dev_state *ps, void __user *arg)
                usb_lock_device(dev);
                snoop_urb(dev, NULL, pipe, max(i, 0), min(i, 0), COMPLETE, NULL, 0);
        }
-       free_page((unsigned long)tbuf);
        if (i < 0 && i != -EPIPE) {
                dev_printk(KERN_DEBUG, &dev->dev, "usbfs: USBDEVFS_CONTROL "
                           "failed cmd %s rqt %u rq %u len %u ret %d\n",
                           current->comm, ctrl.bRequestType, ctrl.bRequest,
                           ctrl.wLength, i);
        }
-       return i;
+       ret = i;
+ done:
+       free_page((unsigned long) tbuf);
+       usbfs_decrease_memory_usage(PAGE_SIZE + sizeof(struct urb) +
+                       sizeof(struct usb_ctrlrequest));
+       return ret;
 }
 
 static int proc_bulk(struct dev_state *ps, void __user *arg)
@@ -877,15 +926,20 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
        if (!usb_maxpacket(dev, pipe, !(bulk.ep & USB_DIR_IN)))
                return -EINVAL;
        len1 = bulk.len;
-       if (len1 > MAX_USBFS_BUFFER_SIZE)
+       if (len1 >= USBFS_XFER_MAX)
                return -EINVAL;
-       if (!(tbuf = kmalloc(len1, GFP_KERNEL)))
-               return -ENOMEM;
+       ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb));
+       if (ret)
+               return ret;
+       if (!(tbuf = kmalloc(len1, GFP_KERNEL))) {
+               ret = -ENOMEM;
+               goto done;
+       }
        tmo = bulk.timeout;
        if (bulk.ep & 0x80) {
                if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) {
-                       kfree(tbuf);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto done;
                }
                snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0);
 
@@ -896,15 +950,15 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
 
                if (!i && len2) {
                        if (copy_to_user(bulk.data, tbuf, len2)) {
-                               kfree(tbuf);
-                               return -EFAULT;
+                               ret = -EFAULT;
+                               goto done;
                        }
                }
        } else {
                if (len1) {
                        if (copy_from_user(tbuf, bulk.data, len1)) {
-                               kfree(tbuf);
-                               return -EFAULT;
+                               ret = -EFAULT;
+                               goto done;
                        }
                }
                snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, tbuf, len1);
@@ -914,10 +968,11 @@ static int proc_bulk(struct dev_state *ps, void __user *arg)
                usb_lock_device(dev);
                snoop_urb(dev, NULL, pipe, len2, i, COMPLETE, NULL, 0);
        }
+       ret = (i < 0 ? i : len2);
+ done:
        kfree(tbuf);
-       if (i < 0)
-               return i;
-       return len2;
+       usbfs_decrease_memory_usage(len1 + sizeof(struct urb));
+       return ret;
 }
 
 static int proc_resetep(struct dev_state *ps, void __user *arg)
@@ -1062,7 +1117,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 {
        struct usbdevfs_iso_packet_desc *isopkt = NULL;
        struct usb_host_endpoint *ep;
-       struct async *as;
+       struct async *as = NULL;
        struct usb_ctrlrequest *dr = NULL;
        unsigned int u, totlen, isofrmlen;
        int ret, ifnum = -1;
@@ -1095,32 +1150,30 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
        }
        if (!ep)
                return -ENOENT;
+
+       u = 0;
        switch(uurb->type) {
        case USBDEVFS_URB_TYPE_CONTROL:
                if (!usb_endpoint_xfer_control(&ep->desc))
                        return -EINVAL;
-               /* min 8 byte setup packet,
-                * max 8 byte setup plus an arbitrary data stage */
-               if (uurb->buffer_length < 8 ||
-                   uurb->buffer_length > (8 + MAX_USBFS_BUFFER_SIZE))
+               /* min 8 byte setup packet */
+               if (uurb->buffer_length < 8)
                        return -EINVAL;
                dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
                if (!dr)
                        return -ENOMEM;
                if (copy_from_user(dr, uurb->buffer, 8)) {
-                       kfree(dr);
-                       return -EFAULT;
+                       ret = -EFAULT;
+                       goto error;
                }
                if (uurb->buffer_length < (le16_to_cpup(&dr->wLength) + 8)) {
-                       kfree(dr);
-                       return -EINVAL;
+                       ret = -EINVAL;
+                       goto error;
                }
                ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest,
                                      le16_to_cpup(&dr->wIndex));
-               if (ret) {
-                       kfree(dr);
-                       return ret;
-               }
+               if (ret)
+                       goto error;
                uurb->number_of_packets = 0;
                uurb->buffer_length = le16_to_cpup(&dr->wLength);
                uurb->buffer += 8;
@@ -1138,6 +1191,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                        __le16_to_cpup(&dr->wValue),
                        __le16_to_cpup(&dr->wIndex),
                        __le16_to_cpup(&dr->wLength));
+               u = sizeof(struct usb_ctrlrequest);
                break;
 
        case USBDEVFS_URB_TYPE_BULK:
@@ -1151,8 +1205,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                        goto interrupt_urb;
                }
                uurb->number_of_packets = 0;
-               if (uurb->buffer_length > MAX_USBFS_BUFFER_SIZE)
-                       return -EINVAL;
                break;
 
        case USBDEVFS_URB_TYPE_INTERRUPT:
@@ -1160,8 +1212,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                        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:
@@ -1176,50 +1226,53 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                if (!(isopkt = kmalloc(isofrmlen, GFP_KERNEL)))
                        return -ENOMEM;
                if (copy_from_user(isopkt, iso_frame_desc, isofrmlen)) {
-                       kfree(isopkt);
-                       return -EFAULT;
+                       ret = -EFAULT;
+                       goto error;
                }
                for (totlen = u = 0; u < uurb->number_of_packets; u++) {
                        /* arbitrary limit,
                         * sufficient for USB 2.0 high-bandwidth iso */
                        if (isopkt[u].length > 8192) {
-                               kfree(isopkt);
-                               return -EINVAL;
+                               ret = -EINVAL;
+                               goto error;
                        }
                        totlen += isopkt[u].length;
                }
-               /* 3072 * 64 microframes */
-               if (totlen > 196608) {
-                       kfree(isopkt);
-                       return -EINVAL;
-               }
+               u *= sizeof(struct usb_iso_packet_descriptor);
                uurb->buffer_length = totlen;
                break;
 
        default:
                return -EINVAL;
        }
+
+       if (uurb->buffer_length >= USBFS_XFER_MAX) {
+               ret = -EINVAL;
+               goto error;
+       }
        if (uurb->buffer_length > 0 &&
                        !access_ok(is_in ? VERIFY_WRITE : VERIFY_READ,
                                uurb->buffer, uurb->buffer_length)) {
-               kfree(isopkt);
-               kfree(dr);
-               return -EFAULT;
+               ret = -EFAULT;
+               goto error;
        }
        as = alloc_async(uurb->number_of_packets);
        if (!as) {
-               kfree(isopkt);
-               kfree(dr);
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto error;
        }
+       u += sizeof(struct async) + sizeof(struct urb) + uurb->buffer_length;
+       ret = usbfs_increase_memory_usage(u);
+       if (ret)
+               goto error;
+       as->mem_usage = u;
+
        if (uurb->buffer_length > 0) {
                as->urb->transfer_buffer = kmalloc(uurb->buffer_length,
                                GFP_KERNEL);
                if (!as->urb->transfer_buffer) {
-                       kfree(isopkt);
-                       kfree(dr);
-                       free_async(as);
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto error;
                }
                /* Isochronous input data may end up being discontiguous
                 * if some of the packets are short.  Clear the buffer so
@@ -1253,6 +1306,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 
        as->urb->transfer_buffer_length = uurb->buffer_length;
        as->urb->setup_packet = (unsigned char *)dr;
+       dr = NULL;
        as->urb->start_frame = uurb->start_frame;
        as->urb->number_of_packets = uurb->number_of_packets;
        if (uurb->type == USBDEVFS_URB_TYPE_ISO ||
@@ -1268,6 +1322,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                totlen += isopkt[u].length;
        }
        kfree(isopkt);
+       isopkt = NULL;
        as->ps = ps;
        as->userurb = arg;
        if (is_in && uurb->buffer_length > 0)
@@ -1282,8 +1337,8 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
        if (!is_in && uurb->buffer_length > 0) {
                if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
                                uurb->buffer_length)) {
-                       free_async(as);
-                       return -EFAULT;
+                       ret = -EFAULT;
+                       goto error;
                }
        }
        snoop_urb(ps->dev, as->userurb, as->urb->pipe,
@@ -1329,10 +1384,16 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
                snoop_urb(ps->dev, as->userurb, as->urb->pipe,
                                0, ret, COMPLETE, NULL, 0);
                async_removepending(as);
-               free_async(as);
-               return ret;
+               goto error;
        }
        return 0;
+
+ error:
+       kfree(isopkt);
+       kfree(dr);
+       if (as)
+               free_async(as);
+       return ret;
 }
 
 static int proc_submiturb(struct dev_state *ps, void __user *arg)
index 45887a0..d40ff95 100644 (file)
@@ -45,10 +45,12 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
        struct usb_dynid *dynid;
        u32 idVendor = 0;
        u32 idProduct = 0;
+       unsigned int bInterfaceClass = 0;
        int fields = 0;
        int retval = 0;
 
-       fields = sscanf(buf, "%x %x", &idVendor, &idProduct);
+       fields = sscanf(buf, "%x %x %x", &idVendor, &idProduct,
+                                       &bInterfaceClass);
        if (fields < 2)
                return -EINVAL;
 
@@ -60,6 +62,10 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
        dynid->id.idVendor = idVendor;
        dynid->id.idProduct = idProduct;
        dynid->id.match_flags = USB_DEVICE_ID_MATCH_DEVICE;
+       if (fields == 3) {
+               dynid->id.bInterfaceClass = (u8)bInterfaceClass;
+               dynid->id.match_flags |= USB_DEVICE_ID_MATCH_INT_CLASS;
+       }
 
        spin_lock(&dynids->lock);
        list_add_tail(&dynid->node, &dynids->list);
@@ -1073,17 +1079,10 @@ static int usb_suspend_interface(struct usb_device *udev,
                goto done;
        driver = to_usb_driver(intf->dev.driver);
 
-       if (driver->suspend) {
-               status = driver->suspend(intf, msg);
-               if (status && !PMSG_IS_AUTO(msg))
-                       dev_err(&intf->dev, "%s error %d\n",
-                                       "suspend", status);
-       } else {
-               /* Later we will unbind the driver and reprobe */
-               intf->needs_binding = 1;
-               dev_warn(&intf->dev, "no %s for driver %s?\n",
-                               "suspend", driver->name);
-       }
+       /* at this time we know the driver supports suspend */
+       status = driver->suspend(intf, msg);
+       if (status && !PMSG_IS_AUTO(msg))
+               dev_err(&intf->dev, "suspend error %d\n", status);
 
  done:
        dev_vdbg(&intf->dev, "%s: status %d\n", __func__, status);
@@ -1132,16 +1131,9 @@ static int usb_resume_interface(struct usb_device *udev,
                                        "reset_resume", driver->name);
                }
        } else {
-               if (driver->resume) {
-                       status = driver->resume(intf);
-                       if (status)
-                               dev_err(&intf->dev, "%s error %d\n",
-                                               "resume", status);
-               } else {
-                       intf->needs_binding = 1;
-                       dev_warn(&intf->dev, "no %s for driver %s?\n",
-                                       "resume", driver->name);
-               }
+               status = driver->resume(intf);
+               if (status)
+                       dev_err(&intf->dev, "resume error %d\n", status);
        }
 
 done:
index a004db3..d136b8f 100644 (file)
@@ -453,10 +453,6 @@ static int resume_common(struct device *dev, int event)
 
        pci_set_master(pci_dev);
 
-       clear_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
-       if (hcd->shared_hcd)
-               clear_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);
-
        if (hcd->driver->pci_resume && !HCD_DEAD(hcd)) {
                if (event != PM_EVENT_AUTO_RESUME)
                        wait_for_companions(pci_dev, hcd);
index 13222d3..eb19cba 100644 (file)
@@ -658,7 +658,7 @@ error:
                                len > offsetof(struct usb_device_descriptor,
                                                bDeviceProtocol))
                        ((struct usb_device_descriptor *) ubuf)->
-                                       bDeviceProtocol = 1;
+                               bDeviceProtocol = USB_HUB_PR_HS_SINGLE_TT;
        }
 
        /* any errors get returned through the urb completion */
@@ -1168,20 +1168,6 @@ int usb_hcd_check_unlink_urb(struct usb_hcd *hcd, struct urb *urb,
        if (urb->unlinked)
                return -EBUSY;
        urb->unlinked = status;
-
-       /* IRQ setup can easily be broken so that USB controllers
-        * never get completion IRQs ... maybe even the ones we need to
-        * finish unlinking the initial failed usb_set_address()
-        * or device descriptor fetch.
-        */
-       if (!HCD_SAW_IRQ(hcd) && !is_root_hub(urb->dev)) {
-               dev_warn(hcd->self.controller, "Unlink after no-IRQ?  "
-                       "Controller is probably using the wrong IRQ.\n");
-               set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
-               if (hcd->shared_hcd)
-                       set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);
-       }
-
        return 0;
 }
 EXPORT_SYMBOL_GPL(usb_hcd_check_unlink_urb);
@@ -1412,11 +1398,10 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb,
                                        ret = -EAGAIN;
                                else
                                        urb->transfer_flags |= URB_DMA_MAP_SG;
-                               if (n != urb->num_sgs) {
-                                       urb->num_sgs = n;
+                               urb->num_mapped_sgs = n;
+                               if (n != urb->num_sgs)
                                        urb->transfer_flags |=
                                                        URB_DMA_SG_COMBINED;
-                               }
                        } else if (urb->sg) {
                                struct scatterlist *sg = urb->sg;
                                urb->transfer_dma = dma_map_page(
@@ -2148,16 +2133,12 @@ irqreturn_t usb_hcd_irq (int irq, void *__hcd)
         */
        local_irq_save(flags);
 
-       if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd))) {
+       if (unlikely(HCD_DEAD(hcd) || !HCD_HW_ACCESSIBLE(hcd)))
                rc = IRQ_NONE;
-       } else if (hcd->driver->irq(hcd) == IRQ_NONE) {
+       else if (hcd->driver->irq(hcd) == IRQ_NONE)
                rc = IRQ_NONE;
-       } else {
-               set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
-               if (hcd->shared_hcd)
-                       set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags);
+       else
                rc = IRQ_HANDLED;
-       }
 
        local_irq_restore(flags);
        return rc;
index 7978146..79d339e 100644 (file)
@@ -84,7 +84,7 @@ struct usb_hub {
 
 static inline int hub_is_superspeed(struct usb_device *hdev)
 {
-       return (hdev->descriptor.bDeviceProtocol == 3);
+       return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS);
 }
 
 /* Protect struct usb_device->state and ->children members
@@ -1041,58 +1041,58 @@ static int hub_configure(struct usb_hub *hub,
                dev_dbg(hub_dev, "standalone hub\n");
 
        switch (wHubCharacteristics & HUB_CHAR_LPSM) {
-               case 0x00:
-                       dev_dbg(hub_dev, "ganged power switching\n");
-                       break;
-               case 0x01:
-                       dev_dbg(hub_dev, "individual port power switching\n");
-                       break;
-               case 0x02:
-               case 0x03:
-                       dev_dbg(hub_dev, "no power switching (usb 1.0)\n");
-                       break;
+       case HUB_CHAR_COMMON_LPSM:
+               dev_dbg(hub_dev, "ganged power switching\n");
+               break;
+       case HUB_CHAR_INDV_PORT_LPSM:
+               dev_dbg(hub_dev, "individual port power switching\n");
+               break;
+       case HUB_CHAR_NO_LPSM:
+       case HUB_CHAR_LPSM:
+               dev_dbg(hub_dev, "no power switching (usb 1.0)\n");
+               break;
        }
 
        switch (wHubCharacteristics & HUB_CHAR_OCPM) {
-               case 0x00:
-                       dev_dbg(hub_dev, "global over-current protection\n");
-                       break;
-               case 0x08:
-                       dev_dbg(hub_dev, "individual port over-current protection\n");
-                       break;
-               case 0x10:
-               case 0x18:
-                       dev_dbg(hub_dev, "no over-current protection\n");
-                        break;
+       case HUB_CHAR_COMMON_OCPM:
+               dev_dbg(hub_dev, "global over-current protection\n");
+               break;
+       case HUB_CHAR_INDV_PORT_OCPM:
+               dev_dbg(hub_dev, "individual port over-current protection\n");
+               break;
+       case HUB_CHAR_NO_OCPM:
+       case HUB_CHAR_OCPM:
+               dev_dbg(hub_dev, "no over-current protection\n");
+               break;
        }
 
        spin_lock_init (&hub->tt.lock);
        INIT_LIST_HEAD (&hub->tt.clear_list);
        INIT_WORK(&hub->tt.clear_work, hub_tt_work);
        switch (hdev->descriptor.bDeviceProtocol) {
-               case 0:
-                       break;
-               case 1:
-                       dev_dbg(hub_dev, "Single TT\n");
-                       hub->tt.hub = hdev;
-                       break;
-               case 2:
-                       ret = usb_set_interface(hdev, 0, 1);
-                       if (ret == 0) {
-                               dev_dbg(hub_dev, "TT per port\n");
-                               hub->tt.multi = 1;
-                       } else
-                               dev_err(hub_dev, "Using single TT (err %d)\n",
-                                       ret);
-                       hub->tt.hub = hdev;
-                       break;
-               case 3:
-                       /* USB 3.0 hubs don't have a TT */
-                       break;
-               default:
-                       dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",
-                               hdev->descriptor.bDeviceProtocol);
-                       break;
+       case USB_HUB_PR_FS:
+               break;
+       case USB_HUB_PR_HS_SINGLE_TT:
+               dev_dbg(hub_dev, "Single TT\n");
+               hub->tt.hub = hdev;
+               break;
+       case USB_HUB_PR_HS_MULTI_TT:
+               ret = usb_set_interface(hdev, 0, 1);
+               if (ret == 0) {
+                       dev_dbg(hub_dev, "TT per port\n");
+                       hub->tt.multi = 1;
+               } else
+                       dev_err(hub_dev, "Using single TT (err %d)\n",
+                               ret);
+               hub->tt.hub = hdev;
+               break;
+       case USB_HUB_PR_SS:
+               /* USB 3.0 hubs don't have a TT */
+               break;
+       default:
+               dev_dbg(hub_dev, "Unrecognized hub protocol %d\n",
+                       hdev->descriptor.bDeviceProtocol);
+               break;
        }
 
        /* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */
@@ -1360,7 +1360,6 @@ descriptor_error:
        return -ENODEV;
 }
 
-/* No BKL needed */
 static int
 hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data)
 {
index ecf12e1..4c65eb6 100644 (file)
@@ -117,9 +117,12 @@ static const struct usb_device_id usb_quirk_list[] = {
        { USB_DEVICE(0x06a3, 0x0006), .driver_info =
                        USB_QUIRK_CONFIG_INTF_STRINGS },
 
-       /* Guillemot Webcam Hercules Dualpix Exchange*/
+       /* Guillemot Webcam Hercules Dualpix Exchange (2nd ID) */
        { USB_DEVICE(0x06f8, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME },
 
+       /* Guillemot Webcam Hercules Dualpix Exchange*/
+       { USB_DEVICE(0x06f8, 0x3005), .driver_info = USB_QUIRK_RESET_RESUME },
+
        /* M-Systems Flash Disk Pioneers */
        { USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
 
index 3888778..45e8479 100644 (file)
@@ -132,20 +132,6 @@ static inline int is_usb_device_driver(struct device_driver *drv)
                        for_devices;
 }
 
-/* translate USB error codes to codes user space understands */
-static inline int usb_translate_errors(int error_code)
-{
-       switch (error_code) {
-       case 0:
-       case -ENOMEM:
-       case -ENODEV:
-               return error_code;
-       default:
-               return -EIO;
-       }
-}
-
-
 /* for labeling diagnostics */
 extern const char *usbcore_name;
 
index 3c1d67d..d8f741f 100644 (file)
@@ -1,7 +1,10 @@
 config USB_DWC3
        tristate "DesignWare USB3 DRD Core Support"
-       depends on (USB || USB_GADGET)
+       depends on (USB && USB_GADGET)
        select USB_OTG_UTILS
+       select USB_GADGET_DUALSPEED
+       select USB_GADGET_SUPERSPEED
+       select USB_XHCI_PLATFORM
        help
          Say Y or M here if your system has a Dual Role SuperSpeed
          USB controller based on the DesignWare USB3 IP Core.
index 593d1db..900ae74 100644 (file)
@@ -4,10 +4,8 @@ ccflags-$(CONFIG_USB_DWC3_VERBOSE)     += -DVERBOSE_DEBUG
 obj-$(CONFIG_USB_DWC3)                 += dwc3.o
 
 dwc3-y                                 := core.o
-
-ifneq ($(CONFIG_USB_GADGET_DWC3),)
-       dwc3-y                          += gadget.o ep0.o
-endif
+dwc3-y                                 += host.o
+dwc3-y                                 += gadget.o ep0.o
 
 ifneq ($(CONFIG_DEBUG_FS),)
        dwc3-y                          += debugfs.o
index 600d823..7c9df63 100644 (file)
 
 #include "debug.h"
 
+static char *maximum_speed = "super";
+module_param(maximum_speed, charp, 0);
+MODULE_PARM_DESC(maximum_speed, "Maximum supported speed.");
+
+/* -------------------------------------------------------------------------- */
+
+#define DWC3_DEVS_POSSIBLE     32
+
+static DECLARE_BITMAP(dwc3_devs, DWC3_DEVS_POSSIBLE);
+
+int dwc3_get_device_id(void)
+{
+       int             id;
+
+again:
+       id = find_first_zero_bit(dwc3_devs, DWC3_DEVS_POSSIBLE);
+       if (id < DWC3_DEVS_POSSIBLE) {
+               int old;
+
+               old = test_and_set_bit(id, dwc3_devs);
+               if (old)
+                       goto again;
+       } else {
+               pr_err("dwc3: no space for new device\n");
+               id = -ENOMEM;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(dwc3_get_device_id);
+
+void dwc3_put_device_id(int id)
+{
+       int                     ret;
+
+       if (id < 0)
+               return;
+
+       ret = test_bit(id, dwc3_devs);
+       WARN(!ret, "dwc3: ID %d not in use\n", id);
+       clear_bit(id, dwc3_devs);
+}
+EXPORT_SYMBOL_GPL(dwc3_put_device_id);
+
+void dwc3_set_mode(struct dwc3 *dwc, u32 mode)
+{
+       u32 reg;
+
+       reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+       reg &= ~(DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG));
+       reg |= DWC3_GCTL_PRTCAPDIR(mode);
+       dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+}
+
 /**
  * dwc3_core_soft_reset - Issues core soft reset and PHY reset
  * @dwc: pointer to our context structure
@@ -150,7 +204,7 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)
        struct dwc3_event_buffer        *evt;
        int i;
 
-       for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) {
+       for (i = 0; i < dwc->num_event_buffers; i++) {
                evt = dwc->ev_buffs[i];
                if (evt) {
                        dwc3_free_one_event_buffer(dwc, evt);
@@ -162,17 +216,25 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)
 /**
  * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
  * @dwc: Pointer to out controller context structure
- * @num: number of event buffers to allocate
  * @length: size of event buffer
  *
  * Returns 0 on success otherwise negative errno. In error the case, dwc
  * may contain some buffers allocated but not all which were requested.
  */
-static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned num,
-               unsigned length)
+static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
 {
+       int                     num;
        int                     i;
 
+       num = DWC3_NUM_INT(dwc->hwparams.hwparams1);
+       dwc->num_event_buffers = num;
+
+       dwc->ev_buffs = kzalloc(sizeof(*dwc->ev_buffs) * num, GFP_KERNEL);
+       if (!dwc->ev_buffs) {
+               dev_err(dwc->dev, "can't allocate event buffers array\n");
+               return -ENOMEM;
+       }
+
        for (i = 0; i < num; i++) {
                struct dwc3_event_buffer        *evt;
 
@@ -198,7 +260,7 @@ static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc)
        struct dwc3_event_buffer        *evt;
        int                             n;
 
-       for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) {
+       for (n = 0; n < dwc->num_event_buffers; n++) {
                evt = dwc->ev_buffs[n];
                dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
                                evt->buf, (unsigned long long) evt->dma,
@@ -221,7 +283,7 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
        struct dwc3_event_buffer        *evt;
        int                             n;
 
-       for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) {
+       for (n = 0; n < dwc->num_event_buffers; n++) {
                evt = dwc->ev_buffs[n];
                dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
                dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
@@ -285,8 +347,32 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
                cpu_relax();
        } while (true);
 
-       ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_NUM,
-                       DWC3_EVENT_BUFFERS_SIZE);
+       dwc3_cache_hwparams(dwc);
+
+       reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+       reg &= ~DWC3_GCTL_SCALEDOWN(3);
+       reg &= ~DWC3_GCTL_DISSCRAMBLE;
+
+       switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
+       case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
+               reg &= ~DWC3_GCTL_DSBLCLKGTNG;
+               break;
+       default:
+               dev_dbg(dwc->dev, "No power optimization available\n");
+       }
+
+       /*
+        * WORKAROUND: DWC3 revisions <1.90a have a bug
+        * when The device fails to connect at SuperSpeed
+        * and falls back to high-speed mode which causes
+        * the device to enter in a Connect/Disconnect loop
+        */
+       if (dwc->revision < DWC3_REVISION_190A)
+               reg |= DWC3_GCTL_U2RSTECN;
+
+       dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+       ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_SIZE);
        if (ret) {
                dev_err(dwc->dev, "failed to allocate event buffers\n");
                ret = -ENOMEM;
@@ -299,8 +385,6 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
                goto err1;
        }
 
-       dwc3_cache_hwparams(dwc);
-
        return 0;
 
 err1:
@@ -320,15 +404,17 @@ static void dwc3_core_exit(struct dwc3 *dwc)
 
 static int __devinit dwc3_probe(struct platform_device *pdev)
 {
-       const struct platform_device_id *id = platform_get_device_id(pdev);
        struct resource         *res;
        struct dwc3             *dwc;
-       void __iomem            *regs;
-       unsigned int            features = id->driver_data;
+
        int                     ret = -ENOMEM;
        int                     irq;
+
+       void __iomem            *regs;
        void                    *mem;
 
+       u8                      mode;
+
        mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
        if (!mem) {
                dev_err(&pdev->dev, "not enough memory\n");
@@ -343,6 +429,8 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
                goto err1;
        }
 
+       dwc->res = res;
+
        res = request_mem_region(res->start, resource_size(res),
                        dev_name(&pdev->dev));
        if (!res) {
@@ -370,6 +458,17 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
        dwc->dev        = &pdev->dev;
        dwc->irq        = irq;
 
+       if (!strncmp("super", maximum_speed, 5))
+               dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
+       else if (!strncmp("high", maximum_speed, 4))
+               dwc->maximum_speed = DWC3_DCFG_HIGHSPEED;
+       else if (!strncmp("full", maximum_speed, 4))
+               dwc->maximum_speed = DWC3_DCFG_FULLSPEED1;
+       else if (!strncmp("low", maximum_speed, 3))
+               dwc->maximum_speed = DWC3_DCFG_LOWSPEED;
+       else
+               dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
+
        pm_runtime_enable(&pdev->dev);
        pm_runtime_get_sync(&pdev->dev);
        pm_runtime_forbid(&pdev->dev);
@@ -380,13 +479,44 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
                goto err3;
        }
 
-       if (features & DWC3_HAS_PERIPHERAL) {
+       mode = DWC3_MODE(dwc->hwparams.hwparams0);
+
+       switch (mode) {
+       case DWC3_MODE_DEVICE:
+               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
                ret = dwc3_gadget_init(dwc);
                if (ret) {
-                       dev_err(&pdev->dev, "failed to initialized gadget\n");
+                       dev_err(&pdev->dev, "failed to initialize gadget\n");
                        goto err4;
                }
+               break;
+       case DWC3_MODE_HOST:
+               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_HOST);
+               ret = dwc3_host_init(dwc);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to initialize host\n");
+                       goto err4;
+               }
+               break;
+       case DWC3_MODE_DRD:
+               dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_OTG);
+               ret = dwc3_host_init(dwc);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to initialize host\n");
+                       goto err4;
+               }
+
+               ret = dwc3_gadget_init(dwc);
+               if (ret) {
+                       dev_err(&pdev->dev, "failed to initialize gadget\n");
+                       goto err4;
+               }
+               break;
+       default:
+               dev_err(&pdev->dev, "Unsupported mode of operation %d\n", mode);
+               goto err4;
        }
+       dwc->mode = mode;
 
        ret = dwc3_debugfs_init(dwc);
        if (ret) {
@@ -399,8 +529,21 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
        return 0;
 
 err5:
-       if (features & DWC3_HAS_PERIPHERAL)
+       switch (mode) {
+       case DWC3_MODE_DEVICE:
+               dwc3_gadget_exit(dwc);
+               break;
+       case DWC3_MODE_HOST:
+               dwc3_host_exit(dwc);
+               break;
+       case DWC3_MODE_DRD:
+               dwc3_host_exit(dwc);
                dwc3_gadget_exit(dwc);
+               break;
+       default:
+               /* do nothing */
+               break;
+       }
 
 err4:
        dwc3_core_exit(dwc);
@@ -420,10 +563,8 @@ err0:
 
 static int __devexit dwc3_remove(struct platform_device *pdev)
 {
-       const struct platform_device_id *id = platform_get_device_id(pdev);
        struct dwc3     *dwc = platform_get_drvdata(pdev);
        struct resource *res;
-       unsigned int    features = id->driver_data;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
@@ -432,8 +573,21 @@ static int __devexit dwc3_remove(struct platform_device *pdev)
 
        dwc3_debugfs_exit(dwc);
 
-       if (features & DWC3_HAS_PERIPHERAL)
+       switch (dwc->mode) {
+       case DWC3_MODE_DEVICE:
+               dwc3_gadget_exit(dwc);
+               break;
+       case DWC3_MODE_HOST:
+               dwc3_host_exit(dwc);
+               break;
+       case DWC3_MODE_DRD:
+               dwc3_host_exit(dwc);
                dwc3_gadget_exit(dwc);
+               break;
+       default:
+               /* do nothing */
+               break;
+       }
 
        dwc3_core_exit(dwc);
        release_mem_region(res->start, resource_size(res));
@@ -443,30 +597,15 @@ static int __devexit dwc3_remove(struct platform_device *pdev)
        return 0;
 }
 
-static const struct platform_device_id dwc3_id_table[] __devinitconst = {
-       {
-               .name   = "dwc3-omap",
-               .driver_data = (DWC3_HAS_PERIPHERAL
-                       | DWC3_HAS_XHCI
-                       | DWC3_HAS_OTG),
-       },
-       {
-               .name   = "dwc3-pci",
-               .driver_data = DWC3_HAS_PERIPHERAL,
-       },
-       {  },   /* Terminating Entry */
-};
-MODULE_DEVICE_TABLE(platform, dwc3_id_table);
-
 static struct platform_driver dwc3_driver = {
        .probe          = dwc3_probe,
        .remove         = __devexit_p(dwc3_remove),
        .driver         = {
                .name   = "dwc3",
        },
-       .id_table       = dwc3_id_table,
 };
 
+MODULE_ALIAS("platform:dwc3");
 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
index 29a8e16..9e57f8e 100644 (file)
@@ -41,6 +41,7 @@
 
 #include <linux/device.h>
 #include <linux/spinlock.h>
+#include <linux/ioport.h>
 #include <linux/list.h>
 #include <linux/dma-mapping.h>
 #include <linux/mm.h>
@@ -52,7 +53,6 @@
 /* Global constants */
 #define DWC3_ENDPOINTS_NUM     32
 
-#define DWC3_EVENT_BUFFERS_NUM 2
 #define DWC3_EVENT_BUFFERS_SIZE        PAGE_SIZE
 #define DWC3_EVENT_TYPE_MASK   0xfe
 
 #define DWC3_GCTL_CLK_PIPEHALF (2)
 #define DWC3_GCTL_CLK_MASK     (3)
 
+#define DWC3_GCTL_PRTCAP(n)    (((n) & (3 << 12)) >> 12)
 #define DWC3_GCTL_PRTCAPDIR(n) (n << 12)
 #define DWC3_GCTL_PRTCAP_HOST  1
 #define DWC3_GCTL_PRTCAP_DEVICE        2
@@ -347,6 +348,7 @@ struct dwc3_ep {
        u32                     free_slot;
        u32                     busy_slot;
        const struct usb_endpoint_descriptor *desc;
+       const struct usb_ss_ep_comp_descriptor *comp_desc;
        struct dwc3             *dwc;
 
        unsigned                flags;
@@ -536,6 +538,31 @@ struct dwc3_hwparams {
        u32     hwparams8;
 };
 
+/* HWPARAMS0 */
+#define DWC3_MODE(n)           ((n) & 0x7)
+
+#define DWC3_MODE_DEVICE       0
+#define DWC3_MODE_HOST         1
+#define DWC3_MODE_DRD          2
+#define DWC3_MODE_HUB          3
+
+/* HWPARAMS1 */
+#define DWC3_NUM_INT(n)        (((n) & (0x3f << 15)) >> 15)
+
+struct dwc3_request {
+       struct usb_request      request;
+       struct list_head        list;
+       struct dwc3_ep          *dep;
+
+       u8                      epnum;
+       struct dwc3_trb_hw      *trb;
+       dma_addr_t              trb_dma;
+
+       unsigned                direction:1;
+       unsigned                mapped:1;
+       unsigned                queued:1;
+};
+
 /**
  * struct dwc3 - representation of our controller
  * @ctrl_req: usb control request which is used for ep0
@@ -549,19 +576,24 @@ struct dwc3_hwparams {
  * @ep0_bounce_addr: dma address of ep0_bounce
  * @lock: for synchronizing
  * @dev: pointer to our struct device
+ * @xhci: pointer to our xHCI child
  * @event_buffer_list: a list of event buffers
  * @gadget: device side representation of the peripheral controller
  * @gadget_driver: pointer to the gadget driver
  * @regs: base address for our registers
  * @regs_size: address space size
  * @irq: IRQ number
+ * @num_event_buffers: calculated number of event buffers
+ * @u1u2: only used on revisions <1.83a for workaround
+ * @maximum_speed: maximum speed requested (mainly for testing purposes)
  * @revision: revision register contents
+ * @mode: mode of operation
  * @is_selfpowered: true when we are selfpowered
  * @three_stage_setup: set if we perform a three phase setup
- * @ep0_status_pending: ep0 status response without a req is pending
  * @ep0_bounced: true when we used bounce buffer
  * @ep0_expect_in: true when we expect a DATA IN transfer
  * @start_config_issued: true when StartConfig command has been issued
+ * @setup_packet_pending: true when there's a Setup Packet in FIFO. Workaround
  * @ep0_next_event: hold the next expected event
  * @ep0state: state of endpoint zero
  * @link_state: link state
@@ -579,12 +611,15 @@ struct dwc3 {
        dma_addr_t              ep0_trb_addr;
        dma_addr_t              setup_buf_addr;
        dma_addr_t              ep0_bounce_addr;
-       struct usb_request      ep0_usb_req;
+       struct dwc3_request     ep0_usb_req;
        /* device lock */
        spinlock_t              lock;
        struct device           *dev;
 
-       struct dwc3_event_buffer *ev_buffs[DWC3_EVENT_BUFFERS_NUM];
+       struct platform_device  *xhci;
+       struct resource         *res;
+
+       struct dwc3_event_buffer **ev_buffs;
        struct dwc3_ep          *eps[DWC3_ENDPOINTS_NUM];
 
        struct usb_gadget       gadget;
@@ -595,7 +630,11 @@ struct dwc3 {
 
        int                     irq;
 
+       u32                     num_event_buffers;
+       u32                     u1u2;
+       u32                     maximum_speed;
        u32                     revision;
+       u32                     mode;
 
 #define DWC3_REVISION_173A     0x5533173a
 #define DWC3_REVISION_175A     0x5533175a
@@ -607,10 +646,11 @@ struct dwc3 {
 
        unsigned                is_selfpowered:1;
        unsigned                three_stage_setup:1;
-       unsigned                ep0_status_pending:1;
        unsigned                ep0_bounced:1;
        unsigned                ep0_expect_in:1;
        unsigned                start_config_issued:1;
+       unsigned                setup_packet_pending:1;
+       unsigned                delayed_status:1;
 
        enum dwc3_ep0_next      ep0_next_event;
        enum dwc3_ep0_state     ep0state;
@@ -765,4 +805,16 @@ union dwc3_event {
 #define DWC3_HAS_XHCI                  BIT(1)
 #define DWC3_HAS_OTG                   BIT(3)
 
+/* prototypes */
+void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
+
+int dwc3_host_init(struct dwc3 *dwc);
+void dwc3_host_exit(struct dwc3 *dwc);
+
+int dwc3_gadget_init(struct dwc3 *dwc);
+void dwc3_gadget_exit(struct dwc3 *dwc);
+
+extern int dwc3_get_device_id(void);
+extern void dwc3_put_device_id(int id);
+
 #endif /* __DRIVERS_USB_DWC3_CORE_H */
index fcfa915..433c97c 100644 (file)
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 #include <linux/delay.h>
-
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #include "core.h"
 #include "gadget.h"
 #include "io.h"
+#include "debug.h"
 
 #define dump_register(nm)                              \
 {                                                      \
@@ -395,6 +395,75 @@ static const struct file_operations dwc3_regdump_fops = {
        .release                = single_release,
 };
 
+static int dwc3_mode_show(struct seq_file *s, void *unused)
+{
+       struct dwc3             *dwc = s->private;
+       unsigned long           flags;
+       u32                     reg;
+
+       spin_lock_irqsave(&dwc->lock, flags);
+       reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+       spin_unlock_irqrestore(&dwc->lock, flags);
+
+       switch (DWC3_GCTL_PRTCAP(reg)) {
+       case DWC3_GCTL_PRTCAP_HOST:
+               seq_printf(s, "host\n");
+               break;
+       case DWC3_GCTL_PRTCAP_DEVICE:
+               seq_printf(s, "device\n");
+               break;
+       case DWC3_GCTL_PRTCAP_OTG:
+               seq_printf(s, "OTG\n");
+               break;
+       default:
+               seq_printf(s, "UNKNOWN %08x\n", DWC3_GCTL_PRTCAP(reg));
+       }
+
+       return 0;
+}
+
+static int dwc3_mode_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, dwc3_mode_show, inode->i_private);
+}
+
+static ssize_t dwc3_mode_write(struct file *file,
+               const char __user *ubuf, size_t count, loff_t *ppos)
+{
+       struct seq_file         *s = file->private_data;
+       struct dwc3             *dwc = s->private;
+       unsigned long           flags;
+       u32                     mode = 0;
+       char                    buf[32];
+
+       if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+               return -EFAULT;
+
+       if (!strncmp(buf, "host", 4))
+               mode |= DWC3_GCTL_PRTCAP_HOST;
+
+       if (!strncmp(buf, "device", 6))
+               mode |= DWC3_GCTL_PRTCAP_DEVICE;
+
+       if (!strncmp(buf, "otg", 3))
+               mode |= DWC3_GCTL_PRTCAP_OTG;
+
+       if (mode) {
+               spin_lock_irqsave(&dwc->lock, flags);
+               dwc3_set_mode(dwc, mode);
+               spin_unlock_irqrestore(&dwc->lock, flags);
+       }
+       return count;
+}
+
+static const struct file_operations dwc3_mode_fops = {
+       .open                   = dwc3_mode_open,
+       .write                  = dwc3_mode_write,
+       .read                   = seq_read,
+       .llseek                 = seq_lseek,
+       .release                = single_release,
+};
+
 int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
 {
        struct dentry           *root;
@@ -402,7 +471,7 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
        int                     ret;
 
        root = debugfs_create_dir(dev_name(dwc->dev), NULL);
-       if (IS_ERR(root)){
+       if (IS_ERR(root)) {
                ret = PTR_ERR(root);
                goto err0;
        }
@@ -415,6 +484,14 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
                ret = PTR_ERR(file);
                goto err1;
        }
+
+       file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
+                       dwc, &dwc3_mode_fops);
+       if (IS_ERR(file)) {
+               ret = PTR_ERR(file);
+               goto err1;
+       }
+
        return 0;
 
 err1:
index 062552b..3274ac8 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/io.h>
 #include <linux/module.h>
 
+#include "core.h"
 #include "io.h"
 
 /*
@@ -200,6 +201,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
        struct dwc3_omap        *omap;
        struct resource         *res;
 
+       int                     devid;
        int                     ret = -ENOMEM;
        int                     irq;
 
@@ -236,16 +238,20 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
                goto err1;
        }
 
-       dwc3 = platform_device_alloc("dwc3-omap", -1);
+       devid = dwc3_get_device_id();
+       if (devid < 0)
+               goto err2;
+
+       dwc3 = platform_device_alloc("dwc3", devid);
        if (!dwc3) {
                dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
-               goto err2;
+               goto err3;
        }
 
        context = kzalloc(resource_size(res), GFP_KERNEL);
        if (!context) {
                dev_err(&pdev->dev, "couldn't allocate dwc3 context memory\n");
-               goto err3;
+               goto err4;
        }
 
        spin_lock_init(&omap->lock);
@@ -299,7 +305,7 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
        if (ret) {
                dev_err(&pdev->dev, "failed to request IRQ #%d --> %d\n",
                                omap->irq, ret);
-               goto err4;
+               goto err5;
        }
 
        /* enable all IRQs */
@@ -322,26 +328,29 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
                        pdev->num_resources);
        if (ret) {
                dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
-               goto err5;
+               goto err6;
        }
 
        ret = platform_device_add(dwc3);
        if (ret) {
                dev_err(&pdev->dev, "failed to register dwc3 device\n");
-               goto err5;
+               goto err6;
        }
 
        return 0;
 
-err5:
+err6:
        free_irq(omap->irq, omap);
 
-err4:
+err5:
        kfree(omap->context);
 
-err3:
+err4:
        platform_device_put(dwc3);
 
+err3:
+       dwc3_put_device_id(devid);
+
 err2:
        iounmap(base);
 
@@ -358,6 +367,7 @@ static int __devexit dwc3_omap_remove(struct platform_device *pdev)
 
        platform_device_unregister(omap->dwc3);
 
+       dwc3_put_device_id(omap->dwc3->id);
        free_irq(omap->irq, omap);
        iounmap(omap->base);
 
@@ -384,18 +394,9 @@ static struct platform_driver dwc3_omap_driver = {
        },
 };
 
+module_platform_driver(dwc3_omap_driver);
+
+MODULE_ALIAS("platform:omap-dwc3");
 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer");
-
-static int __devinit dwc3_omap_init(void)
-{
-       return platform_driver_register(&dwc3_omap_driver);
-}
-module_init(dwc3_omap_init);
-
-static void __exit dwc3_omap_exit(void)
-{
-       platform_driver_unregister(&dwc3_omap_driver);
-}
-module_exit(dwc3_omap_exit);
index f77c000..64e1f7c 100644 (file)
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 
+#include "core.h"
+
 /* FIXME define these in <linux/pci_ids.h> */
 #define PCI_VENDOR_ID_SYNOPSYS         0x16c3
 #define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3        0xabcd
 
-#define DWC3_PCI_DEVS_POSSIBLE 32
-
 struct dwc3_pci {
        struct device           *dev;
        struct platform_device  *dwc3;
 };
 
-static DECLARE_BITMAP(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
-
-static int dwc3_pci_get_device_id(struct dwc3_pci *glue)
-{
-       int             id;
-
-again:
-       id = find_first_zero_bit(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
-       if (id < DWC3_PCI_DEVS_POSSIBLE) {
-               int old;
-
-               old = test_and_set_bit(id, dwc3_pci_devs);
-               if (old)
-                       goto again;
-       } else {
-               dev_err(glue->dev, "no space for new device\n");
-               id = -ENOMEM;
-       }
-
-       return 0;
-}
-
-static void dwc3_pci_put_device_id(struct dwc3_pci *glue, int id)
-{
-       int                     ret;
-
-       if (id < 0)
-               return;
-
-       ret = test_bit(id, dwc3_pci_devs);
-       WARN(!ret, "Device: %s\nID %d not in use\n",
-                       dev_driver_string(glue->dev), id);
-       clear_bit(id, dwc3_pci_devs);
-}
-
 static int __devinit dwc3_pci_probe(struct pci_dev *pci,
                const struct pci_device_id *id)
 {
@@ -114,11 +79,11 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,
        pci_set_power_state(pci, PCI_D0);
        pci_set_master(pci);
 
-       devid = dwc3_pci_get_device_id(glue);
+       devid = dwc3_get_device_id();
        if (devid < 0)
                goto err2;
 
-       dwc3 = platform_device_alloc("dwc3-pci", devid);
+       dwc3 = platform_device_alloc("dwc3", devid);
        if (!dwc3) {
                dev_err(&pci->dev, "couldn't allocate dwc3 device\n");
                goto err3;
@@ -163,13 +128,13 @@ err4:
        platform_device_put(dwc3);
 
 err3:
-       dwc3_pci_put_device_id(glue, devid);
+       dwc3_put_device_id(devid);
 
 err2:
        pci_disable_device(pci);
 
 err1:
-       kfree(pci);
+       kfree(glue);
 
 err0:
        return ret;
@@ -179,7 +144,7 @@ static void __devexit dwc3_pci_remove(struct pci_dev *pci)
 {
        struct dwc3_pci *glue = pci_get_drvdata(pci);
 
-       dwc3_pci_put_device_id(glue, glue->dwc3->id);
+       dwc3_put_device_id(glue->dwc3->id);
        platform_device_unregister(glue->dwc3);
        pci_set_drvdata(pci, NULL);
        pci_disable_device(pci);
@@ -196,7 +161,7 @@ static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
 MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
 
 static struct pci_driver dwc3_pci_driver = {
-       .name           = "pci-dwc3",
+       .name           = "dwc3-pci",
        .id_table       = dwc3_pci_id_table,
        .probe          = dwc3_pci_probe,
        .remove         = __devexit_p(dwc3_pci_remove),
index 69a4e43..2f51de5 100644 (file)
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
+#include <linux/usb/composite.h>
 
 #include "core.h"
 #include "gadget.h"
 #include "io.h"
 
-static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
-               const struct dwc3_event_depevt *event);
+static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum);
 
 static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
 {
@@ -125,6 +125,8 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
 static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
                struct dwc3_request *req)
 {
+       struct dwc3             *dwc = dep->dwc;
+       u32                     type;
        int                     ret = 0;
 
        req->request.actual     = 0;
@@ -143,9 +145,7 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
         * IRQ we were waiting for is long gone.
         */
        if (dep->flags & DWC3_EP_PENDING_REQUEST) {
-               struct dwc3     *dwc = dep->dwc;
                unsigned        direction;
-               u32             type;
 
                direction = !!(dep->flags & DWC3_EP0_DIR_IN);
 
@@ -165,6 +165,13 @@ static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
                                req->request.dma, req->request.length, type);
                dep->flags &= ~(DWC3_EP_PENDING_REQUEST |
                                DWC3_EP0_DIR_IN);
+       } else if (dwc->delayed_status) {
+               dwc->delayed_status = false;
+
+               if (dwc->ep0state == EP0_STATUS_PHASE)
+                       dwc3_ep0_do_control_status(dwc, 1);
+               else
+                       dev_dbg(dwc->dev, "too early for delayed status\n");
        }
 
        return ret;
@@ -190,9 +197,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
        }
 
        /* we share one TRB for ep0/1 */
-       if (!list_empty(&dwc->eps[0]->request_list) ||
-                       !list_empty(&dwc->eps[1]->request_list) ||
-                       dwc->ep0_status_pending) {
+       if (!list_empty(&dep->request_list)) {
                ret = -EBUSY;
                goto out;
        }
@@ -214,8 +219,9 @@ static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
        struct dwc3_ep          *dep = dwc->eps[0];
 
        /* stall is always issued on EP0 */
-       __dwc3_gadget_ep_set_halt(dwc->eps[0], 1);
-       dwc->eps[0]->flags = DWC3_EP_ENABLED;
+       __dwc3_gadget_ep_set_halt(dep, 1);
+       dep->flags = DWC3_EP_ENABLED;
+       dwc->delayed_status = false;
 
        if (!list_empty(&dep->request_list)) {
                struct dwc3_request     *req;
@@ -254,17 +260,14 @@ static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le)
        return NULL;
 }
 
-static void dwc3_ep0_send_status_response(struct dwc3 *dwc)
+static void dwc3_ep0_status_cmpl(struct usb_ep *ep, struct usb_request *req)
 {
-       dwc3_ep0_start_trans(dwc, 1, dwc->setup_buf_addr,
-                       dwc->ep0_usb_req.length,
-                       DWC3_TRBCTL_CONTROL_DATA);
 }
-
 /*
  * ch 9.4.5
  */
-static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+static int dwc3_ep0_handle_status(struct dwc3 *dwc,
+               struct usb_ctrlrequest *ctrl)
 {
        struct dwc3_ep          *dep;
        u32                     recip;
@@ -291,7 +294,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl
        case USB_RECIP_ENDPOINT:
                dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
                if (!dep)
-                      return -EINVAL;
+                       return -EINVAL;
 
                if (dep->flags & DWC3_EP_STALL)
                        usb_status = 1 << USB_ENDPOINT_HALT;
@@ -302,10 +305,14 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl
 
        response_pkt = (__le16 *) dwc->setup_buf;
        *response_pkt = cpu_to_le16(usb_status);
-       dwc->ep0_usb_req.length = sizeof(*response_pkt);
-       dwc->ep0_status_pending = 1;
 
-       return 0;
+       dep = dwc->eps[0];
+       dwc->ep0_usb_req.dep = dep;
+       dwc->ep0_usb_req.request.length = sizeof(*response_pkt);
+       dwc->ep0_usb_req.request.dma = dwc->setup_buf_addr;
+       dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl;
+
+       return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);
 }
 
 static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
@@ -396,8 +403,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
        case USB_RECIP_ENDPOINT:
                switch (wValue) {
                case USB_ENDPOINT_HALT:
-
-                       dep =  dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
+                       dep =  dwc3_wIndex_to_dep(dwc, wIndex);
                        if (!dep)
                                return -EINVAL;
                        ret = __dwc3_gadget_ep_set_halt(dep, set);
@@ -422,8 +428,15 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
        u32 reg;
 
        addr = le16_to_cpu(ctrl->wValue);
-       if (addr > 127)
+       if (addr > 127) {
+               dev_dbg(dwc->dev, "invalid device address %d\n", addr);
                return -EINVAL;
+       }
+
+       if (dwc->dev_state == DWC3_CONFIGURED_STATE) {
+               dev_dbg(dwc->dev, "trying to set address when configured\n");
+               return -EINVAL;
+       }
 
        reg = dwc3_readl(dwc->regs, DWC3_DCFG);
        reg &= ~(DWC3_DCFG_DEVADDR_MASK);
@@ -473,8 +486,10 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
                if (!cfg)
                        dwc->dev_state = DWC3_ADDRESS_STATE;
                break;
+       default:
+               ret = -EINVAL;
        }
-       return 0;
+       return ret;
 }
 
 static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
@@ -537,6 +552,9 @@ static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
        else
                ret = dwc3_ep0_delegate_req(dwc, ctrl);
 
+       if (ret == USB_GADGET_DELAYED_STATUS)
+               dwc->delayed_status = true;
+
        if (ret >= 0)
                return;
 
@@ -550,27 +568,21 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
        struct dwc3_request     *r = NULL;
        struct usb_request      *ur;
        struct dwc3_trb         trb;
-       struct dwc3_ep          *dep;
+       struct dwc3_ep          *ep0;
        u32                     transferred;
        u8                      epnum;
 
        epnum = event->endpoint_number;
-       dep = dwc->eps[epnum];
+       ep0 = dwc->eps[0];
 
        dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
 
-       if (!dwc->ep0_status_pending) {
-               r = next_request(&dwc->eps[0]->request_list);
-               ur = &r->request;
-       } else {
-               ur = &dwc->ep0_usb_req;
-               dwc->ep0_status_pending = 0;
-       }
+       r = next_request(&ep0->request_list);
+       ur = &r->request;
 
        dwc3_trb_to_nat(dwc->ep0_trb, &trb);
 
        if (dwc->ep0_bounced) {
-               struct dwc3_ep  *ep0 = dwc->eps[0];
 
                transferred = min_t(u32, ur->length,
                                ep0->endpoint.maxpacket - trb.length);
@@ -591,7 +603,7 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
                 * seems to be case when req.length > maxpacket. Could it be?
                 */
                if (r)
-                       dwc3_gadget_giveback(dep, r, 0);
+                       dwc3_gadget_giveback(ep0, r, 0);
        }
 }
 
@@ -619,6 +631,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
        struct dwc3_ep          *dep = dwc->eps[event->endpoint_number];
 
        dep->flags &= ~DWC3_EP_BUSY;
+       dwc->setup_packet_pending = false;
 
        switch (dwc->ep0state) {
        case EP0_SETUP_PHASE:
@@ -643,7 +656,6 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
 static void dwc3_ep0_do_control_setup(struct dwc3 *dwc,
                const struct dwc3_event_depevt *event)
 {
-       dwc->ep0state = EP0_SETUP_PHASE;
        dwc3_ep0_out_start(dwc);
 }
 
@@ -655,12 +667,6 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
        int                     ret;
 
        dep = dwc->eps[0];
-       dwc->ep0state = EP0_DATA_PHASE;
-
-       if (dwc->ep0_status_pending) {
-               dwc3_ep0_send_status_response(dwc);
-               return;
-       }
 
        if (list_empty(&dep->request_list)) {
                dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n");
@@ -674,7 +680,6 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
        req = next_request(&dep->request_list);
        req->direction = !!event->endpoint_number;
 
-       dwc->ep0state = EP0_DATA_PHASE;
        if (req->request.length == 0) {
                ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
                                dwc->ctrl_req_addr, 0,
@@ -706,35 +711,79 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
        WARN_ON(ret < 0);
 }
 
-static void dwc3_ep0_do_control_status(struct dwc3 *dwc,
-               const struct dwc3_event_depevt *event)
+static int dwc3_ep0_start_control_status(struct dwc3_ep *dep)
 {
+       struct dwc3             *dwc = dep->dwc;
        u32                     type;
-       int                     ret;
-
-       dwc->ep0state = EP0_STATUS_PHASE;
 
        type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3
                : DWC3_TRBCTL_CONTROL_STATUS2;
 
-       ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
+       return dwc3_ep0_start_trans(dwc, dep->number,
                        dwc->ctrl_req_addr, 0, type);
+}
 
-       WARN_ON(ret < 0);
+static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum)
+{
+       struct dwc3_ep          *dep = dwc->eps[epnum];
+
+       WARN_ON(dwc3_ep0_start_control_status(dep));
 }
 
 static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
                const struct dwc3_event_depevt *event)
 {
+       dwc->setup_packet_pending = true;
+
+       /*
+        * This part is very tricky: If we has just handled
+        * XferNotReady(Setup) and we're now expecting a
+        * XferComplete but, instead, we receive another
+        * XferNotReady(Setup), we should STALL and restart
+        * the state machine.
+        *
+        * In all other cases, we just continue waiting
+        * for the XferComplete event.
+        *
+        * We are a little bit unsafe here because we're
+        * not trying to ensure that last event was, indeed,
+        * XferNotReady(Setup).
+        *
+        * Still, we don't expect any condition where that
+        * should happen and, even if it does, it would be
+        * another error condition.
+        */
+       if (dwc->ep0_next_event == DWC3_EP0_COMPLETE) {
+               switch (event->status) {
+               case DEPEVT_STATUS_CONTROL_SETUP:
+                       dev_vdbg(dwc->dev, "Unexpected XferNotReady(Setup)\n");
+                       dwc3_ep0_stall_and_restart(dwc);
+                       break;
+               case DEPEVT_STATUS_CONTROL_DATA:
+                       /* FALLTHROUGH */
+               case DEPEVT_STATUS_CONTROL_STATUS:
+                       /* FALLTHROUGH */
+               default:
+                       dev_vdbg(dwc->dev, "waiting for XferComplete\n");
+               }
+
+               return;
+       }
+
        switch (event->status) {
        case DEPEVT_STATUS_CONTROL_SETUP:
                dev_vdbg(dwc->dev, "Control Setup\n");
+
+               dwc->ep0state = EP0_SETUP_PHASE;
+
                dwc3_ep0_do_control_setup(dwc, event);
                break;
 
        case DEPEVT_STATUS_CONTROL_DATA:
                dev_vdbg(dwc->dev, "Control Data\n");
 
+               dwc->ep0state = EP0_DATA_PHASE;
+
                if (dwc->ep0_next_event != DWC3_EP0_NRDY_DATA) {
                        dev_vdbg(dwc->dev, "Expected %d got %d\n",
                                        dwc->ep0_next_event,
@@ -764,6 +813,8 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
        case DEPEVT_STATUS_CONTROL_STATUS:
                dev_vdbg(dwc->dev, "Control Status\n");
 
+               dwc->ep0state = EP0_STATUS_PHASE;
+
                if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) {
                        dev_vdbg(dwc->dev, "Expected %d got %d\n",
                                        dwc->ep0_next_event,
@@ -772,12 +823,19 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
                        dwc3_ep0_stall_and_restart(dwc);
                        return;
                }
-               dwc3_ep0_do_control_status(dwc, event);
+
+               if (dwc->delayed_status) {
+                       WARN_ON_ONCE(event->endpoint_number != 1);
+                       dev_vdbg(dwc->dev, "Mass Storage delayed status\n");
+                       return;
+               }
+
+               dwc3_ep0_do_control_status(dwc, event->endpoint_number);
        }
 }
 
 void dwc3_ep0_interrupt(struct dwc3 *dwc,
-               const const struct dwc3_event_depevt *event)
+               const struct dwc3_event_depevt *event)
 {
        u8                      epnum = event->endpoint_number;
 
index 25dbd86..a696bde 100644 (file)
@@ -65,6 +65,22 @@ void dwc3_map_buffer_to_dma(struct dwc3_request *req)
                return;
        }
 
+       if (req->request.num_sgs) {
+               int     mapped;
+
+               mapped = dma_map_sg(dwc->dev, req->request.sg,
+                               req->request.num_sgs,
+                               req->direction ? DMA_TO_DEVICE
+                               : DMA_FROM_DEVICE);
+               if (mapped < 0) {
+                       dev_err(dwc->dev, "failed to map SGs\n");
+                       return;
+               }
+
+               req->request.num_mapped_sgs = mapped;
+               return;
+       }
+
        if (req->request.dma == DMA_ADDR_INVALID) {
                req->request.dma = dma_map_single(dwc->dev, req->request.buf,
                                req->request.length, req->direction
@@ -82,6 +98,17 @@ void dwc3_unmap_buffer_from_dma(struct dwc3_request *req)
                return;
        }
 
+       if (req->request.num_mapped_sgs) {
+               req->request.dma = DMA_ADDR_INVALID;
+               dma_unmap_sg(dwc->dev, req->request.sg,
+                               req->request.num_sgs,
+                               req->direction ? DMA_TO_DEVICE
+                               : DMA_FROM_DEVICE);
+
+               req->request.num_mapped_sgs = 0;
+               return;
+       }
+
        if (req->mapped) {
                dma_unmap_single(dwc->dev, req->request.dma,
                                req->request.length, req->direction
@@ -97,7 +124,11 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
        struct dwc3                     *dwc = dep->dwc;
 
        if (req->queued) {
-               dep->busy_slot++;
+               if (req->request.num_mapped_sgs)
+                       dep->busy_slot += req->request.num_mapped_sgs;
+               else
+                       dep->busy_slot++;
+
                /*
                 * Skip LINK TRB. We can't use req->trb and check for
                 * DWC3_TRBCTL_LINK_TRB because it points the TRB we just
@@ -108,6 +139,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
                        dep->busy_slot++;
        }
        list_del(&req->list);
+       req->trb = NULL;
 
        if (req->request.status == -EINPROGRESS)
                req->request.status = status;
@@ -251,7 +283,8 @@ static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
 }
 
 static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
-               const struct usb_endpoint_descriptor *desc)
+               const struct usb_endpoint_descriptor *desc,
+               const struct usb_ss_ep_comp_descriptor *comp_desc)
 {
        struct dwc3_gadget_ep_cmd_params params;
 
@@ -264,7 +297,7 @@ static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
        params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN
                | DWC3_DEPCFG_XFER_NOT_READY_EN;
 
-       if (usb_endpoint_xfer_bulk(desc) && dep->endpoint.max_streams) {
+       if (usb_ss_max_streams(comp_desc) && usb_endpoint_xfer_bulk(desc)) {
                params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE
                        | DWC3_DEPCFG_STREAM_EVENT_EN;
                dep->stream_capable = true;
@@ -317,7 +350,8 @@ static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)
  * Caller should take care of locking
  */
 static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
-               const struct usb_endpoint_descriptor *desc)
+               const struct usb_endpoint_descriptor *desc,
+               const struct usb_ss_ep_comp_descriptor *comp_desc)
 {
        struct dwc3             *dwc = dep->dwc;
        u32                     reg;
@@ -329,7 +363,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
                        return ret;
        }
 
-       ret = dwc3_gadget_set_ep_config(dwc, dep, desc);
+       ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc);
        if (ret)
                return ret;
 
@@ -343,6 +377,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
                        return ret;
 
                dep->desc = desc;
+               dep->comp_desc = comp_desc;
                dep->type = usb_endpoint_type(desc);
                dep->flags |= DWC3_EP_ENABLED;
 
@@ -405,6 +440,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
 
        dep->stream_capable = false;
        dep->desc = NULL;
+       dep->comp_desc = NULL;
        dep->type = 0;
        dep->flags = 0;
 
@@ -473,7 +509,7 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
        dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
 
        spin_lock_irqsave(&dwc->lock, flags);
-       ret = __dwc3_gadget_ep_enable(dep, desc);
+       ret = __dwc3_gadget_ep_enable(dep, desc, ep->comp_desc);
        spin_unlock_irqrestore(&dwc->lock, flags);
 
        return ret;
@@ -539,6 +575,85 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
        kfree(req);
 }
 
+/**
+ * dwc3_prepare_one_trb - setup one TRB from one request
+ * @dep: endpoint for which this request is prepared
+ * @req: dwc3_request pointer
+ */
+static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
+               struct dwc3_request *req, dma_addr_t dma,
+               unsigned length, unsigned last, unsigned chain)
+{
+       struct dwc3             *dwc = dep->dwc;
+       struct dwc3_trb_hw      *trb_hw;
+       struct dwc3_trb         trb;
+
+       unsigned int            cur_slot;
+
+       dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
+                       dep->name, req, (unsigned long long) dma,
+                       length, last ? " last" : "",
+                       chain ? " chain" : "");
+
+       trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+       cur_slot = dep->free_slot;
+       dep->free_slot++;
+
+       /* Skip the LINK-TRB on ISOC */
+       if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
+                       usb_endpoint_xfer_isoc(dep->desc))
+               return;
+
+       memset(&trb, 0, sizeof(trb));
+       if (!req->trb) {
+               dwc3_gadget_move_request_queued(req);
+               req->trb = trb_hw;
+               req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
+       }
+
+       if (usb_endpoint_xfer_isoc(dep->desc)) {
+               trb.isp_imi = true;
+               trb.csp = true;
+       } else {
+               trb.chn = chain;
+               trb.lst = last;
+       }
+
+       if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
+               trb.sid_sofn = req->request.stream_id;
+
+       switch (usb_endpoint_type(dep->desc)) {
+       case USB_ENDPOINT_XFER_CONTROL:
+               trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
+               break;
+
+       case USB_ENDPOINT_XFER_ISOC:
+               trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
+
+               /* IOC every DWC3_TRB_NUM / 4 so we can refill */
+               if (!(cur_slot % (DWC3_TRB_NUM / 4)))
+                       trb.ioc = last;
+               break;
+
+       case USB_ENDPOINT_XFER_BULK:
+       case USB_ENDPOINT_XFER_INT:
+               trb.trbctl = DWC3_TRBCTL_NORMAL;
+               break;
+       default:
+               /*
+                * This is only possible with faulty memory because we
+                * checked it already :)
+                */
+               BUG();
+       }
+
+       trb.length      = length;
+       trb.bplh        = dma;
+       trb.hwo         = true;
+
+       dwc3_trb_to_hw(&trb, trb_hw);
+}
+
 /*
  * dwc3_prepare_trbs - setup TRBs from requests
  * @dep: endpoint for which requests are being prepared
@@ -548,18 +663,17 @@ static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
  * transfers. The functions returns once there are not more TRBs available or
  * it run out of requests.
  */
-static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,
-               bool starting)
+static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
 {
-       struct dwc3_request     *req, *n, *ret = NULL;
-       struct dwc3_trb_hw      *trb_hw;
-       struct dwc3_trb         trb;
+       struct dwc3_request     *req, *n;
        u32                     trbs_left;
+       unsigned int            last_one = 0;
 
        BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
 
        /* the first request must not be queued */
        trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
+
        /*
         * if busy & slot are equal than it is either full or empty. If we are
         * starting to proceed requests then we are empty. Otherwise we ar
@@ -567,7 +681,7 @@ static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,
         */
        if (!trbs_left) {
                if (!starting)
-                       return NULL;
+                       return;
                trbs_left = DWC3_TRB_NUM;
                /*
                 * In case we start from scratch, we queue the ISOC requests
@@ -591,94 +705,62 @@ static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,
 
        /* The last TRB is a link TRB, not used for xfer */
        if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->desc))
-               return NULL;
+               return;
 
        list_for_each_entry_safe(req, n, &dep->request_list, list) {
-               unsigned int last_one = 0;
-               unsigned int cur_slot;
+               unsigned        length;
+               dma_addr_t      dma;
 
-               trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
-               cur_slot = dep->free_slot;
-               dep->free_slot++;
+               if (req->request.num_mapped_sgs > 0) {
+                       struct usb_request *request = &req->request;
+                       struct scatterlist *sg = request->sg;
+                       struct scatterlist *s;
+                       int             i;
 
-               /* Skip the LINK-TRB on ISOC */
-               if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
-                               usb_endpoint_xfer_isoc(dep->desc))
-                       continue;
+                       for_each_sg(sg, s, request->num_mapped_sgs, i) {
+                               unsigned chain = true;
 
-               dwc3_gadget_move_request_queued(req);
-               memset(&trb, 0, sizeof(trb));
-               trbs_left--;
+                               length = sg_dma_len(s);
+                               dma = sg_dma_address(s);
 
-               /* Is our TRB pool empty? */
-               if (!trbs_left)
-                       last_one = 1;
-               /* Is this the last request? */
-               if (list_empty(&dep->request_list))
-                       last_one = 1;
+                               if (i == (request->num_mapped_sgs - 1)
+                                               || sg_is_last(s)) {
+                                       last_one = true;
+                                       chain = false;
+                               }
 
-               /*
-                * FIXME we shouldn't need to set LST bit always but we are
-                * facing some weird problem with the Hardware where it doesn't
-                * complete even though it has been previously started.
-                *
-                * While we're debugging the problem, as a workaround to
-                * multiple TRBs handling, use only one TRB at a time.
-                */
-               last_one = 1;
+                               trbs_left--;
+                               if (!trbs_left)
+                                       last_one = true;
 
-               req->trb = trb_hw;
-               if (!ret)
-                       ret = req;
+                               if (last_one)
+                                       chain = false;
 
-               trb.bplh = req->request.dma;
+                               dwc3_prepare_one_trb(dep, req, dma, length,
+                                               last_one, chain);
 
-               if (usb_endpoint_xfer_isoc(dep->desc)) {
-                       trb.isp_imi = true;
-                       trb.csp = true;
+                               if (last_one)
+                                       break;
+                       }
                } else {
-                       trb.lst = last_one;
-               }
+                       dma = req->request.dma;
+                       length = req->request.length;
+                       trbs_left--;
 
-               if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
-                       trb.sid_sofn = req->request.stream_id;
-
-               switch (usb_endpoint_type(dep->desc)) {
-               case USB_ENDPOINT_XFER_CONTROL:
-                       trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
-                       break;
+                       if (!trbs_left)
+                               last_one = 1;
 
-               case USB_ENDPOINT_XFER_ISOC:
-                       trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
+                       /* Is this the last request? */
+                       if (list_is_last(&req->list, &dep->request_list))
+                               last_one = 1;
 
-                       /* IOC every DWC3_TRB_NUM / 4 so we can refill */
-                       if (!(cur_slot % (DWC3_TRB_NUM / 4)))
-                               trb.ioc = last_one;
-                       break;
+                       dwc3_prepare_one_trb(dep, req, dma, length,
+                                       last_one, false);
 
-               case USB_ENDPOINT_XFER_BULK:
-               case USB_ENDPOINT_XFER_INT:
-                       trb.trbctl = DWC3_TRBCTL_NORMAL;
-                       break;
-               default:
-                       /*
-                        * This is only possible with faulty memory because we
-                        * checked it already :)
-                        */
-                       BUG();
+                       if (last_one)
+                               break;
                }
-
-               trb.length      = req->request.length;
-               trb.hwo = true;
-
-               dwc3_trb_to_hw(&trb, trb_hw);
-               req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
-
-               if (last_one)
-                       break;
        }
-
-       return ret;
 }
 
 static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
@@ -707,11 +789,13 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
                /* req points to the first request which will be sent */
                req = next_request(&dep->req_queued);
        } else {
+               dwc3_prepare_trbs(dep, start_new);
+
                /*
                 * req points to the first request where HWO changed
                 * from 0 to 1
                 */
-               req = dwc3_prepare_trbs(dep, start_new);
+               req = next_request(&dep->req_queued);
        }
        if (!req) {
                dep->flags |= DWC3_EP_PENDING_REQUEST;
@@ -745,8 +829,9 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
        dep->flags |= DWC3_EP_BUSY;
        dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
                        dep->number);
-       if (!dep->res_trans_idx)
-               printk_once(KERN_ERR "%s() res_trans_idx is invalid\n", __func__);
+
+       WARN_ON_ONCE(!dep->res_trans_idx);
+
        return 0;
 }
 
@@ -1155,35 +1240,9 @@ static int dwc3_gadget_start(struct usb_gadget *g,
        dwc->gadget_driver      = driver;
        dwc->gadget.dev.driver  = &driver->driver;
 
-       reg = dwc3_readl(dwc->regs, DWC3_GCTL);
-
-       reg &= ~DWC3_GCTL_SCALEDOWN(3);
-       reg &= ~DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG);
-       reg &= ~DWC3_GCTL_DISSCRAMBLE;
-       reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE);
-
-       switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams0)) {
-       case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
-               reg &= ~DWC3_GCTL_DSBLCLKGTNG;
-               break;
-       default:
-               dev_dbg(dwc->dev, "No power optimization available\n");
-       }
-
-       /*
-        * WORKAROUND: DWC3 revisions <1.90a have a bug
-        * when The device fails to connect at SuperSpeed
-        * and falls back to high-speed mode which causes
-        * the device to enter in a Connect/Disconnect loop
-        */
-       if (dwc->revision < DWC3_REVISION_190A)
-               reg |= DWC3_GCTL_U2RSTECN;
-
-       dwc3_writel(dwc->regs, DWC3_GCTL, reg);
-
        reg = dwc3_readl(dwc->regs, DWC3_DCFG);
        reg &= ~(DWC3_DCFG_SPEED_MASK);
-       reg |= DWC3_DCFG_SUPERSPEED;
+       reg |= dwc->maximum_speed;
        dwc3_writel(dwc->regs, DWC3_DCFG, reg);
 
        dwc->start_config_issued = false;
@@ -1192,14 +1251,14 @@ static int dwc3_gadget_start(struct usb_gadget *g,
        dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
 
        dep = dwc->eps[0];
-       ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+       ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
        if (ret) {
                dev_err(dwc->dev, "failed to enable %s\n", dep->name);
                goto err0;
        }
 
        dep = dwc->eps[1];
-       ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+       ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
        if (ret) {
                dev_err(dwc->dev, "failed to enable %s\n", dep->name);
                goto err1;
@@ -1290,11 +1349,10 @@ static int __devinit dwc3_gadget_init_endpoints(struct dwc3 *dwc)
                                        &dwc->gadget.ep_list);
 
                        ret = dwc3_alloc_trb_pool(dep);
-                       if (ret) {
-                               dev_err(dwc->dev, "%s: failed to allocate TRB pool\n", dep->name);
+                       if (ret)
                                return ret;
-                       }
                }
+
                INIT_LIST_HEAD(&dep->request_list);
                INIT_LIST_HEAD(&dep->req_queued);
        }
@@ -1334,8 +1392,10 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
 
        do {
                req = next_request(&dep->req_queued);
-               if (!req)
-                       break;
+               if (!req) {
+                       WARN_ON_ONCE(1);
+                       return 1;
+               }
 
                dwc3_trb_to_nat(req->trb, &trb);
 
@@ -1400,6 +1460,31 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
                dep->flags &= ~DWC3_EP_BUSY;
                dep->res_trans_idx = 0;
        }
+
+       /*
+        * WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround.
+        * See dwc3_gadget_linksts_change_interrupt() for 1st half.
+        */
+       if (dwc->revision < DWC3_REVISION_183A) {
+               u32             reg;
+               int             i;
+
+               for (i = 0; i < DWC3_ENDPOINTS_NUM; i++) {
+                       struct dwc3_ep  *dep = dwc->eps[i];
+
+                       if (!(dep->flags & DWC3_EP_ENABLED))
+                               continue;
+
+                       if (!list_empty(&dep->req_queued))
+                               return;
+               }
+
+               reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+               reg |= dwc->u1u2;
+               dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+               dwc->u1u2 = 0;
+       }
 }
 
 static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
@@ -1639,6 +1724,7 @@ static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
        dwc->start_config_issued = false;
 
        dwc->gadget.speed = USB_SPEED_UNKNOWN;
+       dwc->setup_packet_pending = false;
 }
 
 static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on)
@@ -1675,6 +1761,40 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
 
        dev_vdbg(dwc->dev, "%s\n", __func__);
 
+       /*
+        * WORKAROUND: DWC3 revisions <1.88a have an issue which
+        * would cause a missing Disconnect Event if there's a
+        * pending Setup Packet in the FIFO.
+        *
+        * There's no suggested workaround on the official Bug
+        * report, which states that "unless the driver/application
+        * is doing any special handling of a disconnect event,
+        * there is no functional issue".
+        *
+        * Unfortunately, it turns out that we _do_ some special
+        * handling of a disconnect event, namely complete all
+        * pending transfers, notify gadget driver of the
+        * disconnection, and so on.
+        *
+        * Our suggested workaround is to follow the Disconnect
+        * Event steps here, instead, based on a setup_packet_pending
+        * flag. Such flag gets set whenever we have a XferNotReady
+        * event on EP0 and gets cleared on XferComplete for the
+        * same endpoint.
+        *
+        * Refers to:
+        *
+        * STAR#9000466709: RTL: Device : Disconnect event not
+        * generated if setup packet pending in FIFO
+        */
+       if (dwc->revision < DWC3_REVISION_188A) {
+               if (dwc->setup_packet_pending)
+                       dwc3_gadget_disconnect_interrupt(dwc);
+       }
+
+       /* after reset -> Default State */
+       dwc->dev_state = DWC3_DEFAULT_STATE;
+
        /* Enable PHYs */
        dwc3_gadget_usb2_phy_power(dwc, true);
        dwc3_gadget_usb3_phy_power(dwc, true);
@@ -1755,6 +1875,22 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
 
        switch (speed) {
        case DWC3_DCFG_SUPERSPEED:
+               /*
+                * WORKAROUND: DWC3 revisions <1.90a have an issue which
+                * would cause a missing USB3 Reset event.
+                *
+                * In such situations, we should force a USB3 Reset
+                * event by calling our dwc3_gadget_reset_interrupt()
+                * routine.
+                *
+                * Refers to:
+                *
+                * STAR#9000483510: RTL: SS : USB3 reset event may
+                * not be generated always when the link enters poll
+                */
+               if (dwc->revision < DWC3_REVISION_190A)
+                       dwc3_gadget_reset_interrupt(dwc);
+
                dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
                dwc->gadget.ep0->maxpacket = 512;
                dwc->gadget.speed = USB_SPEED_SUPER;
@@ -1781,14 +1917,14 @@ static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
        dwc3_gadget_disable_phy(dwc, dwc->gadget.speed);
 
        dep = dwc->eps[0];
-       ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+       ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
        if (ret) {
                dev_err(dwc->dev, "failed to enable %s\n", dep->name);
                return;
        }
 
        dep = dwc->eps[1];
-       ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+       ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL);
        if (ret) {
                dev_err(dwc->dev, "failed to enable %s\n", dep->name);
                return;
@@ -1818,8 +1954,55 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
 static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
                unsigned int evtinfo)
 {
-       /*  The fith bit says SuperSpeed yes or no. */
-       dwc->link_state = evtinfo & DWC3_LINK_STATE_MASK;
+       enum dwc3_link_state    next = evtinfo & DWC3_LINK_STATE_MASK;
+
+       /*
+        * WORKAROUND: DWC3 Revisions <1.83a have an issue which, depending
+        * on the link partner, the USB session might do multiple entry/exit
+        * of low power states before a transfer takes place.
+        *
+        * Due to this problem, we might experience lower throughput. The
+        * suggested workaround is to disable DCTL[12:9] bits if we're
+        * transitioning from U1/U2 to U0 and enable those bits again
+        * after a transfer completes and there are no pending transfers
+        * on any of the enabled endpoints.
+        *
+        * This is the first half of that workaround.
+        *
+        * Refers to:
+        *
+        * STAR#9000446952: RTL: Device SS : if U1/U2 ->U0 takes >128us
+        * core send LGO_Ux entering U0
+        */
+       if (dwc->revision < DWC3_REVISION_183A) {
+               if (next == DWC3_LINK_STATE_U0) {
+                       u32     u1u2;
+                       u32     reg;
+
+                       switch (dwc->link_state) {
+                       case DWC3_LINK_STATE_U1:
+                       case DWC3_LINK_STATE_U2:
+                               reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+                               u1u2 = reg & (DWC3_DCTL_INITU2ENA
+                                               | DWC3_DCTL_ACCEPTU2ENA
+                                               | DWC3_DCTL_INITU1ENA
+                                               | DWC3_DCTL_ACCEPTU1ENA);
+
+                               if (!dwc->u1u2)
+                                       dwc->u1u2 = reg & u1u2;
+
+                               reg &= ~u1u2;
+
+                               dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+                               break;
+                       default:
+                               /* do nothing */
+                               break;
+                       }
+               }
+       }
+
+       dwc->link_state = next;
 
        dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
 }
@@ -1925,7 +2108,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
 
        spin_lock(&dwc->lock);
 
-       for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) {
+       for (i = 0; i < dwc->num_event_buffers; i++) {
                irqreturn_t status;
 
                status = dwc3_process_event_buf(dwc, i);
@@ -1986,9 +2169,10 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
        dev_set_name(&dwc->gadget.dev, "gadget");
 
        dwc->gadget.ops                 = &dwc3_gadget_ops;
-       dwc->gadget.is_dualspeed        = true;
+       dwc->gadget.max_speed           = USB_SPEED_SUPER;
        dwc->gadget.speed               = USB_SPEED_UNKNOWN;
        dwc->gadget.dev.parent          = dwc->dev;
+       dwc->gadget.sg_supported        = true;
 
        dma_set_coherent_mask(&dwc->gadget.dev, dwc->dev->coherent_dma_mask);
 
@@ -2076,7 +2260,6 @@ err0:
 void dwc3_gadget_exit(struct dwc3 *dwc)
 {
        int                     irq;
-       int                     i;
 
        usb_del_gadget_udc(&dwc->gadget);
        irq = platform_get_irq(to_platform_device(dwc->dev), 0);
@@ -2084,9 +2267,6 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
        dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
        free_irq(irq, dwc);
 
-       for (i = 0; i < ARRAY_SIZE(dwc->eps); i++)
-               __dwc3_gadget_ep_disable(dwc->eps[i]);
-
        dwc3_gadget_free_endpoints(dwc);
 
        dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
index 71145a4..d97f467 100644 (file)
@@ -79,19 +79,6 @@ struct dwc3_gadget_ep_cmd_params {
 
 /* -------------------------------------------------------------------------- */
 
-struct dwc3_request {
-       struct usb_request      request;
-       struct list_head        list;
-       struct dwc3_ep          *dep;
-
-       u8                      epnum;
-       struct dwc3_trb_hw      *trb;
-       dma_addr_t              trb_dma;
-
-       unsigned                direction:1;
-       unsigned                mapped:1;
-       unsigned                queued:1;
-};
 #define to_dwc3_request(r)     (container_of(r, struct dwc3_request, request))
 
 static inline struct dwc3_request *next_request(struct list_head *list)
@@ -110,23 +97,11 @@ static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
        list_move_tail(&req->list, &dep->req_queued);
 }
 
-#if defined(CONFIG_USB_GADGET_DWC3) || defined(CONFIG_USB_GADGET_DWC3_MODULE)
-int dwc3_gadget_init(struct dwc3 *dwc);
-void dwc3_gadget_exit(struct dwc3 *dwc);
-#else
-static inline int dwc3_gadget_init(struct dwc3 *dwc) { return 0; }
-static inline void dwc3_gadget_exit(struct dwc3 *dwc) { }
-static inline int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
-               unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
-{
-       return 0;
-}
-#endif
-
 void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
                int status);
 
-void dwc3_ep0_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event);
+void dwc3_ep0_interrupt(struct dwc3 *dwc,
+               const struct dwc3_event_depevt *event);
 void dwc3_ep0_out_start(struct dwc3 *dwc);
 int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
                gfp_t gfp_flags);
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
new file mode 100644 (file)
index 0000000..7cfe211
--- /dev/null
@@ -0,0 +1,102 @@
+/**
+ * host.c - DesignWare USB3 DRD Controller Host Glue
+ *
+ * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/platform_device.h>
+
+#include "core.h"
+
+static struct resource generic_resources[] = {
+       {
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .flags = IORESOURCE_MEM,
+       },
+};
+
+int dwc3_host_init(struct dwc3 *dwc)
+{
+       struct platform_device  *xhci;
+       int                     ret;
+
+       xhci = platform_device_alloc("xhci", -1);
+       if (!xhci) {
+               dev_err(dwc->dev, "couldn't allocate xHCI device\n");
+               ret = -ENOMEM;
+               goto err0;
+       }
+
+       dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask);
+
+       xhci->dev.parent        = dwc->dev;
+       xhci->dev.dma_mask      = dwc->dev->dma_mask;
+       xhci->dev.dma_parms     = dwc->dev->dma_parms;
+
+       dwc->xhci = xhci;
+
+       /* setup resources */
+       generic_resources[0].start = dwc->irq;
+
+       generic_resources[1].start = dwc->res->start;
+       generic_resources[1].end = dwc->res->start + 0x7fff;
+
+       ret = platform_device_add_resources(xhci, generic_resources,
+                       ARRAY_SIZE(generic_resources));
+       if (ret) {
+               dev_err(dwc->dev, "couldn't add resources to xHCI device\n");
+               goto err1;
+       }
+
+       ret = platform_device_add(xhci);
+       if (ret) {
+               dev_err(dwc->dev, "failed to register xHCI device\n");
+               goto err1;
+       }
+
+       return 0;
+
+err1:
+       platform_device_put(xhci);
+
+err0:
+       return ret;
+}
+
+void dwc3_host_exit(struct dwc3 *dwc)
+{
+       platform_device_unregister(dwc->xhci);
+}
index bc957db..071d561 100644 (file)
@@ -39,7 +39,7 @@
 #ifndef __DRIVERS_USB_DWC3_IO_H
 #define __DRIVERS_USB_DWC3_IO_H
 
-#include <asm/io.h>
+#include <linux/io.h>
 
 static inline u32 dwc3_readl(void __iomem *base, u32 offset)
 {
index 12a401a..7ecb68a 100644 (file)
@@ -15,6 +15,7 @@
 
 menuconfig USB_GADGET
        tristate "USB Gadget Support"
+       select NLS
        help
           USB is a master/slave protocol, organized with one master
           host (such as a PC) controlling up to 127 peripheral devices.
@@ -124,7 +125,6 @@ config USB_GADGET_STORAGE_NUM_BUFFERS
 #
 choice
        prompt "USB Peripheral Controller"
-       depends on USB_GADGET
        help
           A USB device uses a controller to talk to its host.
           Systems should have only one such upstream link.
@@ -234,7 +234,6 @@ config USB_R8A66597
 
 config USB_RENESAS_USBHS_UDC
        tristate 'Renesas USBHS controller'
-       depends on SUPERH || ARCH_SHMOBILE
        depends on USB_RENESAS_USBHS
        select USB_GADGET_DUALSPEED
        help
@@ -309,25 +308,13 @@ config USB_S3C_HSUDC
 
          This driver has been tested on S3C2416 and S3C2450 processors.
 
-config USB_PXA_U2O
-       tristate "PXA9xx Processor USB2.0 controller"
-       depends on ARCH_MMP
+config USB_MV_UDC
+       tristate "Marvell USB2.0 Device Controller"
        select USB_GADGET_DUALSPEED
        help
-         PXA9xx Processor series include a high speed USB2.0 device
-         controller, which support high speed and full speed USB peripheral.
-
-config USB_GADGET_DWC3
-       tristate "DesignWare USB3.0 (DRD) Controller"
-       depends on USB_DWC3
-       select USB_GADGET_DUALSPEED
-       select USB_GADGET_SUPERSPEED
-       help
-         DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
-         which can be configured for peripheral-only, host-only, hub-only
-         and Dual-Role operation. This Controller was first integrated into
-         the OMAP5 series of processors. More information about the OMAP5
-         version of this controller, refer to http://www.ti.com/omap5.
+         Marvell Socs (including PXA and MMP series) include a high speed
+         USB2.0 OTG controller, which can be configured as high speed or
+         full speed USB peripheral.
 
 #
 # Controllers available in both integrated and discrete versions
@@ -543,12 +530,10 @@ endchoice
 # Selected by UDC drivers that support high-speed operation.
 config USB_GADGET_DUALSPEED
        bool
-       depends on USB_GADGET
 
 # Selected by UDC drivers that support super-speed opperation
 config USB_GADGET_SUPERSPEED
        bool
-       depends on USB_GADGET
        depends on USB_GADGET_DUALSPEED
 
 #
@@ -556,7 +541,6 @@ config USB_GADGET_SUPERSPEED
 #
 choice
        tristate "USB Gadget Drivers"
-       depends on USB_GADGET
        default USB_ETH
        help
          A Linux "Gadget Driver" talks to the USB Peripheral Controller
index b54ac61..b7f6eef 100644 (file)
@@ -27,7 +27,7 @@ obj-$(CONFIG_USB_S3C_HSOTG)   += s3c-hsotg.o
 obj-$(CONFIG_USB_S3C_HSUDC)    += s3c-hsudc.o
 obj-$(CONFIG_USB_LANGWELL)     += langwell_udc.o
 obj-$(CONFIG_USB_EG20T)                += pch_udc.o
-obj-$(CONFIG_USB_PXA_U2O)      += mv_udc.o
+obj-$(CONFIG_USB_MV_UDC)       += mv_udc.o
 mv_udc-y                       := mv_udc_core.o
 obj-$(CONFIG_USB_CI13XXX_MSM)  += ci13xxx_msm.o
 obj-$(CONFIG_USB_FUSB300)      += fusb300_udc.o
index 45f422a..e9a2c5c 100644 (file)
@@ -1959,7 +1959,7 @@ static int amd5536_start(struct usb_gadget_driver *driver,
        u32 tmp;
 
        if (!driver || !bind || !driver->setup
-                       || driver->speed < USB_SPEED_HIGH)
+                       || driver->max_speed < USB_SPEED_HIGH)
                return -EINVAL;
        if (!dev)
                return -ENODEV;
@@ -3349,7 +3349,7 @@ static int udc_probe(struct udc *dev)
        dev_set_name(&dev->gadget.dev, "gadget");
        dev->gadget.dev.release = gadget_release;
        dev->gadget.name = name;
-       dev->gadget.is_dualspeed = 1;
+       dev->gadget.max_speed = USB_SPEED_HIGH;
 
        /* init registers, interrupts, ... */
        startup_registers(dev);
index 8efe0fa..ac41f71 100644 (file)
@@ -1633,7 +1633,7 @@ static int at91_start(struct usb_gadget_driver *driver,
        unsigned long   flags;
 
        if (!driver
-                       || driver->speed < USB_SPEED_FULL
+                       || driver->max_speed < USB_SPEED_FULL
                        || !bind
                        || !driver->setup) {
                DBG("bad parameter.\n");
index 271a9d8..e2fb6d5 100644 (file)
@@ -1038,7 +1038,7 @@ static struct usba_udc the_udc = {
        .gadget = {
                .ops            = &usba_udc_ops,
                .ep_list        = LIST_HEAD_INIT(the_udc.gadget.ep_list),
-               .is_dualspeed   = 1,
+               .max_speed      = USB_SPEED_HIGH,
                .name           = "atmel_usba_udc",
                .dev    = {
                        .init_name      = "gadget",
index 9a0c397..27e3137 100644 (file)
@@ -182,6 +182,16 @@ static inline int hw_ep_bit(int num, int dir)
        return num + (dir ? 16 : 0);
 }
 
+static int ep_to_bit(int n)
+{
+       int fill = 16 - hw_ep_max / 2;
+
+       if (n >= hw_ep_max / 2)
+               n += fill;
+
+       return n;
+}
+
 /**
  * hw_aread: reads from register bitfield
  * @addr: address relative to bus map
@@ -440,12 +450,13 @@ static int hw_ep_get_halt(int num, int dir)
 /**
  * hw_test_and_clear_setup_status: test & clear setup status (execute without
  *                                 interruption)
- * @n: bit number (endpoint)
+ * @n: endpoint number
  *
  * This function returns setup status
  */
 static int hw_test_and_clear_setup_status(int n)
 {
+       n = ep_to_bit(n);
        return hw_ctest_and_clear(CAP_ENDPTSETUPSTAT, BIT(n));
 }
 
@@ -641,12 +652,13 @@ static int hw_register_write(u16 addr, u32 data)
 /**
  * hw_test_and_clear_complete: test & clear complete status (execute without
  *                             interruption)
- * @n: bit number (endpoint)
+ * @n: endpoint number
  *
  * This function returns complete status
  */
 static int hw_test_and_clear_complete(int n)
 {
+       n = ep_to_bit(n);
        return hw_ctest_and_clear(CAP_ENDPTCOMPLETE, BIT(n));
 }
 
@@ -754,8 +766,11 @@ static ssize_t show_device(struct device *dev, struct device_attribute *attr,
 
        n += scnprintf(buf + n, PAGE_SIZE - n, "speed             = %d\n",
                       gadget->speed);
+       n += scnprintf(buf + n, PAGE_SIZE - n, "max_speed         = %d\n",
+                      gadget->max_speed);
+       /* TODO: Scheduled for removal in 3.8. */
        n += scnprintf(buf + n, PAGE_SIZE - n, "is_dualspeed      = %d\n",
-                      gadget->is_dualspeed);
+                      gadget_is_dualspeed(gadget));
        n += scnprintf(buf + n, PAGE_SIZE - n, "is_otg            = %d\n",
                       gadget->is_otg);
        n += scnprintf(buf + n, PAGE_SIZE - n, "is_a_peripheral   = %d\n",
@@ -798,7 +813,7 @@ static ssize_t show_driver(struct device *dev, struct device_attribute *attr,
        n += scnprintf(buf + n, PAGE_SIZE - n, "function  = %s\n",
                       (driver->function ? driver->function : ""));
        n += scnprintf(buf + n, PAGE_SIZE - n, "max speed = %d\n",
-                      driver->speed);
+                      driver->max_speed);
 
        return n;
 }
@@ -2563,9 +2578,7 @@ static int ci13xxx_start(struct usb_gadget_driver *driver,
        if (driver             == NULL ||
            bind               == NULL ||
            driver->setup      == NULL ||
-           driver->disconnect == NULL ||
-           driver->suspend    == NULL ||
-           driver->resume     == NULL)
+           driver->disconnect == NULL)
                return -EINVAL;
        else if (udc         == NULL)
                return -ENODEV;
@@ -2693,8 +2706,6 @@ static int ci13xxx_stop(struct usb_gadget_driver *driver)
            driver->unbind     == NULL ||
            driver->setup      == NULL ||
            driver->disconnect == NULL ||
-           driver->suspend    == NULL ||
-           driver->resume     == NULL ||
            driver             != udc->driver)
                return -EINVAL;
 
@@ -2793,7 +2804,7 @@ static irqreturn_t udc_irq(void)
                        isr_statistics.pci++;
                        udc->gadget.speed = hw_port_is_high_speed() ?
                                USB_SPEED_HIGH : USB_SPEED_FULL;
-                       if (udc->suspended) {
+                       if (udc->suspended && udc->driver->resume) {
                                spin_unlock(udc->lock);
                                udc->driver->resume(&udc->gadget);
                                spin_lock(udc->lock);
@@ -2807,7 +2818,8 @@ static irqreturn_t udc_irq(void)
                        isr_tr_complete_handler(udc);
                }
                if (USBi_SLI & intr) {
-                       if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
+                       if (udc->gadget.speed != USB_SPEED_UNKNOWN &&
+                           udc->driver->suspend) {
                                udc->suspended = 1;
                                spin_unlock(udc->lock);
                                udc->driver->suspend(&udc->gadget);
@@ -2871,7 +2883,7 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
 
        udc->gadget.ops          = &usb_gadget_ops;
        udc->gadget.speed        = USB_SPEED_UNKNOWN;
-       udc->gadget.is_dualspeed = 1;
+       udc->gadget.max_speed    = USB_SPEED_HIGH;
        udc->gadget.is_otg       = 0;
        udc->gadget.name         = driver->name;
 
index 2370777..f4871e1 100644 (file)
@@ -127,7 +127,7 @@ struct ci13xxx {
        struct ci13xxx_ep          ci13xxx_ep[ENDPT_MAX]; /* extended endpts */
        u32                        ep0_dir;    /* ep0 direction */
 #define ep0out ci13xxx_ep[0]
-#define ep0in  ci13xxx_ep[16]
+#define ep0in  ci13xxx_ep[hw_ep_max / 2]
        u8                         remote_wakeup; /* Is remote wakeup feature
                                                        enabled by the host? */
        u8                         suspended;  /* suspended by the host */
index f71b078..a95de6a 100644 (file)
@@ -1535,9 +1535,9 @@ composite_resume(struct usb_gadget *gadget)
 
 static struct usb_gadget_driver composite_driver = {
 #ifdef CONFIG_USB_GADGET_SUPERSPEED
-       .speed          = USB_SPEED_SUPER,
+       .max_speed      = USB_SPEED_SUPER,
 #else
-       .speed          = USB_SPEED_HIGH,
+       .max_speed      = USB_SPEED_HIGH,
 #endif
 
        .unbind         = composite_unbind,
@@ -1584,8 +1584,8 @@ int usb_composite_probe(struct usb_composite_driver *driver,
                driver->iProduct = driver->name;
        composite_driver.function =  (char *) driver->name;
        composite_driver.driver.name = driver->name;
-       composite_driver.speed = min((u8)composite_driver.speed,
-                                    (u8)driver->max_speed);
+       composite_driver.max_speed =
+               min_t(u8, composite_driver.max_speed, driver->max_speed);
        composite = driver;
        composite_gadget_bind = bind;
 
index 6256420..19d7bb0 100644 (file)
@@ -404,7 +404,7 @@ fail:
 
 static struct usb_gadget_driver dbgp_driver = {
        .function = "dbgp",
-       .speed = USB_SPEED_HIGH,
+       .max_speed = USB_SPEED_HIGH,
        .unbind = dbgp_unbind,
        .setup = dbgp_setup,
        .disconnect = dbgp_disconnect,
index ab8f1b4..db815c2 100644 (file)
@@ -823,19 +823,18 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value)
 
        if (value && dum->driver) {
                if (mod_data.is_super_speed)
-                       dum->gadget.speed = dum->driver->speed;
+                       dum->gadget.speed = dum->driver->max_speed;
                else if (mod_data.is_high_speed)
                        dum->gadget.speed = min_t(u8, USB_SPEED_HIGH,
-                                       dum->driver->speed);
+                                       dum->driver->max_speed);
                else
                        dum->gadget.speed = USB_SPEED_FULL;
                dummy_udc_udpate_ep0(dum);
 
-               if (dum->gadget.speed < dum->driver->speed)
+               if (dum->gadget.speed < dum->driver->max_speed)
                        dev_dbg(udc_dev(dum), "This device can perform faster"
-                                       " if you connect it to a %s port...\n",
-                                       (dum->driver->speed == USB_SPEED_SUPER ?
-                                        "SuperSpeed" : "HighSpeed"));
+                               " if you connect it to a %s port...\n",
+                               usb_speed_string(dum->driver->max_speed));
        }
        dum_hcd = gadget_to_dummy_hcd(_gadget);
 
@@ -898,7 +897,7 @@ static int dummy_udc_start(struct usb_gadget *g,
        struct dummy_hcd        *dum_hcd = gadget_to_dummy_hcd(g);
        struct dummy            *dum = dum_hcd->dum;
 
-       if (driver->speed == USB_SPEED_UNKNOWN)
+       if (driver->max_speed == USB_SPEED_UNKNOWN)
                return -EINVAL;
 
        /*
@@ -977,7 +976,7 @@ static int dummy_udc_probe (struct platform_device *pdev)
 
        dum->gadget.name = gadget_name;
        dum->gadget.ops = &dummy_ops;
-       dum->gadget.is_dualspeed = 1;
+       dum->gadget.max_speed = USB_SPEED_SUPER;
 
        dev_set_name(&dum->gadget.dev, "gadget");
        dum->gadget.dev.parent = &pdev->dev;
index 4dff83d..753aa06 100644 (file)
@@ -149,7 +149,7 @@ ep_matches (
        switch (type) {
        case USB_ENDPOINT_XFER_INT:
                /* INT:  limit 64 bytes full speed, 1024 high/super speed */
-               if (!gadget->is_dualspeed && max > 64)
+               if (!gadget_is_dualspeed(gadget) && max > 64)
                        return 0;
                /* FALLTHROUGH */
 
@@ -157,12 +157,12 @@ ep_matches (
                /* ISO:  limit 1023 bytes full speed, 1024 high/super speed */
                if (ep->maxpacket < max)
                        return 0;
-               if (!gadget->is_dualspeed && max > 1023)
+               if (!gadget_is_dualspeed(gadget) && max > 1023)
                        return 0;
 
                /* BOTH:  "high bandwidth" works only at high speed */
                if ((desc->wMaxPacketSize & cpu_to_le16(3<<11))) {
-                       if (!gadget->is_dualspeed)
+                       if (!gadget_is_dualspeed(gadget))
                                return 0;
                        /* configure your hardware with enough buffering!! */
                }
index b5f6f9f..f63dc6c 100644 (file)
@@ -1399,7 +1399,7 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
        ENTER();
 
        count = ffs->eps_count;
-       epfiles = kzalloc(count * sizeof *epfiles, GFP_KERNEL);
+       epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL);
        if (!epfiles)
                return -ENOMEM;
 
index 1a6f415..6353eca 100644 (file)
@@ -1873,17 +1873,14 @@ static int check_command(struct fsg_common *common, int cmnd_size,
                    common->lun, lun);
 
        /* Check the LUN */
-       if (common->lun < common->nluns) {
-               curlun = &common->luns[common->lun];
-               common->curlun = curlun;
+       curlun = common->curlun;
+       if (curlun) {
                if (common->cmnd[0] != REQUEST_SENSE) {
                        curlun->sense_data = SS_NO_SENSE;
                        curlun->sense_data_info = 0;
                        curlun->info_valid = 0;
                }
        } else {
-               common->curlun = NULL;
-               curlun = NULL;
                common->bad_lun_okay = 0;
 
                /*
@@ -1929,6 +1926,17 @@ static int check_command(struct fsg_common *common, int cmnd_size,
        return 0;
 }
 
+/* wrapper of check_command for data size in blocks handling */
+static int check_command_size_in_blocks(struct fsg_common *common,
+               int cmnd_size, enum data_direction data_dir,
+               unsigned int mask, int needs_medium, const char *name)
+{
+       if (common->curlun)
+               common->data_size_from_cmnd <<= common->curlun->blkbits;
+       return check_command(common, cmnd_size, data_dir,
+                       mask, needs_medium, name);
+}
+
 static int do_scsi_command(struct fsg_common *common)
 {
        struct fsg_buffhd       *bh;
@@ -2011,9 +2019,9 @@ static int do_scsi_command(struct fsg_common *common)
 
        case READ_6:
                i = common->cmnd[4];
-               common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
-                               common->curlun->blkbits;
-               reply = check_command(common, 6, DATA_DIR_TO_HOST,
+               common->data_size_from_cmnd = (i == 0) ? 256 : i;
+               reply = check_command_size_in_blocks(common, 6,
+                                     DATA_DIR_TO_HOST,
                                      (7<<1) | (1<<4), 1,
                                      "READ(6)");
                if (reply == 0)
@@ -2022,9 +2030,9 @@ static int do_scsi_command(struct fsg_common *common)
 
        case READ_10:
                common->data_size_from_cmnd =
-                               get_unaligned_be16(&common->cmnd[7]) <<
-                                               common->curlun->blkbits;
-               reply = check_command(common, 10, DATA_DIR_TO_HOST,
+                               get_unaligned_be16(&common->cmnd[7]);
+               reply = check_command_size_in_blocks(common, 10,
+                                     DATA_DIR_TO_HOST,
                                      (1<<1) | (0xf<<2) | (3<<7), 1,
                                      "READ(10)");
                if (reply == 0)
@@ -2033,9 +2041,9 @@ static int do_scsi_command(struct fsg_common *common)
 
        case READ_12:
                common->data_size_from_cmnd =
-                               get_unaligned_be32(&common->cmnd[6]) <<
-                                               common->curlun->blkbits;
-               reply = check_command(common, 12, DATA_DIR_TO_HOST,
+                               get_unaligned_be32(&common->cmnd[6]);
+               reply = check_command_size_in_blocks(common, 12,
+                                     DATA_DIR_TO_HOST,
                                      (1<<1) | (0xf<<2) | (0xf<<6), 1,
                                      "READ(12)");
                if (reply == 0)
@@ -2134,9 +2142,9 @@ static int do_scsi_command(struct fsg_common *common)
 
        case WRITE_6:
                i = common->cmnd[4];
-               common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
-                                       common->curlun->blkbits;
-               reply = check_command(common, 6, DATA_DIR_FROM_HOST,
+               common->data_size_from_cmnd = (i == 0) ? 256 : i;
+               reply = check_command_size_in_blocks(common, 6,
+                                     DATA_DIR_FROM_HOST,
                                      (7<<1) | (1<<4), 1,
                                      "WRITE(6)");
                if (reply == 0)
@@ -2145,9 +2153,9 @@ static int do_scsi_command(struct fsg_common *common)
 
        case WRITE_10:
                common->data_size_from_cmnd =
-                               get_unaligned_be16(&common->cmnd[7]) <<
-                                               common->curlun->blkbits;
-               reply = check_command(common, 10, DATA_DIR_FROM_HOST,
+                               get_unaligned_be16(&common->cmnd[7]);
+               reply = check_command_size_in_blocks(common, 10,
+                                     DATA_DIR_FROM_HOST,
                                      (1<<1) | (0xf<<2) | (3<<7), 1,
                                      "WRITE(10)");
                if (reply == 0)
@@ -2156,9 +2164,9 @@ static int do_scsi_command(struct fsg_common *common)
 
        case WRITE_12:
                common->data_size_from_cmnd =
-                               get_unaligned_be32(&common->cmnd[6]) <<
-                                               common->curlun->blkbits;
-               reply = check_command(common, 12, DATA_DIR_FROM_HOST,
+                               get_unaligned_be32(&common->cmnd[6]);
+               reply = check_command_size_in_blocks(common, 12,
+                                     DATA_DIR_FROM_HOST,
                                      (1<<1) | (0xf<<2) | (0xf<<6), 1,
                                      "WRITE(12)");
                if (reply == 0)
@@ -2273,6 +2281,10 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
        if (common->data_size == 0)
                common->data_dir = DATA_DIR_NONE;
        common->lun = cbw->Lun;
+       if (common->lun >= 0 && common->lun < common->nluns)
+               common->curlun = &common->luns[common->lun];
+       else
+               common->curlun = NULL;
        common->tag = cbw->Tag;
        return 0;
 }
@@ -2763,7 +2775,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
         * Create the LUNs, open their backing files, and register the
         * LUN devices in sysfs.
         */
-       curlun = kzalloc(nluns * sizeof *curlun, GFP_KERNEL);
+       curlun = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL);
        if (unlikely(!curlun)) {
                rc = -ENOMEM;
                goto error_release;
index 11b5196..e0f30fc 100644 (file)
@@ -2297,19 +2297,17 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size,
                        DBG(fsg, "using LUN %d from CBW, "
                                        "not LUN %d from CDB\n",
                                        fsg->lun, lun);
-       } else
-               fsg->lun = lun;         // Use LUN from the command
+       }
 
        /* Check the LUN */
-       if (fsg->lun < fsg->nluns) {
-               fsg->curlun = curlun = &fsg->luns[fsg->lun];
+       curlun = fsg->curlun;
+       if (curlun) {
                if (fsg->cmnd[0] != REQUEST_SENSE) {
                        curlun->sense_data = SS_NO_SENSE;
                        curlun->sense_data_info = 0;
                        curlun->info_valid = 0;
                }
        } else {
-               fsg->curlun = curlun = NULL;
                fsg->bad_lun_okay = 0;
 
                /* INQUIRY and REQUEST SENSE commands are explicitly allowed
@@ -2351,6 +2349,16 @@ static int check_command(struct fsg_dev *fsg, int cmnd_size,
        return 0;
 }
 
+/* wrapper of check_command for data size in blocks handling */
+static int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size,
+               enum data_direction data_dir, unsigned int mask,
+               int needs_medium, const char *name)
+{
+       if (fsg->curlun)
+               fsg->data_size_from_cmnd <<= fsg->curlun->blkbits;
+       return check_command(fsg, cmnd_size, data_dir,
+                       mask, needs_medium, name);
+}
 
 static int do_scsi_command(struct fsg_dev *fsg)
 {
@@ -2425,26 +2433,27 @@ static int do_scsi_command(struct fsg_dev *fsg)
 
        case READ_6:
                i = fsg->cmnd[4];
-               fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits;
-               if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
+               fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
+               if ((reply = check_command_size_in_blocks(fsg, 6,
+                               DATA_DIR_TO_HOST,
                                (7<<1) | (1<<4), 1,
                                "READ(6)")) == 0)
                        reply = do_read(fsg);
                break;
 
        case READ_10:
-               fsg->data_size_from_cmnd =
-                               get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits;
-               if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
+               fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
+               if ((reply = check_command_size_in_blocks(fsg, 10,
+                               DATA_DIR_TO_HOST,
                                (1<<1) | (0xf<<2) | (3<<7), 1,
                                "READ(10)")) == 0)
                        reply = do_read(fsg);
                break;
 
        case READ_12:
-               fsg->data_size_from_cmnd =
-                               get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits;
-               if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST,
+               fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
+               if ((reply = check_command_size_in_blocks(fsg, 12,
+                               DATA_DIR_TO_HOST,
                                (1<<1) | (0xf<<2) | (0xf<<6), 1,
                                "READ(12)")) == 0)
                        reply = do_read(fsg);
@@ -2529,26 +2538,27 @@ static int do_scsi_command(struct fsg_dev *fsg)
 
        case WRITE_6:
                i = fsg->cmnd[4];
-               fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits;
-               if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
+               fsg->data_size_from_cmnd = (i == 0) ? 256 : i;
+               if ((reply = check_command_size_in_blocks(fsg, 6,
+                               DATA_DIR_FROM_HOST,
                                (7<<1) | (1<<4), 1,
                                "WRITE(6)")) == 0)
                        reply = do_write(fsg);
                break;
 
        case WRITE_10:
-               fsg->data_size_from_cmnd =
-                               get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits;
-               if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
+               fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]);
+               if ((reply = check_command_size_in_blocks(fsg, 10,
+                               DATA_DIR_FROM_HOST,
                                (1<<1) | (0xf<<2) | (3<<7), 1,
                                "WRITE(10)")) == 0)
                        reply = do_write(fsg);
                break;
 
        case WRITE_12:
-               fsg->data_size_from_cmnd =
-                               get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits;
-               if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST,
+               fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]);
+               if ((reply = check_command_size_in_blocks(fsg, 12,
+                               DATA_DIR_FROM_HOST,
                                (1<<1) | (0xf<<2) | (0xf<<6), 1,
                                "WRITE(12)")) == 0)
                        reply = do_write(fsg);
@@ -2715,7 +2725,17 @@ static int get_next_command(struct fsg_dev *fsg)
                memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size);
                fsg->cbbuf_cmnd_size = 0;
                spin_unlock_irq(&fsg->lock);
+
+               /* Use LUN from the command */
+               fsg->lun = fsg->cmnd[1] >> 5;
        }
+
+       /* Update current lun */
+       if (fsg->lun >= 0 && fsg->lun < fsg->nluns)
+               fsg->curlun = &fsg->luns[fsg->lun];
+       else
+               fsg->curlun = NULL;
+
        return rc;
 }
 
@@ -3584,7 +3604,7 @@ static void fsg_resume(struct usb_gadget *gadget)
 /*-------------------------------------------------------------------------*/
 
 static struct usb_gadget_driver                fsg_driver = {
-       .speed          = USB_SPEED_SUPER,
+       .max_speed      = USB_SPEED_SUPER,
        .function       = (char *) fsg_string_product,
        .unbind         = fsg_unbind,
        .disconnect     = fsg_disconnect,
index e00cf92..b95697c 100644 (file)
@@ -2336,7 +2336,7 @@ static int fsl_qe_start(struct usb_gadget_driver *driver,
        if (!udc_controller)
                return -ENODEV;
 
-       if (!driver || driver->speed < USB_SPEED_FULL
+       if (!driver || driver->max_speed < USB_SPEED_FULL
                        || !bind || !driver->disconnect || !driver->setup)
                return -EINVAL;
 
@@ -2350,7 +2350,7 @@ static int fsl_qe_start(struct usb_gadget_driver *driver,
        /* hook up the driver */
        udc_controller->driver = driver;
        udc_controller->gadget.dev.driver = &driver->driver;
-       udc_controller->gadget.speed = (enum usb_device_speed)(driver->speed);
+       udc_controller->gadget.speed = driver->max_speed;
        spin_unlock_irqrestore(&udc_controller->lock, flags);
 
        retval = bind(&udc_controller->gadget);
@@ -2814,20 +2814,7 @@ static struct platform_driver udc_driver = {
 #endif
 };
 
-static int __init qe_udc_init(void)
-{
-       printk(KERN_INFO "%s: %s, %s\n", driver_name, driver_desc,
-                       DRIVER_VERSION);
-       return platform_driver_register(&udc_driver);
-}
-
-static void __exit qe_udc_exit(void)
-{
-       platform_driver_unregister(&udc_driver);
-}
-
-module_init(qe_udc_init);
-module_exit(qe_udc_exit);
+module_platform_driver(udc_driver);
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_AUTHOR(DRIVER_AUTHOR);
index dd28ef3..d7ea6c0 100644 (file)
@@ -1934,7 +1934,7 @@ static int fsl_start(struct usb_gadget_driver *driver,
        if (!udc_controller)
                return -ENODEV;
 
-       if (!driver || driver->speed < USB_SPEED_FULL
+       if (!driver || driver->max_speed < USB_SPEED_FULL
                        || !bind || !driver->disconnect || !driver->setup)
                return -EINVAL;
 
@@ -2525,7 +2525,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
 
        /* Setup gadget structure */
        udc_controller->gadget.ops = &fsl_gadget_ops;
-       udc_controller->gadget.is_dualspeed = 1;
+       udc_controller->gadget.max_speed = USB_SPEED_HIGH;
        udc_controller->gadget.ep0 = &udc_controller->eps[0].ep;
        INIT_LIST_HEAD(&udc_controller->gadget.ep_list);
        udc_controller->gadget.speed = USB_SPEED_UNKNOWN;
index 74da206..5831cb4 100644 (file)
@@ -1317,7 +1317,7 @@ static int fusb300_udc_start(struct usb_gadget_driver *driver,
        int retval;
 
        if (!driver
-                       || driver->speed < USB_SPEED_FULL
+                       || driver->max_speed < USB_SPEED_FULL
                        || !bind
                        || !driver->setup)
                return -EINVAL;
@@ -1463,7 +1463,7 @@ static int __init fusb300_probe(struct platform_device *pdev)
 
        dev_set_name(&fusb300->gadget.dev, "gadget");
 
-       fusb300->gadget.is_dualspeed = 1;
+       fusb300->gadget.max_speed = USB_SPEED_HIGH;
        fusb300->gadget.dev.parent = &pdev->dev;
        fusb300->gadget.dev.dma_mask = pdev->dev.dma_mask;
        fusb300->gadget.dev.release = pdev->dev.release;
index 7f87805..5af70fc 100644 (file)
@@ -1357,7 +1357,7 @@ static int goku_start(struct usb_gadget_driver *driver,
        int                     retval;
 
        if (!driver
-                       || driver->speed < USB_SPEED_FULL
+                       || driver->max_speed < USB_SPEED_FULL
                        || !bind
                        || !driver->disconnect
                        || !driver->setup)
@@ -1796,6 +1796,7 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        spin_lock_init(&dev->lock);
        dev->pdev = pdev;
        dev->gadget.ops = &goku_ops;
+       dev->gadget.max_speed = USB_SPEED_FULL;
 
        /* the "gadget" abstracts/virtualizes the controller */
        dev_set_name(&dev->gadget.dev, "gadget");
index 2d978c0..8d1c75a 100644 (file)
@@ -1336,7 +1336,7 @@ static int imx_udc_start(struct usb_gadget_driver *driver,
        int retval;
 
        if (!driver
-               || driver->speed < USB_SPEED_FULL
+               || driver->max_speed < USB_SPEED_FULL
                || !bind
                || !driver->disconnect
                || !driver->setup)
index 6b7ea25..ae04266 100644 (file)
@@ -1766,9 +1766,9 @@ gadgetfs_suspend (struct usb_gadget *gadget)
 
 static struct usb_gadget_driver gadgetfs_driver = {
 #ifdef CONFIG_USB_GADGET_DUALSPEED
-       .speed          = USB_SPEED_HIGH,
+       .max_speed      = USB_SPEED_HIGH,
 #else
-       .speed          = USB_SPEED_FULL,
+       .max_speed      = USB_SPEED_FULL,
 #endif
        .function       = (char *) driver_desc,
        .unbind         = gadgetfs_unbind,
@@ -1792,7 +1792,7 @@ static int gadgetfs_probe (struct usb_gadget *gadget)
 }
 
 static struct usb_gadget_driver probe_driver = {
-       .speed          = USB_SPEED_HIGH,
+       .max_speed      = USB_SPEED_HIGH,
        .unbind         = gadgetfs_nop,
        .setup          = (void *)gadgetfs_nop,
        .disconnect     = gadgetfs_nop,
index c9fa3bf..fa0fcc1 100644 (file)
@@ -3267,7 +3267,7 @@ static int langwell_udc_probe(struct pci_dev *pdev,
        dev->gadget.ep0 = &dev->ep[0].ep;       /* gadget ep0 */
        INIT_LIST_HEAD(&dev->gadget.ep_list);   /* ep_list */
        dev->gadget.speed = USB_SPEED_UNKNOWN;  /* speed */
-       dev->gadget.is_dualspeed = 1;           /* support dual speed */
+       dev->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */
 #ifdef OTG_TRANSCEIVER
        dev->gadget.is_otg = 1;                 /* support otg mode */
 #endif
index 9aa1cbb..3608b3b 100644 (file)
@@ -1472,7 +1472,7 @@ static int m66592_start(struct usb_gadget_driver *driver,
        int retval;
 
        if (!driver
-                       || driver->speed < USB_SPEED_HIGH
+                       || driver->max_speed < USB_SPEED_HIGH
                        || !bind
                        || !driver->setup)
                return -EINVAL;
@@ -1653,7 +1653,7 @@ static int __init m66592_probe(struct platform_device *pdev)
        m66592->gadget.ops = &m66592_gadget_ops;
        device_initialize(&m66592->gadget.dev);
        dev_set_name(&m66592->gadget.dev, "gadget");
-       m66592->gadget.is_dualspeed = 1;
+       m66592->gadget.max_speed = USB_SPEED_HIGH;
        m66592->gadget.dev.parent = &pdev->dev;
        m66592->gadget.dev.dma_mask = pdev->dev.dma_mask;
        m66592->gadget.dev.release = pdev->dev.release;
index daa75c1..34aadfa 100644 (file)
@@ -180,7 +180,7 @@ struct mv_udc {
 
        struct mv_cap_regs __iomem      *cap_regs;
        struct mv_op_regs __iomem       *op_regs;
-       unsigned int                    phy_regs;
+       void __iomem                    *phy_regs;
        unsigned int                    max_eps;
        struct mv_dqh                   *ep_dqh;
        size_t                          ep_dqh_size;
@@ -211,11 +211,14 @@ struct mv_udc {
                                softconnected:1,
                                force_fs:1,
                                clock_gating:1,
-                               active:1;
+                               active:1,
+                               stopped:1;      /* stop bit is setted */
 
        struct work_struct      vbus_work;
        struct workqueue_struct *qwork;
 
+       struct otg_transceiver  *transceiver;
+
        struct mv_usb_platform_data     *pdata;
 
        /* some SOC has mutiple clock sources for USB*/
index 8924121..f97e737 100644 (file)
@@ -276,11 +276,12 @@ static void done(struct mv_ep *ep, struct mv_req *req, int status)
 
 static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
 {
-       u32 tmp, epstatus, bit_pos, direction;
        struct mv_udc *udc;
        struct mv_dqh *dqh;
+       u32 bit_pos, direction;
+       u32 usbcmd, epstatus;
        unsigned int loops;
-       int readsafe, retval = 0;
+       int retval = 0;
 
        udc = ep->udc;
        direction = ep_dir(ep);
@@ -293,30 +294,18 @@ static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
                lastreq = list_entry(ep->queue.prev, struct mv_req, queue);
                lastreq->tail->dtd_next =
                        req->head->td_dma & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
-               if (readl(&udc->op_regs->epprime) & bit_pos) {
-                       loops = LOOPS(PRIME_TIMEOUT);
-                       while (readl(&udc->op_regs->epprime) & bit_pos) {
-                               if (loops == 0) {
-                                       retval = -ETIME;
-                                       goto done;
-                               }
-                               udelay(LOOPS_USEC);
-                               loops--;
-                       }
-                       if (readl(&udc->op_regs->epstatus) & bit_pos)
-                               goto done;
-               }
-               readsafe = 0;
+
+               wmb();
+
+               if (readl(&udc->op_regs->epprime) & bit_pos)
+                       goto done;
+
                loops = LOOPS(READSAFE_TIMEOUT);
-               while (readsafe == 0) {
-                       if (loops == 0) {
-                               retval = -ETIME;
-                               goto done;
-                       }
+               while (1) {
                        /* start with setting the semaphores */
-                       tmp = readl(&udc->op_regs->usbcmd);
-                       tmp |= USBCMD_ATDTW_TRIPWIRE_SET;
-                       writel(tmp, &udc->op_regs->usbcmd);
+                       usbcmd = readl(&udc->op_regs->usbcmd);
+                       usbcmd |= USBCMD_ATDTW_TRIPWIRE_SET;
+                       writel(usbcmd, &udc->op_regs->usbcmd);
 
                        /* read the endpoint status */
                        epstatus = readl(&udc->op_regs->epstatus) & bit_pos;
@@ -329,98 +318,46 @@ static int queue_dtd(struct mv_ep *ep, struct mv_req *req)
                         * primed.
                         */
                        if (readl(&udc->op_regs->usbcmd)
-                               & USBCMD_ATDTW_TRIPWIRE_SET) {
-                               readsafe = 1;
-                       }
+                               & USBCMD_ATDTW_TRIPWIRE_SET)
+                               break;
+
                        loops--;
+                       if (loops == 0) {
+                               dev_err(&udc->dev->dev,
+                                       "Timeout for ATDTW_TRIPWIRE...\n");
+                               retval = -ETIME;
+                               goto done;
+                       }
                        udelay(LOOPS_USEC);
                }
 
                /* Clear the semaphore */
-               tmp = readl(&udc->op_regs->usbcmd);
-               tmp &= USBCMD_ATDTW_TRIPWIRE_CLEAR;
-               writel(tmp, &udc->op_regs->usbcmd);
-
-               /* If endpoint is not active, we activate it now. */
-               if (!epstatus) {
-                       if (direction == EP_DIR_IN) {
-                               struct mv_dtd *curr_dtd = dma_to_virt(
-                                       &udc->dev->dev, dqh->curr_dtd_ptr);
-
-                               loops = LOOPS(DTD_TIMEOUT);
-                               while (curr_dtd->size_ioc_sts
-                                       & DTD_STATUS_ACTIVE) {
-                                       if (loops == 0) {
-                                               retval = -ETIME;
-                                               goto done;
-                                       }
-                                       loops--;
-                                       udelay(LOOPS_USEC);
-                               }
-                       }
-                       /* No other transfers on the queue */
+               usbcmd = readl(&udc->op_regs->usbcmd);
+               usbcmd &= USBCMD_ATDTW_TRIPWIRE_CLEAR;
+               writel(usbcmd, &udc->op_regs->usbcmd);
 
-                       /* Write dQH next pointer and terminate bit to 0 */
-                       dqh->next_dtd_ptr = req->head->td_dma
-                               & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
-                       dqh->size_ioc_int_sts = 0;
+               if (epstatus)
+                       goto done;
+       }
 
-                       /*
-                        * Ensure that updates to the QH will
-                        * occur before priming.
-                        */
-                       wmb();
+       /* Write dQH next pointer and terminate bit to 0 */
+       dqh->next_dtd_ptr = req->head->td_dma
+                               & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
 
-                       /* Prime the Endpoint */
-                       writel(bit_pos, &udc->op_regs->epprime);
-               }
-       } else {
-               /* Write dQH next pointer and terminate bit to 0 */
-               dqh->next_dtd_ptr = req->head->td_dma
-                       & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
-               dqh->size_ioc_int_sts = 0;
+       /* clear active and halt bit, in case set from a previous error */
+       dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED);
 
-               /* Ensure that updates to the QH will occur before priming. */
-               wmb();
+       /* Ensure that updates to the QH will occure before priming. */
+       wmb();
 
-               /* Prime the Endpoint */
-               writel(bit_pos, &udc->op_regs->epprime);
+       /* Prime the Endpoint */
+       writel(bit_pos, &udc->op_regs->epprime);
 
-               if (direction == EP_DIR_IN) {
-                       /* FIXME add status check after prime the IN ep */
-                       int prime_again;
-                       u32 curr_dtd_ptr = dqh->curr_dtd_ptr;
-
-                       loops = LOOPS(DTD_TIMEOUT);
-                       prime_again = 0;
-                       while ((curr_dtd_ptr != req->head->td_dma)) {
-                               curr_dtd_ptr = dqh->curr_dtd_ptr;
-                               if (loops == 0) {
-                                       dev_err(&udc->dev->dev,
-                                               "failed to prime %s\n",
-                                               ep->name);
-                                       retval = -ETIME;
-                                       goto done;
-                               }
-                               loops--;
-                               udelay(LOOPS_USEC);
-
-                               if (loops == (LOOPS(DTD_TIMEOUT) >> 2)) {
-                                       if (prime_again)
-                                               goto done;
-                                       dev_info(&udc->dev->dev,
-                                               "prime again\n");
-                                       writel(bit_pos,
-                                               &udc->op_regs->epprime);
-                                       prime_again = 1;
-                               }
-                       }
-               }
-       }
 done:
        return retval;
 }
 
+
 static struct mv_dtd *build_dtd(struct mv_req *req, unsigned *length,
                dma_addr_t *dma, int *is_last)
 {
@@ -841,6 +778,27 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
        return 0;
 }
 
+static void mv_prime_ep(struct mv_ep *ep, struct mv_req *req)
+{
+       struct mv_dqh *dqh = ep->dqh;
+       u32 bit_pos;
+
+       /* Write dQH next pointer and terminate bit to 0 */
+       dqh->next_dtd_ptr = req->head->td_dma
+               & EP_QUEUE_HEAD_NEXT_POINTER_MASK;
+
+       /* clear active and halt bit, in case set from a previous error */
+       dqh->size_ioc_int_sts &= ~(DTD_STATUS_ACTIVE | DTD_STATUS_HALTED);
+
+       /* Ensure that updates to the QH will occure before priming. */
+       wmb();
+
+       bit_pos = 1 << (((ep_dir(ep) == EP_DIR_OUT) ? 0 : 16) + ep->ep_num);
+
+       /* Prime the Endpoint */
+       writel(bit_pos, &ep->udc->op_regs->epprime);
+}
+
 /* dequeues (cancels, unlinks) an I/O request from an endpoint */
 static int mv_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
 {
@@ -883,15 +841,13 @@ static int mv_ep_dequeue(struct usb_ep *_ep, struct usb_request *_req)
 
                /* The request isn't the last request in this ep queue */
                if (req->queue.next != &ep->queue) {
-                       struct mv_dqh *qh;
                        struct mv_req *next_req;
 
-                       qh = ep->dqh;
-                       next_req = list_entry(req->queue.next, struct mv_req,
-                                       queue);
+                       next_req = list_entry(req->queue.next,
+                               struct mv_req, queue);
 
                        /* Point the QH to the first TD of next request */
-                       writel((u32) next_req->head, &qh->curr_dtd_ptr);
+                       mv_prime_ep(ep, next_req);
                } else {
                        struct mv_dqh *qh;
 
@@ -1056,6 +1012,8 @@ static void udc_stop(struct mv_udc *udc)
                USBINTR_PORT_CHANGE_DETECT_EN | USBINTR_RESET_EN);
        writel(tmp, &udc->op_regs->usbintr);
 
+       udc->stopped = 1;
+
        /* Reset the Run the bit in the command register to stop VUSB */
        tmp = readl(&udc->op_regs->usbcmd);
        tmp &= ~USBCMD_RUN_STOP;
@@ -1072,6 +1030,8 @@ static void udc_start(struct mv_udc *udc)
        /* Enable interrupts */
        writel(usbintr, &udc->op_regs->usbintr);
 
+       udc->stopped = 0;
+
        /* Set the Run bit in the command register */
        writel(USBCMD_RUN_STOP, &udc->op_regs->usbcmd);
 }
@@ -1134,11 +1094,11 @@ static int udc_reset(struct mv_udc *udc)
        return 0;
 }
 
-static int mv_udc_enable(struct mv_udc *udc)
+static int mv_udc_enable_internal(struct mv_udc *udc)
 {
        int retval;
 
-       if (udc->clock_gating == 0 || udc->active)
+       if (udc->active)
                return 0;
 
        dev_dbg(&udc->dev->dev, "enable udc\n");
@@ -1157,9 +1117,17 @@ static int mv_udc_enable(struct mv_udc *udc)
        return 0;
 }
 
-static void mv_udc_disable(struct mv_udc *udc)
+static int mv_udc_enable(struct mv_udc *udc)
 {
-       if (udc->clock_gating && udc->active) {
+       if (udc->clock_gating)
+               return mv_udc_enable_internal(udc);
+
+       return 0;
+}
+
+static void mv_udc_disable_internal(struct mv_udc *udc)
+{
+       if (udc->active) {
                dev_dbg(&udc->dev->dev, "disable udc\n");
                if (udc->pdata->phy_deinit)
                        udc->pdata->phy_deinit(udc->phy_regs);
@@ -1168,6 +1136,12 @@ static void mv_udc_disable(struct mv_udc *udc)
        }
 }
 
+static void mv_udc_disable(struct mv_udc *udc)
+{
+       if (udc->clock_gating)
+               mv_udc_disable_internal(udc);
+}
+
 static int mv_udc_get_frame(struct usb_gadget *gadget)
 {
        struct mv_udc *udc;
@@ -1178,7 +1152,7 @@ static int mv_udc_get_frame(struct usb_gadget *gadget)
 
        udc = container_of(gadget, struct mv_udc, gadget);
 
-       retval = readl(udc->op_regs->frindex) & USB_FRINDEX_MASKS;
+       retval = readl(&udc->op_regs->frindex) & USB_FRINDEX_MASKS;
 
        return retval;
 }
@@ -1212,10 +1186,11 @@ static int mv_udc_vbus_session(struct usb_gadget *gadget, int is_active)
        udc = container_of(gadget, struct mv_udc, gadget);
        spin_lock_irqsave(&udc->lock, flags);
 
+       udc->vbus_active = (is_active != 0);
+
        dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n",
                __func__, udc->softconnect, udc->vbus_active);
 
-       udc->vbus_active = (is_active != 0);
        if (udc->driver && udc->softconnect && udc->vbus_active) {
                retval = mv_udc_enable(udc);
                if (retval == 0) {
@@ -1244,10 +1219,11 @@ static int mv_udc_pullup(struct usb_gadget *gadget, int is_on)
        udc = container_of(gadget, struct mv_udc, gadget);
        spin_lock_irqsave(&udc->lock, flags);
 
+       udc->softconnect = (is_on != 0);
+
        dev_dbg(&udc->dev->dev, "%s: softconnect %d, vbus_active %d\n",
                        __func__, udc->softconnect, udc->vbus_active);
 
-       udc->softconnect = (is_on != 0);
        if (udc->driver && udc->softconnect && udc->vbus_active) {
                retval = mv_udc_enable(udc);
                if (retval == 0) {
@@ -1407,6 +1383,20 @@ static int mv_udc_start(struct usb_gadget_driver *driver,
                return retval;
        }
 
+       if (udc->transceiver) {
+               retval = otg_set_peripheral(udc->transceiver, &udc->gadget);
+               if (retval) {
+                       dev_err(&udc->dev->dev,
+                               "unable to register peripheral to otg\n");
+                       if (driver->unbind) {
+                               driver->unbind(&udc->gadget);
+                               udc->gadget.dev.driver = NULL;
+                               udc->driver = NULL;
+                       }
+                       return retval;
+               }
+       }
+
        /* pullup is always on */
        mv_udc_pullup(&udc->gadget, 1);
 
@@ -2026,6 +2016,10 @@ static irqreturn_t mv_udc_irq(int irq, void *dev)
        struct mv_udc *udc = (struct mv_udc *)dev;
        u32 status, intr;
 
+       /* Disable ISR when stopped bit is set */
+       if (udc->stopped)
+               return IRQ_NONE;
+
        spin_lock(&udc->lock);
 
        status = readl(&udc->op_regs->usbsts);
@@ -2109,7 +2103,12 @@ static int __devexit mv_udc_remove(struct platform_device *dev)
                destroy_workqueue(udc->qwork);
        }
 
-       if (udc->pdata && udc->pdata->vbus && udc->clock_gating)
+       /*
+        * If we have transceiver inited,
+        * then vbus irq will not be requested in udc driver.
+        */
+       if (udc->pdata && udc->pdata->vbus
+               && udc->clock_gating && udc->transceiver == NULL)
                free_irq(udc->pdata->vbus->irq, &dev->dev);
 
        /* free memory allocated in probe */
@@ -2129,11 +2128,9 @@ static int __devexit mv_udc_remove(struct platform_device *dev)
 
        if (udc->cap_regs)
                iounmap(udc->cap_regs);
-       udc->cap_regs = NULL;
 
        if (udc->phy_regs)
-               iounmap((void *)udc->phy_regs);
-       udc->phy_regs = 0;
+               iounmap(udc->phy_regs);
 
        if (udc->status_req) {
                kfree(udc->status_req->req.buf);
@@ -2182,6 +2179,11 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
 
        udc->dev = dev;
 
+#ifdef CONFIG_USB_OTG_UTILS
+       if (pdata->mode == MV_USB_MODE_OTG)
+               udc->transceiver = otg_get_transceiver();
+#endif
+
        udc->clknum = pdata->clknum;
        for (clk_i = 0; clk_i < udc->clknum; clk_i++) {
                udc->clk[clk_i] = clk_get(&dev->dev, pdata->clkname[clk_i]);
@@ -2213,24 +2215,20 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
                goto err_iounmap_capreg;
        }
 
-       udc->phy_regs = (unsigned int)ioremap(r->start, resource_size(r));
-       if (udc->phy_regs == 0) {
+       udc->phy_regs = ioremap(r->start, resource_size(r));
+       if (udc->phy_regs == NULL) {
                dev_err(&dev->dev, "failed to map phy I/O memory\n");
                retval = -EBUSY;
                goto err_iounmap_capreg;
        }
 
        /* we will acces controller register, so enable the clk */
-       udc_clock_enable(udc);
-       if (pdata->phy_init) {
-               retval = pdata->phy_init(udc->phy_regs);
-               if (retval) {
-                       dev_err(&dev->dev, "phy init error %d\n", retval);
-                       goto err_iounmap_phyreg;
-               }
-       }
+       retval = mv_udc_enable_internal(udc);
+       if (retval)
+               goto err_iounmap_phyreg;
 
-       udc->op_regs = (struct mv_op_regs __iomem *)((u32)udc->cap_regs
+       udc->op_regs =
+               (struct mv_op_regs __iomem *)((unsigned long)udc->cap_regs
                + (readl(&udc->cap_regs->caplength_hciversion)
                        & CAPLENGTH_MASK));
        udc->max_eps = readl(&udc->cap_regs->dccparams) & DCCPARAMS_DEN_MASK;
@@ -2312,7 +2310,7 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
        udc->gadget.ep0 = &udc->eps[0].ep;      /* gadget ep0 */
        INIT_LIST_HEAD(&udc->gadget.ep_list);   /* ep_list */
        udc->gadget.speed = USB_SPEED_UNKNOWN;  /* speed */
-       udc->gadget.is_dualspeed = 1;           /* support dual speed */
+       udc->gadget.max_speed = USB_SPEED_HIGH; /* support dual speed */
 
        /* the "gadget" abstracts/virtualizes the controller */
        dev_set_name(&udc->gadget.dev, "gadget");
@@ -2328,7 +2326,9 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
        eps_init(udc);
 
        /* VBUS detect: we can disable/enable clock on demand.*/
-       if (pdata->vbus) {
+       if (udc->transceiver)
+               udc->clock_gating = 1;
+       else if (pdata->vbus) {
                udc->clock_gating = 1;
                retval = request_threaded_irq(pdata->vbus->irq, NULL,
                                mv_udc_vbus_irq, IRQF_ONESHOT, "vbus", udc);
@@ -2354,11 +2354,9 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
         * If not, it means that VBUS detection is not supported, we
         * have to enable vbus active all the time to let controller work.
         */
-       if (udc->clock_gating) {
-               if (udc->pdata->phy_deinit)
-                       udc->pdata->phy_deinit(udc->phy_regs);
-               udc_clock_disable(udc);
-       } else
+       if (udc->clock_gating)
+               mv_udc_disable_internal(udc);
+       else
                udc->vbus_active = 1;
 
        retval = usb_add_gadget_udc(&dev->dev, &udc->gadget);
@@ -2371,7 +2369,8 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
        return 0;
 
 err_unregister:
-       if (udc->pdata && udc->pdata->vbus && udc->clock_gating)
+       if (udc->pdata && udc->pdata->vbus
+               && udc->clock_gating && udc->transceiver == NULL)
                free_irq(pdata->vbus->irq, &dev->dev);
        device_unregister(&udc->gadget.dev);
 err_free_irq:
@@ -2387,11 +2386,9 @@ err_free_dma:
        dma_free_coherent(&dev->dev, udc->ep_dqh_size,
                        udc->ep_dqh, udc->ep_dqh_dma);
 err_disable_clock:
-       if (udc->pdata->phy_deinit)
-               udc->pdata->phy_deinit(udc->phy_regs);
-       udc_clock_disable(udc);
+       mv_udc_disable_internal(udc);
 err_iounmap_phyreg:
-       iounmap((void *)udc->phy_regs);
+       iounmap(udc->phy_regs);
 err_iounmap_capreg:
        iounmap(udc->cap_regs);
 err_put_clk:
@@ -2407,7 +2404,30 @@ static int mv_udc_suspend(struct device *_dev)
 {
        struct mv_udc *udc = the_controller;
 
-       udc_stop(udc);
+       /* if OTG is enabled, the following will be done in OTG driver*/
+       if (udc->transceiver)
+               return 0;
+
+       if (udc->pdata->vbus && udc->pdata->vbus->poll)
+               if (udc->pdata->vbus->poll() == VBUS_HIGH) {
+                       dev_info(&udc->dev->dev, "USB cable is connected!\n");
+                       return -EAGAIN;
+               }
+
+       /*
+        * only cable is unplugged, udc can suspend.
+        * So do not care about clock_gating == 1.
+        */
+       if (!udc->clock_gating) {
+               udc_stop(udc);
+
+               spin_lock_irq(&udc->lock);
+               /* stop all usb activities */
+               stop_activity(udc, udc->driver);
+               spin_unlock_irq(&udc->lock);
+
+               mv_udc_disable_internal(udc);
+       }
 
        return 0;
 }
@@ -2417,20 +2437,22 @@ static int mv_udc_resume(struct device *_dev)
        struct mv_udc *udc = the_controller;
        int retval;
 
-       if (udc->pdata->phy_init) {
-               retval = udc->pdata->phy_init(udc->phy_regs);
-               if (retval) {
-                       dev_err(&udc->dev->dev,
-                               "init phy error %d when resume back\n",
-                               retval);
+       /* if OTG is enabled, the following will be done in OTG driver*/
+       if (udc->transceiver)
+               return 0;
+
+       if (!udc->clock_gating) {
+               retval = mv_udc_enable_internal(udc);
+               if (retval)
                        return retval;
+
+               if (udc->driver && udc->softconnect) {
+                       udc_reset(udc);
+                       ep0_reset(udc);
+                       udc_start(udc);
                }
        }
 
-       udc_reset(udc);
-       ep0_reset(udc);
-       udc_start(udc);
-
        return 0;
 }
 
@@ -2457,30 +2479,16 @@ static struct platform_driver udc_driver = {
        .shutdown       = mv_udc_shutdown,
        .driver         = {
                .owner  = THIS_MODULE,
-               .name   = "pxa-u2o",
+               .name   = "mv-udc",
 #ifdef CONFIG_PM
                .pm     = &mv_udc_pm_ops,
 #endif
        },
 };
-MODULE_ALIAS("platform:pxa-u2o");
 
+module_platform_driver(udc_driver);
+MODULE_ALIAS("platform:mv-udc");
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>");
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
-
-
-static int __init init(void)
-{
-       return platform_driver_register(&udc_driver);
-}
-module_init(init);
-
-
-static void __exit cleanup(void)
-{
-       platform_driver_unregister(&udc_driver);
-}
-module_exit(cleanup);
-
index d1b7636..4c81d54 100644 (file)
@@ -1459,7 +1459,7 @@ static int net2272_start(struct usb_gadget *_gadget,
        unsigned i;
 
        if (!driver || !driver->unbind || !driver->setup ||
-           driver->speed != USB_SPEED_HIGH)
+           driver->max_speed != USB_SPEED_HIGH)
                return -EINVAL;
 
        dev = container_of(_gadget, struct net2272, gadget);
@@ -2235,7 +2235,7 @@ net2272_probe_init(struct device *dev, unsigned int irq)
        ret->irq = irq;
        ret->dev = dev;
        ret->gadget.ops = &net2272_ops;
-       ret->gadget.is_dualspeed = 1;
+       ret->gadget.max_speed = USB_SPEED_HIGH;
 
        /* the "gadget" abstracts/virtualizes the controller */
        dev_set_name(&ret->gadget.dev, "gadget");
index da2b9d0..cf1f364 100644 (file)
@@ -1881,7 +1881,7 @@ static int net2280_start(struct usb_gadget *_gadget,
         * (dev->usb->xcvrdiag & FORCE_FULL_SPEED_MODE)
         * "must not be used in normal operation"
         */
-       if (!driver || driver->speed < USB_SPEED_HIGH
+       if (!driver || driver->max_speed < USB_SPEED_HIGH
                        || !driver->setup)
                return -EINVAL;
 
@@ -2698,7 +2698,7 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
        spin_lock_init (&dev->lock);
        dev->pdev = pdev;
        dev->gadget.ops = &net2280_ops;
-       dev->gadget.is_dualspeed = 1;
+       dev->gadget.max_speed = USB_SPEED_HIGH;
 
        /* the "gadget" abstracts/virtualizes the controller */
        dev_set_name(&dev->gadget.dev, "gadget");
index 788989a..7db5bbe 100644 (file)
@@ -2110,7 +2110,7 @@ static int omap_udc_start(struct usb_gadget_driver *driver,
                return -ENODEV;
        if (!driver
                        // FIXME if otg, check:  driver->is_otg
-                       || driver->speed < USB_SPEED_FULL
+                       || driver->max_speed < USB_SPEED_FULL
                        || !bind || !driver->setup)
                return -EINVAL;
 
@@ -2676,6 +2676,7 @@ omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv)
        INIT_LIST_HEAD(&udc->gadget.ep_list);
        INIT_LIST_HEAD(&udc->iso);
        udc->gadget.speed = USB_SPEED_UNKNOWN;
+       udc->gadget.max_speed = USB_SPEED_FULL;
        udc->gadget.name = driver_name;
 
        device_initialize(&udc->gadget.dev);
index 5048a0c..dd2313c 100644 (file)
@@ -2693,7 +2693,7 @@ static int pch_udc_start(struct usb_gadget_driver *driver,
        struct pch_udc_dev      *dev = pch_udc;
        int                     retval;
 
-       if (!driver || (driver->speed == USB_SPEED_UNKNOWN) || !bind ||
+       if (!driver || (driver->max_speed == USB_SPEED_UNKNOWN) || !bind ||
            !driver->setup || !driver->unbind || !driver->disconnect) {
                dev_err(&dev->pdev->dev,
                        "%s: invalid driver parameter\n", __func__);
@@ -2941,7 +2941,7 @@ static int pch_udc_probe(struct pci_dev *pdev,
        dev->gadget.dev.dma_mask = pdev->dev.dma_mask;
        dev->gadget.dev.release = gadget_release;
        dev->gadget.name = KBUILD_MODNAME;
-       dev->gadget.is_dualspeed = 1;
+       dev->gadget.max_speed = USB_SPEED_HIGH;
 
        retval = device_register(&dev->gadget.dev);
        if (retval)
index 65a8834..d83134b 100644 (file)
@@ -1141,7 +1141,7 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                                break;
 #ifdef CONFIG_USB_GADGET_DUALSPEED
                        case USB_DT_DEVICE_QUALIFIER:
-                               if (!gadget->is_dualspeed)
+                               if (!gadget_is_dualspeed(gadget))
                                        break;
                                /*
                                 * assumes ep0 uses the same value for both
@@ -1155,7 +1155,7 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
                                break;
 
                        case USB_DT_OTHER_SPEED_CONFIG:
-                               if (!gadget->is_dualspeed)
+                               if (!gadget_is_dualspeed(gadget))
                                        break;
                                /* FALLTHROUGH */
 #endif /* CONFIG_USB_GADGET_DUALSPEED */
@@ -1535,7 +1535,7 @@ fail:
 /*-------------------------------------------------------------------------*/
 
 static struct usb_gadget_driver printer_driver = {
-       .speed          = DEVSPEED,
+       .max_speed      = DEVSPEED,
 
        .function       = (char *) driver_desc,
        .unbind         = printer_unbind,
index c090a7e..dd47063 100644 (file)
@@ -1264,7 +1264,7 @@ static int pxa25x_start(struct usb_gadget_driver *driver,
        int                     retval;
 
        if (!driver
-                       || driver->speed < USB_SPEED_FULL
+                       || driver->max_speed < USB_SPEED_FULL
                        || !bind
                        || !driver->disconnect
                        || !driver->setup)
index 18b6b09..f4c44eb 100644 (file)
@@ -1807,7 +1807,7 @@ static int pxa27x_udc_start(struct usb_gadget_driver *driver,
        struct pxa_udc *udc = the_controller;
        int retval;
 
-       if (!driver || driver->speed < USB_SPEED_FULL || !bind
+       if (!driver || driver->max_speed < USB_SPEED_FULL || !bind
                        || !driver->disconnect || !driver->setup)
                return -EINVAL;
        if (!udc)
index fc719a3..f5b8d21 100644 (file)
@@ -1746,7 +1746,7 @@ static int r8a66597_start(struct usb_gadget *gadget,
        struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget);
 
        if (!driver
-                       || driver->speed < USB_SPEED_HIGH
+                       || driver->max_speed < USB_SPEED_HIGH
                        || !driver->setup)
                return -EINVAL;
        if (!r8a66597)
@@ -1911,7 +1911,7 @@ static int __init r8a66597_probe(struct platform_device *pdev)
 
        r8a66597->gadget.ops = &r8a66597_gadget_ops;
        dev_set_name(&r8a66597->gadget.dev, "gadget");
-       r8a66597->gadget.is_dualspeed = 1;
+       r8a66597->gadget.max_speed = USB_SPEED_HIGH;
        r8a66597->gadget.dev.parent = &pdev->dev;
        r8a66597->gadget.dev.dma_mask = pdev->dev.dma_mask;
        r8a66597->gadget.dev.release = pdev->dev.release;
index b314482..69295ba 100644 (file)
@@ -2586,7 +2586,7 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver,
                return -EINVAL;
        }
 
-       if (driver->speed < USB_SPEED_FULL)
+       if (driver->max_speed < USB_SPEED_FULL)
                dev_err(hsotg->dev, "%s: bad speed\n", __func__);
 
        if (!bind || !driver->setup) {
@@ -3362,7 +3362,7 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
 
        dev_set_name(&hsotg->gadget.dev, "gadget");
 
-       hsotg->gadget.is_dualspeed = 1;
+       hsotg->gadget.max_speed = USB_SPEED_HIGH;
        hsotg->gadget.ops = &s3c_hsotg_gadget_ops;
        hsotg->gadget.name = dev_name(dev);
 
@@ -3467,18 +3467,7 @@ static struct platform_driver s3c_hsotg_driver = {
        .resume         = s3c_hsotg_resume,
 };
 
-static int __init s3c_hsotg_modinit(void)
-{
-       return platform_driver_register(&s3c_hsotg_driver);
-}
-
-static void __exit s3c_hsotg_modexit(void)
-{
-       platform_driver_unregister(&s3c_hsotg_driver);
-}
-
-module_init(s3c_hsotg_modinit);
-module_exit(s3c_hsotg_modexit);
+module_platform_driver(s3c_hsotg_driver);
 
 MODULE_DESCRIPTION("Samsung S3C USB High-speed/OtG device");
 MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
index 20a553b..df8661d 100644 (file)
 #include <linux/usb/gadget.h>
 #include <linux/usb/otg.h>
 #include <linux/prefetch.h>
+#include <linux/platform_data/s3c-hsudc.h>
+#include <linux/regulator/consumer.h>
 
 #include <mach/regs-s3c2443-clock.h>
-#include <plat/udc.h>
 
 #define S3C_HSUDC_REG(x)       (x)
 
 #define DATA_STATE_XMIT                        (1)
 #define DATA_STATE_RECV                        (2)
 
+static const char * const s3c_hsudc_supply_names[] = {
+       "vdda",         /* analog phy supply, 3.3V */
+       "vddi",         /* digital phy supply, 1.2V */
+       "vddosc",       /* oscillator supply, 1.8V - 3.3V */
+};
+
 /**
  * struct s3c_hsudc_ep - Endpoint representation used by driver.
  * @ep: USB gadget layer representation of device endpoint.
@@ -139,6 +146,7 @@ struct s3c_hsudc {
        struct device *dev;
        struct s3c24xx_hsudc_platdata *pd;
        struct otg_transceiver *transceiver;
+       struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsudc_supply_names)];
        spinlock_t lock;
        void __iomem *regs;
        struct resource *mem_rsrc;
@@ -153,7 +161,6 @@ struct s3c_hsudc {
 #define ep_index(_ep)          ((_ep)->bEndpointAddress & \
                                        USB_ENDPOINT_NUMBER_MASK)
 
-static struct s3c_hsudc *the_controller;
 static const char driver_name[] = "s3c-udc";
 static const char ep0name[] = "ep0-control";
 
@@ -282,8 +289,7 @@ static void s3c_hsudc_nuke_ep(struct s3c_hsudc_ep *hsep, int status)
  * All the endpoints are stopped and any pending transfer requests if any on
  * the endpoint are terminated.
  */
-static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc,
-                         struct usb_gadget_driver *driver)
+static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc)
 {
        struct s3c_hsudc_ep *hsep;
        int epnum;
@@ -295,10 +301,6 @@ static void s3c_hsudc_stop_activity(struct s3c_hsudc *hsudc,
                hsep->stopped = 1;
                s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN);
        }
-
-       spin_unlock(&hsudc->lock);
-       driver->disconnect(&hsudc->gadget);
-       spin_lock(&hsudc->lock);
 }
 
 /**
@@ -1135,16 +1137,15 @@ static irqreturn_t s3c_hsudc_irq(int irq, void *_dev)
        return IRQ_HANDLED;
 }
 
-static int s3c_hsudc_start(struct usb_gadget_driver *driver,
-               int (*bind)(struct usb_gadget *))
+static int s3c_hsudc_start(struct usb_gadget *gadget,
+               struct usb_gadget_driver *driver)
 {
-       struct s3c_hsudc *hsudc = the_controller;
+       struct s3c_hsudc *hsudc = to_hsudc(gadget);
        int ret;
 
        if (!driver
-               || driver->speed < USB_SPEED_FULL
-               || !bind
-               || !driver->unbind || !driver->disconnect || !driver->setup)
+               || driver->max_speed < USB_SPEED_FULL
+               || !driver->setup)
                return -EINVAL;
 
        if (!hsudc)
@@ -1155,21 +1156,12 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver,
 
        hsudc->driver = driver;
        hsudc->gadget.dev.driver = &driver->driver;
-       hsudc->gadget.speed = USB_SPEED_UNKNOWN;
-       ret = device_add(&hsudc->gadget.dev);
-       if (ret) {
-               dev_err(hsudc->dev, "failed to probe gadget device");
-               return ret;
-       }
 
-       ret = bind(&hsudc->gadget);
-       if (ret) {
-               dev_err(hsudc->dev, "%s: bind failed\n", hsudc->gadget.name);
-               device_del(&hsudc->gadget.dev);
-
-               hsudc->driver = NULL;
-               hsudc->gadget.dev.driver = NULL;
-               return ret;
+       ret = regulator_bulk_enable(ARRAY_SIZE(hsudc->supplies),
+                                   hsudc->supplies);
+       if (ret != 0) {
+               dev_err(hsudc->dev, "failed to enable supplies: %d\n", ret);
+               goto err_supplies;
        }
 
        /* connect to bus through transceiver */
@@ -1178,13 +1170,7 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver,
                if (ret) {
                        dev_err(hsudc->dev, "%s: can't bind to transceiver\n",
                                        hsudc->gadget.name);
-                       driver->unbind(&hsudc->gadget);
-
-                       device_del(&hsudc->gadget.dev);
-
-                       hsudc->driver = NULL;
-                       hsudc->gadget.dev.driver = NULL;
-                       return ret;
+                       goto err_otg;
                }
        }
 
@@ -1197,34 +1183,43 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver,
                hsudc->pd->gpio_init();
 
        return 0;
+err_otg:
+       regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
+err_supplies:
+       hsudc->driver = NULL;
+       hsudc->gadget.dev.driver = NULL;
+       return ret;
 }
 
-static int s3c_hsudc_stop(struct usb_gadget_driver *driver)
+static int s3c_hsudc_stop(struct usb_gadget *gadget,
+               struct usb_gadget_driver *driver)
 {
-       struct s3c_hsudc *hsudc = the_controller;
+       struct s3c_hsudc *hsudc = to_hsudc(gadget);
        unsigned long flags;
 
        if (!hsudc)
                return -ENODEV;
 
-       if (!driver || driver != hsudc->driver || !driver->unbind)
+       if (!driver || driver != hsudc->driver)
                return -EINVAL;
 
        spin_lock_irqsave(&hsudc->lock, flags);
-       hsudc->driver = 0;
+       hsudc->driver = NULL;
+       hsudc->gadget.dev.driver = NULL;
+       hsudc->gadget.speed = USB_SPEED_UNKNOWN;
        s3c_hsudc_uninit_phy();
        if (hsudc->pd->gpio_uninit)
                hsudc->pd->gpio_uninit();
-       s3c_hsudc_stop_activity(hsudc, driver);
+       s3c_hsudc_stop_activity(hsudc);
        spin_unlock_irqrestore(&hsudc->lock, flags);
 
        if (hsudc->transceiver)
                (void) otg_set_peripheral(hsudc->transceiver, NULL);
 
-       driver->unbind(&hsudc->gadget);
-       device_del(&hsudc->gadget.dev);
        disable_irq(hsudc->irq);
 
+       regulator_bulk_disable(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
+
        dev_info(hsudc->dev, "unregistered gadget driver '%s'\n",
                        driver->driver.name);
        return 0;
@@ -1242,7 +1237,7 @@ static int s3c_hsudc_gadget_getframe(struct usb_gadget *gadget)
 
 static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA)
 {
-       struct s3c_hsudc *hsudc = the_controller;
+       struct s3c_hsudc *hsudc = to_hsudc(gadget);
 
        if (!hsudc)
                return -ENODEV;
@@ -1255,18 +1250,18 @@ static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA)
 
 static struct usb_gadget_ops s3c_hsudc_gadget_ops = {
        .get_frame      = s3c_hsudc_gadget_getframe,
-       .start          = s3c_hsudc_start,
-       .stop           = s3c_hsudc_stop,
+       .udc_start      = s3c_hsudc_start,
+       .udc_stop       = s3c_hsudc_stop,
        .vbus_draw      = s3c_hsudc_vbus_draw,
 };
 
-static int s3c_hsudc_probe(struct platform_device *pdev)
+static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
        struct resource *res;
        struct s3c_hsudc *hsudc;
        struct s3c24xx_hsudc_platdata *pd = pdev->dev.platform_data;
-       int ret;
+       int ret, i;
 
        hsudc = kzalloc(sizeof(struct s3c_hsudc) +
                        sizeof(struct s3c_hsudc_ep) * pd->epnum,
@@ -1276,13 +1271,22 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
-       the_controller = hsudc;
        platform_set_drvdata(pdev, dev);
        hsudc->dev = dev;
        hsudc->pd = pdev->dev.platform_data;
 
        hsudc->transceiver = otg_get_transceiver();
 
+       for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++)
+               hsudc->supplies[i].supply = s3c_hsudc_supply_names[i];
+
+       ret = regulator_bulk_get(dev, ARRAY_SIZE(hsudc->supplies),
+                                hsudc->supplies);
+       if (ret != 0) {
+               dev_err(dev, "failed to request supplies: %d\n", ret);
+               goto err_supplies;
+       }
+
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res) {
                dev_err(dev, "unable to obtain driver resource data\n");
@@ -1307,10 +1311,9 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
 
        spin_lock_init(&hsudc->lock);
 
-       device_initialize(&hsudc->gadget.dev);
        dev_set_name(&hsudc->gadget.dev, "gadget");
 
-       hsudc->gadget.is_dualspeed = 1;
+       hsudc->gadget.max_speed = USB_SPEED_HIGH;
        hsudc->gadget.ops = &s3c_hsudc_gadget_ops;
        hsudc->gadget.name = dev_name(dev);
        hsudc->gadget.dev.parent = dev;
@@ -1319,6 +1322,7 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
 
        hsudc->gadget.is_otg = 0;
        hsudc->gadget.is_a_peripheral = 0;
+       hsudc->gadget.speed = USB_SPEED_UNKNOWN;
 
        s3c_hsudc_setup_ep(hsudc);
 
@@ -1348,12 +1352,20 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
        disable_irq(hsudc->irq);
        local_irq_enable();
 
+       ret = device_register(&hsudc->gadget.dev);
+       if (ret) {
+               put_device(&hsudc->gadget.dev);
+               goto err_add_device;
+       }
+
        ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget);
        if (ret)
                goto err_add_udc;
 
        return 0;
 err_add_udc:
+       device_unregister(&hsudc->gadget.dev);
+err_add_device:
        clk_disable(hsudc->uclk);
        clk_put(hsudc->uclk);
 err_clk:
@@ -1362,10 +1374,13 @@ err_irq:
        iounmap(hsudc->regs);
 
 err_remap:
-       release_resource(hsudc->mem_rsrc);
-       kfree(hsudc->mem_rsrc);
-
+       release_mem_region(res->start, resource_size(res));
 err_res:
+       if (hsudc->transceiver)
+               otg_put_transceiver(hsudc->transceiver);
+
+       regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
+err_supplies:
        kfree(hsudc);
        return ret;
 }
@@ -1377,21 +1392,10 @@ static struct platform_driver s3c_hsudc_driver = {
        },
        .probe          = s3c_hsudc_probe,
 };
-MODULE_ALIAS("platform:s3c-hsudc");
-
-static int __init s3c_hsudc_modinit(void)
-{
-       return platform_driver_register(&s3c_hsudc_driver);
-}
 
-static void __exit s3c_hsudc_modexit(void)
-{
-       platform_driver_unregister(&s3c_hsudc_driver);
-}
-
-module_init(s3c_hsudc_modinit);
-module_exit(s3c_hsudc_modexit);
+module_platform_driver(s3c_hsudc_driver);
 
 MODULE_DESCRIPTION("Samsung S3C24XX USB high-speed controller driver");
 MODULE_AUTHOR("Thomas Abraham <thomas.ab@samsung.com>");
 MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:s3c-hsudc");
index fac4c65..3f87cb9 100644 (file)
@@ -1683,9 +1683,9 @@ static int s3c2410_udc_start(struct usb_gadget_driver *driver,
        if (udc->driver)
                return -EBUSY;
 
-       if (!bind || !driver->setup || driver->speed < USB_SPEED_FULL) {
+       if (!bind || !driver->setup || driver->max_speed < USB_SPEED_FULL) {
                printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n",
-                       bind, driver->setup, driver->speed);
+                       bind, driver->setup, driver->max_speed);
                return -EINVAL;
        }
 #if defined(MODULE)
index 6939e17..0b0d12c 100644 (file)
@@ -371,14 +371,28 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
 }
 static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store);
 
-static ssize_t usb_udc_speed_show(struct device *dev,
+#define USB_UDC_SPEED_ATTR(name, param)                                        \
+ssize_t usb_udc_##param##_show(struct device *dev,                     \
+               struct device_attribute *attr, char *buf)               \
+{                                                                      \
+       struct usb_udc *udc = container_of(dev, struct usb_udc, dev);   \
+       return snprintf(buf, PAGE_SIZE, "%s\n",                         \
+                       usb_speed_string(udc->gadget->param));          \
+}                                                                      \
+static DEVICE_ATTR(name, S_IRUSR, usb_udc_##param##_show, NULL)
+
+static USB_UDC_SPEED_ATTR(current_speed, speed);
+static USB_UDC_SPEED_ATTR(maximum_speed, max_speed);
+
+/* TODO: Scheduled for removal in 3.8. */
+static ssize_t usb_udc_is_dualspeed_show(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
        struct usb_udc          *udc = container_of(dev, struct usb_udc, dev);
-       return snprintf(buf, PAGE_SIZE, "%s\n",
-                       usb_speed_string(udc->gadget->speed));
+       return snprintf(buf, PAGE_SIZE, "%d\n",
+                       gadget_is_dualspeed(udc->gadget));
 }
-static DEVICE_ATTR(speed, S_IRUGO, usb_udc_speed_show, NULL);
+static DEVICE_ATTR(is_dualspeed, S_IRUSR, usb_udc_is_dualspeed_show, NULL);
 
 #define USB_UDC_ATTR(name)                                     \
 ssize_t usb_udc_##name##_show(struct device *dev,              \
@@ -391,7 +405,6 @@ ssize_t usb_udc_##name##_show(struct device *dev,           \
 }                                                              \
 static DEVICE_ATTR(name, S_IRUGO, usb_udc_##name##_show, NULL)
 
-static USB_UDC_ATTR(is_dualspeed);
 static USB_UDC_ATTR(is_otg);
 static USB_UDC_ATTR(is_a_peripheral);
 static USB_UDC_ATTR(b_hnp_enable);
@@ -401,7 +414,8 @@ static USB_UDC_ATTR(a_alt_hnp_support);
 static struct attribute *usb_udc_attrs[] = {
        &dev_attr_srp.attr,
        &dev_attr_soft_connect.attr,
-       &dev_attr_speed.attr,
+       &dev_attr_current_speed.attr,
+       &dev_attr_maximum_speed.attr,
 
        &dev_attr_is_dualspeed.attr,
        &dev_attr_is_otg.attr,
index 58c4d37..4d25b90 100644 (file)
 #include <linux/string.h>
 #include <linux/device.h>
 #include <linux/init.h>
+#include <linux/nls.h>
 
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
 
-#include <asm/unaligned.h>
-
-
-static int utf8_to_utf16le(const char *s, __le16 *cp, unsigned len)
-{
-       int     count = 0;
-       u8      c;
-       u16     uchar;
-
-       /* this insists on correct encodings, though not minimal ones.
-        * BUT it currently rejects legit 4-byte UTF-8 code points,
-        * which need surrogate pairs.  (Unicode 3.1 can use them.)
-        */
-       while (len != 0 && (c = (u8) *s++) != 0) {
-               if (unlikely(c & 0x80)) {
-                       // 2-byte sequence:
-                       // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx
-                       if ((c & 0xe0) == 0xc0) {
-                               uchar = (c & 0x1f) << 6;
-
-                               c = (u8) *s++;
-                               if ((c & 0xc0) != 0x80)
-                                       goto fail;
-                               c &= 0x3f;
-                               uchar |= c;
-
-                       // 3-byte sequence (most CJKV characters):
-                       // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx
-                       } else if ((c & 0xf0) == 0xe0) {
-                               uchar = (c & 0x0f) << 12;
-
-                               c = (u8) *s++;
-                               if ((c & 0xc0) != 0x80)
-                                       goto fail;
-                               c &= 0x3f;
-                               uchar |= c << 6;
-
-                               c = (u8) *s++;
-                               if ((c & 0xc0) != 0x80)
-                                       goto fail;
-                               c &= 0x3f;
-                               uchar |= c;
-
-                               /* no bogus surrogates */
-                               if (0xd800 <= uchar && uchar <= 0xdfff)
-                                       goto fail;
-
-                       // 4-byte sequence (surrogate pairs, currently rare):
-                       // 11101110wwwwzzzzyy + 110111yyyyxxxxxx
-                       //     = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
-                       // (uuuuu = wwww + 1)
-                       // FIXME accept the surrogate code points (only)
-
-                       } else
-                               goto fail;
-               } else
-                       uchar = c;
-               put_unaligned_le16(uchar, cp++);
-               count++;
-               len--;
-       }
-       return count;
-fail:
-       return -1;
-}
-
 
 /**
  * usb_gadget_get_string - fill out a string descriptor 
  * @table: of c strings encoded using UTF-8
  * @id: string id, from low byte of wValue in get string descriptor
- * @buf: at least 256 bytes
+ * @buf: at least 256 bytes, must be 16-bit aligned
  *
  * Finds the UTF-8 string matching the ID, and converts it into a
  * string descriptor in utf16-le.
@@ -125,8 +60,8 @@ usb_gadget_get_string (struct usb_gadget_strings *table, int id, u8 *buf)
 
        /* string descriptors have length, tag, then UTF16-LE text */
        len = min ((size_t) 126, strlen (s->s));
-       memset (buf + 2, 0, 2 * len);   /* zero all the bytes */
-       len = utf8_to_utf16le(s->s, (__le16 *)&buf[2], len);
+       len = utf8s_to_utf16s(s->s, len, UTF16_LITTLE_ENDIAN,
+                       (wchar_t *) &buf[2], 126);
        if (len < 0)
                return -EINVAL;
        buf [0] = (len + 1) * 2;
index 060e0e2..a52769b 100644 (file)
@@ -194,6 +194,15 @@ config USB_EHCI_S5P
        help
         Enable support for the S5P SOC's on-chip EHCI controller.
 
+config USB_EHCI_MV
+       bool "EHCI support for Marvell on-chip controller"
+       depends on USB_EHCI_HCD
+       select USB_EHCI_ROOT_HUB_TT
+       ---help---
+         Enables support for Marvell (including PXA and MMP series) on-chip
+         USB SPH and OTG controller. SPH is a single port host, and it can
+         only be EHCI host. OTG is controller that can switch to host mode.
+
 config USB_W90X900_EHCI
        bool "W90X900(W90P910) EHCI support"
        depends on USB_EHCI_HCD && ARCH_W90X900
index 18bafa9..bf7441a 100644 (file)
@@ -23,6 +23,7 @@ static int au1xxx_ehci_setup(struct usb_hcd *hcd)
        int ret = ehci_init(hcd);
 
        ehci->need_io_watchdog = 0;
+       ehci_reset(ehci);
        return ret;
 }
 
index 3ff9f82..e311a51 100644 (file)
 #include <asm/system.h>
 #include <asm/unaligned.h>
 
+#if defined(CONFIG_PPC_PS3)
+#include <asm/firmware.h>
+#endif
+
 /*-------------------------------------------------------------------------*/
 
 /*
@@ -230,12 +234,58 @@ static int ehci_halt (struct ehci_hcd *ehci)
                          STS_HALT, STS_HALT, 16 * 125);
 }
 
+#if defined(CONFIG_USB_SUSPEND) && defined(CONFIG_PPC_PS3)
+
+/*
+ * The EHCI controller of the Cell Super Companion Chip used in the
+ * PS3 will stop the root hub after all root hub ports are suspended.
+ * When in this condition handshake will return -ETIMEDOUT.  The
+ * STS_HLT bit will not be set, so inspection of the frame index is
+ * used here to test for the condition.  If the condition is found
+ * return success to allow the USB suspend to complete.
+ */
+
+static int handshake_for_broken_root_hub(struct ehci_hcd *ehci,
+                                        void __iomem *ptr, u32 mask, u32 done,
+                                        int usec)
+{
+       unsigned int old_index;
+       int error;
+
+       if (!firmware_has_feature(FW_FEATURE_PS3_LV1))
+               return -ETIMEDOUT;
+
+       old_index = ehci_read_frame_index(ehci);
+
+       error = handshake(ehci, ptr, mask, done, usec);
+
+       if (error == -ETIMEDOUT && ehci_read_frame_index(ehci) == old_index)
+               return 0;
+
+       return error;
+}
+
+#else
+
+static int handshake_for_broken_root_hub(struct ehci_hcd *ehci,
+                                        void __iomem *ptr, u32 mask, u32 done,
+                                        int usec)
+{
+       return -ETIMEDOUT;
+}
+
+#endif
+
 static int handshake_on_error_set_halt(struct ehci_hcd *ehci, void __iomem *ptr,
                                       u32 mask, u32 done, int usec)
 {
        int error;
 
        error = handshake(ehci, ptr, mask, done, usec);
+       if (error == -ETIMEDOUT)
+               error = handshake_for_broken_root_hub(ehci, ptr, mask, done,
+                                                     usec);
+
        if (error) {
                ehci_halt(ehci);
                ehci->rh_state = EHCI_RH_HALTED;
@@ -620,6 +670,7 @@ static int ehci_init(struct usb_hcd *hcd)
        hw = ehci->async->hw;
        hw->hw_next = QH_NEXT(ehci, ehci->async->qh_dma);
        hw->hw_info1 = cpu_to_hc32(ehci, QH_HEAD);
+       hw->hw_info1 |= cpu_to_hc32(ehci, (1 << 7));    /* I = 1 */
        hw->hw_token = cpu_to_hc32(ehci, QTD_STS_HALT);
        hw->hw_qtd_next = EHCI_LIST_END(ehci);
        ehci->async->qh_state = QH_STATE_LINKED;
@@ -677,22 +728,13 @@ static int ehci_init(struct usb_hcd *hcd)
 static int ehci_run (struct usb_hcd *hcd)
 {
        struct ehci_hcd         *ehci = hcd_to_ehci (hcd);
-       int                     retval;
        u32                     temp;
        u32                     hcc_params;
 
        hcd->uses_new_polling = 1;
 
        /* EHCI spec section 4.1 */
-       /*
-        * TDI driver does the ehci_reset in their reset callback.
-        * Don't reset here, because configuration settings will
-        * vanish.
-        */
-       if (!ehci_is_TDI(ehci) && (retval = ehci_reset(ehci)) != 0) {
-               ehci_mem_cleanup(ehci);
-               return retval;
-       }
+
        ehci_writel(ehci, ehci->periodic_dma, &ehci->regs->frame_list);
        ehci_writel(ehci, (u32)ehci->async->qh_dma, &ehci->regs->async_next);
 
@@ -1324,11 +1366,16 @@ MODULE_LICENSE ("GPL");
 #define PLATFORM_DRIVER                ehci_pxa168_driver
 #endif
 
-#ifdef CONFIG_NLM_XLR
+#ifdef CONFIG_CPU_XLR
 #include "ehci-xls.c"
 #define PLATFORM_DRIVER                ehci_xls_driver
 #endif
 
+#ifdef CONFIG_USB_EHCI_MV
+#include "ehci-mv.c"
+#define        PLATFORM_DRIVER         ehci_mv_driver
+#endif
+
 #if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
     !defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
     !defined(XILINX_OF_PLATFORM_DRIVER)
diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c
new file mode 100644 (file)
index 0000000..52a604f
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ * Author: Chao Xie <chao.xie@marvell.com>
+ *        Neil Zhang <zhangwm@marvell.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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <linux/usb/otg.h>
+#include <linux/platform_data/mv_usb.h>
+
+#define CAPLENGTH_MASK         (0xff)
+
+struct ehci_hcd_mv {
+       struct usb_hcd *hcd;
+
+       /* Which mode does this ehci running OTG/Host ? */
+       int mode;
+
+       void __iomem *phy_regs;
+       void __iomem *cap_regs;
+       void __iomem *op_regs;
+
+       struct otg_transceiver *otg;
+
+       struct mv_usb_platform_data *pdata;
+
+       /* clock source and total clock number */
+       unsigned int clknum;
+       struct clk *clk[0];
+};
+
+static void ehci_clock_enable(struct ehci_hcd_mv *ehci_mv)
+{
+       unsigned int i;
+
+       for (i = 0; i < ehci_mv->clknum; i++)
+               clk_enable(ehci_mv->clk[i]);
+}
+
+static void ehci_clock_disable(struct ehci_hcd_mv *ehci_mv)
+{
+       unsigned int i;
+
+       for (i = 0; i < ehci_mv->clknum; i++)
+               clk_disable(ehci_mv->clk[i]);
+}
+
+static int mv_ehci_enable(struct ehci_hcd_mv *ehci_mv)
+{
+       int retval;
+
+       ehci_clock_enable(ehci_mv);
+       if (ehci_mv->pdata->phy_init) {
+               retval = ehci_mv->pdata->phy_init(ehci_mv->phy_regs);
+               if (retval)
+                       return retval;
+       }
+
+       return 0;
+}
+
+static void mv_ehci_disable(struct ehci_hcd_mv *ehci_mv)
+{
+       if (ehci_mv->pdata->phy_deinit)
+               ehci_mv->pdata->phy_deinit(ehci_mv->phy_regs);
+       ehci_clock_disable(ehci_mv);
+}
+
+static int mv_ehci_reset(struct usb_hcd *hcd)
+{
+       struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+       struct device *dev = hcd->self.controller;
+       struct ehci_hcd_mv *ehci_mv = dev_get_drvdata(dev);
+       int retval;
+
+       if (ehci_mv == NULL) {
+               dev_err(dev, "Can not find private ehci data\n");
+               return -ENODEV;
+       }
+
+       /*
+        * data structure init
+        */
+       retval = ehci_init(hcd);
+       if (retval) {
+               dev_err(dev, "ehci_init failed %d\n", retval);
+               return retval;
+       }
+
+       hcd->has_tt = 1;
+       ehci->sbrn = 0x20;
+
+       retval = ehci_reset(ehci);
+       if (retval) {
+               dev_err(dev, "ehci_reset failed %d\n", retval);
+               return retval;
+       }
+
+       return 0;
+}
+
+static const struct hc_driver mv_ehci_hc_driver = {
+       .description = hcd_name,
+       .product_desc = "Marvell EHCI",
+       .hcd_priv_size = sizeof(struct ehci_hcd),
+
+       /*
+        * generic hardware linkage
+        */
+       .irq = ehci_irq,
+       .flags = HCD_MEMORY | HCD_USB2,
+
+       /*
+        * basic lifecycle operations
+        */
+       .reset = mv_ehci_reset,
+       .start = ehci_run,
+       .stop = ehci_stop,
+       .shutdown = ehci_shutdown,
+
+       /*
+        * managing i/o requests and associated device resources
+        */
+       .urb_enqueue = ehci_urb_enqueue,
+       .urb_dequeue = ehci_urb_dequeue,
+       .endpoint_disable = ehci_endpoint_disable,
+       .endpoint_reset = ehci_endpoint_reset,
+       .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+
+       /*
+        * scheduling support
+        */
+       .get_frame_number = ehci_get_frame,
+
+       /*
+        * root hub support
+        */
+       .hub_status_data = ehci_hub_status_data,
+       .hub_control = ehci_hub_control,
+       .bus_suspend = ehci_bus_suspend,
+       .bus_resume = ehci_bus_resume,
+};
+
+static int mv_ehci_probe(struct platform_device *pdev)
+{
+       struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
+       struct usb_hcd *hcd;
+       struct ehci_hcd *ehci;
+       struct ehci_hcd_mv *ehci_mv;
+       struct resource *r;
+       int clk_i, retval = -ENODEV;
+       u32 offset;
+       size_t size;
+
+       if (!pdata) {
+               dev_err(&pdev->dev, "missing platform_data\n");
+               return -ENODEV;
+       }
+
+       if (usb_disabled())
+               return -ENODEV;
+
+       hcd = usb_create_hcd(&mv_ehci_hc_driver, &pdev->dev, "mv ehci");
+       if (!hcd)
+               return -ENOMEM;
+
+       size = sizeof(*ehci_mv) + sizeof(struct clk *) * pdata->clknum;
+       ehci_mv = kzalloc(size, GFP_KERNEL);
+       if (ehci_mv == NULL) {
+               dev_err(&pdev->dev, "cannot allocate ehci_hcd_mv\n");
+               retval = -ENOMEM;
+               goto err_put_hcd;
+       }
+
+       platform_set_drvdata(pdev, ehci_mv);
+       ehci_mv->pdata = pdata;
+       ehci_mv->hcd = hcd;
+
+       ehci_mv->clknum = pdata->clknum;
+       for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++) {
+               ehci_mv->clk[clk_i] =
+                   clk_get(&pdev->dev, pdata->clkname[clk_i]);
+               if (IS_ERR(ehci_mv->clk[clk_i])) {
+                       dev_err(&pdev->dev, "error get clck \"%s\"\n",
+                               pdata->clkname[clk_i]);
+                       retval = PTR_ERR(ehci_mv->clk[clk_i]);
+                       goto err_put_clk;
+               }
+       }
+
+       r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phyregs");
+       if (r == NULL) {
+               dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
+               retval = -ENODEV;
+               goto err_put_clk;
+       }
+
+       ehci_mv->phy_regs = ioremap(r->start, resource_size(r));
+       if (ehci_mv->phy_regs == 0) {
+               dev_err(&pdev->dev, "failed to map phy I/O memory\n");
+               retval = -EFAULT;
+               goto err_put_clk;
+       }
+
+       r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "capregs");
+       if (!r) {
+               dev_err(&pdev->dev, "no I/O memory resource defined\n");
+               retval = -ENODEV;
+               goto err_iounmap_phyreg;
+       }
+
+       ehci_mv->cap_regs = ioremap(r->start, resource_size(r));
+       if (ehci_mv->cap_regs == NULL) {
+               dev_err(&pdev->dev, "failed to map I/O memory\n");
+               retval = -EFAULT;
+               goto err_iounmap_phyreg;
+       }
+
+       retval = mv_ehci_enable(ehci_mv);
+       if (retval) {
+               dev_err(&pdev->dev, "init phy error %d\n", retval);
+               goto err_iounmap_capreg;
+       }
+
+       offset = readl(ehci_mv->cap_regs) & CAPLENGTH_MASK;
+       ehci_mv->op_regs =
+               (void __iomem *) ((unsigned long) ehci_mv->cap_regs + offset);
+
+       hcd->rsrc_start = r->start;
+       hcd->rsrc_len = r->end - r->start + 1;
+       hcd->regs = ehci_mv->op_regs;
+
+       hcd->irq = platform_get_irq(pdev, 0);
+       if (!hcd->irq) {
+               dev_err(&pdev->dev, "Cannot get irq.");
+               retval = -ENODEV;
+               goto err_disable_clk;
+       }
+
+       ehci = hcd_to_ehci(hcd);
+       ehci->caps = (struct ehci_caps *) ehci_mv->cap_regs;
+       ehci->regs = (struct ehci_regs *) ehci_mv->op_regs;
+       ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
+
+       ehci_mv->mode = pdata->mode;
+       if (ehci_mv->mode == MV_USB_MODE_OTG) {
+#ifdef CONFIG_USB_OTG_UTILS
+               ehci_mv->otg = otg_get_transceiver();
+               if (!ehci_mv->otg) {
+                       dev_err(&pdev->dev,
+                               "unable to find transceiver\n");
+                       retval = -ENODEV;
+                       goto err_disable_clk;
+               }
+
+               retval = otg_set_host(ehci_mv->otg, &hcd->self);
+               if (retval < 0) {
+                       dev_err(&pdev->dev,
+                               "unable to register with transceiver\n");
+                       retval = -ENODEV;
+                       goto err_put_transceiver;
+               }
+               /* otg will enable clock before use as host */
+               mv_ehci_disable(ehci_mv);
+#else
+               dev_info(&pdev->dev, "MV_USB_MODE_OTG "
+                        "must have CONFIG_USB_OTG_UTILS enabled\n");
+               goto err_disable_clk;
+#endif
+       } else {
+               if (pdata->set_vbus)
+                       pdata->set_vbus(1);
+
+               retval = usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
+               if (retval) {
+                       dev_err(&pdev->dev,
+                               "failed to add hcd with err %d\n", retval);
+                       goto err_set_vbus;
+               }
+       }
+
+       if (pdata->private_init)
+               pdata->private_init(ehci_mv->op_regs, ehci_mv->phy_regs);
+
+       dev_info(&pdev->dev,
+                "successful find EHCI device with regs 0x%p irq %d"
+                " working in %s mode\n", hcd->regs, hcd->irq,
+                ehci_mv->mode == MV_USB_MODE_OTG ? "OTG" : "Host");
+
+       return 0;
+
+err_set_vbus:
+       if (pdata->set_vbus)
+               pdata->set_vbus(0);
+#ifdef CONFIG_USB_OTG_UTILS
+err_put_transceiver:
+       if (ehci_mv->otg)
+               otg_put_transceiver(ehci_mv->otg);
+#endif
+err_disable_clk:
+       mv_ehci_disable(ehci_mv);
+err_iounmap_capreg:
+       iounmap(ehci_mv->cap_regs);
+err_iounmap_phyreg:
+       iounmap(ehci_mv->phy_regs);
+err_put_clk:
+       for (clk_i--; clk_i >= 0; clk_i--)
+               clk_put(ehci_mv->clk[clk_i]);
+       platform_set_drvdata(pdev, NULL);
+       kfree(ehci_mv);
+err_put_hcd:
+       usb_put_hcd(hcd);
+
+       return retval;
+}
+
+static int mv_ehci_remove(struct platform_device *pdev)
+{
+       struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev);
+       struct usb_hcd *hcd = ehci_mv->hcd;
+       int clk_i;
+
+       if (hcd->rh_registered)
+               usb_remove_hcd(hcd);
+
+       if (ehci_mv->otg) {
+               otg_set_host(ehci_mv->otg, NULL);
+               otg_put_transceiver(ehci_mv->otg);
+       }
+
+       if (ehci_mv->mode == MV_USB_MODE_HOST) {
+               if (ehci_mv->pdata->set_vbus)
+                       ehci_mv->pdata->set_vbus(0);
+
+               mv_ehci_disable(ehci_mv);
+       }
+
+       iounmap(ehci_mv->cap_regs);
+       iounmap(ehci_mv->phy_regs);
+
+       for (clk_i = 0; clk_i < ehci_mv->clknum; clk_i++)
+               clk_put(ehci_mv->clk[clk_i]);
+
+       platform_set_drvdata(pdev, NULL);
+
+       kfree(ehci_mv);
+       usb_put_hcd(hcd);
+
+       return 0;
+}
+
+MODULE_ALIAS("mv-ehci");
+
+static const struct platform_device_id ehci_id_table[] = {
+       {"pxa-u2oehci", PXA_U2OEHCI},
+       {"pxa-sph", PXA_SPH},
+       {"mmp3-hsic", MMP3_HSIC},
+       {"mmp3-fsic", MMP3_FSIC},
+       {},
+};
+
+static void mv_ehci_shutdown(struct platform_device *pdev)
+{
+       struct ehci_hcd_mv *ehci_mv = platform_get_drvdata(pdev);
+       struct usb_hcd *hcd = ehci_mv->hcd;
+
+       if (!hcd->rh_registered)
+               return;
+
+       if (hcd->driver->shutdown)
+               hcd->driver->shutdown(hcd);
+}
+
+static struct platform_driver ehci_mv_driver = {
+       .probe = mv_ehci_probe,
+       .remove = mv_ehci_remove,
+       .shutdown = mv_ehci_shutdown,
+       .driver = {
+                  .name = "mv-ehci",
+                  .bus = &platform_bus_type,
+                  },
+       .id_table = ehci_id_table,
+};
index ba1f513..c010488 100644 (file)
@@ -155,6 +155,8 @@ static int ehci_octeon_drv_probe(struct platform_device *pdev)
        /* cache this readonly data; minimize chip reads */
        ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
 
+       ehci_reset(ehci);
+
        ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (ret) {
                dev_dbg(&pdev->dev, "failed to add hcd with err %d\n", ret);
index e39b029..e33baf9 100644 (file)
@@ -228,6 +228,8 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
        /* cache this readonly data; minimize chip reads */
        omap_ehci->hcs_params = readl(&omap_ehci->caps->hcs_params);
 
+       ehci_reset(omap_ehci);
+
        ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (ret) {
                dev_err(dev, "failed to add hcd with err %d\n", ret);
index 2dc32da..a20e496 100644 (file)
 #include <asm/firmware.h>
 #include <asm/ps3.h>
 
+static void ps3_ehci_setup_insnreg(struct ehci_hcd *ehci)
+{
+       /* PS3 HC internal setup register offsets. */
+
+       enum ps3_ehci_hc_insnreg {
+               ps3_ehci_hc_insnreg01 = 0x084,
+               ps3_ehci_hc_insnreg02 = 0x088,
+               ps3_ehci_hc_insnreg03 = 0x08c,
+       };
+
+       /* PS3 EHCI HC errata fix 316 - The PS3 EHCI HC will reset its
+        * internal INSNREGXX setup regs back to the chip default values
+        * on Host Controller Reset (CMD_RESET) or Light Host Controller
+        * Reset (CMD_LRESET).  The work-around for this is for the HC
+        * driver to re-initialise these regs when ever the HC is reset.
+        */
+
+       /* Set burst transfer counts to 256 out, 32 in. */
+
+       writel_be(0x01000020, (void __iomem *)ehci->regs +
+               ps3_ehci_hc_insnreg01);
+
+       /* Enable burst transfer counts. */
+
+       writel_be(0x00000001, (void __iomem *)ehci->regs +
+               ps3_ehci_hc_insnreg03);
+}
+
 static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
 {
        int result;
@@ -49,6 +77,8 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd)
 
        ehci_reset(ehci);
 
+       ps3_ehci_setup_insnreg(ehci);
+
        return result;
 }
 
index ac0c16e..8d0e7a2 100644 (file)
@@ -299,7 +299,7 @@ static int __devinit ehci_pxa168_drv_probe(struct platform_device *pdev)
        ehci = hcd_to_ehci(hcd);
        ehci->caps = hcd->regs + 0x100;
        ehci->regs = hcd->regs + 0x100 +
-               HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
+               HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
        ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
        hcd->has_tt = 1;
        ehci->sbrn = 0x20;
index 4e4066c..36ca507 100644 (file)
@@ -373,6 +373,17 @@ qh_completions (struct ehci_hcd *ehci, struct ehci_qh *qh)
  retry_xacterr:
                if ((token & QTD_STS_ACTIVE) == 0) {
 
+                       /* Report Data Buffer Error: non-fatal but useful */
+                       if (token & QTD_STS_DBE)
+                               ehci_dbg(ehci,
+                                       "detected DataBufferErr for urb %p ep%d%s len %d, qtd %p [qh %p]\n",
+                                       urb,
+                                       usb_endpoint_num(&urb->ep->desc),
+                                       usb_endpoint_dir_in(&urb->ep->desc) ? "in" : "out",
+                                       urb->transfer_buffer_length,
+                                       qtd,
+                                       qh);
+
                        /* on STALL, error, and short reads this urb must
                         * complete and all its qtds must be recycled.
                         */
@@ -647,7 +658,7 @@ qh_urb_transaction (
        /*
         * data transfer stage:  buffer setup
         */
-       i = urb->num_sgs;
+       i = urb->num_mapped_sgs;
        if (len > 0 && i > 0) {
                sg = urb->sg;
                buf = sg_dma_address(sg);
index 024b65c..293f741 100644 (file)
@@ -14,8 +14,6 @@
 
 #include <linux/clk.h>
 #include <linux/platform_device.h>
-#include <mach/regs-pmu.h>
-#include <plat/cpu.h>
 #include <plat/ehci.h>
 #include <plat/usb-phy.h>
 
@@ -136,6 +134,8 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
        /* cache this readonly data; minimize chip reads */
        ehci->hcs_params = readl(&ehci->caps->hcs_params);
 
+       ehci_reset(ehci);
+
        err = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (err) {
                dev_err(&pdev->dev, "Failed to add USB HCD\n");
index 54d1ab8..c1eda73 100644 (file)
@@ -132,6 +132,8 @@ static int vt8500_ehci_drv_probe(struct platform_device *pdev)
 
        ehci_port_power(ehci, 1);
 
+       ehci_reset(ehci);
+
        ret = usb_add_hcd(hcd, pdev->resource[1].start,
                          IRQF_SHARED);
        if (ret == 0) {
index d661cf7..3d2e26c 100644 (file)
@@ -78,6 +78,8 @@ static int __devinit usb_w90x900_probe(const struct hc_driver *driver,
        if (irq < 0)
                goto err4;
 
+       ehci_reset(ehci);
+
        retval = usb_add_hcd(hcd, irq, IRQF_SHARED);
        if (retval != 0)
                goto err4;
index b4fb511..72f0819 100644 (file)
@@ -69,7 +69,7 @@ int ehci_xls_probe_internal(const struct hc_driver *driver,
        }
 
        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 4ed6d19..d262374 100644 (file)
@@ -824,17 +824,7 @@ static struct platform_driver of_fhci_driver = {
        .remove         = __devexit_p(of_fhci_remove),
 };
 
-static int __init fhci_module_init(void)
-{
-       return platform_driver_register(&of_fhci_driver);
-}
-module_init(fhci_module_init);
-
-static void __exit fhci_module_exit(void)
-{
-       platform_driver_unregister(&of_fhci_driver);
-}
-module_exit(fhci_module_exit);
+module_platform_driver(of_fhci_driver);
 
 MODULE_DESCRIPTION("USB Freescale Host Controller Interface Driver");
 MODULE_AUTHOR("Shlomi Gridish <gridish@freescale.com>, "
index 9037035..7916e56 100644 (file)
@@ -297,17 +297,7 @@ static struct platform_driver fsl_usb2_mph_dr_driver = {
        .remove = __devexit_p(fsl_usb2_mph_dr_of_remove),
 };
 
-static int __init fsl_usb2_mph_dr_init(void)
-{
-       return platform_driver_register(&fsl_usb2_mph_dr_driver);
-}
-module_init(fsl_usb2_mph_dr_init);
-
-static void __exit fsl_usb2_mph_dr_exit(void)
-{
-       platform_driver_unregister(&fsl_usb2_mph_dr_driver);
-}
-module_exit(fsl_usb2_mph_dr_exit);
+module_platform_driver(fsl_usb2_mph_dr_driver);
 
 MODULE_DESCRIPTION("FSL MPH DR OF devices driver");
 MODULE_AUTHOR("Anatolij Gustschin <agust@denx.de>");
index 43b3ca4..104730d 100644 (file)
@@ -776,7 +776,6 @@ static int hwahc_probe(struct usb_interface *usb_iface,
                goto error_alloc;
        }
        usb_hcd->wireless = 1;
-       set_bit(HCD_FLAG_SAW_IRQ, &usb_hcd->flags);
        wusbhc = usb_hcd_to_wusbhc(usb_hcd);
        hwahc = container_of(wusbhc, struct hwahc, wusbhc);
        hwahc_init(hwahc);
index dbf0f15..ff471c1 100644 (file)
@@ -1924,18 +1924,7 @@ static struct platform_driver imx21_hcd_driver = {
        .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_platform_driver(imx21_hcd_driver);
 
 MODULE_DESCRIPTION("i.MX21 USB Host controller");
 MODULE_AUTHOR("Martin Fuzzey");
index 27dfab8..fc72d44 100644 (file)
@@ -32,6 +32,13 @@ static struct kmem_cache *qtd_cachep;
 static struct kmem_cache *qh_cachep;
 static struct kmem_cache *urb_listitem_cachep;
 
+enum queue_head_types {
+       QH_CONTROL,
+       QH_BULK,
+       QH_INTERRUPT,
+       QH_END
+};
+
 struct isp1760_hcd {
        u32 hcs_params;
        spinlock_t              lock;
@@ -40,7 +47,7 @@ struct isp1760_hcd {
        struct slotinfo         int_slots[32];
        int                     int_done_map;
        struct memory_chunk memory_pool[BLOCKS];
-       struct list_head        controlqhs, bulkqhs, interruptqhs;
+       struct list_head        qh_list[QH_END];
 
        /* periodic schedule support */
 #define        DEFAULT_I_TDPS          1024
@@ -406,12 +413,12 @@ static int priv_init(struct usb_hcd *hcd)
 {
        struct isp1760_hcd              *priv = hcd_to_priv(hcd);
        u32                     hcc_params;
+       int i;
 
        spin_lock_init(&priv->lock);
 
-       INIT_LIST_HEAD(&priv->interruptqhs);
-       INIT_LIST_HEAD(&priv->controlqhs);
-       INIT_LIST_HEAD(&priv->bulkqhs);
+       for (i = 0; i < QH_END; i++)
+               INIT_LIST_HEAD(&priv->qh_list[i]);
 
        /*
         * hw default: 1K periodic list heads, one per frame.
@@ -930,9 +937,9 @@ void schedule_ptds(struct usb_hcd *hcd)
        struct isp1760_hcd *priv;
        struct isp1760_qh *qh, *qh_next;
        struct list_head *ep_queue;
-       struct usb_host_endpoint *ep;
        LIST_HEAD(urb_list);
        struct urb_listitem *urb_listitem, *urb_listitem_next;
+       int i;
 
        if (!hcd) {
                WARN_ON(1);
@@ -944,28 +951,13 @@ void schedule_ptds(struct usb_hcd *hcd)
        /*
         * check finished/retired xfers, transfer payloads, call urb_done()
         */
-       ep_queue = &priv->interruptqhs;
-       while (ep_queue) {
+       for (i = 0; i < QH_END; i++) {
+               ep_queue = &priv->qh_list[i];
                list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list) {
-                       ep = list_entry(qh->qtd_list.next, struct isp1760_qtd,
-                                                       qtd_list)->urb->ep;
                        collect_qtds(hcd, qh, &urb_list);
-                       if (list_empty(&qh->qtd_list)) {
+                       if (list_empty(&qh->qtd_list))
                                list_del(&qh->qh_list);
-                               if (ep->hcpriv == NULL) {
-                                       /* Endpoint has been disabled, so we
-                                       can free the associated queue head. */
-                                       qh_free(qh);
-                               }
-                       }
                }
-
-               if (ep_queue == &priv->interruptqhs)
-                       ep_queue = &priv->controlqhs;
-               else if (ep_queue == &priv->controlqhs)
-                       ep_queue = &priv->bulkqhs;
-               else
-                       ep_queue = NULL;
        }
 
        list_for_each_entry_safe(urb_listitem, urb_listitem_next, &urb_list,
@@ -998,17 +990,10 @@ void schedule_ptds(struct usb_hcd *hcd)
         *
         * I'm sure this scheme could be improved upon!
         */
-       ep_queue = &priv->controlqhs;
-       while (ep_queue) {
+       for (i = 0; i < QH_END; i++) {
+               ep_queue = &priv->qh_list[i];
                list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list)
                        enqueue_qtds(hcd, qh);
-
-               if (ep_queue == &priv->controlqhs)
-                       ep_queue = &priv->interruptqhs;
-               else if (ep_queue == &priv->interruptqhs)
-                       ep_queue = &priv->bulkqhs;
-               else
-                       ep_queue = NULL;
        }
 }
 
@@ -1543,16 +1528,16 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
 
        switch (usb_pipetype(urb->pipe)) {
        case PIPE_CONTROL:
-               ep_queue = &priv->controlqhs;
+               ep_queue = &priv->qh_list[QH_CONTROL];
                break;
        case PIPE_BULK:
-               ep_queue = &priv->bulkqhs;
+               ep_queue = &priv->qh_list[QH_BULK];
                break;
        case PIPE_INTERRUPT:
                if (urb->interval < 0)
                        return -EINVAL;
                /* FIXME: Check bandwidth  */
-               ep_queue = &priv->interruptqhs;
+               ep_queue = &priv->qh_list[QH_INTERRUPT];
                break;
        case PIPE_ISOCHRONOUS:
                dev_err(hcd->self.controller, "%s: isochronous USB packets "
@@ -1714,8 +1699,8 @@ static void isp1760_endpoint_disable(struct usb_hcd *hcd,
 {
        struct isp1760_hcd *priv = hcd_to_priv(hcd);
        unsigned long spinflags;
-       struct isp1760_qh *qh;
-       struct isp1760_qtd *qtd;
+       struct isp1760_qh *qh, *qh_iter;
+       int i;
 
        spin_lock_irqsave(&priv->lock, spinflags);
 
@@ -1723,14 +1708,17 @@ static void isp1760_endpoint_disable(struct usb_hcd *hcd,
        if (!qh)
                goto out;
 
-       list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
-               if (qtd->status != QTD_RETIRE) {
-                       dequeue_urb_from_qtd(hcd, qh, qtd);
-                       qtd->urb->status = -ECONNRESET;
-               }
+       WARN_ON(!list_empty(&qh->qtd_list));
 
+       for (i = 0; i < QH_END; i++)
+               list_for_each_entry(qh_iter, &priv->qh_list[i], qh_list)
+                       if (qh_iter == qh) {
+                               list_del(&qh_iter->qh_list);
+                               i = QH_END;
+                               break;
+                       }
+       qh_free(qh);
        ep->hcpriv = NULL;
-       /* Cannot free qh here since it will be parsed by schedule_ptds() */
 
        schedule_ptds(hcd);
 
index 2ac4ac2..4592dc1 100644 (file)
@@ -47,23 +47,27 @@ static int of_isp1760_probe(struct platform_device *dev)
        int virq;
        resource_size_t res_len;
        int ret;
-       const unsigned int *prop;
        unsigned int devflags = 0;
        enum of_gpio_flags gpio_flags;
+       u32 bus_width = 0;
 
        drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
        if (!drvdata)
                return -ENOMEM;
 
        ret = of_address_to_resource(dp, 0, &memory);
-       if (ret)
-               return -ENXIO;
+       if (ret) {
+               ret = -ENXIO;
+               goto free_data;
+       }
 
        res_len = resource_size(&memory);
 
        res = request_mem_region(memory.start, res_len, dev_name(&dev->dev));
-       if (!res)
-               return -EBUSY;
+       if (!res) {
+               ret = -EBUSY;
+               goto free_data;
+       }
 
        if (of_irq_map_one(dp, 0, &oirq)) {
                ret = -ENODEV;
@@ -77,8 +81,8 @@ static int of_isp1760_probe(struct platform_device *dev)
                devflags |= ISP1760_FLAG_ISP1761;
 
        /* Some systems wire up only 16 of the 32 data lines */
-       prop = of_get_property(dp, "bus-width", NULL);
-       if (prop && *prop == 16)
+       of_property_read_u32(dp, "bus-width", &bus_width);
+       if (bus_width == 16)
                devflags |= ISP1760_FLAG_BUS_WIDTH_16;
 
        if (of_get_property(dp, "port1-otg", NULL) != NULL)
@@ -125,6 +129,7 @@ free_gpio:
                gpio_free(drvdata->rst_gpio);
 release_reg:
        release_mem_region(memory.start, res_len);
+free_data:
        kfree(drvdata);
        return ret;
 }
index 9b66df8..40d886a 100644 (file)
@@ -173,12 +173,9 @@ static int ohci_hcd_au1xxx_drv_suspend(struct device *dev)
         * mark HW unaccessible, bail out if RH has been resumed. Use
         * the spinlock to properly synchronize with possible pending
         * RH suspend or resume activity.
-        *
-        * This is still racy as hcd->state is manipulated outside of
-        * any locks =P But that will be a different fix.
         */
        spin_lock_irqsave(&ohci->lock, flags);
-       if (hcd->state != HC_STATE_SUSPENDED) {
+       if (ohci->rh_state != OHCI_RH_SUSPENDED) {
                rc = -EINVAL;
                goto bail;
        }
index d7d3449..5179fcd 100644 (file)
@@ -127,6 +127,19 @@ static char *hcfs2string (int state)
        return "?";
 }
 
+static const char *rh_state_string(struct ohci_hcd *ohci)
+{
+       switch (ohci->rh_state) {
+       case OHCI_RH_HALTED:
+               return "halted";
+       case OHCI_RH_SUSPENDED:
+               return "suspended";
+       case OHCI_RH_RUNNING:
+               return "running";
+       }
+       return "?";
+}
+
 // dump control and status registers
 static void
 ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size)
@@ -136,9 +149,10 @@ ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size)
 
        temp = ohci_readl (controller, &regs->revision) & 0xff;
        ohci_dbg_sw (controller, next, size,
-               "OHCI %d.%d, %s legacy support registers\n",
+               "OHCI %d.%d, %s legacy support registers, rh state %s\n",
                0x03 & (temp >> 4), (temp & 0x0f),
-               (temp & 0x0100) ? "with" : "NO");
+               (temp & 0x0100) ? "with" : "NO",
+               rh_state_string(controller));
 
        temp = ohci_readl (controller, &regs->control);
        ohci_dbg_sw (controller, next, size,
index dc45d48..3d63574 100644 (file)
@@ -179,8 +179,6 @@ static int ohci_hcd_ep93xx_drv_suspend(struct platform_device *pdev, pm_message_
        ohci->next_statechange = jiffies;
 
        ep93xx_stop_hc(&pdev->dev);
-       hcd->state = HC_STATE_SUSPENDED;
-
        return 0;
 }
 
index b263919..4fa5d8c 100644 (file)
@@ -209,7 +209,7 @@ static int ohci_urb_enqueue (
                retval = -ENODEV;
                goto fail;
        }
-       if (!HC_IS_RUNNING(hcd->state)) {
+       if (ohci->rh_state != OHCI_RH_RUNNING) {
                retval = -ENODEV;
                goto fail;
        }
@@ -274,7 +274,7 @@ static int ohci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
        rc = usb_hcd_check_unlink_urb(hcd, urb, status);
        if (rc) {
                ;       /* Do nothing */
-       } else if (HC_IS_RUNNING(hcd->state)) {
+       } else if (ohci->rh_state == OHCI_RH_RUNNING) {
                urb_priv_t  *urb_priv;
 
                /* Unless an IRQ completed the unlink while it was being
@@ -321,7 +321,7 @@ ohci_endpoint_disable (struct usb_hcd *hcd, struct usb_host_endpoint *ep)
 rescan:
        spin_lock_irqsave (&ohci->lock, flags);
 
-       if (!HC_IS_RUNNING (hcd->state)) {
+       if (ohci->rh_state != OHCI_RH_RUNNING) {
 sanitize:
                ed->state = ED_IDLE;
                if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT)
@@ -377,6 +377,7 @@ static void ohci_usb_reset (struct ohci_hcd *ohci)
        ohci->hc_control = ohci_readl (ohci, &ohci->regs->control);
        ohci->hc_control &= OHCI_CTRL_RWC;
        ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
+       ohci->rh_state = OHCI_RH_HALTED;
 }
 
 /* ohci_shutdown forcibly disables IRQs and DMA, helping kexec and
@@ -500,7 +501,7 @@ static int ohci_init (struct ohci_hcd *ohci)
        if (distrust_firmware)
                ohci->flags |= OHCI_QUIRK_HUB_POWER;
 
-       disable (ohci);
+       ohci->rh_state = OHCI_RH_HALTED;
        ohci->regs = hcd->regs;
 
        /* REVISIT this BIOS handshake is now moved into PCI "quirks", and
@@ -575,7 +576,7 @@ static int ohci_run (struct ohci_hcd *ohci)
        int                     first = ohci->fminterval == 0;
        struct usb_hcd          *hcd = ohci_to_hcd(ohci);
 
-       disable (ohci);
+       ohci->rh_state = OHCI_RH_HALTED;
 
        /* boot firmware should have set this up (5.1.1.3.1) */
        if (first) {
@@ -688,7 +689,7 @@ retry:
        ohci->hc_control &= OHCI_CTRL_RWC;
        ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER;
        ohci_writel (ohci, ohci->hc_control, &ohci->regs->control);
-       hcd->state = HC_STATE_RUNNING;
+       ohci->rh_state = OHCI_RH_RUNNING;
 
        /* wake on ConnectStatusChange, matching external hubs */
        ohci_writel (ohci, RH_HS_DRWE, &ohci->regs->roothub.status);
@@ -725,7 +726,6 @@ retry:
 
        // POTPGT delay is bits 24-31, in 2 ms units.
        mdelay ((val >> 23) & 0x1fe);
-       hcd->state = HC_STATE_RUNNING;
 
        if (quirk_zfmicro(ohci)) {
                /* Create timer to watch for bad queue state on ZF Micro */
@@ -761,7 +761,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
         * of dead, unclocked, or unplugged (CardBus...) devices
         */
        if (ints == ~(u32)0) {
-               disable (ohci);
+               ohci->rh_state = OHCI_RH_HALTED;
                ohci_dbg (ohci, "device removed!\n");
                usb_hc_died(hcd);
                return IRQ_HANDLED;
@@ -771,7 +771,7 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
        ints &= ohci_readl(ohci, &regs->intrenable);
 
        /* interrupt for some other device? */
-       if (ints == 0 || unlikely(hcd->state == HC_STATE_HALT))
+       if (ints == 0 || unlikely(ohci->rh_state == OHCI_RH_HALTED))
                return IRQ_NOTMINE;
 
        if (ints & OHCI_INTR_UE) {
@@ -786,8 +786,8 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
 
                        schedule_work (&ohci->nec_work);
                } else {
-                       disable (ohci);
                        ohci_err (ohci, "OHCI Unrecoverable Error, disabled\n");
+                       ohci->rh_state = OHCI_RH_HALTED;
                        usb_hc_died(hcd);
                }
 
@@ -871,11 +871,11 @@ static irqreturn_t ohci_irq (struct usb_hcd *hcd)
        if ((ints & OHCI_INTR_SF) != 0
                        && !ohci->ed_rm_list
                        && !ohci->ed_to_check
-                       && HC_IS_RUNNING(hcd->state))
+                       && ohci->rh_state == OHCI_RH_RUNNING)
                ohci_writel (ohci, OHCI_INTR_SF, &regs->intrdisable);
        spin_unlock (&ohci->lock);
 
-       if (HC_IS_RUNNING(hcd->state)) {
+       if (ohci->rh_state == OHCI_RH_RUNNING) {
                ohci_writel (ohci, ints, &regs->intrstatus);
                ohci_writel (ohci, OHCI_INTR_MIE, &regs->intrenable);
                // flush those writes
@@ -929,7 +929,7 @@ static int ohci_restart (struct ohci_hcd *ohci)
        struct urb_priv *priv;
 
        spin_lock_irq(&ohci->lock);
-       disable (ohci);
+       ohci->rh_state = OHCI_RH_HALTED;
 
        /* Recycle any "live" eds/tds (and urbs). */
        if (!list_empty (&ohci->pending))
@@ -1111,7 +1111,7 @@ MODULE_LICENSE ("GPL");
 #define PLATFORM_DRIVER                ohci_hcd_ath79_driver
 #endif
 
-#ifdef CONFIG_NLM_XLR
+#ifdef CONFIG_CPU_XLR
 #include "ohci-xls.c"
 #define PLATFORM_DRIVER                ohci_xls_driver
 #endif
index 2f00040..836772d 100644 (file)
@@ -111,6 +111,7 @@ __acquires(ohci->lock)
        if (!autostop) {
                ohci->next_statechange = jiffies + msecs_to_jiffies (5);
                ohci->autostop = 0;
+               ohci->rh_state = OHCI_RH_SUSPENDED;
        }
 
 done:
@@ -140,7 +141,7 @@ __acquires(ohci->lock)
 
        if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) {
                /* this can happen after resuming a swsusp snapshot */
-               if (hcd->state == HC_STATE_RESUMING) {
+               if (ohci->rh_state != OHCI_RH_RUNNING) {
                        ohci_dbg (ohci, "BIOS/SMM active, control %03x\n",
                                        ohci->hc_control);
                        status = -EBUSY;
@@ -274,6 +275,7 @@ skip_resume:
                (void) ohci_readl (ohci, &ohci->regs->control);
        }
 
+       ohci->rh_state = OHCI_RH_RUNNING;
        return 0;
 }
 
@@ -336,11 +338,8 @@ static void ohci_finish_controller_resume(struct usb_hcd *hcd)
        /* If needed, reinitialize and suspend the root hub */
        if (need_reinit) {
                spin_lock_irq(&ohci->lock);
-               hcd->state = HC_STATE_RESUMING;
                ohci_rh_resume(ohci);
-               hcd->state = HC_STATE_QUIESCING;
                ohci_rh_suspend(ohci, 0);
-               hcd->state = HC_STATE_SUSPENDED;
                spin_unlock_irq(&ohci->lock);
        }
 
index e4b8782..db39686 100644 (file)
@@ -516,7 +516,6 @@ static int ohci_omap_suspend(struct platform_device *dev, pm_message_t message)
        ohci->next_statechange = jiffies;
 
        omap_ohci_clock_power(0);
-       ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
        return 0;
 }
 
index bc01b06..6109810 100644 (file)
@@ -308,12 +308,9 @@ static int ohci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup)
         * mark HW unaccessible, bail out if RH has been resumed. Use
         * the spinlock to properly synchronize with possible pending
         * RH suspend or resume activity.
-        *
-        * This is still racy as hcd->state is manipulated outside of
-        * any locks =P But that will be a different fix.
         */
        spin_lock_irqsave (&ohci->lock, flags);
-       if (hcd->state != HC_STATE_SUSPENDED) {
+       if (ohci->rh_state != OHCI_RH_SUSPENDED) {
                rc = -EINVAL;
                goto bail;
        }
index 29dfefe..6313e44 100644 (file)
@@ -502,8 +502,6 @@ static int ohci_hcd_pxa27x_drv_suspend(struct device *dev)
        ohci->ohci.next_statechange = jiffies;
 
        pxa27x_stop_hc(ohci, dev);
-       hcd->state = HC_STATE_SUSPENDED;
-
        return 0;
 }
 
index 15dc51d..c5a1ea9 100644 (file)
@@ -912,7 +912,7 @@ rescan_all:
                /* only take off EDs that the HC isn't using, accounting for
                 * frame counter wraps and EDs with partially retired TDs
                 */
-               if (likely (HC_IS_RUNNING(ohci_to_hcd(ohci)->state))) {
+               if (likely(ohci->rh_state == OHCI_RH_RUNNING)) {
                        if (tick_before (tick, ed->tick)) {
 skip_ed:
                                last = &ed->ed_next;
@@ -1012,7 +1012,7 @@ rescan_this:
 
                /* but if there's work queued, reschedule */
                if (!list_empty (&ed->td_list)) {
-                       if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state))
+                       if (ohci->rh_state == OHCI_RH_RUNNING)
                                ed_schedule (ohci, ed);
                }
 
@@ -1021,9 +1021,7 @@ rescan_this:
        }
 
        /* maybe reenable control and bulk lists */
-       if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state)
-                       && ohci_to_hcd(ohci)->state != HC_STATE_QUIESCING
-                       && !ohci->ed_rm_list) {
+       if (ohci->rh_state == OHCI_RH_RUNNING && !ohci->ed_rm_list) {
                u32     command = 0, control = 0;
 
                if (ohci->ed_controltail) {
index a1877c4..56dcf06 100644 (file)
@@ -486,15 +486,66 @@ static int __devexit ohci_hcd_s3c2410_drv_remove(struct platform_device *pdev)
        return 0;
 }
 
+#ifdef CONFIG_PM
+static int ohci_hcd_s3c2410_drv_suspend(struct device *dev)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(dev);
+       struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+       struct platform_device *pdev = to_platform_device(dev);
+       unsigned long flags;
+       int rc = 0;
+
+       /*
+        * Root hub was already suspended. Disable irq emission and
+        * mark HW unaccessible, bail out if RH has been resumed. Use
+        * the spinlock to properly synchronize with possible pending
+        * RH suspend or resume activity.
+        */
+       spin_lock_irqsave(&ohci->lock, flags);
+       if (ohci->rh_state != OHCI_RH_SUSPENDED) {
+               rc = -EINVAL;
+               goto bail;
+       }
+
+       clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+       s3c2410_stop_hc(pdev);
+bail:
+       spin_unlock_irqrestore(&ohci->lock, flags);
+
+       return rc;
+}
+
+static int ohci_hcd_s3c2410_drv_resume(struct device *dev)
+{
+       struct usb_hcd *hcd = dev_get_drvdata(dev);
+       struct platform_device *pdev = to_platform_device(dev);
+
+       s3c2410_start_hc(pdev, hcd);
+
+       set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+       ohci_finish_controller_resume(hcd);
+
+       return 0;
+}
+#else
+#define ohci_hcd_s3c2410_drv_suspend   NULL
+#define ohci_hcd_s3c2410_drv_resume    NULL
+#endif
+
+static const struct dev_pm_ops ohci_hcd_s3c2410_pm_ops = {
+       .suspend        = ohci_hcd_s3c2410_drv_suspend,
+       .resume         = ohci_hcd_s3c2410_drv_resume,
+};
+
 static struct platform_driver ohci_hcd_s3c2410_driver = {
        .probe          = ohci_hcd_s3c2410_drv_probe,
        .remove         = __devexit_p(ohci_hcd_s3c2410_drv_remove),
        .shutdown       = usb_hcd_platform_shutdown,
-       /*.suspend      = ohci_hcd_s3c2410_drv_suspend, */
-       /*.resume       = ohci_hcd_s3c2410_drv_resume, */
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "s3c2410-ohci",
+               .pm     = &ohci_hcd_s3c2410_pm_ops,
        },
 };
 
index afc4eb6..84686d9 100644 (file)
@@ -29,7 +29,6 @@ static int ohci_sh_start(struct usb_hcd *hcd)
        ohci_hcd_init(ohci);
        ohci_init(ohci);
        ohci_run(ohci);
-       hcd->state = HC_STATE_RUNNING;
        return 0;
 }
 
index 968cea2..5596ac2 100644 (file)
@@ -224,7 +224,6 @@ static int ohci_sm501_suspend(struct platform_device *pdev, pm_message_t msg)
        ohci->next_statechange = jiffies;
 
        sm501_unit_power(dev->parent, SM501_GATE_USB_HOST, 0);
-       ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
        return 0;
 }
 
index 6987465..95c1648 100644 (file)
@@ -203,7 +203,6 @@ static int spear_ohci_hcd_drv_suspend(struct platform_device *dev,
        ohci->next_statechange = jiffies;
 
        spear_stop_ohci(ohci_p);
-       ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
        return 0;
 }
 
index 06331d9..120bfe6 100644 (file)
@@ -318,9 +318,6 @@ static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t s
                if (ret)
                        return ret;
        }
-
-       hcd->state = HC_STATE_SUSPENDED;
-
        return 0;
 }
 
index a3a9c6f..a224786 100644 (file)
@@ -40,7 +40,7 @@ static int ohci_xls_probe_internal(const struct hc_driver *driver,
                goto err1;
        }
        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 0795b93..8ff6f7e 100644 (file)
@@ -344,6 +344,12 @@ typedef struct urb_priv {
  * a subset of what the full implementation needs. (Linus)
  */
 
+enum ohci_rh_state {
+       OHCI_RH_HALTED,
+       OHCI_RH_SUSPENDED,
+       OHCI_RH_RUNNING
+};
+
 struct ohci_hcd {
        spinlock_t              lock;
 
@@ -384,6 +390,7 @@ struct ohci_hcd {
        /*
         * driver state
         */
+       enum ohci_rh_state      rh_state;
        int                     num_ports;
        int                     load [NUM_INTS];
        u32                     hc_control;     /* copy of hc control reg */
@@ -679,11 +686,6 @@ static inline u16 ohci_hwPSW(const struct ohci_hcd *ohci,
 
 /*-------------------------------------------------------------------------*/
 
-static inline void disable (struct ohci_hcd *ohci)
-{
-       ohci_to_hcd(ohci)->state = HC_STATE_HALT;
-}
-
 #define        FI                      0x2edf          /* 12000 bits per frame (-1) */
 #define        FSMP(fi)                (0x7fff & ((6 * ((fi) - 210)) / 7))
 #define        FIT                     (1 << 31)
@@ -707,7 +709,7 @@ static inline void periodic_reinit (struct ohci_hcd *ohci)
 #define read_roothub(hc, register, mask) ({ \
        u32 temp = ohci_readl (hc, &hc->regs->roothub.register); \
        if (temp == -1) \
-               disable (hc); \
+               hc->rh_state = OHCI_RH_HALTED; \
        else if (hc->flags & OHCI_QUIRK_AMD756) \
                while (temp & mask) \
                        temp = ohci_readl (hc, &hc->regs->roothub.register); \
index dcd8898..6f62de5 100644 (file)
@@ -3951,24 +3951,7 @@ static struct platform_driver oxu_driver = {
        }
 };
 
-static int __init oxu_module_init(void)
-{
-       int retval = 0;
-
-       retval = platform_driver_register(&oxu_driver);
-       if (retval < 0)
-               return retval;
-
-       return retval;
-}
-
-static void __exit oxu_module_cleanup(void)
-{
-       platform_driver_unregister(&oxu_driver);
-}
-
-module_init(oxu_module_init);
-module_exit(oxu_module_cleanup);
+module_platform_driver(oxu_driver);
 
 MODULE_DESCRIPTION("Oxford OXU210HP HCD driver - ver. " DRIVER_VERSION);
 MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
index f6ca80e..d2c6f5a 100644 (file)
@@ -943,7 +943,7 @@ static int uhci_submit_common(struct uhci_hcd *uhci, struct urb *urb,
        if (usb_pipein(urb->pipe))
                status |= TD_CTRL_SPD;
 
-       i = urb->num_sgs;
+       i = urb->num_mapped_sgs;
        if (len > 0 && i > 0) {
                sg = urb->sg;
                data = sg_dma_address(sg);
index a403b53..76083ae 100644 (file)
@@ -443,7 +443,7 @@ static int qset_add_urb_sg(struct whc *whc, struct whc_qset *qset, struct urb *u
 
        remaining = urb->transfer_buffer_length;
 
-       for_each_sg(urb->sg, sg, urb->num_sgs, i) {
+       for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
                dma_addr_t dma_addr;
                size_t dma_remaining;
                dma_addr_t sp, ep;
@@ -561,7 +561,7 @@ static int qset_add_urb_sg_linearize(struct whc *whc, struct whc_qset *qset,
 
        remaining = urb->transfer_buffer_length;
 
-       for_each_sg(urb->sg, sg, urb->num_sgs, i) {
+       for_each_sg(urb->sg, sg, urb->num_mapped_sgs, i) {
                size_t len;
                size_t sg_remaining;
                void *orig;
index 430e88f..35e257f 100644 (file)
@@ -57,17 +57,15 @@ static void xhci_common_hub_descriptor(struct xhci_hcd *xhci,
        desc->bHubContrCurrent = 0;
 
        desc->bNbrPorts = ports;
-       /* Ugh, these should be #defines, FIXME */
-       /* Using table 11-13 in USB 2.0 spec. */
        temp = 0;
-       /* Bits 1:0 - support port power switching, or power always on */
+       /* Bits 1:0 - support per-port power switching, or power always on */
        if (HCC_PPC(xhci->hcc_params))
-               temp |= 0x0001;
+               temp |= HUB_CHAR_INDV_PORT_LPSM;
        else
-               temp |= 0x0002;
+               temp |= HUB_CHAR_NO_LPSM;
        /* Bit  2 - root hubs are not part of a compound device */
        /* Bits 4:3 - individual port over current protection */
-       temp |= 0x0008;
+       temp |= HUB_CHAR_INDV_PORT_OCPM;
        /* Bits 6:5 - no TTs in root ports */
        /* Bit  7 - no port indicators */
        desc->wHubCharacteristics = cpu_to_le16(temp);
@@ -86,9 +84,9 @@ static void xhci_usb2_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
        ports = xhci->num_usb2_ports;
 
        xhci_common_hub_descriptor(xhci, desc, ports);
-       desc->bDescriptorType = 0x29;
+       desc->bDescriptorType = USB_DT_HUB;
        temp = 1 + (ports / 8);
-       desc->bDescLength = 7 + 2 * temp;
+       desc->bDescLength = USB_DT_HUB_NONVAR_SIZE + 2 * temp;
 
        /* The Device Removable bits are reported on a byte granularity.
         * If the port doesn't exist within that byte, the bit is set to 0.
@@ -137,8 +135,8 @@ static void xhci_usb3_hub_descriptor(struct usb_hcd *hcd, struct xhci_hcd *xhci,
 
        ports = xhci->num_usb3_ports;
        xhci_common_hub_descriptor(xhci, desc, ports);
-       desc->bDescriptorType = 0x2a;
-       desc->bDescLength = 12;
+       desc->bDescriptorType = USB_DT_SS_HUB;
+       desc->bDescLength = USB_DT_SS_HUB_SIZE;
 
        /* header decode latency should be zero for roothubs,
         * see section 4.23.5.2.
index 0e4b25f..36cbe22 100644 (file)
@@ -42,15 +42,12 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, gfp_t flag
        seg = kzalloc(sizeof *seg, flags);
        if (!seg)
                return NULL;
-       xhci_dbg(xhci, "Allocating priv segment structure at %p\n", seg);
 
        seg->trbs = dma_pool_alloc(xhci->segment_pool, flags, &dma);
        if (!seg->trbs) {
                kfree(seg);
                return NULL;
        }
-       xhci_dbg(xhci, "// Allocating segment at %p (virtual) 0x%llx (DMA)\n",
-                       seg->trbs, (unsigned long long)dma);
 
        memset(seg->trbs, 0, SEGMENT_SIZE);
        seg->dma = dma;
@@ -62,12 +59,9 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, gfp_t flag
 static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg)
 {
        if (seg->trbs) {
-               xhci_dbg(xhci, "Freeing DMA segment at %p (virtual) 0x%llx (DMA)\n",
-                               seg->trbs, (unsigned long long)seg->dma);
                dma_pool_free(xhci->segment_pool, seg->trbs, seg->dma);
                seg->trbs = NULL;
        }
-       xhci_dbg(xhci, "Freeing priv segment structure at %p\n", seg);
        kfree(seg);
 }
 
@@ -101,9 +95,6 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
                        val |= TRB_CHAIN;
                prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val);
        }
-       xhci_dbg(xhci, "Linking segment 0x%llx to segment 0x%llx (DMA)\n",
-                       (unsigned long long)prev->dma,
-                       (unsigned long long)next->dma);
 }
 
 /* XXX: Do we need the hcd structure in all these functions? */
@@ -117,7 +108,6 @@ void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
        if (ring->first_seg) {
                first_seg = ring->first_seg;
                seg = first_seg->next;
-               xhci_dbg(xhci, "Freeing ring at %p\n", ring);
                while (seg != first_seg) {
                        struct xhci_segment *next = seg->next;
                        xhci_segment_free(xhci, seg);
@@ -160,7 +150,6 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
        struct xhci_segment     *prev;
 
        ring = kzalloc(sizeof *(ring), flags);
-       xhci_dbg(xhci, "Allocating ring at %p\n", ring);
        if (!ring)
                return NULL;
 
@@ -191,9 +180,6 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
                /* See section 4.9.2.1 and 6.4.4.1 */
                prev->trbs[TRBS_PER_SEGMENT-1].link.control |=
                        cpu_to_le32(LINK_TOGGLE);
-               xhci_dbg(xhci, "Wrote link toggle flag to"
-                               " segment %p (virtual), 0x%llx (DMA)\n",
-                               prev, (unsigned long long)prev->dma);
        }
        xhci_initialize_ring_info(ring);
        return ring;
index 9f1d4b1..b90e138 100644 (file)
@@ -155,10 +155,6 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
        while (last_trb(xhci, ring, ring->deq_seg, next)) {
                if (consumer && last_trb_on_last_seg(xhci, ring, ring->deq_seg, next)) {
                        ring->cycle_state = (ring->cycle_state ? 0 : 1);
-                       if (!in_interrupt())
-                               xhci_dbg(xhci, "Toggle cycle state for ring %p = %i\n",
-                                               ring,
-                                               (unsigned int) ring->cycle_state);
                }
                ring->deq_seg = ring->deq_seg->next;
                ring->dequeue = ring->deq_seg->trbs;
@@ -231,10 +227,6 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
                        /* Toggle the cycle bit after the last ring segment. */
                        if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
                                ring->cycle_state = (ring->cycle_state ? 0 : 1);
-                               if (!in_interrupt())
-                                       xhci_dbg(xhci, "Toggle cycle state for ring %p = %i\n",
-                                                       ring,
-                                                       (unsigned int) ring->cycle_state);
                        }
                }
                ring->enq_seg = ring->enq_seg->next;
@@ -560,12 +552,9 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
                                        cpu_to_le32(TRB_CYCLE);
                        cur_trb->generic.field[3] |= cpu_to_le32(
                                TRB_TYPE(TRB_TR_NOOP));
-                       xhci_dbg(xhci, "Cancel TRB %p (0x%llx dma) "
-                                       "in seg %p (0x%llx dma)\n",
-                                       cur_trb,
-                                       (unsigned long long)xhci_trb_virt_to_dma(cur_seg, cur_trb),
-                                       cur_seg,
-                                       (unsigned long long)cur_seg->dma);
+                       xhci_dbg(xhci, "TRB to noop at offset 0x%llx\n",
+                                       (unsigned long long)
+                                       xhci_trb_virt_to_dma(cur_seg, cur_trb));
                }
                if (cur_trb == cur_td->last_trb)
                        break;
@@ -705,9 +694,9 @@ static void handle_stopped_endpoint(struct xhci_hcd *xhci,
         */
        list_for_each(entry, &ep->cancelled_td_list) {
                cur_td = list_entry(entry, struct xhci_td, cancelled_td_list);
-               xhci_dbg(xhci, "Cancelling TD starting at %p, 0x%llx (dma).\n",
-                               cur_td->first_trb,
-                               (unsigned long long)xhci_trb_virt_to_dma(cur_td->start_seg, cur_td->first_trb));
+               xhci_dbg(xhci, "Removing canceled TD starting at 0x%llx (dma).\n",
+                               (unsigned long long)xhci_trb_virt_to_dma(
+                                       cur_td->start_seg, cur_td->first_trb));
                ep_ring = xhci_urb_to_transfer_ring(xhci, cur_td->urb);
                if (!ep_ring) {
                        /* This shouldn't happen unless a driver is mucking
@@ -1627,7 +1616,6 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
        ep_ctx = xhci_get_ep_ctx(xhci, xdev->out_ctx, ep_index);
        trb_comp_code = GET_COMP_CODE(le32_to_cpu(event->transfer_len));
 
-       xhci_debug_trb(xhci, xhci->event_ring->dequeue);
        switch (trb_comp_code) {
        case COMP_SUCCESS:
                if (event_trb == ep_ring->dequeue) {
@@ -1643,7 +1631,6 @@ static int process_ctrl_td(struct xhci_hcd *xhci, struct xhci_td *td,
                }
                break;
        case COMP_SHORT_TX:
-               xhci_warn(xhci, "WARN: short transfer on control ep\n");
                if (td->urb->transfer_flags & URB_SHORT_NOT_OK)
                        *status = -EREMOTEIO;
                else
@@ -1946,6 +1933,16 @@ static int handle_tx_event(struct xhci_hcd *xhci,
        xdev = xhci->devs[slot_id];
        if (!xdev) {
                xhci_err(xhci, "ERROR Transfer event pointed to bad slot\n");
+               xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n",
+                        (unsigned long long) xhci_trb_virt_to_dma(
+                                xhci->event_ring->deq_seg,
+                                xhci->event_ring->dequeue),
+                        lower_32_bits(le64_to_cpu(event->buffer)),
+                        upper_32_bits(le64_to_cpu(event->buffer)),
+                        le32_to_cpu(event->transfer_len),
+                        le32_to_cpu(event->flags));
+               xhci_dbg(xhci, "Event ring:\n");
+               xhci_debug_segment(xhci, xhci->event_ring->deq_seg);
                return -ENODEV;
        }
 
@@ -1959,6 +1956,16 @@ static int handle_tx_event(struct xhci_hcd *xhci,
            EP_STATE_DISABLED) {
                xhci_err(xhci, "ERROR Transfer event for disabled endpoint "
                                "or incorrect stream ring\n");
+               xhci_err(xhci, "@%016llx %08x %08x %08x %08x\n",
+                        (unsigned long long) xhci_trb_virt_to_dma(
+                                xhci->event_ring->deq_seg,
+                                xhci->event_ring->dequeue),
+                        lower_32_bits(le64_to_cpu(event->buffer)),
+                        upper_32_bits(le64_to_cpu(event->buffer)),
+                        le32_to_cpu(event->transfer_len),
+                        le32_to_cpu(event->flags));
+               xhci_dbg(xhci, "Event ring:\n");
+               xhci_debug_segment(xhci, xhci->event_ring->deq_seg);
                return -ENODEV;
        }
 
@@ -1985,7 +1992,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                xhci_dbg(xhci, "Stopped on No-op or Link TRB\n");
                break;
        case COMP_STALL:
-               xhci_warn(xhci, "WARN: Stalled endpoint\n");
+               xhci_dbg(xhci, "Stalled endpoint\n");
                ep->ep_state |= EP_HALTED;
                status = -EPIPE;
                break;
@@ -1995,11 +2002,11 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                break;
        case COMP_SPLIT_ERR:
        case COMP_TX_ERR:
-               xhci_warn(xhci, "WARN: transfer error on endpoint\n");
+               xhci_dbg(xhci, "Transfer error on endpoint\n");
                status = -EPROTO;
                break;
        case COMP_BABBLE:
-               xhci_warn(xhci, "WARN: babble error on endpoint\n");
+               xhci_dbg(xhci, "Babble error on endpoint\n");
                status = -EOVERFLOW;
                break;
        case COMP_DB_ERR:
@@ -2390,17 +2397,7 @@ hw_died:
 
 irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd)
 {
-       irqreturn_t ret;
-       struct xhci_hcd *xhci;
-
-       xhci = hcd_to_xhci(hcd);
-       set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
-       if (xhci->shared_hcd)
-               set_bit(HCD_FLAG_SAW_IRQ, &xhci->shared_hcd->flags);
-
-       ret = xhci_irq(hcd);
-
-       return ret;
+       return xhci_irq(hcd);
 }
 
 /****          Endpoint Ring Operations        ****/
@@ -2488,11 +2485,6 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
                        /* Toggle the cycle bit after the last ring segment. */
                        if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
                                ring->cycle_state = (ring->cycle_state ? 0 : 1);
-                               if (!in_interrupt()) {
-                                       xhci_dbg(xhci, "queue_trb: Toggle cycle "
-                                               "state for ring %p = %i\n",
-                                               ring, (unsigned int)ring->cycle_state);
-                               }
                        }
                        ring->enq_seg = ring->enq_seg->next;
                        ring->enqueue = ring->enq_seg->trbs;
@@ -2561,13 +2553,11 @@ static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb)
        struct scatterlist *sg;
 
        sg = NULL;
-       num_sgs = urb->num_sgs;
+       num_sgs = urb->num_mapped_sgs;
        temp = urb->transfer_buffer_length;
 
-       xhci_dbg(xhci, "count sg list trbs: \n");
        num_trbs = 0;
        for_each_sg(urb->sg, sg, num_sgs, i) {
-               unsigned int previous_total_trbs = num_trbs;
                unsigned int len = sg_dma_len(sg);
 
                /* Scatter gather list entries may cross 64KB boundaries */
@@ -2582,22 +2572,11 @@ static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb)
                        num_trbs++;
                        running_total += TRB_MAX_BUFF_SIZE;
                }
-               xhci_dbg(xhci, " sg #%d: dma = %#llx, len = %#x (%d), num_trbs = %d\n",
-                               i, (unsigned long long)sg_dma_address(sg),
-                               len, len, num_trbs - previous_total_trbs);
-
                len = min_t(int, len, temp);
                temp -= len;
                if (temp == 0)
                        break;
        }
-       xhci_dbg(xhci, "\n");
-       if (!in_interrupt())
-               xhci_dbg(xhci, "ep %#x - urb len = %d, sglist used, "
-                               "num_trbs = %d\n",
-                               urb->ep->desc.bEndpointAddress,
-                               urb->transfer_buffer_length,
-                               num_trbs);
        return num_trbs;
 }
 
@@ -2745,7 +2724,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                return -EINVAL;
 
        num_trbs = count_sg_trbs_needed(xhci, urb);
-       num_sgs = urb->num_sgs;
+       num_sgs = urb->num_mapped_sgs;
        total_packet_count = roundup(urb->transfer_buffer_length,
                        usb_endpoint_maxp(&urb->ep->desc));
 
@@ -2783,8 +2762,6 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        trb_buff_len = min_t(int, trb_buff_len, this_sg_len);
        if (trb_buff_len > urb->transfer_buffer_length)
                trb_buff_len = urb->transfer_buffer_length;
-       xhci_dbg(xhci, "First length to xfer from 1st sglist entry = %u\n",
-                       trb_buff_len);
 
        first_trb = true;
        /* Queue the first TRB, even if it's zero-length */
@@ -2816,11 +2793,6 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                if (usb_urb_dir_in(urb))
                        field |= TRB_ISP;
 
-               xhci_dbg(xhci, " sg entry: dma = %#x, len = %#x (%d), "
-                               "64KB boundary at %#x, end dma = %#x\n",
-                               (unsigned int) addr, trb_buff_len, trb_buff_len,
-                               (unsigned int) (addr + TRB_MAX_BUFF_SIZE) & ~(TRB_MAX_BUFF_SIZE - 1),
-                               (unsigned int) addr + trb_buff_len);
                if (TRB_MAX_BUFF_SIZE -
                                (addr & (TRB_MAX_BUFF_SIZE - 1)) < trb_buff_len) {
                        xhci_warn(xhci, "WARN: sg dma xfer crosses 64KB boundaries!\n");
@@ -2926,15 +2898,6 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        }
        /* FIXME: this doesn't deal with URB_ZERO_PACKET - need one more */
 
-       if (!in_interrupt())
-               xhci_dbg(xhci, "ep %#x - urb len = %#x (%d), "
-                               "addr = %#llx, num_trbs = %d\n",
-                               urb->ep->desc.bEndpointAddress,
-                               urb->transfer_buffer_length,
-                               urb->transfer_buffer_length,
-                               (unsigned long long)urb->transfer_dma,
-                               num_trbs);
-
        ret = prepare_transfer(xhci, xhci->devs[slot_id],
                        ep_index, urb->stream_id,
                        num_trbs, urb, 0, false, mem_flags);
@@ -3055,9 +3018,6 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
        if (!urb->setup_packet)
                return -EINVAL;
 
-       if (!in_interrupt())
-               xhci_dbg(xhci, "Queueing ctrl tx for slot id %d, ep %d\n",
-                               slot_id, ep_index);
        /* 1 TRB for setup, 1 for status */
        num_trbs = 2;
        /*
@@ -3249,15 +3209,6 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
                return -EINVAL;
        }
 
-       if (!in_interrupt())
-               xhci_dbg(xhci, "ep %#x - urb len = %#x (%d),"
-                               " addr = %#llx, num_tds = %d\n",
-                               urb->ep->desc.bEndpointAddress,
-                               urb->transfer_buffer_length,
-                               urb->transfer_buffer_length,
-                               (unsigned long long)urb->transfer_dma,
-                               num_tds);
-
        start_addr = (u64) urb->transfer_dma;
        start_trb = &ep_ring->enqueue->generic;
        start_cycle = ep_ring->cycle_state;
index a1afb7c..6bbe3c3 100644 (file)
@@ -200,14 +200,14 @@ static int xhci_setup_msi(struct xhci_hcd *xhci)
 
        ret = pci_enable_msi(pdev);
        if (ret) {
-               xhci_err(xhci, "failed to allocate MSI entry\n");
+               xhci_dbg(xhci, "failed to allocate MSI entry\n");
                return ret;
        }
 
        ret = request_irq(pdev->irq, (irq_handler_t)xhci_msi_irq,
                                0, "xhci_hcd", xhci_to_hcd(xhci));
        if (ret) {
-               xhci_err(xhci, "disable MSI interrupt\n");
+               xhci_dbg(xhci, "disable MSI interrupt\n");
                pci_disable_msi(pdev);
        }
 
@@ -270,7 +270,7 @@ static int xhci_setup_msix(struct xhci_hcd *xhci)
 
        ret = pci_enable_msix(pdev, xhci->msix_entries, xhci->msix_count);
        if (ret) {
-               xhci_err(xhci, "Failed to enable MSI-X\n");
+               xhci_dbg(xhci, "Failed to enable MSI-X\n");
                goto free_entries;
        }
 
@@ -286,7 +286,7 @@ static int xhci_setup_msix(struct xhci_hcd *xhci)
        return ret;
 
 disable_msix:
-       xhci_err(xhci, "disable MSI-X interrupt\n");
+       xhci_dbg(xhci, "disable MSI-X interrupt\n");
        xhci_free_irq(xhci);
        pci_disable_msix(pdev);
 free_entries:
@@ -1333,9 +1333,6 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                goto done;
        }
 
-       xhci_dbg(xhci, "Cancel URB %p\n", urb);
-       xhci_dbg(xhci, "Event ring:\n");
-       xhci_debug_ring(xhci, xhci->event_ring);
        ep_index = xhci_get_endpoint_index(&urb->ep->desc);
        ep = &xhci->devs[urb->dev->slot_id]->eps[ep_index];
        ep_ring = xhci_urb_to_transfer_ring(xhci, urb);
@@ -1344,12 +1341,18 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                goto done;
        }
 
-       xhci_dbg(xhci, "Endpoint ring:\n");
-       xhci_debug_ring(xhci, ep_ring);
-
        urb_priv = urb->hcpriv;
-
-       for (i = urb_priv->td_cnt; i < urb_priv->length; i++) {
+       i = urb_priv->td_cnt;
+       if (i < urb_priv->length)
+               xhci_dbg(xhci, "Cancel URB %p, dev %s, ep 0x%x, "
+                               "starting at offset 0x%llx\n",
+                               urb, urb->dev->devpath,
+                               urb->ep->desc.bEndpointAddress,
+                               (unsigned long long) xhci_trb_virt_to_dma(
+                                       urb_priv->td[i]->start_seg,
+                                       urb_priv->td[i]->first_trb));
+
+       for (; i < urb_priv->length; i++) {
                td = urb_priv->td[i];
                list_add_tail(&td->cancelled_td_list, &ep->cancelled_td_list);
        }
@@ -1620,6 +1623,7 @@ static int xhci_configure_endpoint_result(struct xhci_hcd *xhci,
                /* FIXME: can we allocate more resources for the HC? */
                break;
        case COMP_BW_ERR:
+       case COMP_2ND_BW_ERR:
                dev_warn(&udev->dev, "Not enough bandwidth "
                                "for new device state.\n");
                ret = -ENOSPC;
@@ -2796,8 +2800,7 @@ static int xhci_calculate_streams_and_bitmask(struct xhci_hcd *xhci,
                if (ret < 0)
                        return ret;
 
-               max_streams = USB_SS_MAX_STREAMS(
-                               eps[i]->ss_ep_comp.bmAttributes);
+               max_streams = usb_ss_max_streams(&eps[i]->ss_ep_comp);
                if (max_streams < (*num_streams - 1)) {
                        xhci_dbg(xhci, "Ep 0x%x only supports %u stream IDs.\n",
                                        eps[i]->desc.bEndpointAddress,
index 3c8fbd2..fb99c83 100644 (file)
@@ -1033,7 +1033,6 @@ struct xhci_transfer_event {
 /* Invalid Stream ID Error */
 #define COMP_STRID_ERR 34
 /* Secondary Bandwidth Error - may be returned by a Configure Endpoint cmd */
-/* FIXME - check for this */
 #define COMP_2ND_BW_ERR        35
 /* Split Transaction Error */
 #define        COMP_SPLIT_ERR  36
@@ -1356,7 +1355,7 @@ static inline unsigned int hcd_index(struct usb_hcd *hcd)
                return 1;
 }
 
-/* There is one ehci_hci structure per controller */
+/* There is one xhci_hcd structure per controller */
 struct xhci_hcd {
        struct usb_hcd *main_hcd;
        struct usb_hcd *shared_hcd;
index 1dc7e95..1c61830 100644 (file)
@@ -55,8 +55,9 @@ static int isight_firmware_load(struct usb_interface *intf,
 
        ptr = firmware->data;
 
+       buf[0] = 0x01;
        if (usb_control_msg
-           (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\1", 1,
+           (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, buf, 1,
             300) != 1) {
                printk(KERN_ERR
                       "Failed to initialise isight firmware loader\n");
@@ -100,8 +101,9 @@ static int isight_firmware_load(struct usb_interface *intf,
                }
        }
 
+       buf[0] = 0x00;
        if (usb_control_msg
-           (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\0", 1,
+           (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, buf, 1,
             300) != 1) {
                printk(KERN_ERR "isight firmware loading completion failed\n");
                ret = -ENODEV;
index bd6d008..959145b 100644 (file)
@@ -1765,7 +1765,6 @@ static int test_unaligned_bulk(
  * off just killing the userspace task and waiting for it to exit.
  */
 
-/* No BKL needed */
 static int
 usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
 {
index 07a0346..f70cab3 100644 (file)
@@ -5,14 +5,13 @@
 
 # (M)HDRC = (Multipoint) Highspeed Dual-Role Controller
 config USB_MUSB_HDRC
+       tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
        depends on USB && USB_GADGET
-       depends on (ARM || (BF54x && !BF544) || (BF52x && !BF522 && !BF523))
        select NOP_USB_XCEIV if (ARCH_DAVINCI || MACH_OMAP3EVM || BLACKFIN)
        select TWL4030_USB if MACH_OMAP_3430SDP
        select TWL6030_USB if MACH_OMAP_4430SDP || MACH_OMAP4_PANDA
        select USB_OTG_UTILS
        select USB_GADGET_DUALSPEED
-       tristate 'Inventra Highspeed Dual Role Controller (TI, ADI, ...)'
        help
          Say Y here if your system has a dual role high speed USB
          controller based on the Mentor Graphics silicon IP.  Then
@@ -31,9 +30,10 @@ config USB_MUSB_HDRC
          To compile this driver as a module, choose M here; the
          module will be called "musb-hdrc".
 
+if USB_MUSB_HDRC
+
 choice
        prompt "Platform Glue Layer"
-       depends on USB_MUSB_HDRC
 
 config USB_MUSB_DAVINCI
        tristate "DaVinci"
@@ -45,7 +45,6 @@ config USB_MUSB_DA8XX
 
 config USB_MUSB_TUSB6010
        tristate "TUSB6010"
-       depends on ARCH_OMAP
 
 config USB_MUSB_OMAP2PLUS
        tristate "OMAP2430 and onwards"
@@ -65,46 +64,54 @@ config USB_MUSB_UX500
 
 endchoice
 
-config MUSB_PIO_ONLY
-       bool 'Disable DMA (always use PIO)'
-       depends on USB_MUSB_HDRC
-       default USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X
+choice
+       prompt 'MUSB DMA mode'
+       default USB_UX500_DMA if USB_MUSB_UX500
+       default USB_INVENTRA_DMA if USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN
+       default USB_TI_CPPI_DMA if USB_MUSB_DAVINCI
+       default USB_TUSB_OMAP_DMA if USB_MUSB_TUSB6010
+       default MUSB_PIO_ONLY if USB_MUSB_TUSB6010 || USB_MUSB_DA8XX || USB_MUSB_AM35X
        help
-         All data is copied between memory and FIFO by the CPU.
-         DMA controllers are ignored.
-
-         Do not select 'n' here unless DMA support for your SOC or board
-         is unavailable (or unstable).  When DMA is enabled at compile time,
-         you can still disable it at run time using the "use_dma=n" module
-         parameter.
+         Unfortunately, only one option can be enabled here. Ideally one
+         should be able to build all these drivers into one kernel to
+         allow using DMA on multiplatform kernels.
 
 config USB_UX500_DMA
-       bool
-       depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
-       default USB_MUSB_UX500
+       bool 'ST Ericsson U8500 and U5500'
+       depends on USB_MUSB_UX500
        help
          Enable DMA transfers on UX500 platforms.
 
 config USB_INVENTRA_DMA
-       bool
-       depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
-       default USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN
+       bool 'Inventra'
+       depends on USB_MUSB_OMAP2PLUS || USB_MUSB_BLACKFIN
        help
          Enable DMA transfers using Mentor's engine.
 
 config USB_TI_CPPI_DMA
-       bool
-       depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
-       default USB_MUSB_DAVINCI
+       bool 'TI CPPI (Davinci)'
+       depends on USB_MUSB_DAVINCI
        help
          Enable DMA transfers when TI CPPI DMA is available.
 
 config USB_TUSB_OMAP_DMA
-       bool
-       depends on USB_MUSB_HDRC && !MUSB_PIO_ONLY
+       bool 'TUSB 6010'
        depends on USB_MUSB_TUSB6010
        depends on ARCH_OMAP
-       default y
        help
          Enable DMA transfers on TUSB 6010 when OMAP DMA is available.
 
+config MUSB_PIO_ONLY
+       bool 'Disable DMA (always use PIO)'
+       help
+         All data is copied between memory and FIFO by the CPU.
+         DMA controllers are ignored.
+
+         Do not choose this unless DMA support for your SOC or board
+         is unavailable (or unstable).  When DMA is enabled at compile time,
+         you can still disable it at run time using the "use_dma=n" module
+         parameter.
+
+endchoice
+
+endif # USB_MUSB_HDRC
index d8fd9d0..88bfb9d 100644 (file)
@@ -24,25 +24,7 @@ obj-$(CONFIG_USB_MUSB_UX500)                 += ux500.o
 # PIO only, or DMA (several potential schemes).
 # though PIO is always there to back up DMA, and for ep0
 
-ifneq ($(CONFIG_MUSB_PIO_ONLY),y)
-
-  ifeq ($(CONFIG_USB_INVENTRA_DMA),y)
-    musb_hdrc-y                        += musbhsdma.o
-
-  else
-    ifeq ($(CONFIG_USB_TI_CPPI_DMA),y)
-      musb_hdrc-y              += cppi_dma.o
-
-    else
-      ifeq ($(CONFIG_USB_TUSB_OMAP_DMA),y)
-       musb_hdrc-y             += tusb6010_omap.o
-
-      else
-        ifeq ($(CONFIG_USB_UX500_DMA),y)
-         musb_hdrc-y           += ux500_dma.o
-
-        endif
-      endif
-    endif
-  endif
-endif
+musb_hdrc-$(CONFIG_USB_INVENTRA_DMA)           += musbhsdma.o
+musb_hdrc-$(CONFIG_USB_TI_CPPI_DMA)            += cppi_dma.o
+musb_hdrc-$(CONFIG_USB_TUSB_OMAP_DMA)          += tusb6010_omap.o
+musb_hdrc-$(CONFIG_USB_UX500_DMA)              += ux500_dma.o
index b63ab15..f6ff792 100644 (file)
@@ -661,7 +661,6 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
 
                handled = IRQ_HANDLED;
                musb->is_active = 1;
-               set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags);
 
                musb->ep0_stage = MUSB_EP0_START;
 
@@ -1432,7 +1431,7 @@ static int __init musb_core_init(u16 musb_type, struct musb *musb)
                struct musb_hw_ep       *hw_ep = musb->endpoints + i;
 
                hw_ep->fifo = MUSB_FIFO_OFFSET(i) + mbase;
-#ifdef CONFIG_USB_MUSB_TUSB6010
+#if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE)
                hw_ep->fifo_async = musb->async + 0x400 + MUSB_FIFO_OFFSET(i);
                hw_ep->fifo_sync = musb->sync + 0x400 + MUSB_FIFO_OFFSET(i);
                hw_ep->fifo_sync_va =
@@ -1631,6 +1630,7 @@ void musb_dma_completion(struct musb *musb, u8 epnum, u8 transmit)
                }
        }
 }
+EXPORT_SYMBOL_GPL(musb_dma_completion);
 
 #else
 #define use_dma                        0
@@ -2012,8 +2012,6 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
        if (status < 0)
                goto fail3;
 
-       pm_runtime_put(musb->controller);
-
        status = musb_init_debugfs(musb);
        if (status < 0)
                goto fail4;
@@ -2158,6 +2156,7 @@ static void musb_save_context(struct musb *musb)
                if (!epio)
                        continue;
 
+               musb_writeb(musb_base, MUSB_INDEX, i);
                musb->context.index_regs[i].txmaxp =
                        musb_readw(epio, MUSB_TXMAXP);
                musb->context.index_regs[i].txcsr =
@@ -2233,6 +2232,7 @@ static void musb_restore_context(struct musb *musb)
                if (!epio)
                        continue;
 
+               musb_writeb(musb_base, MUSB_INDEX, i);
                musb_writew(epio, MUSB_TXMAXP,
                        musb->context.index_regs[i].txmaxp);
                musb_writew(epio, MUSB_TXCSR,
index b3c065a..3d28fb8 100644 (file)
@@ -40,7 +40,6 @@
 #include <linux/interrupt.h>
 #include <linux/errno.h>
 #include <linux/timer.h>
-#include <linux/clk.h>
 #include <linux/device.h>
 #include <linux/usb/ch9.h>
 #include <linux/usb/gadget.h>
@@ -311,6 +310,7 @@ struct musb_context_registers {
        u8 index, testmode;
 
        u8 devctl, busctl, misc;
+       u32 otg_interfsel;
 
        struct musb_csr_regs index_regs[MUSB_C_NUM_EPS];
 };
@@ -327,6 +327,7 @@ struct musb {
 
        irqreturn_t             (*isr)(int, void *);
        struct work_struct      irq_work;
+       struct work_struct      otg_notifier_work;
        u16                     hwvers;
 
 /* this hub status bit is reserved by USB 2.0 and not seen by usbcore */
@@ -372,6 +373,7 @@ struct musb {
        u16                     int_tx;
 
        struct otg_transceiver  *xceiv;
+       u8                      xceiv_event;
 
        int nIrq;
        unsigned                irq_wake:1;
index 742eada..27ba8f7 100644 (file)
@@ -43,8 +43,8 @@
 #define ERR(fmt, args...) yprintk(KERN_ERR, fmt, ## args)
 
 #ifdef CONFIG_DEBUG_FS
-extern int musb_init_debugfs(struct musb *musb);
-extern void musb_exit_debugfs(struct musb *musb);
+int musb_init_debugfs(struct musb *musb);
+void musb_exit_debugfs(struct musb *musb);
 #else
 static inline int musb_init_debugfs(struct musb *musb)
 {
index 61f4ee4..13d9af9 100644 (file)
 
 #include <linux/module.h>
 #include <linux/kernel.h>
-#include <linux/sched.h>
 #include <linux/init.h>
-#include <linux/list.h>
-#include <linux/platform_device.h>
-#include <linux/io.h>
 #include <linux/debugfs.h>
 #include <linux/seq_file.h>
 
 #include "musb_core.h"
 #include "musb_debug.h"
 
-#ifdef CONFIG_ARCH_DAVINCI
-#include "davinci.h"
-#endif
-
 struct musb_register_map {
        char                    *name;
        unsigned                offset;
index 922148f..ac3d2ee 100644 (file)
@@ -40,8 +40,6 @@
 #include <linux/smp.h>
 #include <linux/spinlock.h>
 #include <linux/delay.h>
-#include <linux/moduleparam.h>
-#include <linux/stat.h>
 #include <linux/dma-mapping.h>
 #include <linux/slab.h>
 
@@ -1844,7 +1842,7 @@ int __init musb_gadget_setup(struct musb *musb)
         */
 
        musb->g.ops = &musb_gadget_operations;
-       musb->g.is_dualspeed = 1;
+       musb->g.max_speed = USB_SPEED_HIGH;
        musb->g.speed = USB_SPEED_UNKNOWN;
 
        /* this "gadget" abstracts/virtualizes the controller */
@@ -1903,7 +1901,7 @@ static int musb_gadget_start(struct usb_gadget *g,
        unsigned long           flags;
        int                     retval = -EINVAL;
 
-       if (driver->speed < USB_SPEED_HIGH)
+       if (driver->max_speed < USB_SPEED_HIGH)
                goto err0;
 
        pm_runtime_get_sync(musb->controller);
index 6a0d046..e40d764 100644 (file)
@@ -37,7 +37,6 @@
 #include <linux/list.h>
 #include <linux/timer.h>
 #include <linux/spinlock.h>
-#include <linux/init.h>
 #include <linux/device.h>
 #include <linux/interrupt.h>
 
index 03c6ccd..e61aa95 100644 (file)
@@ -74,7 +74,7 @@ static inline void musb_writel(void __iomem *addr, unsigned offset, u32 data)
        { __raw_writel(data, addr + offset); }
 
 
-#ifdef CONFIG_USB_MUSB_TUSB6010
+#if defined(CONFIG_USB_MUSB_TUSB6010) || defined (CONFIG_USB_MUSB_TUSB6010_MODULE)
 
 /*
  * TUSB6010 doesn't allow 8-bit access; 16-bit access is the minimum.
index ba85f27..c27bbbf 100644 (file)
@@ -29,7 +29,6 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/list.h>
-#include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/platform_device.h>
 #include <linux/dma-mapping.h>
@@ -228,21 +227,25 @@ static int musb_otg_notifications(struct notifier_block *nb,
                unsigned long event, void *unused)
 {
        struct musb     *musb = container_of(nb, struct musb, nb);
+
+       musb->xceiv_event = event;
+       schedule_work(&musb->otg_notifier_work);
+
+       return 0;
+}
+
+static void musb_otg_notifier_work(struct work_struct *data_notifier_work)
+{
+       struct musb *musb = container_of(data_notifier_work, struct musb, otg_notifier_work);
        struct device *dev = musb->controller;
        struct musb_hdrc_platform_data *pdata = dev->platform_data;
        struct omap_musb_board_data *data = pdata->board_data;
 
-       switch (event) {
+       switch (musb->xceiv_event) {
        case USB_EVENT_ID:
                dev_dbg(musb->controller, "ID GND\n");
 
-               if (is_otg_enabled(musb)) {
-                       if (musb->gadget_driver) {
-                               pm_runtime_get_sync(musb->controller);
-                               otg_init(musb->xceiv);
-                               omap2430_musb_set_vbus(musb, 1);
-                       }
-               } else {
+               if (!is_otg_enabled(musb) || musb->gadget_driver) {
                        pm_runtime_get_sync(musb->controller);
                        otg_init(musb->xceiv);
                        omap2430_musb_set_vbus(musb, 1);
@@ -274,10 +277,7 @@ static int musb_otg_notifications(struct notifier_block *nb,
                break;
        default:
                dev_dbg(musb->controller, "ID float\n");
-               return NOTIFY_DONE;
        }
-
-       return NOTIFY_OK;
 }
 
 static int omap2430_musb_init(struct musb *musb)
@@ -297,6 +297,8 @@ static int omap2430_musb_init(struct musb *musb)
                return -ENODEV;
        }
 
+       INIT_WORK(&musb->otg_notifier_work, musb_otg_notifier_work);
+
        status = pm_runtime_get_sync(dev);
        if (status < 0) {
                dev_err(dev, "pm_runtime_get_sync FAILED");
@@ -334,7 +336,6 @@ static int omap2430_musb_init(struct musb *musb)
        return 0;
 
 err1:
-       pm_runtime_disable(dev);
        return status;
 }
 
@@ -350,20 +351,19 @@ static void omap2430_musb_enable(struct musb *musb)
 
        case USB_EVENT_ID:
                otg_init(musb->xceiv);
-               if (data->interface_type == MUSB_INTERFACE_UTMI) {
-                       devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
-                       /* start the session */
-                       devctl |= MUSB_DEVCTL_SESSION;
-                       musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
-                       while (musb_readb(musb->mregs, MUSB_DEVCTL) &
-                                               MUSB_DEVCTL_BDEVICE) {
-                               cpu_relax();
-
-                               if (time_after(jiffies, timeout)) {
-                                       dev_err(musb->controller,
-                                       "configured as A device timeout");
-                                       break;
-                               }
+               if (data->interface_type != MUSB_INTERFACE_UTMI)
+                       break;
+               devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
+               /* start the session */
+               devctl |= MUSB_DEVCTL_SESSION;
+               musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
+               while (musb_readb(musb->mregs, MUSB_DEVCTL) &
+                               MUSB_DEVCTL_BDEVICE) {
+                       cpu_relax();
+
+                       if (time_after(jiffies, timeout)) {
+                               dev_err(dev, "configured as A device timeout");
+                               break;
                        }
                }
                break;
@@ -478,7 +478,6 @@ static int __exit omap2430_remove(struct platform_device *pdev)
        platform_device_del(glue->musb);
        platform_device_put(glue->musb);
        pm_runtime_put(&pdev->dev);
-       pm_runtime_disable(&pdev->dev);
        kfree(glue);
 
        return 0;
@@ -491,6 +490,9 @@ static int omap2430_runtime_suspend(struct device *dev)
        struct omap2430_glue            *glue = dev_get_drvdata(dev);
        struct musb                     *musb = glue_to_musb(glue);
 
+       musb->context.otg_interfsel = musb_readl(musb->mregs,
+                                               OTG_INTERFSEL);
+
        omap2430_low_level_exit(musb);
        otg_set_suspend(musb->xceiv, 1);
 
@@ -503,6 +505,9 @@ static int omap2430_runtime_resume(struct device *dev)
        struct musb                     *musb = glue_to_musb(glue);
 
        omap2430_low_level_init(musb);
+       musb_writel(musb->mregs, OTG_INTERFSEL,
+                                       musb->context.otg_interfsel);
+
        otg_set_suspend(musb->xceiv, 0);
 
        return 0;
index ec14801..1f40561 100644 (file)
@@ -56,6 +56,7 @@ u8 tusb_get_revision(struct musb *musb)
 
        return rev;
 }
+EXPORT_SYMBOL_GPL(tusb_get_revision);
 
 static int tusb_print_revision(struct musb *musb)
 {
index ef4333f..a163632 100644 (file)
@@ -37,7 +37,6 @@ struct ux500_dma_channel {
        struct dma_channel channel;
        struct ux500_dma_controller *controller;
        struct musb_hw_ep *hw_ep;
-       struct work_struct channel_work;
        struct dma_chan *dma_chan;
        unsigned int cur_len;
        dma_cookie_t cookie;
@@ -56,31 +55,11 @@ struct ux500_dma_controller {
        dma_addr_t phy_base;
 };
 
-/* Work function invoked from DMA callback to handle tx transfers. */
-static void ux500_tx_work(struct work_struct *data)
-{
-       struct ux500_dma_channel *ux500_channel = container_of(data,
-               struct ux500_dma_channel, channel_work);
-       struct musb_hw_ep       *hw_ep = ux500_channel->hw_ep;
-       struct musb *musb = hw_ep->musb;
-       unsigned long flags;
-
-       dev_dbg(musb->controller, "DMA tx transfer done on hw_ep=%d\n",
-               hw_ep->epnum);
-
-       spin_lock_irqsave(&musb->lock, flags);
-       ux500_channel->channel.actual_len = ux500_channel->cur_len;
-       ux500_channel->channel.status = MUSB_DMA_STATUS_FREE;
-       musb_dma_completion(musb, hw_ep->epnum,
-                               ux500_channel->is_tx);
-       spin_unlock_irqrestore(&musb->lock, flags);
-}
-
 /* Work function invoked from DMA callback to handle rx transfers. */
-static void ux500_rx_work(struct work_struct *data)
+void ux500_dma_callback(void *private_data)
 {
-       struct ux500_dma_channel *ux500_channel = container_of(data,
-               struct ux500_dma_channel, channel_work);
+       struct dma_channel *channel = private_data;
+       struct ux500_dma_channel *ux500_channel = channel->private_data;
        struct musb_hw_ep       *hw_ep = ux500_channel->hw_ep;
        struct musb *musb = hw_ep->musb;
        unsigned long flags;
@@ -94,14 +73,7 @@ static void ux500_rx_work(struct work_struct *data)
        musb_dma_completion(musb, hw_ep->epnum,
                ux500_channel->is_tx);
        spin_unlock_irqrestore(&musb->lock, flags);
-}
-
-void ux500_dma_callback(void *private_data)
-{
-       struct dma_channel *channel = (struct dma_channel *)private_data;
-       struct ux500_dma_channel *ux500_channel = channel->private_data;
 
-       schedule_work(&ux500_channel->channel_work);
 }
 
 static bool ux500_configure_channel(struct dma_channel *channel,
@@ -330,7 +302,6 @@ static int ux500_dma_controller_start(struct dma_controller *c)
        void **param_array;
        struct ux500_dma_channel *channel_array;
        u32 ch_count;
-       void (*musb_channel_work)(struct work_struct *);
        dma_cap_mask_t mask;
 
        if ((data->num_rx_channels > UX500_MUSB_DMA_NUM_RX_CHANNELS) ||
@@ -347,7 +318,6 @@ static int ux500_dma_controller_start(struct dma_controller *c)
        channel_array = controller->rx_channel;
        ch_count = data->num_rx_channels;
        param_array = data->dma_rx_param_array;
-       musb_channel_work = ux500_rx_work;
 
        for (dir = 0; dir < 2; dir++) {
                for (ch_num = 0; ch_num < ch_count; ch_num++) {
@@ -374,15 +344,12 @@ static int ux500_dma_controller_start(struct dma_controller *c)
                                return -EBUSY;
                        }
 
-                       INIT_WORK(&ux500_channel->channel_work,
-                               musb_channel_work);
                }
 
                /* Prepare the loop for TX channels */
                channel_array = controller->tx_channel;
                ch_count = data->num_tx_channels;
                param_array = data->dma_tx_param_array;
-               musb_channel_work = ux500_tx_work;
                is_tx = 1;
        }
 
index c66481a..2a25955 100644 (file)
@@ -82,9 +82,9 @@ config NOP_USB_XCEIV
        tristate "NOP USB Transceiver Driver"
        select USB_OTG_UTILS
        help
-        this driver is to be used by all the usb transceiver which are either
-        built-in with usb ip or which are autonomous and doesn't require any
-        phy programming such as ISP1x04 etc.
+         This driver is to be used by all the usb transceiver which are either
+         built-in with usb ip or which are autonomous and doesn't require any
+         phy programming such as ISP1x04 etc.
 
 config USB_LANGWELL_OTG
        tristate "Intel Langwell USB OTG dual-role support"
@@ -114,13 +114,13 @@ config USB_MSM_OTG
          has an external PHY.
 
 config AB8500_USB
-        tristate "AB8500 USB Transceiver Driver"
-        depends on AB8500_CORE
-        select USB_OTG_UTILS
-        help
-          Enable this to support the USB OTG transceiver in AB8500 chip.
-          This transceiver supports high and full speed devices plus,
-          in host mode, low speed.
+       tristate "AB8500 USB Transceiver Driver"
+       depends on AB8500_CORE
+       select USB_OTG_UTILS
+       help
+         Enable this to support the USB OTG transceiver in AB8500 chip.
+         This transceiver supports high and full speed devices plus,
+         in host mode, low speed.
 
 config FSL_USB2_OTG
        bool "Freescale USB OTG Transceiver Driver"
@@ -130,4 +130,16 @@ config FSL_USB2_OTG
        help
          Enable this to support Freescale USB OTG transceiver.
 
+config USB_MV_OTG
+       tristate "Marvell USB OTG support"
+       depends on USB_MV_UDC
+       select USB_OTG
+       select USB_OTG_UTILS
+       help
+         Say Y here if you want to build Marvell USB OTG transciever
+         driver in kernel (including PXA and MMP series). This driver
+         implements role switch between EHCI host driver and gadget driver.
+
+         To compile this driver as a module, choose M here.
+
 endif # USB || OTG
index 566655c..b2c5a95 100644 (file)
@@ -21,3 +21,4 @@ obj-$(CONFIG_USB_MSM_OTG)     += msm_otg.o
 obj-$(CONFIG_AB8500_USB)       += ab8500-usb.o
 fsl_usb2_otg-objs              := fsl_otg.o otg_fsm.o
 obj-$(CONFIG_FSL_USB2_OTG)     += fsl_usb2_otg.o
+obj-$(CONFIG_USB_MV_OTG)       += mv_otg.o
index 2d9cc44..a190850 100644 (file)
@@ -1151,18 +1151,7 @@ struct platform_driver fsl_otg_driver = {
        },
 };
 
-static int __init fsl_usb_otg_init(void)
-{
-       pr_info(DRIVER_INFO "\n");
-       return platform_driver_register(&fsl_otg_driver);
-}
-module_init(fsl_usb_otg_init);
-
-static void __exit fsl_usb_otg_exit(void)
-{
-       platform_driver_unregister(&fsl_otg_driver);
-}
-module_exit(fsl_usb_otg_exit);
+module_platform_driver(fsl_otg_driver);
 
 MODULE_DESCRIPTION(DRIVER_INFO);
 MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/otg/mv_otg.c
new file mode 100644 (file)
index 0000000..db0d4fc
--- /dev/null
@@ -0,0 +1,957 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ * Author: Chao Xie <chao.xie@marvell.com>
+ *        Neil Zhang <zhangwm@marvell.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.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/device.h>
+#include <linux/proc_fs.h>
+#include <linux/clk.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/otg.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/hcd.h>
+#include <linux/platform_data/mv_usb.h>
+
+#include "mv_otg.h"
+
+#define        DRIVER_DESC     "Marvell USB OTG transceiver driver"
+#define        DRIVER_VERSION  "Jan 20, 2010"
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+static const char driver_name[] = "mv-otg";
+
+static char *state_string[] = {
+       "undefined",
+       "b_idle",
+       "b_srp_init",
+       "b_peripheral",
+       "b_wait_acon",
+       "b_host",
+       "a_idle",
+       "a_wait_vrise",
+       "a_wait_bcon",
+       "a_host",
+       "a_suspend",
+       "a_peripheral",
+       "a_wait_vfall",
+       "a_vbus_err"
+};
+
+static int mv_otg_set_vbus(struct otg_transceiver *otg, bool on)
+{
+       struct mv_otg *mvotg = container_of(otg, struct mv_otg, otg);
+       if (mvotg->pdata->set_vbus == NULL)
+               return -ENODEV;
+
+       return mvotg->pdata->set_vbus(on);
+}
+
+static int mv_otg_set_host(struct otg_transceiver *otg,
+                          struct usb_bus *host)
+{
+       otg->host = host;
+
+       return 0;
+}
+
+static int mv_otg_set_peripheral(struct otg_transceiver *otg,
+                                struct usb_gadget *gadget)
+{
+       otg->gadget = gadget;
+
+       return 0;
+}
+
+static void mv_otg_run_state_machine(struct mv_otg *mvotg,
+                                    unsigned long delay)
+{
+       dev_dbg(&mvotg->pdev->dev, "transceiver is updated\n");
+       if (!mvotg->qwork)
+               return;
+
+       queue_delayed_work(mvotg->qwork, &mvotg->work, delay);
+}
+
+static void mv_otg_timer_await_bcon(unsigned long data)
+{
+       struct mv_otg *mvotg = (struct mv_otg *) data;
+
+       mvotg->otg_ctrl.a_wait_bcon_timeout = 1;
+
+       dev_info(&mvotg->pdev->dev, "B Device No Response!\n");
+
+       if (spin_trylock(&mvotg->wq_lock)) {
+               mv_otg_run_state_machine(mvotg, 0);
+               spin_unlock(&mvotg->wq_lock);
+       }
+}
+
+static int mv_otg_cancel_timer(struct mv_otg *mvotg, unsigned int id)
+{
+       struct timer_list *timer;
+
+       if (id >= OTG_TIMER_NUM)
+               return -EINVAL;
+
+       timer = &mvotg->otg_ctrl.timer[id];
+
+       if (timer_pending(timer))
+               del_timer(timer);
+
+       return 0;
+}
+
+static int mv_otg_set_timer(struct mv_otg *mvotg, unsigned int id,
+                           unsigned long interval,
+                           void (*callback) (unsigned long))
+{
+       struct timer_list *timer;
+
+       if (id >= OTG_TIMER_NUM)
+               return -EINVAL;
+
+       timer = &mvotg->otg_ctrl.timer[id];
+       if (timer_pending(timer)) {
+               dev_err(&mvotg->pdev->dev, "Timer%d is already running\n", id);
+               return -EBUSY;
+       }
+
+       init_timer(timer);
+       timer->data = (unsigned long) mvotg;
+       timer->function = callback;
+       timer->expires = jiffies + interval;
+       add_timer(timer);
+
+       return 0;
+}
+
+static int mv_otg_reset(struct mv_otg *mvotg)
+{
+       unsigned int loops;
+       u32 tmp;
+
+       /* Stop the controller */
+       tmp = readl(&mvotg->op_regs->usbcmd);
+       tmp &= ~USBCMD_RUN_STOP;
+       writel(tmp, &mvotg->op_regs->usbcmd);
+
+       /* Reset the controller to get default values */
+       writel(USBCMD_CTRL_RESET, &mvotg->op_regs->usbcmd);
+
+       loops = 500;
+       while (readl(&mvotg->op_regs->usbcmd) & USBCMD_CTRL_RESET) {
+               if (loops == 0) {
+                       dev_err(&mvotg->pdev->dev,
+                               "Wait for RESET completed TIMEOUT\n");
+                       return -ETIMEDOUT;
+               }
+               loops--;
+               udelay(20);
+       }
+
+       writel(0x0, &mvotg->op_regs->usbintr);
+       tmp = readl(&mvotg->op_regs->usbsts);
+       writel(tmp, &mvotg->op_regs->usbsts);
+
+       return 0;
+}
+
+static void mv_otg_init_irq(struct mv_otg *mvotg)
+{
+       u32 otgsc;
+
+       mvotg->irq_en = OTGSC_INTR_A_SESSION_VALID
+           | OTGSC_INTR_A_VBUS_VALID;
+       mvotg->irq_status = OTGSC_INTSTS_A_SESSION_VALID
+           | OTGSC_INTSTS_A_VBUS_VALID;
+
+       if (mvotg->pdata->vbus == NULL) {
+               mvotg->irq_en |= OTGSC_INTR_B_SESSION_VALID
+                   | OTGSC_INTR_B_SESSION_END;
+               mvotg->irq_status |= OTGSC_INTSTS_B_SESSION_VALID
+                   | OTGSC_INTSTS_B_SESSION_END;
+       }
+
+       if (mvotg->pdata->id == NULL) {
+               mvotg->irq_en |= OTGSC_INTR_USB_ID;
+               mvotg->irq_status |= OTGSC_INTSTS_USB_ID;
+       }
+
+       otgsc = readl(&mvotg->op_regs->otgsc);
+       otgsc |= mvotg->irq_en;
+       writel(otgsc, &mvotg->op_regs->otgsc);
+}
+
+static void mv_otg_start_host(struct mv_otg *mvotg, int on)
+{
+       struct otg_transceiver *otg = &mvotg->otg;
+       struct usb_hcd *hcd;
+
+       if (!otg->host)
+               return;
+
+       dev_info(&mvotg->pdev->dev, "%s host\n", on ? "start" : "stop");
+
+       hcd = bus_to_hcd(otg->host);
+
+       if (on)
+               usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
+       else
+               usb_remove_hcd(hcd);
+}
+
+static void mv_otg_start_periphrals(struct mv_otg *mvotg, int on)
+{
+       struct otg_transceiver *otg = &mvotg->otg;
+
+       if (!otg->gadget)
+               return;
+
+       dev_info(otg->dev, "gadget %s\n", on ? "on" : "off");
+
+       if (on)
+               usb_gadget_vbus_connect(otg->gadget);
+       else
+               usb_gadget_vbus_disconnect(otg->gadget);
+}
+
+static void otg_clock_enable(struct mv_otg *mvotg)
+{
+       unsigned int i;
+
+       for (i = 0; i < mvotg->clknum; i++)
+               clk_enable(mvotg->clk[i]);
+}
+
+static void otg_clock_disable(struct mv_otg *mvotg)
+{
+       unsigned int i;
+
+       for (i = 0; i < mvotg->clknum; i++)
+               clk_disable(mvotg->clk[i]);
+}
+
+static int mv_otg_enable_internal(struct mv_otg *mvotg)
+{
+       int retval = 0;
+
+       if (mvotg->active)
+               return 0;
+
+       dev_dbg(&mvotg->pdev->dev, "otg enabled\n");
+
+       otg_clock_enable(mvotg);
+       if (mvotg->pdata->phy_init) {
+               retval = mvotg->pdata->phy_init(mvotg->phy_regs);
+               if (retval) {
+                       dev_err(&mvotg->pdev->dev,
+                               "init phy error %d\n", retval);
+                       otg_clock_disable(mvotg);
+                       return retval;
+               }
+       }
+       mvotg->active = 1;
+
+       return 0;
+
+}
+
+static int mv_otg_enable(struct mv_otg *mvotg)
+{
+       if (mvotg->clock_gating)
+               return mv_otg_enable_internal(mvotg);
+
+       return 0;
+}
+
+static void mv_otg_disable_internal(struct mv_otg *mvotg)
+{
+       if (mvotg->active) {
+               dev_dbg(&mvotg->pdev->dev, "otg disabled\n");
+               if (mvotg->pdata->phy_deinit)
+                       mvotg->pdata->phy_deinit(mvotg->phy_regs);
+               otg_clock_disable(mvotg);
+               mvotg->active = 0;
+       }
+}
+
+static void mv_otg_disable(struct mv_otg *mvotg)
+{
+       if (mvotg->clock_gating)
+               mv_otg_disable_internal(mvotg);
+}
+
+static void mv_otg_update_inputs(struct mv_otg *mvotg)
+{
+       struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl;
+       u32 otgsc;
+
+       otgsc = readl(&mvotg->op_regs->otgsc);
+
+       if (mvotg->pdata->vbus) {
+               if (mvotg->pdata->vbus->poll() == VBUS_HIGH) {
+                       otg_ctrl->b_sess_vld = 1;
+                       otg_ctrl->b_sess_end = 0;
+               } else {
+                       otg_ctrl->b_sess_vld = 0;
+                       otg_ctrl->b_sess_end = 1;
+               }
+       } else {
+               otg_ctrl->b_sess_vld = !!(otgsc & OTGSC_STS_B_SESSION_VALID);
+               otg_ctrl->b_sess_end = !!(otgsc & OTGSC_STS_B_SESSION_END);
+       }
+
+       if (mvotg->pdata->id)
+               otg_ctrl->id = !!mvotg->pdata->id->poll();
+       else
+               otg_ctrl->id = !!(otgsc & OTGSC_STS_USB_ID);
+
+       if (mvotg->pdata->otg_force_a_bus_req && !otg_ctrl->id)
+               otg_ctrl->a_bus_req = 1;
+
+       otg_ctrl->a_sess_vld = !!(otgsc & OTGSC_STS_A_SESSION_VALID);
+       otg_ctrl->a_vbus_vld = !!(otgsc & OTGSC_STS_A_VBUS_VALID);
+
+       dev_dbg(&mvotg->pdev->dev, "%s: ", __func__);
+       dev_dbg(&mvotg->pdev->dev, "id %d\n", otg_ctrl->id);
+       dev_dbg(&mvotg->pdev->dev, "b_sess_vld %d\n", otg_ctrl->b_sess_vld);
+       dev_dbg(&mvotg->pdev->dev, "b_sess_end %d\n", otg_ctrl->b_sess_end);
+       dev_dbg(&mvotg->pdev->dev, "a_vbus_vld %d\n", otg_ctrl->a_vbus_vld);
+       dev_dbg(&mvotg->pdev->dev, "a_sess_vld %d\n", otg_ctrl->a_sess_vld);
+}
+
+static void mv_otg_update_state(struct mv_otg *mvotg)
+{
+       struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl;
+       struct otg_transceiver *otg = &mvotg->otg;
+       int old_state = otg->state;
+
+       switch (old_state) {
+       case OTG_STATE_UNDEFINED:
+               otg->state = OTG_STATE_B_IDLE;
+               /* FALL THROUGH */
+       case OTG_STATE_B_IDLE:
+               if (otg_ctrl->id == 0)
+                       otg->state = OTG_STATE_A_IDLE;
+               else if (otg_ctrl->b_sess_vld)
+                       otg->state = OTG_STATE_B_PERIPHERAL;
+               break;
+       case OTG_STATE_B_PERIPHERAL:
+               if (!otg_ctrl->b_sess_vld || otg_ctrl->id == 0)
+                       otg->state = OTG_STATE_B_IDLE;
+               break;
+       case OTG_STATE_A_IDLE:
+               if (otg_ctrl->id)
+                       otg->state = OTG_STATE_B_IDLE;
+               else if (!(otg_ctrl->a_bus_drop) &&
+                        (otg_ctrl->a_bus_req || otg_ctrl->a_srp_det))
+                       otg->state = OTG_STATE_A_WAIT_VRISE;
+               break;
+       case OTG_STATE_A_WAIT_VRISE:
+               if (otg_ctrl->a_vbus_vld)
+                       otg->state = OTG_STATE_A_WAIT_BCON;
+               break;
+       case OTG_STATE_A_WAIT_BCON:
+               if (otg_ctrl->id || otg_ctrl->a_bus_drop
+                   || otg_ctrl->a_wait_bcon_timeout) {
+                       mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
+                       mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
+                       otg->state = OTG_STATE_A_WAIT_VFALL;
+                       otg_ctrl->a_bus_req = 0;
+               } else if (!otg_ctrl->a_vbus_vld) {
+                       mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
+                       mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
+                       otg->state = OTG_STATE_A_VBUS_ERR;
+               } else if (otg_ctrl->b_conn) {
+                       mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
+                       mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
+                       otg->state = OTG_STATE_A_HOST;
+               }
+               break;
+       case OTG_STATE_A_HOST:
+               if (otg_ctrl->id || !otg_ctrl->b_conn
+                   || otg_ctrl->a_bus_drop)
+                       otg->state = OTG_STATE_A_WAIT_BCON;
+               else if (!otg_ctrl->a_vbus_vld)
+                       otg->state = OTG_STATE_A_VBUS_ERR;
+               break;
+       case OTG_STATE_A_WAIT_VFALL:
+               if (otg_ctrl->id
+                   || (!otg_ctrl->b_conn && otg_ctrl->a_sess_vld)
+                   || otg_ctrl->a_bus_req)
+                       otg->state = OTG_STATE_A_IDLE;
+               break;
+       case OTG_STATE_A_VBUS_ERR:
+               if (otg_ctrl->id || otg_ctrl->a_clr_err
+                   || otg_ctrl->a_bus_drop) {
+                       otg_ctrl->a_clr_err = 0;
+                       otg->state = OTG_STATE_A_WAIT_VFALL;
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+static void mv_otg_work(struct work_struct *work)
+{
+       struct mv_otg *mvotg;
+       struct otg_transceiver *otg;
+       int old_state;
+
+       mvotg = container_of((struct delayed_work *)work, struct mv_otg, work);
+
+run:
+       /* work queue is single thread, or we need spin_lock to protect */
+       otg = &mvotg->otg;
+       old_state = otg->state;
+
+       if (!mvotg->active)
+               return;
+
+       mv_otg_update_inputs(mvotg);
+       mv_otg_update_state(mvotg);
+
+       if (old_state != otg->state) {
+               dev_info(&mvotg->pdev->dev, "change from state %s to %s\n",
+                        state_string[old_state],
+                        state_string[otg->state]);
+
+               switch (otg->state) {
+               case OTG_STATE_B_IDLE:
+                       mvotg->otg.default_a = 0;
+                       if (old_state == OTG_STATE_B_PERIPHERAL)
+                               mv_otg_start_periphrals(mvotg, 0);
+                       mv_otg_reset(mvotg);
+                       mv_otg_disable(mvotg);
+                       break;
+               case OTG_STATE_B_PERIPHERAL:
+                       mv_otg_enable(mvotg);
+                       mv_otg_start_periphrals(mvotg, 1);
+                       break;
+               case OTG_STATE_A_IDLE:
+                       mvotg->otg.default_a = 1;
+                       mv_otg_enable(mvotg);
+                       if (old_state == OTG_STATE_A_WAIT_VFALL)
+                               mv_otg_start_host(mvotg, 0);
+                       mv_otg_reset(mvotg);
+                       break;
+               case OTG_STATE_A_WAIT_VRISE:
+                       mv_otg_set_vbus(&mvotg->otg, 1);
+                       break;
+               case OTG_STATE_A_WAIT_BCON:
+                       if (old_state != OTG_STATE_A_HOST)
+                               mv_otg_start_host(mvotg, 1);
+                       mv_otg_set_timer(mvotg, A_WAIT_BCON_TIMER,
+                                        T_A_WAIT_BCON,
+                                        mv_otg_timer_await_bcon);
+                       /*
+                        * Now, we directly enter A_HOST. So set b_conn = 1
+                        * here. In fact, it need host driver to notify us.
+                        */
+                       mvotg->otg_ctrl.b_conn = 1;
+                       break;
+               case OTG_STATE_A_HOST:
+                       break;
+               case OTG_STATE_A_WAIT_VFALL:
+                       /*
+                        * Now, we has exited A_HOST. So set b_conn = 0
+                        * here. In fact, it need host driver to notify us.
+                        */
+                       mvotg->otg_ctrl.b_conn = 0;
+                       mv_otg_set_vbus(&mvotg->otg, 0);
+                       break;
+               case OTG_STATE_A_VBUS_ERR:
+                       break;
+               default:
+                       break;
+               }
+               goto run;
+       }
+}
+
+static irqreturn_t mv_otg_irq(int irq, void *dev)
+{
+       struct mv_otg *mvotg = dev;
+       u32 otgsc;
+
+       otgsc = readl(&mvotg->op_regs->otgsc);
+       writel(otgsc, &mvotg->op_regs->otgsc);
+
+       /*
+        * if we have vbus, then the vbus detection for B-device
+        * will be done by mv_otg_inputs_irq().
+        */
+       if (mvotg->pdata->vbus)
+               if ((otgsc & OTGSC_STS_USB_ID) &&
+                   !(otgsc & OTGSC_INTSTS_USB_ID))
+                       return IRQ_NONE;
+
+       if ((otgsc & mvotg->irq_status) == 0)
+               return IRQ_NONE;
+
+       mv_otg_run_state_machine(mvotg, 0);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t mv_otg_inputs_irq(int irq, void *dev)
+{
+       struct mv_otg *mvotg = dev;
+
+       /* The clock may disabled at this time */
+       if (!mvotg->active) {
+               mv_otg_enable(mvotg);
+               mv_otg_init_irq(mvotg);
+       }
+
+       mv_otg_run_state_machine(mvotg, 0);
+
+       return IRQ_HANDLED;
+}
+
+static ssize_t
+get_a_bus_req(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       struct mv_otg *mvotg = dev_get_drvdata(dev);
+       return scnprintf(buf, PAGE_SIZE, "%d\n",
+                        mvotg->otg_ctrl.a_bus_req);
+}
+
+static ssize_t
+set_a_bus_req(struct device *dev, struct device_attribute *attr,
+             const char *buf, size_t count)
+{
+       struct mv_otg *mvotg = dev_get_drvdata(dev);
+
+       if (count > 2)
+               return -1;
+
+       /* We will use this interface to change to A device */
+       if (mvotg->otg.state != OTG_STATE_B_IDLE
+           && mvotg->otg.state != OTG_STATE_A_IDLE)
+               return -1;
+
+       /* The clock may disabled and we need to set irq for ID detected */
+       mv_otg_enable(mvotg);
+       mv_otg_init_irq(mvotg);
+
+       if (buf[0] == '1') {
+               mvotg->otg_ctrl.a_bus_req = 1;
+               mvotg->otg_ctrl.a_bus_drop = 0;
+               dev_dbg(&mvotg->pdev->dev,
+                       "User request: a_bus_req = 1\n");
+
+               if (spin_trylock(&mvotg->wq_lock)) {
+                       mv_otg_run_state_machine(mvotg, 0);
+                       spin_unlock(&mvotg->wq_lock);
+               }
+       }
+
+       return count;
+}
+
+static DEVICE_ATTR(a_bus_req, S_IRUGO | S_IWUSR, get_a_bus_req,
+                  set_a_bus_req);
+
+static ssize_t
+set_a_clr_err(struct device *dev, struct device_attribute *attr,
+             const char *buf, size_t count)
+{
+       struct mv_otg *mvotg = dev_get_drvdata(dev);
+       if (!mvotg->otg.default_a)
+               return -1;
+
+       if (count > 2)
+               return -1;
+
+       if (buf[0] == '1') {
+               mvotg->otg_ctrl.a_clr_err = 1;
+               dev_dbg(&mvotg->pdev->dev,
+                       "User request: a_clr_err = 1\n");
+       }
+
+       if (spin_trylock(&mvotg->wq_lock)) {
+               mv_otg_run_state_machine(mvotg, 0);
+               spin_unlock(&mvotg->wq_lock);
+       }
+
+       return count;
+}
+
+static DEVICE_ATTR(a_clr_err, S_IWUSR, NULL, set_a_clr_err);
+
+static ssize_t
+get_a_bus_drop(struct device *dev, struct device_attribute *attr,
+              char *buf)
+{
+       struct mv_otg *mvotg = dev_get_drvdata(dev);
+       return scnprintf(buf, PAGE_SIZE, "%d\n",
+                        mvotg->otg_ctrl.a_bus_drop);
+}
+
+static ssize_t
+set_a_bus_drop(struct device *dev, struct device_attribute *attr,
+              const char *buf, size_t count)
+{
+       struct mv_otg *mvotg = dev_get_drvdata(dev);
+       if (!mvotg->otg.default_a)
+               return -1;
+
+       if (count > 2)
+               return -1;
+
+       if (buf[0] == '0') {
+               mvotg->otg_ctrl.a_bus_drop = 0;
+               dev_dbg(&mvotg->pdev->dev,
+                       "User request: a_bus_drop = 0\n");
+       } else if (buf[0] == '1') {
+               mvotg->otg_ctrl.a_bus_drop = 1;
+               mvotg->otg_ctrl.a_bus_req = 0;
+               dev_dbg(&mvotg->pdev->dev,
+                       "User request: a_bus_drop = 1\n");
+               dev_dbg(&mvotg->pdev->dev,
+                       "User request: and a_bus_req = 0\n");
+       }
+
+       if (spin_trylock(&mvotg->wq_lock)) {
+               mv_otg_run_state_machine(mvotg, 0);
+               spin_unlock(&mvotg->wq_lock);
+       }
+
+       return count;
+}
+
+static DEVICE_ATTR(a_bus_drop, S_IRUGO | S_IWUSR,
+                  get_a_bus_drop, set_a_bus_drop);
+
+static struct attribute *inputs_attrs[] = {
+       &dev_attr_a_bus_req.attr,
+       &dev_attr_a_clr_err.attr,
+       &dev_attr_a_bus_drop.attr,
+       NULL,
+};
+
+static struct attribute_group inputs_attr_group = {
+       .name = "inputs",
+       .attrs = inputs_attrs,
+};
+
+int mv_otg_remove(struct platform_device *pdev)
+{
+       struct mv_otg *mvotg = platform_get_drvdata(pdev);
+       int clk_i;
+
+       sysfs_remove_group(&mvotg->pdev->dev.kobj, &inputs_attr_group);
+
+       if (mvotg->irq)
+               free_irq(mvotg->irq, mvotg);
+
+       if (mvotg->pdata->vbus)
+               free_irq(mvotg->pdata->vbus->irq, mvotg);
+       if (mvotg->pdata->id)
+               free_irq(mvotg->pdata->id->irq, mvotg);
+
+       if (mvotg->qwork) {
+               flush_workqueue(mvotg->qwork);
+               destroy_workqueue(mvotg->qwork);
+       }
+
+       mv_otg_disable(mvotg);
+
+       if (mvotg->cap_regs)
+               iounmap(mvotg->cap_regs);
+
+       if (mvotg->phy_regs)
+               iounmap(mvotg->phy_regs);
+
+       for (clk_i = 0; clk_i <= mvotg->clknum; clk_i++)
+               clk_put(mvotg->clk[clk_i]);
+
+       otg_set_transceiver(NULL);
+       platform_set_drvdata(pdev, NULL);
+
+       kfree(mvotg);
+
+       return 0;
+}
+
+static int mv_otg_probe(struct platform_device *pdev)
+{
+       struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
+       struct mv_otg *mvotg;
+       struct resource *r;
+       int retval = 0, clk_i, i;
+       size_t size;
+
+       if (pdata == NULL) {
+               dev_err(&pdev->dev, "failed to get platform data\n");
+               return -ENODEV;
+       }
+
+       size = sizeof(*mvotg) + sizeof(struct clk *) * pdata->clknum;
+       mvotg = kzalloc(size, GFP_KERNEL);
+       if (!mvotg) {
+               dev_err(&pdev->dev, "failed to allocate memory!\n");
+               return -ENOMEM;
+       }
+
+       platform_set_drvdata(pdev, mvotg);
+
+       mvotg->pdev = pdev;
+       mvotg->pdata = pdata;
+
+       mvotg->clknum = pdata->clknum;
+       for (clk_i = 0; clk_i < mvotg->clknum; clk_i++) {
+               mvotg->clk[clk_i] = clk_get(&pdev->dev, pdata->clkname[clk_i]);
+               if (IS_ERR(mvotg->clk[clk_i])) {
+                       retval = PTR_ERR(mvotg->clk[clk_i]);
+                       goto err_put_clk;
+               }
+       }
+
+       mvotg->qwork = create_singlethread_workqueue("mv_otg_queue");
+       if (!mvotg->qwork) {
+               dev_dbg(&pdev->dev, "cannot create workqueue for OTG\n");
+               retval = -ENOMEM;
+               goto err_put_clk;
+       }
+
+       INIT_DELAYED_WORK(&mvotg->work, mv_otg_work);
+
+       /* OTG common part */
+       mvotg->pdev = pdev;
+       mvotg->otg.dev = &pdev->dev;
+       mvotg->otg.label = driver_name;
+       mvotg->otg.set_host = mv_otg_set_host;
+       mvotg->otg.set_peripheral = mv_otg_set_peripheral;
+       mvotg->otg.set_vbus = mv_otg_set_vbus;
+       mvotg->otg.state = OTG_STATE_UNDEFINED;
+
+       for (i = 0; i < OTG_TIMER_NUM; i++)
+               init_timer(&mvotg->otg_ctrl.timer[i]);
+
+       r = platform_get_resource_byname(mvotg->pdev,
+                                        IORESOURCE_MEM, "phyregs");
+       if (r == NULL) {
+               dev_err(&pdev->dev, "no phy I/O memory resource defined\n");
+               retval = -ENODEV;
+               goto err_destroy_workqueue;
+       }
+
+       mvotg->phy_regs = ioremap(r->start, resource_size(r));
+       if (mvotg->phy_regs == NULL) {
+               dev_err(&pdev->dev, "failed to map phy I/O memory\n");
+               retval = -EFAULT;
+               goto err_destroy_workqueue;
+       }
+
+       r = platform_get_resource_byname(mvotg->pdev,
+                                        IORESOURCE_MEM, "capregs");
+       if (r == NULL) {
+               dev_err(&pdev->dev, "no I/O memory resource defined\n");
+               retval = -ENODEV;
+               goto err_unmap_phyreg;
+       }
+
+       mvotg->cap_regs = ioremap(r->start, resource_size(r));
+       if (mvotg->cap_regs == NULL) {
+               dev_err(&pdev->dev, "failed to map I/O memory\n");
+               retval = -EFAULT;
+               goto err_unmap_phyreg;
+       }
+
+       /* we will acces controller register, so enable the udc controller */
+       retval = mv_otg_enable_internal(mvotg);
+       if (retval) {
+               dev_err(&pdev->dev, "mv otg enable error %d\n", retval);
+               goto err_unmap_capreg;
+       }
+
+       mvotg->op_regs =
+               (struct mv_otg_regs __iomem *) ((unsigned long) mvotg->cap_regs
+                       + (readl(mvotg->cap_regs) & CAPLENGTH_MASK));
+
+       if (pdata->id) {
+               retval = request_threaded_irq(pdata->id->irq, NULL,
+                                             mv_otg_inputs_irq,
+                                             IRQF_ONESHOT, "id", mvotg);
+               if (retval) {
+                       dev_info(&pdev->dev,
+                                "Failed to request irq for ID\n");
+                       pdata->id = NULL;
+               }
+       }
+
+       if (pdata->vbus) {
+               mvotg->clock_gating = 1;
+               retval = request_threaded_irq(pdata->vbus->irq, NULL,
+                                             mv_otg_inputs_irq,
+                                             IRQF_ONESHOT, "vbus", mvotg);
+               if (retval) {
+                       dev_info(&pdev->dev,
+                                "Failed to request irq for VBUS, "
+                                "disable clock gating\n");
+                       mvotg->clock_gating = 0;
+                       pdata->vbus = NULL;
+               }
+       }
+
+       if (pdata->disable_otg_clock_gating)
+               mvotg->clock_gating = 0;
+
+       mv_otg_reset(mvotg);
+       mv_otg_init_irq(mvotg);
+
+       r = platform_get_resource(mvotg->pdev, IORESOURCE_IRQ, 0);
+       if (r == NULL) {
+               dev_err(&pdev->dev, "no IRQ resource defined\n");
+               retval = -ENODEV;
+               goto err_disable_clk;
+       }
+
+       mvotg->irq = r->start;
+       if (request_irq(mvotg->irq, mv_otg_irq, IRQF_SHARED,
+                       driver_name, mvotg)) {
+               dev_err(&pdev->dev, "Request irq %d for OTG failed\n",
+                       mvotg->irq);
+               mvotg->irq = 0;
+               retval = -ENODEV;
+               goto err_disable_clk;
+       }
+
+       retval = otg_set_transceiver(&mvotg->otg);
+       if (retval < 0) {
+               dev_err(&pdev->dev, "can't register transceiver, %d\n",
+                       retval);
+               goto err_free_irq;
+       }
+
+       retval = sysfs_create_group(&pdev->dev.kobj, &inputs_attr_group);
+       if (retval < 0) {
+               dev_dbg(&pdev->dev,
+                       "Can't register sysfs attr group: %d\n", retval);
+               goto err_set_transceiver;
+       }
+
+       spin_lock_init(&mvotg->wq_lock);
+       if (spin_trylock(&mvotg->wq_lock)) {
+               mv_otg_run_state_machine(mvotg, 2 * HZ);
+               spin_unlock(&mvotg->wq_lock);
+       }
+
+       dev_info(&pdev->dev,
+                "successful probe OTG device %s clock gating.\n",
+                mvotg->clock_gating ? "with" : "without");
+
+       return 0;
+
+err_set_transceiver:
+       otg_set_transceiver(NULL);
+err_free_irq:
+       free_irq(mvotg->irq, mvotg);
+err_disable_clk:
+       if (pdata->vbus)
+               free_irq(pdata->vbus->irq, mvotg);
+       if (pdata->id)
+               free_irq(pdata->id->irq, mvotg);
+       mv_otg_disable_internal(mvotg);
+err_unmap_capreg:
+       iounmap(mvotg->cap_regs);
+err_unmap_phyreg:
+       iounmap(mvotg->phy_regs);
+err_destroy_workqueue:
+       flush_workqueue(mvotg->qwork);
+       destroy_workqueue(mvotg->qwork);
+err_put_clk:
+       for (clk_i--; clk_i >= 0; clk_i--)
+               clk_put(mvotg->clk[clk_i]);
+
+       platform_set_drvdata(pdev, NULL);
+       kfree(mvotg);
+
+       return retval;
+}
+
+#ifdef CONFIG_PM
+static int mv_otg_suspend(struct platform_device *pdev, pm_message_t state)
+{
+       struct mv_otg *mvotg = platform_get_drvdata(pdev);
+
+       if (mvotg->otg.state != OTG_STATE_B_IDLE) {
+               dev_info(&pdev->dev,
+                        "OTG state is not B_IDLE, it is %d!\n",
+                        mvotg->otg.state);
+               return -EAGAIN;
+       }
+
+       if (!mvotg->clock_gating)
+               mv_otg_disable_internal(mvotg);
+
+       return 0;
+}
+
+static int mv_otg_resume(struct platform_device *pdev)
+{
+       struct mv_otg *mvotg = platform_get_drvdata(pdev);
+       u32 otgsc;
+
+       if (!mvotg->clock_gating) {
+               mv_otg_enable_internal(mvotg);
+
+               otgsc = readl(&mvotg->op_regs->otgsc);
+               otgsc |= mvotg->irq_en;
+               writel(otgsc, &mvotg->op_regs->otgsc);
+
+               if (spin_trylock(&mvotg->wq_lock)) {
+                       mv_otg_run_state_machine(mvotg, 0);
+                       spin_unlock(&mvotg->wq_lock);
+               }
+       }
+       return 0;
+}
+#endif
+
+static struct platform_driver mv_otg_driver = {
+       .probe = mv_otg_probe,
+       .remove = __exit_p(mv_otg_remove),
+       .driver = {
+                  .owner = THIS_MODULE,
+                  .name = driver_name,
+                  },
+#ifdef CONFIG_PM
+       .suspend = mv_otg_suspend,
+       .resume = mv_otg_resume,
+#endif
+};
+
+static int __init mv_otg_init(void)
+{
+       return platform_driver_register(&mv_otg_driver);
+}
+
+static void __exit mv_otg_exit(void)
+{
+       platform_driver_unregister(&mv_otg_driver);
+}
+
+module_init(mv_otg_init);
+module_exit(mv_otg_exit);
diff --git a/drivers/usb/otg/mv_otg.h b/drivers/usb/otg/mv_otg.h
new file mode 100644 (file)
index 0000000..be6ca14
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ *
+ * 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.
+ */
+
+#ifndef        __MV_USB_OTG_CONTROLLER__
+#define        __MV_USB_OTG_CONTROLLER__
+
+#include <linux/types.h>
+
+/* Command Register Bit Masks */
+#define USBCMD_RUN_STOP                        (0x00000001)
+#define USBCMD_CTRL_RESET              (0x00000002)
+
+/* otgsc Register Bit Masks */
+#define OTGSC_CTRL_VUSB_DISCHARGE              0x00000001
+#define OTGSC_CTRL_VUSB_CHARGE                 0x00000002
+#define OTGSC_CTRL_OTG_TERM                    0x00000008
+#define OTGSC_CTRL_DATA_PULSING                        0x00000010
+#define OTGSC_STS_USB_ID                       0x00000100
+#define OTGSC_STS_A_VBUS_VALID                 0x00000200
+#define OTGSC_STS_A_SESSION_VALID              0x00000400
+#define OTGSC_STS_B_SESSION_VALID              0x00000800
+#define OTGSC_STS_B_SESSION_END                        0x00001000
+#define OTGSC_STS_1MS_TOGGLE                   0x00002000
+#define OTGSC_STS_DATA_PULSING                 0x00004000
+#define OTGSC_INTSTS_USB_ID                    0x00010000
+#define OTGSC_INTSTS_A_VBUS_VALID              0x00020000
+#define OTGSC_INTSTS_A_SESSION_VALID           0x00040000
+#define OTGSC_INTSTS_B_SESSION_VALID           0x00080000
+#define OTGSC_INTSTS_B_SESSION_END             0x00100000
+#define OTGSC_INTSTS_1MS                       0x00200000
+#define OTGSC_INTSTS_DATA_PULSING              0x00400000
+#define OTGSC_INTR_USB_ID                      0x01000000
+#define OTGSC_INTR_A_VBUS_VALID                        0x02000000
+#define OTGSC_INTR_A_SESSION_VALID             0x04000000
+#define OTGSC_INTR_B_SESSION_VALID             0x08000000
+#define OTGSC_INTR_B_SESSION_END               0x10000000
+#define OTGSC_INTR_1MS_TIMER                   0x20000000
+#define OTGSC_INTR_DATA_PULSING                        0x40000000
+
+#define CAPLENGTH_MASK         (0xff)
+
+/* Timer's interval, unit 10ms */
+#define T_A_WAIT_VRISE         100
+#define T_A_WAIT_BCON          2000
+#define T_A_AIDL_BDIS          100
+#define T_A_BIDL_ADIS          20
+#define T_B_ASE0_BRST          400
+#define T_B_SE0_SRP            300
+#define T_B_SRP_FAIL           2000
+#define T_B_DATA_PLS           10
+#define T_B_SRP_INIT           100
+#define T_A_SRP_RSPNS          10
+#define T_A_DRV_RSM            5
+
+enum otg_function {
+       OTG_B_DEVICE = 0,
+       OTG_A_DEVICE
+};
+
+enum mv_otg_timer {
+       A_WAIT_BCON_TIMER = 0,
+       OTG_TIMER_NUM
+};
+
+/* PXA OTG state machine */
+struct mv_otg_ctrl {
+       /* internal variables */
+       u8 a_set_b_hnp_en;      /* A-Device set b_hnp_en */
+       u8 b_srp_done;
+       u8 b_hnp_en;
+
+       /* OTG inputs */
+       u8 a_bus_drop;
+       u8 a_bus_req;
+       u8 a_clr_err;
+       u8 a_bus_resume;
+       u8 a_bus_suspend;
+       u8 a_conn;
+       u8 a_sess_vld;
+       u8 a_srp_det;
+       u8 a_vbus_vld;
+       u8 b_bus_req;           /* B-Device Require Bus */
+       u8 b_bus_resume;
+       u8 b_bus_suspend;
+       u8 b_conn;
+       u8 b_se0_srp;
+       u8 b_sess_end;
+       u8 b_sess_vld;
+       u8 id;
+       u8 a_suspend_req;
+
+       /*Timer event */
+       u8 a_aidl_bdis_timeout;
+       u8 b_ase0_brst_timeout;
+       u8 a_bidl_adis_timeout;
+       u8 a_wait_bcon_timeout;
+
+       struct timer_list timer[OTG_TIMER_NUM];
+};
+
+#define VUSBHS_MAX_PORTS       8
+
+struct mv_otg_regs {
+       u32 usbcmd;             /* Command register */
+       u32 usbsts;             /* Status register */
+       u32 usbintr;            /* Interrupt enable */
+       u32 frindex;            /* Frame index */
+       u32 reserved1[1];
+       u32 deviceaddr;         /* Device Address */
+       u32 eplistaddr;         /* Endpoint List Address */
+       u32 ttctrl;             /* HOST TT status and control */
+       u32 burstsize;          /* Programmable Burst Size */
+       u32 txfilltuning;       /* Host Transmit Pre-Buffer Packet Tuning */
+       u32 reserved[4];
+       u32 epnak;              /* Endpoint NAK */
+       u32 epnaken;            /* Endpoint NAK Enable */
+       u32 configflag;         /* Configured Flag register */
+       u32 portsc[VUSBHS_MAX_PORTS];   /* Port Status/Control x, x = 1..8 */
+       u32 otgsc;
+       u32 usbmode;            /* USB Host/Device mode */
+       u32 epsetupstat;        /* Endpoint Setup Status */
+       u32 epprime;            /* Endpoint Initialize */
+       u32 epflush;            /* Endpoint De-initialize */
+       u32 epstatus;           /* Endpoint Status */
+       u32 epcomplete;         /* Endpoint Interrupt On Complete */
+       u32 epctrlx[16];        /* Endpoint Control, where x = 0.. 15 */
+       u32 mcr;                /* Mux Control */
+       u32 isr;                /* Interrupt Status */
+       u32 ier;                /* Interrupt Enable */
+};
+
+struct mv_otg {
+       struct otg_transceiver otg;
+       struct mv_otg_ctrl otg_ctrl;
+
+       /* base address */
+       void __iomem *phy_regs;
+       void __iomem *cap_regs;
+       struct mv_otg_regs __iomem *op_regs;
+
+       struct platform_device *pdev;
+       int irq;
+       u32 irq_status;
+       u32 irq_en;
+
+       struct delayed_work work;
+       struct workqueue_struct *qwork;
+
+       spinlock_t wq_lock;
+
+       struct mv_usb_platform_data *pdata;
+
+       unsigned int active;
+       unsigned int clock_gating;
+       unsigned int clknum;
+       struct clk *clk[0];
+};
+
+#endif
index 08c679c..e9a5b1d 100644 (file)
@@ -95,25 +95,15 @@ struct usbhs_priv *usbhs_pdev_to_priv(struct platform_device *pdev)
 /*
  *             syscfg functions
  */
-void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable)
+static void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable)
 {
        usbhs_bset(priv, SYSCFG, SCKE, enable ? SCKE : 0);
 }
 
-void usbhs_sys_hispeed_ctrl(struct usbhs_priv *priv, int enable)
-{
-       usbhs_bset(priv, SYSCFG, HSE, enable ? HSE : 0);
-}
-
-void usbhs_sys_usb_ctrl(struct usbhs_priv *priv, int enable)
-{
-       usbhs_bset(priv, SYSCFG, USBE, enable ? USBE : 0);
-}
-
 void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable)
 {
-       u16 mask = DCFM | DRPD | DPRPU;
-       u16 val  = DCFM | DRPD;
+       u16 mask = DCFM | DRPD | DPRPU | HSE | USBE;
+       u16 val  = DCFM | DRPD | HSE | USBE;
        int has_otg = usbhs_get_dparam(priv, has_otg);
 
        if (has_otg)
@@ -130,8 +120,8 @@ void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable)
 
 void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable)
 {
-       u16 mask = DCFM | DRPD | DPRPU;
-       u16 val  = DPRPU;
+       u16 mask = DCFM | DRPD | DPRPU | HSE | USBE;
+       u16 val  = DPRPU | HSE | USBE;
 
        /*
         * if enable
@@ -142,6 +132,11 @@ void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable)
        usbhs_bset(priv, SYSCFG, mask, enable ? val : 0);
 }
 
+void usbhs_sys_set_test_mode(struct usbhs_priv *priv, u16 mode)
+{
+       usbhs_write(priv, TESTMODE, mode);
+}
+
 /*
  *             frame functions
  */
@@ -229,7 +224,7 @@ static void usbhsc_bus_init(struct usbhs_priv *priv)
 /*
  *             device configuration
  */
-int usbhs_set_device_speed(struct usbhs_priv *priv, int devnum,
+int usbhs_set_device_config(struct usbhs_priv *priv, int devnum,
                           u16 upphub, u16 hubport, u16 speed)
 {
        struct device *dev = usbhs_priv_to_dev(priv);
@@ -301,18 +296,25 @@ static u32 usbhsc_default_pipe_type[] = {
  */
 static void usbhsc_power_ctrl(struct usbhs_priv *priv, int enable)
 {
+       struct platform_device *pdev = usbhs_priv_to_pdev(priv);
        struct device *dev = usbhs_priv_to_dev(priv);
 
        if (enable) {
                /* enable PM */
                pm_runtime_get_sync(dev);
 
+               /* enable platform power */
+               usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable);
+
                /* USB on */
                usbhs_sys_clock_ctrl(priv, enable);
        } else {
                /* USB off */
                usbhs_sys_clock_ctrl(priv, enable);
 
+               /* disable platform power */
+               usbhs_platform_call(priv, power_ctrl, pdev, priv->base, enable);
+
                /* disable PM */
                pm_runtime_put_sync(dev);
        }
@@ -388,7 +390,7 @@ static void usbhsc_notify_hotplug(struct work_struct *work)
        usbhsc_hotplug(priv);
 }
 
-int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev)
+static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev)
 {
        struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
        int delay = usbhs_get_dparam(priv, detection_delay);
@@ -398,7 +400,8 @@ int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev)
         * To make sure safety context,
         * use workqueue for usbhs_notify_hotplug
         */
-       schedule_delayed_work(&priv->notify_hotplug_work, delay);
+       schedule_delayed_work(&priv->notify_hotplug_work,
+                             msecs_to_jiffies(delay));
        return 0;
 }
 
@@ -637,18 +640,7 @@ static struct platform_driver renesas_usbhs_driver = {
        .remove         = __devexit_p(usbhs_remove),
 };
 
-static int __init usbhs_init(void)
-{
-       return platform_driver_register(&renesas_usbhs_driver);
-}
-
-static void __exit usbhs_exit(void)
-{
-       platform_driver_unregister(&renesas_usbhs_driver);
-}
-
-module_init(usbhs_init);
-module_exit(usbhs_exit);
+module_platform_driver(renesas_usbhs_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("Renesas USB driver");
index 8729da5..d79b3e2 100644 (file)
@@ -33,6 +33,7 @@ struct usbhs_priv;
 #define SYSCFG         0x0000
 #define BUSWAIT                0x0002
 #define DVSTCTR                0x0008
+#define TESTMODE       0x000C
 #define CFIFO          0x0014
 #define CFIFOSEL       0x0020
 #define CFIFOCTR       0x0022
@@ -275,19 +276,15 @@ u16 usbhs_read(struct usbhs_priv *priv, u32 reg);
 void usbhs_write(struct usbhs_priv *priv, u32 reg, u16 data);
 void usbhs_bset(struct usbhs_priv *priv, u32 reg, u16 mask, u16 data);
 
-int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev);
-
 #define usbhs_lock(p, f) spin_lock_irqsave(usbhs_priv_to_lock(p), f)
 #define usbhs_unlock(p, f) spin_unlock_irqrestore(usbhs_priv_to_lock(p), f)
 
 /*
  * sysconfig
  */
-void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable);
-void usbhs_sys_hispeed_ctrl(struct usbhs_priv *priv, int enable);
-void usbhs_sys_usb_ctrl(struct usbhs_priv *priv, int enable);
 void usbhs_sys_host_ctrl(struct usbhs_priv *priv, int enable);
 void usbhs_sys_function_ctrl(struct usbhs_priv *priv, int enable);
+void usbhs_sys_set_test_mode(struct usbhs_priv *priv, u16 mode);
 
 /*
  * usb request
@@ -311,7 +308,7 @@ int usbhs_frame_get_num(struct usbhs_priv *priv);
 /*
  * device config
  */
-int usbhs_set_device_speed(struct usbhs_priv *priv, int devnum, u16 upphub,
+int usbhs_set_device_config(struct usbhs_priv *priv, int devnum, u16 upphub,
                           u16 hubport, u16 speed);
 
 /*
index ffdf5d1..b51fcd8 100644 (file)
@@ -56,7 +56,7 @@ static struct usbhs_pkt_handle usbhsf_null_handler = {
 void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
                    void (*done)(struct usbhs_priv *priv,
                                 struct usbhs_pkt *pkt),
-                   void *buf, int len, int zero)
+                   void *buf, int len, int zero, int sequence)
 {
        struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
        struct device *dev = usbhs_priv_to_dev(priv);
@@ -90,6 +90,7 @@ void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
        pkt->zero       = zero;
        pkt->actual     = 0;
        pkt->done       = done;
+       pkt->sequence   = sequence;
 
        usbhs_unlock(priv, flags);
        /********************  spin unlock ******************/
@@ -481,6 +482,9 @@ static int usbhsf_pio_try_push(struct usbhs_pkt *pkt, int *is_done)
        int i, ret, len;
        int is_short;
 
+       usbhs_pipe_data_sequence(pipe, pkt->sequence);
+       pkt->sequence = -1; /* -1 sequence will be ignored */
+
        ret = usbhsf_fifo_select(pipe, fifo, 1);
        if (ret < 0)
                return 0;
@@ -584,6 +588,8 @@ static int usbhsf_prepare_pop(struct usbhs_pkt *pkt, int *is_done)
        /*
         * pipe enable to prepare packet receive
         */
+       usbhs_pipe_data_sequence(pipe, pkt->sequence);
+       pkt->sequence = -1; /* -1 sequence will be ignored */
 
        usbhs_pipe_enable(pipe);
        usbhsf_rx_irq_ctrl(pipe, 1);
@@ -641,6 +647,7 @@ static int usbhsf_pio_try_pop(struct usbhs_pkt *pkt, int *is_done)
         * "Operation" - "FIFO Buffer Memory" - "FIFO Port Function"
         */
        if (0 == rcv_len) {
+               pkt->zero = 1;
                usbhsf_fifo_clear(pipe, fifo);
                goto usbhs_fifo_read_end;
        }
index 32a7b24..f68609c 100644 (file)
@@ -59,6 +59,7 @@ struct usbhs_pkt {
        int trans;
        int actual;
        int zero;
+       int sequence;
 };
 
 struct usbhs_pkt_handle {
@@ -95,7 +96,7 @@ void usbhs_pkt_init(struct usbhs_pkt *pkt);
 void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
                    void (*done)(struct usbhs_priv *priv,
                                 struct usbhs_pkt *pkt),
-                   void *buf, int len, int zero);
+                   void *buf, int len, int zero, int sequence);
 struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt);
 void usbhs_pkt_start(struct usbhs_pipe *pipe);
 
index ad96a38..1b97fb1 100644 (file)
@@ -50,7 +50,9 @@ static int usbhsm_autonomy_irq_vbus(struct usbhs_priv *priv,
 {
        struct platform_device *pdev = usbhs_priv_to_pdev(priv);
 
-       return usbhsc_drvcllbck_notify_hotplug(pdev);
+       renesas_usbhs_call_notify_hotplug(pdev);
+
+       return 0;
 }
 
 void usbhs_mod_autonomy_mode(struct usbhs_priv *priv)
index 7f4e803..528691d 100644 (file)
@@ -14,6 +14,7 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
+#include <linux/delay.h>
 #include <linux/dma-mapping.h>
 #include <linux/io.h>
 #include <linux/module.h>
@@ -44,7 +45,6 @@ struct usbhsg_uep {
 struct usbhsg_gpriv {
        struct usb_gadget        gadget;
        struct usbhs_mod         mod;
-       struct list_head         link;
 
        struct usbhsg_uep       *uep;
        int                      uep_size;
@@ -114,16 +114,6 @@ struct usbhsg_recip_handle {
 #define usbhsg_status_clr(gp, b) (gp->status &= ~b)
 #define usbhsg_status_has(gp, b) (gp->status &   b)
 
-/* controller */
-LIST_HEAD(the_controller_link);
-
-#define usbhsg_for_each_controller(gpriv)\
-       list_for_each_entry(gpriv, &the_controller_link, link)
-#define usbhsg_controller_register(gpriv)\
-       list_add_tail(&(gpriv)->link, &the_controller_link)
-#define usbhsg_controller_unregister(gpriv)\
-       list_del_init(&(gpriv)->link)
-
 /*
  *             queue push/pop
  */
@@ -164,7 +154,7 @@ static void usbhsg_queue_push(struct usbhsg_uep *uep,
        req->actual = 0;
        req->status = -EINPROGRESS;
        usbhs_pkt_push(pipe, pkt, usbhsg_queue_done,
-                      req->buf, req->length, req->zero);
+                      req->buf, req->length, req->zero, -1);
        usbhs_pkt_start(pipe);
 
        dev_dbg(dev, "pipe %d : queue push (%d)\n",
@@ -195,7 +185,7 @@ static int usbhsg_dma_map(struct device *dev,
        }
 
        if (dma_mapping_error(dev, pkt->dma)) {
-               dev_err(dev, "dma mapping error %x\n", pkt->dma);
+               dev_err(dev, "dma mapping error %llx\n", (u64)pkt->dma);
                return -EIO;
        }
 
@@ -271,6 +261,8 @@ static int usbhsg_recip_handler_std_clear_endpoint(struct usbhs_priv *priv,
 
        usbhsg_recip_handler_std_control_done(priv, uep, ctrl);
 
+       usbhs_pkt_start(pipe);
+
        return 0;
 }
 
@@ -281,6 +273,145 @@ struct usbhsg_recip_handle req_clear_feature = {
        .endpoint       = usbhsg_recip_handler_std_clear_endpoint,
 };
 
+/*
+ *             USB_TYPE_STANDARD / set feature functions
+ */
+static int usbhsg_recip_handler_std_set_device(struct usbhs_priv *priv,
+                                                struct usbhsg_uep *uep,
+                                                struct usb_ctrlrequest *ctrl)
+{
+       switch (le16_to_cpu(ctrl->wValue)) {
+       case USB_DEVICE_TEST_MODE:
+               usbhsg_recip_handler_std_control_done(priv, uep, ctrl);
+               udelay(100);
+               usbhs_sys_set_test_mode(priv, le16_to_cpu(ctrl->wIndex >> 8));
+               break;
+       default:
+               usbhsg_recip_handler_std_control_done(priv, uep, ctrl);
+               break;
+       }
+
+       return 0;
+}
+
+static int usbhsg_recip_handler_std_set_endpoint(struct usbhs_priv *priv,
+                                                struct usbhsg_uep *uep,
+                                                struct usb_ctrlrequest *ctrl)
+{
+       struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
+
+       usbhs_pipe_stall(pipe);
+
+       usbhsg_recip_handler_std_control_done(priv, uep, ctrl);
+
+       return 0;
+}
+
+struct usbhsg_recip_handle req_set_feature = {
+       .name           = "set feature",
+       .device         = usbhsg_recip_handler_std_set_device,
+       .interface      = usbhsg_recip_handler_std_control_done,
+       .endpoint       = usbhsg_recip_handler_std_set_endpoint,
+};
+
+/*
+ *             USB_TYPE_STANDARD / get status functions
+ */
+static void __usbhsg_recip_send_complete(struct usb_ep *ep,
+                                        struct usb_request *req)
+{
+       struct usbhsg_request *ureq = usbhsg_req_to_ureq(req);
+
+       /* free allocated recip-buffer/usb_request */
+       kfree(ureq->pkt.buf);
+       usb_ep_free_request(ep, req);
+}
+
+static void __usbhsg_recip_send_status(struct usbhsg_gpriv *gpriv,
+                                      unsigned short status)
+{
+       struct usbhsg_uep *dcp = usbhsg_gpriv_to_dcp(gpriv);
+       struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(dcp);
+       struct device *dev = usbhsg_gpriv_to_dev(gpriv);
+       struct usb_request *req;
+       unsigned short *buf;
+
+       /* alloc new usb_request for recip */
+       req = usb_ep_alloc_request(&dcp->ep, GFP_ATOMIC);
+       if (!req) {
+               dev_err(dev, "recip request allocation fail\n");
+               return;
+       }
+
+       /* alloc recip data buffer */
+       buf = kmalloc(sizeof(*buf), GFP_ATOMIC);
+       if (!buf) {
+               usb_ep_free_request(&dcp->ep, req);
+               dev_err(dev, "recip data allocation fail\n");
+               return;
+       }
+
+       /* recip data is status */
+       *buf = cpu_to_le16(status);
+
+       /* allocated usb_request/buffer will be freed */
+       req->complete   = __usbhsg_recip_send_complete;
+       req->buf        = buf;
+       req->length     = sizeof(*buf);
+       req->zero       = 0;
+
+       /* push packet */
+       pipe->handler = &usbhs_fifo_pio_push_handler;
+       usbhsg_queue_push(dcp, usbhsg_req_to_ureq(req));
+}
+
+static int usbhsg_recip_handler_std_get_device(struct usbhs_priv *priv,
+                                              struct usbhsg_uep *uep,
+                                              struct usb_ctrlrequest *ctrl)
+{
+       struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
+       unsigned short status = 1 << USB_DEVICE_SELF_POWERED;
+
+       __usbhsg_recip_send_status(gpriv, status);
+
+       return 0;
+}
+
+static int usbhsg_recip_handler_std_get_interface(struct usbhs_priv *priv,
+                                                 struct usbhsg_uep *uep,
+                                                 struct usb_ctrlrequest *ctrl)
+{
+       struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
+       unsigned short status = 0;
+
+       __usbhsg_recip_send_status(gpriv, status);
+
+       return 0;
+}
+
+static int usbhsg_recip_handler_std_get_endpoint(struct usbhs_priv *priv,
+                                                struct usbhsg_uep *uep,
+                                                struct usb_ctrlrequest *ctrl)
+{
+       struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
+       struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
+       unsigned short status = 0;
+
+       if (usbhs_pipe_is_stall(pipe))
+               status = 1 << USB_ENDPOINT_HALT;
+
+       __usbhsg_recip_send_status(gpriv, status);
+
+       return 0;
+}
+
+struct usbhsg_recip_handle req_get_status = {
+       .name           = "get status",
+       .device         = usbhsg_recip_handler_std_get_device,
+       .interface      = usbhsg_recip_handler_std_get_interface,
+       .endpoint       = usbhsg_recip_handler_std_get_endpoint,
+};
+
 /*
  *             USB_TYPE handler
  */
@@ -303,8 +434,7 @@ static int usbhsg_recip_run_handle(struct usbhs_priv *priv,
        pipe = usbhsg_uep_to_pipe(uep);
        if (!pipe) {
                dev_err(dev, "wrong recip request\n");
-               ret = -EINVAL;
-               goto usbhsg_recip_run_handle_end;
+               return -EINVAL;
        }
 
        switch (recip) {
@@ -327,20 +457,10 @@ static int usbhsg_recip_run_handle(struct usbhs_priv *priv,
        }
 
        if (func) {
-               unsigned long flags;
-
                dev_dbg(dev, "%s (pipe %d :%s)\n", handler->name, nth, msg);
-
-               /********************  spin lock ********************/
-               usbhs_lock(priv, flags);
                ret = func(priv, uep, ctrl);
-               usbhs_unlock(priv, flags);
-               /********************  spin unlock ******************/
        }
 
-usbhsg_recip_run_handle_end:
-       usbhs_pkt_start(pipe);
-
        return ret;
 }
 
@@ -412,6 +532,12 @@ static int usbhsg_irq_ctrl_stage(struct usbhs_priv *priv,
                case USB_REQ_CLEAR_FEATURE:
                        recip_handler = &req_clear_feature;
                        break;
+               case USB_REQ_SET_FEATURE:
+                       recip_handler = &req_set_feature;
+                       break;
+               case USB_REQ_GET_STATUS:
+                       recip_handler = &req_get_status;
+                       break;
                }
        }
 
@@ -439,14 +565,16 @@ static int usbhsg_pipe_disable(struct usbhsg_uep *uep)
        struct usbhs_pipe *pipe = usbhsg_uep_to_pipe(uep);
        struct usbhs_pkt *pkt;
 
-       usbhs_pipe_disable(pipe);
-
        while (1) {
                pkt = usbhs_pkt_pop(pipe, NULL);
                if (!pkt)
                        break;
+
+               usbhsg_queue_pop(uep, usbhsg_pkt_to_ureq(pkt), -ECONNRESET);
        }
 
+       usbhs_pipe_disable(pipe);
+
        return 0;
 }
 
@@ -681,9 +809,7 @@ static int usbhsg_try_start(struct usbhs_priv *priv, u32 status)
         * - function
         * - usb module
         */
-       usbhs_sys_hispeed_ctrl(priv, 1);
        usbhs_sys_function_ctrl(priv, 1);
-       usbhs_sys_usb_ctrl(priv, 1);
 
        /*
         * enable irq callback
@@ -731,9 +857,8 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status)
        gpriv->gadget.speed = USB_SPEED_UNKNOWN;
 
        /* disable sys */
-       usbhs_sys_hispeed_ctrl(priv, 0);
+       usbhs_sys_set_test_mode(priv, 0);
        usbhs_sys_function_ctrl(priv, 0);
-       usbhs_sys_usb_ctrl(priv, 0);
 
        usbhsg_pipe_disable(dcp);
 
@@ -755,7 +880,7 @@ static int usbhsg_gadget_start(struct usb_gadget *gadget,
 
        if (!driver             ||
            !driver->setup      ||
-           driver->speed < USB_SPEED_FULL)
+           driver->max_speed < USB_SPEED_FULL)
                return -EINVAL;
 
        /* first hook up the driver ... */
@@ -866,7 +991,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
        gpriv->gadget.dev.parent        = dev;
        gpriv->gadget.name              = "renesas_usbhs_udc";
        gpriv->gadget.ops               = &usbhsg_gadget_ops;
-       gpriv->gadget.is_dualspeed      = 1;
+       gpriv->gadget.max_speed         = USB_SPEED_HIGH;
        ret = device_register(&gpriv->gadget.dev);
        if (ret < 0)
                goto err_add_udc;
@@ -896,8 +1021,6 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
                }
        }
 
-       usbhsg_controller_register(gpriv);
-
        ret = usb_add_gadget_udc(dev, &gpriv->gadget);
        if (ret)
                goto err_register;
@@ -926,8 +1049,6 @@ void usbhs_mod_gadget_remove(struct usbhs_priv *priv)
 
        device_unregister(&gpriv->gadget.dev);
 
-       usbhsg_controller_unregister(gpriv);
-
        kfree(gpriv->uep);
        kfree(gpriv);
 }
index 7955de5..1834cf5 100644 (file)
  *
  * +--------+                                  pipes are reused for each uep.
  * | udev 1 |-+- [uep 0 (dcp) ] --+            pipe will be switched when
- * +--------+ |                          |             target device was changed
+ * +--------+ |                          |             other device requested
  *           +- [uep 1 (bulk)] --|---+            +--------------+
  *           |                   +--------------> | pipe0 (dcp)  |
- *           +- [uep 2 (bulk)] --|---|---+        +--------------+
- *                               |   |   |        | pipe1 (isoc) |
- * +--------+                    |   |   |        +--------------+
- * | udev 2 |-+- [uep 0 (dcp) ]        --+   +-- |------> | pipe2 (bulk) |
- * +--------+ |                          |   |   |        +--------------+
- *           +- [uep 1 (int) ] --|-+ |   +------> | pipe3 (bulk) |
- *                               | | |   |        +--------------+
- * +--------+                    | +-|---|------> | pipe4 (int)  |
- * | udev 3 |-+- [uep 0 (dcp) ]        --+   |   |        +--------------+
- * +--------+ |                              |   |        | ....         |
- *           +- [uep 1 (bulk)] ------+   |        | ....         |
+ *           +- [uep 2 (bulk)] -@    |            +--------------+
+ *                                   |            | pipe1 (isoc) |
+ * +--------+                        |            +--------------+
+ * | udev 2 |-+- [uep 0 (dcp) ]        -@    +----------> | pipe2 (bulk) |
+ * +--------+ |                                           +--------------+
+ *           +- [uep 1 (int) ] ----+     +------> | pipe3 (bulk) |
+ *                                 |     |        +--------------+
+ * +--------+                      +-----|------> | pipe4 (int)  |
+ * | udev 3 |-+- [uep 0 (dcp) ]        -@        |        +--------------+
+ * +--------+ |                                  |        | ....         |
+ *           +- [uep 1 (bulk)] -@        |        | ....         |
  *           |                           |
  *           +- [uep 2 (bulk)]-----------+
+ *
+ * @ : uep requested free pipe, but all have been used.
+ *     now it is waiting for free pipe
  */
 
 
 /*
  *             struct
  */
-struct usbhsh_pipe_info {
-       unsigned int            usr_cnt; /* see usbhsh_endpoint_alloc() */
-};
-
 struct usbhsh_request {
        struct urb              *urb;
        struct usbhs_pkt        pkt;
-       struct list_head        ureq_link; /* see hpriv :: ureq_link_xxx */
 };
 
 struct usbhsh_device {
@@ -83,11 +81,10 @@ struct usbhsh_device {
 };
 
 struct usbhsh_ep {
-       struct usbhs_pipe       *pipe;
+       struct usbhs_pipe       *pipe;   /* attached pipe */
        struct usbhsh_device    *udev;   /* attached udev */
+       struct usb_host_endpoint *ep;
        struct list_head        ep_list; /* list to usbhsh_device */
-
-       int maxp;
 };
 
 #define USBHSH_DEVICE_MAX      10 /* see DEVADDn / DCPMAXP / PIPEMAXP */
@@ -98,16 +95,9 @@ struct usbhsh_hpriv {
 
        struct usbhsh_device    udev[USBHSH_DEVICE_MAX];
 
-       struct usbhsh_pipe_info *pipe_info;
-       int                      pipe_size;
-
        u32     port_stat;      /* USB_PORT_STAT_xxx */
 
        struct completion       setup_ack_done;
-
-       /* see usbhsh_req_alloc/free */
-       struct list_head        ureq_link_active;
-       struct list_head        ureq_link_free;
 };
 
 
@@ -119,17 +109,6 @@ static const char usbhsh_hcd_name[] = "renesas_usbhs host";
 #define usbhsh_priv_to_hpriv(priv) \
        container_of(usbhs_mod_get(priv, USBHS_HOST), struct usbhsh_hpriv, mod)
 
-#define __usbhsh_for_each_hpipe(start, pos, h, i)      \
-       for (i = start, pos = (h)->hpipe + i;           \
-            i < (h)->hpipe_size;                       \
-            i++, pos = (h)->hpipe + i)
-
-#define usbhsh_for_each_hpipe(pos, hpriv, i)   \
-       __usbhsh_for_each_hpipe(1, pos, hpriv, i)
-
-#define usbhsh_for_each_hpipe_with_dcp(pos, hpriv, i)  \
-       __usbhsh_for_each_hpipe(0, pos, hpriv, i)
-
 #define __usbhsh_for_each_udev(start, pos, h, i)       \
        for (i = start, pos = (h)->udev + i;            \
             i < USBHSH_DEVICE_MAX;                     \
@@ -152,15 +131,20 @@ static const char usbhsh_hcd_name[] = "renesas_usbhs host";
 #define usbhsh_ep_to_uep(u)    ((u)->hcpriv)
 #define usbhsh_uep_to_pipe(u)  ((u)->pipe)
 #define usbhsh_uep_to_udev(u)  ((u)->udev)
+#define usbhsh_uep_to_ep(u)    ((u)->ep)
+
 #define usbhsh_urb_to_ureq(u)  ((u)->hcpriv)
 #define usbhsh_urb_to_usbv(u)  ((u)->dev)
 
 #define usbhsh_usbv_to_udev(d) dev_get_drvdata(&(d)->dev)
 
 #define usbhsh_udev_to_usbv(h) ((h)->usbv)
+#define usbhsh_udev_is_used(h) usbhsh_udev_to_usbv(h)
 
-#define usbhsh_pipe_info(p)    ((p)->mod_private)
+#define usbhsh_pipe_to_uep(p)  ((p)->mod_private)
 
+#define usbhsh_device_parent(d)                (usbhsh_usbv_to_udev((d)->usbv->parent))
+#define usbhsh_device_hubport(d)       ((d)->usbv->portnum)
 #define usbhsh_device_number(h, d)     ((int)((d) - (h)->udev))
 #define usbhsh_device_nth(h, d)                ((h)->udev + d)
 #define usbhsh_device0(h)              usbhsh_device_nth(h, 0)
@@ -170,38 +154,13 @@ static const char usbhsh_hcd_name[] = "renesas_usbhs host";
 #define usbhsh_port_stat_clear(h, s)   ((h)->port_stat &= ~(s))
 #define usbhsh_port_stat_get(h)                ((h)->port_stat)
 
-#define usbhsh_pkt_to_req(p)   \
+#define usbhsh_pkt_to_ureq(p)  \
        container_of((void *)p, struct usbhsh_request, pkt)
 
 /*
  *             req alloc/free
  */
-static void usbhsh_req_list_init(struct usbhsh_hpriv *hpriv)
-{
-       INIT_LIST_HEAD(&hpriv->ureq_link_active);
-       INIT_LIST_HEAD(&hpriv->ureq_link_free);
-}
-
-static void usbhsh_req_list_quit(struct usbhsh_hpriv *hpriv)
-{
-       struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
-       struct device *dev = usbhsh_hcd_to_dev(hcd);
-       struct usbhsh_request *ureq, *next;
-
-       /* kfree all active ureq */
-       list_for_each_entry_safe(ureq, next,
-                                &hpriv->ureq_link_active,
-                                ureq_link) {
-               dev_err(dev, "active ureq (%p) is force freed\n", ureq);
-               kfree(ureq);
-       }
-
-       /* kfree all free ureq */
-       list_for_each_entry_safe(ureq, next, &hpriv->ureq_link_free, ureq_link)
-               kfree(ureq);
-}
-
-static struct usbhsh_request *usbhsh_req_alloc(struct usbhsh_hpriv *hpriv,
+static struct usbhsh_request *usbhsh_ureq_alloc(struct usbhsh_hpriv *hpriv,
                                               struct urb *urb,
                                               gfp_t mem_flags)
 {
@@ -209,270 +168,460 @@ static struct usbhsh_request *usbhsh_req_alloc(struct usbhsh_hpriv *hpriv,
        struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
        struct device *dev = usbhs_priv_to_dev(priv);
 
-       if (list_empty(&hpriv->ureq_link_free)) {
-               /*
-                * create new one if there is no free ureq
-                */
-               ureq = kzalloc(sizeof(struct usbhsh_request), mem_flags);
-               if (ureq)
-                       INIT_LIST_HEAD(&ureq->ureq_link);
-       } else {
-               /*
-                * reuse "free" ureq if exist
-                */
-               ureq = list_entry(hpriv->ureq_link_free.next,
-                                 struct usbhsh_request,
-                                 ureq_link);
-               if (ureq)
-                       list_del_init(&ureq->ureq_link);
-       }
-
+       ureq = kzalloc(sizeof(struct usbhsh_request), mem_flags);
        if (!ureq) {
                dev_err(dev, "ureq alloc fail\n");
                return NULL;
        }
 
        usbhs_pkt_init(&ureq->pkt);
-
-       /*
-        * push it to "active" list
-        */
-       list_add_tail(&ureq->ureq_link, &hpriv->ureq_link_active);
        ureq->urb = urb;
+       usbhsh_urb_to_ureq(urb) = ureq;
 
        return ureq;
 }
 
-static void usbhsh_req_free(struct usbhsh_hpriv *hpriv,
+static void usbhsh_ureq_free(struct usbhsh_hpriv *hpriv,
                            struct usbhsh_request *ureq)
 {
-       struct usbhs_pkt *pkt = &ureq->pkt;
+       usbhsh_urb_to_ureq(ureq->urb) = NULL;
+       ureq->urb = NULL;
 
-       usbhs_pkt_init(pkt);
+       kfree(ureq);
+}
 
+/*
+ *             status
+ */
+static int usbhsh_is_running(struct usbhsh_hpriv *hpriv)
+{
        /*
-        * removed from "active" list,
-        * and push it to "free" list
+        * we can decide some device is attached or not
+        * by checking mod.irq_attch
+        * see
+        *      usbhsh_irq_attch()
+        *      usbhsh_irq_dtch()
         */
-       ureq->urb = NULL;
-       list_del_init(&ureq->ureq_link);
-       list_add_tail(&ureq->ureq_link, &hpriv->ureq_link_free);
+       return (hpriv->mod.irq_attch == NULL);
 }
 
 /*
- *             device control
+ *             pipe control
  */
-
-static int usbhsh_device_has_endpoint(struct usbhsh_device *udev)
+static void usbhsh_endpoint_sequence_save(struct usbhsh_hpriv *hpriv,
+                                         struct urb *urb,
+                                         struct usbhs_pkt *pkt)
 {
-       return !list_empty(&udev->ep_list_head);
-}
+       int len = urb->actual_length;
+       int maxp = usb_endpoint_maxp(&urb->ep->desc);
+       int t = 0;
 
-static struct usbhsh_device *usbhsh_device_alloc(struct usbhsh_hpriv *hpriv,
-                                                struct urb *urb)
-{
-       struct usbhsh_device *udev = NULL;
-       struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
-       struct device *dev = usbhsh_hcd_to_dev(hcd);
-       struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
-       struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
-       int i;
+       /* DCP is out of sequence control */
+       if (usb_pipecontrol(urb->pipe))
+               return;
 
        /*
-        * device 0
+        * renesas_usbhs pipe has a limitation in a number.
+        * So, driver should re-use the limited pipe for each device/endpoint.
+        * DATA0/1 sequence should be saved for it.
+        * see [image of mod_host]
+        *     [HARDWARE LIMITATION]
         */
-       if (0 == usb_pipedevice(urb->pipe)) {
-               udev = usbhsh_device0(hpriv);
-               goto usbhsh_device_find;
-       }
 
        /*
-        * find unused device
+        * next sequence depends on actual_length
+        *
+        * ex) actual_length = 1147, maxp = 512
+        * data0 : 512
+        * data1 : 512
+        * data0 : 123
+        * data1 is the next sequence
         */
-       usbhsh_for_each_udev(udev, hpriv, i) {
-               if (usbhsh_udev_to_usbv(udev))
-                       continue;
-               goto usbhsh_device_find;
+       t = len / maxp;
+       if (len % maxp)
+               t++;
+       if (pkt->zero)
+               t++;
+       t %= 2;
+
+       if (t)
+               usb_dotoggle(urb->dev,
+                            usb_pipeendpoint(urb->pipe),
+                            usb_pipeout(urb->pipe));
+}
+
+static struct usbhsh_device *usbhsh_device_get(struct usbhsh_hpriv *hpriv,
+                                              struct urb *urb);
+
+static int usbhsh_pipe_attach(struct usbhsh_hpriv *hpriv,
+                             struct urb *urb)
+{
+       struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+       struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep);
+       struct usbhsh_device *udev = usbhsh_device_get(hpriv, urb);
+       struct usbhs_pipe *pipe;
+       struct usb_endpoint_descriptor *desc = &urb->ep->desc;
+       struct device *dev = usbhs_priv_to_dev(priv);
+       unsigned long flags;
+       int dir_in_req = !!usb_pipein(urb->pipe);
+       int is_dcp = usb_endpoint_xfer_control(desc);
+       int i, dir_in;
+       int ret = -EBUSY;
+
+       /********************  spin lock ********************/
+       usbhs_lock(priv, flags);
+
+       if (unlikely(usbhsh_uep_to_pipe(uep))) {
+               dev_err(dev, "uep already has pipe\n");
+               goto usbhsh_pipe_attach_done;
        }
 
-       dev_err(dev, "no free usbhsh_device\n");
+       usbhs_for_each_pipe_with_dcp(pipe, priv, i) {
 
-       return NULL;
+               /* check pipe type */
+               if (!usbhs_pipe_type_is(pipe, usb_endpoint_type(desc)))
+                       continue;
 
-usbhsh_device_find:
-       if (usbhsh_device_has_endpoint(udev))
-               dev_warn(dev, "udev have old endpoint\n");
+               /* check pipe direction if normal pipe */
+               if (!is_dcp) {
+                       dir_in = !!usbhs_pipe_is_dir_in(pipe);
+                       if (0 != (dir_in - dir_in_req))
+                               continue;
+               }
 
-       /* uep will be attached */
-       INIT_LIST_HEAD(&udev->ep_list_head);
+               /* check pipe is free */
+               if (usbhsh_pipe_to_uep(pipe))
+                       continue;
 
-       /*
-        * usbhsh_usbv_to_udev()
-        * usbhsh_udev_to_usbv()
-        * will be enable
-        */
-       dev_set_drvdata(&usbv->dev, udev);
-       udev->usbv = usbv;
+               /*
+                * attach pipe to uep
+                *
+                * usbhs_pipe_config_update() should be called after
+                * usbhs_set_device_config()
+                * see
+                *  DCPMAXP/PIPEMAXP
+                */
+               usbhsh_uep_to_pipe(uep)         = pipe;
+               usbhsh_pipe_to_uep(pipe)        = uep;
 
-       /* set device config */
-       usbhs_set_device_speed(priv,
-                              usbhsh_device_number(hpriv, udev),
-                              usbhsh_device_number(hpriv, udev),
-                              0, /* FIXME no parent */
-                              usbv->speed);
+               usbhs_pipe_config_update(pipe,
+                                        usbhsh_device_number(hpriv, udev),
+                                        usb_endpoint_num(desc),
+                                        usb_endpoint_maxp(desc));
 
-       dev_dbg(dev, "%s [%d](%p)\n", __func__,
-               usbhsh_device_number(hpriv, udev), udev);
+               dev_dbg(dev, "%s [%d-%d(%s:%s)]\n", __func__,
+                       usbhsh_device_number(hpriv, udev),
+                       usb_endpoint_num(desc),
+                       usbhs_pipe_name(pipe),
+                       dir_in_req ? "in" : "out");
 
-       return udev;
+               ret = 0;
+               break;
+       }
+
+usbhsh_pipe_attach_done:
+       usbhs_unlock(priv, flags);
+       /********************  spin unlock ******************/
+
+       return ret;
 }
 
-static void usbhsh_device_free(struct usbhsh_hpriv *hpriv,
-                              struct usbhsh_device *udev)
+static void usbhsh_pipe_detach(struct usbhsh_hpriv *hpriv,
+                              struct usbhsh_ep *uep)
 {
-       struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
-       struct device *dev = usbhsh_hcd_to_dev(hcd);
-       struct usb_device *usbv = usbhsh_udev_to_usbv(udev);
+       struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+       struct usbhs_pipe *pipe;
+       struct device *dev = usbhs_priv_to_dev(priv);
+       unsigned long flags;
 
-       dev_dbg(dev, "%s [%d](%p)\n", __func__,
-               usbhsh_device_number(hpriv, udev), udev);
+       /********************  spin lock ********************/
+       usbhs_lock(priv, flags);
 
-       if (usbhsh_device_has_endpoint(udev))
-               dev_warn(dev, "udev still have endpoint\n");
+       pipe = usbhsh_uep_to_pipe(uep);
 
-       /*
-        * usbhsh_usbv_to_udev()
-        * usbhsh_udev_to_usbv()
-        * will be disable
-        */
-       dev_set_drvdata(&usbv->dev, NULL);
-       udev->usbv = NULL;
+       if (unlikely(!pipe)) {
+               dev_err(dev, "uep doens't have pipe\n");
+       } else {
+               struct usb_host_endpoint *ep = usbhsh_uep_to_ep(uep);
+               struct usbhsh_device *udev = usbhsh_uep_to_udev(uep);
+
+               /* detach pipe from uep */
+               usbhsh_uep_to_pipe(uep)         = NULL;
+               usbhsh_pipe_to_uep(pipe)        = NULL;
+
+               dev_dbg(dev, "%s [%d-%d(%s)]\n", __func__,
+                       usbhsh_device_number(hpriv, udev),
+                       usb_endpoint_num(&ep->desc),
+                       usbhs_pipe_name(pipe));
+       }
+
+       usbhs_unlock(priv, flags);
+       /********************  spin unlock ******************/
 }
 
 /*
- *             end-point control
+ *             endpoint control
  */
-struct usbhsh_ep *usbhsh_endpoint_alloc(struct usbhsh_hpriv *hpriv,
-                                       struct usbhsh_device *udev,
-                                       struct usb_host_endpoint *ep,
-                                       int dir_in_req,
-                                       gfp_t mem_flags)
+static int usbhsh_endpoint_attach(struct usbhsh_hpriv *hpriv,
+                                 struct urb *urb,
+                                 gfp_t mem_flags)
 {
        struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
-       struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
+       struct usbhsh_device *udev = usbhsh_device_get(hpriv, urb);
+       struct usb_host_endpoint *ep = urb->ep;
        struct usbhsh_ep *uep;
-       struct usbhsh_pipe_info *info;
-       struct usbhs_pipe *pipe, *best_pipe;
-       struct device *dev = usbhsh_hcd_to_dev(hcd);
+       struct device *dev = usbhs_priv_to_dev(priv);
        struct usb_endpoint_descriptor *desc = &ep->desc;
-       int type, i, dir_in;
-       unsigned int min_usr;
-
-       dir_in_req = !!dir_in_req;
+       unsigned long flags;
 
        uep = kzalloc(sizeof(struct usbhsh_ep), mem_flags);
        if (!uep) {
                dev_err(dev, "usbhsh_ep alloc fail\n");
-               return NULL;
+               return -ENOMEM;
        }
 
-       if (usb_endpoint_xfer_control(desc)) {
-               best_pipe = usbhsh_hpriv_to_dcp(hpriv);
-               goto usbhsh_endpoint_alloc_find_pipe;
+       /********************  spin lock ********************/
+       usbhs_lock(priv, flags);
+
+       /*
+        * init endpoint
+        */
+       INIT_LIST_HEAD(&uep->ep_list);
+       list_add_tail(&uep->ep_list, &udev->ep_list_head);
+
+       usbhsh_uep_to_udev(uep) = udev;
+       usbhsh_uep_to_ep(uep)   = ep;
+       usbhsh_ep_to_uep(ep)    = uep;
+
+       usbhs_unlock(priv, flags);
+       /********************  spin unlock ******************/
+
+       dev_dbg(dev, "%s [%d-%d]\n", __func__,
+               usbhsh_device_number(hpriv, udev),
+               usb_endpoint_num(desc));
+
+       return 0;
+}
+
+static void usbhsh_endpoint_detach(struct usbhsh_hpriv *hpriv,
+                                  struct usb_host_endpoint *ep)
+{
+       struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+       struct device *dev = usbhs_priv_to_dev(priv);
+       struct usbhsh_ep *uep = usbhsh_ep_to_uep(ep);
+       unsigned long flags;
+
+       if (!uep)
+               return;
+
+       dev_dbg(dev, "%s [%d-%d]\n", __func__,
+               usbhsh_device_number(hpriv, usbhsh_uep_to_udev(uep)),
+               usb_endpoint_num(&ep->desc));
+
+       if (usbhsh_uep_to_pipe(uep))
+               usbhsh_pipe_detach(hpriv, uep);
+
+       /********************  spin lock ********************/
+       usbhs_lock(priv, flags);
+
+       /* remove this endpoint from udev */
+       list_del_init(&uep->ep_list);
+
+       usbhsh_uep_to_udev(uep) = NULL;
+       usbhsh_uep_to_ep(uep)   = NULL;
+       usbhsh_ep_to_uep(ep)    = NULL;
+
+       usbhs_unlock(priv, flags);
+       /********************  spin unlock ******************/
+
+       kfree(uep);
+}
+
+static void usbhsh_endpoint_detach_all(struct usbhsh_hpriv *hpriv,
+                                      struct usbhsh_device *udev)
+{
+       struct usbhsh_ep *uep, *next;
+
+       list_for_each_entry_safe(uep, next, &udev->ep_list_head, ep_list)
+               usbhsh_endpoint_detach(hpriv, usbhsh_uep_to_ep(uep));
+}
+
+/*
+ *             device control
+ */
+static int usbhsh_connected_to_rhdev(struct usb_hcd *hcd,
+                                    struct usbhsh_device *udev)
+{
+       struct usb_device *usbv = usbhsh_udev_to_usbv(udev);
+
+       return hcd->self.root_hub == usbv->parent;
+}
+
+static int usbhsh_device_has_endpoint(struct usbhsh_device *udev)
+{
+       return !list_empty(&udev->ep_list_head);
+}
+
+static struct usbhsh_device *usbhsh_device_get(struct usbhsh_hpriv *hpriv,
+                                              struct urb *urb)
+{
+       struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
+       struct usbhsh_device *udev = usbhsh_usbv_to_udev(usbv);
+
+       /* usbhsh_device_attach() is still not called */
+       if (!udev)
+               return NULL;
+
+       /* if it is device0, return it */
+       if (0 == usb_pipedevice(urb->pipe))
+               return usbhsh_device0(hpriv);
+
+       /* return attached device */
+       return udev;
+}
+
+static struct usbhsh_device *usbhsh_device_attach(struct usbhsh_hpriv *hpriv,
+                                                struct urb *urb)
+{
+       struct usbhsh_device *udev = NULL;
+       struct usbhsh_device *udev0 = usbhsh_device0(hpriv);
+       struct usbhsh_device *pos;
+       struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
+       struct device *dev = usbhsh_hcd_to_dev(hcd);
+       struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
+       struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+       unsigned long flags;
+       u16 upphub, hubport;
+       int i;
+
+       /*
+        * This function should be called only while urb is pointing to device0.
+        * It will attach unused usbhsh_device to urb (usbv),
+        * and initialize device0.
+        * You can use usbhsh_device_get() to get "current" udev,
+        * and usbhsh_usbv_to_udev() is for "attached" udev.
+        */
+       if (0 != usb_pipedevice(urb->pipe)) {
+               dev_err(dev, "%s fail: urb isn't pointing device0\n", __func__);
+               return NULL;
        }
 
+       /********************  spin lock ********************/
+       usbhs_lock(priv, flags);
+
        /*
-        * find best pipe for endpoint
-        * see
-        *      HARDWARE LIMITATION
+        * find unused device
         */
-       type = usb_endpoint_type(desc);
-       min_usr = ~0;
-       best_pipe = NULL;
-       usbhs_for_each_pipe(pipe, priv, i) {
-               if (!usbhs_pipe_type_is(pipe, type))
+       usbhsh_for_each_udev(pos, hpriv, i) {
+               if (usbhsh_udev_is_used(pos))
                        continue;
+               udev = pos;
+               break;
+       }
 
-               dir_in = !!usbhs_pipe_is_dir_in(pipe);
-               if (0 != (dir_in - dir_in_req))
-                       continue;
+       if (udev) {
+               /*
+                * usbhsh_usbv_to_udev()
+                * usbhsh_udev_to_usbv()
+                * will be enable
+                */
+               dev_set_drvdata(&usbv->dev, udev);
+               udev->usbv = usbv;
+       }
 
-               info = usbhsh_pipe_info(pipe);
+       usbhs_unlock(priv, flags);
+       /********************  spin unlock ******************/
 
-               if (min_usr > info->usr_cnt) {
-                       min_usr         = info->usr_cnt;
-                       best_pipe       = pipe;
-               }
+       if (!udev) {
+               dev_err(dev, "no free usbhsh_device\n");
+               return NULL;
        }
 
-       if (unlikely(!best_pipe)) {
-               dev_err(dev, "couldn't find best pipe\n");
-               kfree(uep);
-               return NULL;
+       if (usbhsh_device_has_endpoint(udev)) {
+               dev_warn(dev, "udev have old endpoint\n");
+               usbhsh_endpoint_detach_all(hpriv, udev);
+       }
+
+       if (usbhsh_device_has_endpoint(udev0)) {
+               dev_warn(dev, "udev0 have old endpoint\n");
+               usbhsh_endpoint_detach_all(hpriv, udev0);
        }
-usbhsh_endpoint_alloc_find_pipe:
+
+       /* uep will be attached */
+       INIT_LIST_HEAD(&udev0->ep_list_head);
+       INIT_LIST_HEAD(&udev->ep_list_head);
+
        /*
-        * init uep
+        * set device0 config
         */
-       uep->pipe       = best_pipe;
-       uep->maxp       = usb_endpoint_maxp(desc);
-       usbhsh_uep_to_udev(uep) = udev;
-       usbhsh_ep_to_uep(ep)    = uep;
+       usbhs_set_device_config(priv,
+                               0, 0, 0, usbv->speed);
 
        /*
-        * update pipe user count
+        * set new device config
         */
-       info = usbhsh_pipe_info(best_pipe);
-       info->usr_cnt++;
+       upphub  = 0;
+       hubport = 0;
+       if (!usbhsh_connected_to_rhdev(hcd, udev)) {
+               /* if udev is not connected to rhdev, it means parent is Hub */
+               struct usbhsh_device *parent = usbhsh_device_parent(udev);
 
-       /* init this endpoint, and attach it to udev */
-       INIT_LIST_HEAD(&uep->ep_list);
-       list_add_tail(&uep->ep_list, &udev->ep_list_head);
+               upphub  = usbhsh_device_number(hpriv, parent);
+               hubport = usbhsh_device_hubport(udev);
 
-       /*
-        * usbhs_pipe_config_update() should be called after
-        * usbhs_device_config()
-        * see
-        *  DCPMAXP/PIPEMAXP
-        */
-       usbhs_pipe_sequence_data0(uep->pipe);
-       usbhs_pipe_config_update(uep->pipe,
-                                usbhsh_device_number(hpriv, udev),
-                                usb_endpoint_num(desc),
-                                uep->maxp);
+               dev_dbg(dev, "%s connecte to Hub [%d:%d](%p)\n", __func__,
+                       upphub, hubport, parent);
+       }
 
-       dev_dbg(dev, "%s [%d-%s](%p)\n", __func__,
-               usbhsh_device_number(hpriv, udev),
-               usbhs_pipe_name(uep->pipe), uep);
+       usbhs_set_device_config(priv,
+                              usbhsh_device_number(hpriv, udev),
+                              upphub, hubport, usbv->speed);
 
-       return uep;
+       dev_dbg(dev, "%s [%d](%p)\n", __func__,
+               usbhsh_device_number(hpriv, udev), udev);
+
+       return udev;
 }
 
-void usbhsh_endpoint_free(struct usbhsh_hpriv *hpriv,
-                         struct usb_host_endpoint *ep)
+static void usbhsh_device_detach(struct usbhsh_hpriv *hpriv,
+                              struct usbhsh_device *udev)
 {
+       struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
        struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
-       struct device *dev = usbhs_priv_to_dev(priv);
-       struct usbhsh_ep *uep = usbhsh_ep_to_uep(ep);
-       struct usbhsh_pipe_info *info;
+       struct device *dev = usbhsh_hcd_to_dev(hcd);
+       struct usb_device *usbv = usbhsh_udev_to_usbv(udev);
+       unsigned long flags;
 
-       if (!uep)
-               return;
+       dev_dbg(dev, "%s [%d](%p)\n", __func__,
+               usbhsh_device_number(hpriv, udev), udev);
 
-       dev_dbg(dev, "%s [%d-%s](%p)\n", __func__,
-               usbhsh_device_number(hpriv, usbhsh_uep_to_udev(uep)),
-               usbhs_pipe_name(uep->pipe), uep);
+       if (usbhsh_device_has_endpoint(udev)) {
+               dev_warn(dev, "udev still have endpoint\n");
+               usbhsh_endpoint_detach_all(hpriv, udev);
+       }
 
-       info = usbhsh_pipe_info(uep->pipe);
-       info->usr_cnt--;
+       /*
+        * There is nothing to do if it is device0.
+        * see
+        *  usbhsh_device_attach()
+        *  usbhsh_device_get()
+        */
+       if (0 == usbhsh_device_number(hpriv, udev))
+               return;
 
-       /* remove this endpoint from udev */
-       list_del_init(&uep->ep_list);
+       /********************  spin lock ********************/
+       usbhs_lock(priv, flags);
 
-       usbhsh_uep_to_udev(uep) = NULL;
-       usbhsh_ep_to_uep(ep) = NULL;
+       /*
+        * usbhsh_usbv_to_udev()
+        * usbhsh_udev_to_usbv()
+        * will be disable
+        */
+       dev_set_drvdata(&usbv->dev, NULL);
+       udev->usbv = NULL;
 
-       kfree(uep);
+       usbhs_unlock(priv, flags);
+       /********************  spin unlock ******************/
 }
 
 /*
@@ -480,11 +629,12 @@ void usbhsh_endpoint_free(struct usbhsh_hpriv *hpriv,
  */
 static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt)
 {
-       struct usbhsh_request *ureq = usbhsh_pkt_to_req(pkt);
+       struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt);
        struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);
        struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
        struct urb *urb = ureq->urb;
        struct device *dev = usbhs_priv_to_dev(priv);
+       int status = 0;
 
        dev_dbg(dev, "%s\n", __func__);
 
@@ -493,29 +643,43 @@ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt)
                return;
        }
 
+       if (!usbhsh_is_running(hpriv))
+               status = -ESHUTDOWN;
+
        urb->actual_length = pkt->actual;
-       usbhsh_req_free(hpriv, ureq);
-       usbhsh_urb_to_ureq(urb) = NULL;
+       usbhsh_ureq_free(hpriv, ureq);
+
+       usbhsh_endpoint_sequence_save(hpriv, urb, pkt);
+       usbhsh_pipe_detach(hpriv, usbhsh_ep_to_uep(urb->ep));
 
        usb_hcd_unlink_urb_from_ep(hcd, urb);
-       usb_hcd_giveback_urb(hcd, urb, 0);
+       usb_hcd_giveback_urb(hcd, urb, status);
 }
 
 static int usbhsh_queue_push(struct usb_hcd *hcd,
-                            struct usbhs_pipe *pipe,
-                            struct urb *urb)
+                            struct urb *urb,
+                            gfp_t mem_flags)
 {
-       struct usbhsh_request *ureq = usbhsh_urb_to_ureq(urb);
-       struct usbhs_pkt *pkt = &ureq->pkt;
+       struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd);
+       struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep);
+       struct usbhs_pipe *pipe = usbhsh_uep_to_pipe(uep);
        struct device *dev = usbhsh_hcd_to_dev(hcd);
+       struct usbhsh_request *ureq;
        void *buf;
-       int len;
+       int len, sequence;
 
        if (usb_pipeisoc(urb->pipe)) {
                dev_err(dev, "pipe iso is not supported now\n");
                return -EIO;
        }
 
+       /* this ureq will be freed on usbhsh_queue_done() */
+       ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags);
+       if (unlikely(!ureq)) {
+               dev_err(dev, "ureq alloc fail\n");
+               return -ENOMEM;
+       }
+
        if (usb_pipein(urb->pipe))
                pipe->handler = &usbhs_fifo_pio_pop_handler;
        else
@@ -524,25 +688,59 @@ static int usbhsh_queue_push(struct usb_hcd *hcd,
        buf = (void *)(urb->transfer_buffer + urb->actual_length);
        len = urb->transfer_buffer_length - urb->actual_length;
 
+       sequence = usb_gettoggle(urb->dev,
+                                usb_pipeendpoint(urb->pipe),
+                                usb_pipeout(urb->pipe));
+
        dev_dbg(dev, "%s\n", __func__);
-       usbhs_pkt_push(pipe, pkt, usbhsh_queue_done,
-                      buf, len, (urb->transfer_flags & URB_ZERO_PACKET));
+       usbhs_pkt_push(pipe, &ureq->pkt, usbhsh_queue_done,
+                      buf, len, (urb->transfer_flags & URB_ZERO_PACKET),
+                      sequence);
+
        usbhs_pkt_start(pipe);
 
        return 0;
 }
 
+static void usbhsh_queue_force_pop(struct usbhs_priv *priv,
+                                  struct usbhs_pipe *pipe)
+{
+       struct usbhs_pkt *pkt;
+
+       while (1) {
+               pkt = usbhs_pkt_pop(pipe, NULL);
+               if (!pkt)
+                       break;
+
+               /*
+                * if all packet are gone, usbhsh_endpoint_disable()
+                * will be called.
+                * then, attached device/endpoint/pipe will be detached
+                */
+               usbhsh_queue_done(priv, pkt);
+       }
+}
+
+static void usbhsh_queue_force_pop_all(struct usbhs_priv *priv)
+{
+       struct usbhs_pipe *pos;
+       int i;
+
+       usbhs_for_each_pipe_with_dcp(pos, priv, i)
+               usbhsh_queue_force_pop(priv, pos);
+}
+
 /*
  *             DCP setup stage
  */
 static int usbhsh_is_request_address(struct urb *urb)
 {
-       struct usb_ctrlrequest *cmd;
+       struct usb_ctrlrequest *req;
 
-       cmd = (struct usb_ctrlrequest *)urb->setup_packet;
+       req = (struct usb_ctrlrequest *)urb->setup_packet;
 
-       if ((DeviceOutRequest    == cmd->bRequestType << 8) &&
-           (USB_REQ_SET_ADDRESS == cmd->bRequest))
+       if ((DeviceOutRequest    == req->bRequestType << 8) &&
+           (USB_REQ_SET_ADDRESS == req->bRequest))
                return 1;
        else
                return 0;
@@ -570,11 +768,15 @@ static void usbhsh_setup_stage_packet_push(struct usbhsh_hpriv *hpriv,
        /*
         * renesas_usbhs can not use original usb address.
         * see HARDWARE LIMITATION.
-        * modify usb address here.
+        * modify usb address here to use attached device.
+        * see usbhsh_device_attach()
         */
        if (usbhsh_is_request_address(urb)) {
-               /* FIXME */
-               req.wValue = 1;
+               struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
+               struct usbhsh_device *udev = usbhsh_usbv_to_udev(usbv);
+
+               /* udev is a attached device */
+               req.wValue = usbhsh_device_number(hpriv, udev);
                dev_dbg(dev, "create new address - %d\n", req.wValue);
        }
 
@@ -595,82 +797,80 @@ static void usbhsh_setup_stage_packet_push(struct usbhsh_hpriv *hpriv,
 static void usbhsh_data_stage_packet_done(struct usbhs_priv *priv,
                                          struct usbhs_pkt *pkt)
 {
-       struct usbhsh_request *ureq = usbhsh_pkt_to_req(pkt);
+       struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt);
        struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);
-       struct urb *urb = ureq->urb;
 
        /* this ureq was connected to urb when usbhsh_urb_enqueue()  */
 
-       usbhsh_req_free(hpriv, ureq);
-       usbhsh_urb_to_ureq(urb) = NULL;
+       usbhsh_ureq_free(hpriv, ureq);
 }
 
-static void usbhsh_data_stage_packet_push(struct usbhsh_hpriv *hpriv,
-                                         struct urb *urb,
-                                         struct usbhs_pipe *pipe)
+static int usbhsh_data_stage_packet_push(struct usbhsh_hpriv *hpriv,
+                                        struct urb *urb,
+                                        struct usbhs_pipe *pipe,
+                                        gfp_t mem_flags)
+
 {
        struct usbhsh_request *ureq;
-       struct usbhs_pkt *pkt;
 
-       /*
-        * FIXME
-        *
-        * data stage uses ureq which is connected to urb
-        * see usbhsh_urb_enqueue() :: alloc new request.
-        * it will be freed in usbhsh_data_stage_packet_done()
-        */
-       ureq    = usbhsh_urb_to_ureq(urb);
-       pkt     = &ureq->pkt;
+       /* this ureq will be freed on usbhsh_data_stage_packet_done() */
+       ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags);
+       if (unlikely(!ureq))
+               return -ENOMEM;
 
        if (usb_pipein(urb->pipe))
                pipe->handler = &usbhs_dcp_data_stage_in_handler;
        else
                pipe->handler = &usbhs_dcp_data_stage_out_handler;
 
-       usbhs_pkt_push(pipe, pkt,
+       usbhs_pkt_push(pipe, &ureq->pkt,
                       usbhsh_data_stage_packet_done,
                       urb->transfer_buffer,
                       urb->transfer_buffer_length,
-                      (urb->transfer_flags & URB_ZERO_PACKET));
+                      (urb->transfer_flags & URB_ZERO_PACKET),
+                      -1);
+
+       return 0;
 }
 
 /*
  *             DCP status stage
  */
-static void usbhsh_status_stage_packet_push(struct usbhsh_hpriv *hpriv,
+static int usbhsh_status_stage_packet_push(struct usbhsh_hpriv *hpriv,
                                            struct urb *urb,
-                                           struct usbhs_pipe *pipe)
+                                           struct usbhs_pipe *pipe,
+                                           gfp_t mem_flags)
 {
        struct usbhsh_request *ureq;
-       struct usbhs_pkt *pkt;
 
-       /*
-        * FIXME
-        *
-        * status stage uses allocated ureq.
-        * it will be freed on usbhsh_queue_done()
-        */
-       ureq    = usbhsh_req_alloc(hpriv, urb, GFP_KERNEL);
-       pkt     = &ureq->pkt;
+       /* This ureq will be freed on usbhsh_queue_done() */
+       ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags);
+       if (unlikely(!ureq))
+               return -ENOMEM;
 
        if (usb_pipein(urb->pipe))
                pipe->handler = &usbhs_dcp_status_stage_in_handler;
        else
                pipe->handler = &usbhs_dcp_status_stage_out_handler;
 
-       usbhs_pkt_push(pipe, pkt,
+       usbhs_pkt_push(pipe, &ureq->pkt,
                       usbhsh_queue_done,
                       NULL,
                       urb->transfer_buffer_length,
-                      0);
+                      0, -1);
+
+       return 0;
 }
 
 static int usbhsh_dcp_queue_push(struct usb_hcd *hcd,
-                                struct usbhsh_hpriv *hpriv,
-                                struct usbhs_pipe *pipe,
-                                struct urb *urb)
+                                struct urb *urb,
+                                gfp_t mflags)
 {
+       struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd);
+       struct usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep);
+       struct usbhs_pipe *pipe = usbhsh_uep_to_pipe(uep);
        struct device *dev = usbhsh_hcd_to_dev(hcd);
+       int ret;
 
        dev_dbg(dev, "%s\n", __func__);
 
@@ -686,13 +886,22 @@ static int usbhsh_dcp_queue_push(struct usb_hcd *hcd,
         *
         * It is pushed only when urb has buffer.
         */
-       if (urb->transfer_buffer_length)
-               usbhsh_data_stage_packet_push(hpriv, urb, pipe);
+       if (urb->transfer_buffer_length) {
+               ret = usbhsh_data_stage_packet_push(hpriv, urb, pipe, mflags);
+               if (ret < 0) {
+                       dev_err(dev, "data stage failed\n");
+                       return ret;
+               }
+       }
 
        /*
         * status stage
         */
-       usbhsh_status_stage_packet_push(hpriv, urb, pipe);
+       ret = usbhsh_status_stage_packet_push(hpriv, urb, pipe, mflags);
+       if (ret < 0) {
+               dev_err(dev, "status stage failed\n");
+               return ret;
+       }
 
        /*
         * start pushed packets
@@ -729,71 +938,82 @@ static int usbhsh_urb_enqueue(struct usb_hcd *hcd,
        struct usbhsh_hpriv *hpriv = usbhsh_hcd_to_hpriv(hcd);
        struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
        struct device *dev = usbhs_priv_to_dev(priv);
-       struct usb_device *usbv = usbhsh_urb_to_usbv(urb);
        struct usb_host_endpoint *ep = urb->ep;
-       struct usbhsh_request *ureq;
-       struct usbhsh_device *udev, *new_udev = NULL;
-       struct usbhs_pipe *pipe;
-       struct usbhsh_ep *uep;
+       struct usbhsh_device *new_udev = NULL;
        int is_dir_in = usb_pipein(urb->pipe);
-
+       int i;
        int ret;
 
        dev_dbg(dev, "%s (%s)\n", __func__, is_dir_in ? "in" : "out");
 
+       if (!usbhsh_is_running(hpriv)) {
+               ret = -EIO;
+               dev_err(dev, "host is not running\n");
+               goto usbhsh_urb_enqueue_error_not_linked;
+       }
+
        ret = usb_hcd_link_urb_to_ep(hcd, urb);
-       if (ret)
+       if (ret) {
+               dev_err(dev, "urb link failed\n");
                goto usbhsh_urb_enqueue_error_not_linked;
+       }
 
        /*
-        * get udev
+        * attach udev if needed
+        * see [image of mod_host]
         */
-       udev = usbhsh_usbv_to_udev(usbv);
-       if (!udev) {
-               new_udev = usbhsh_device_alloc(hpriv, urb);
-               if (!new_udev)
+       if (!usbhsh_device_get(hpriv, urb)) {
+               new_udev = usbhsh_device_attach(hpriv, urb);
+               if (!new_udev) {
+                       ret = -EIO;
+                       dev_err(dev, "device attach failed\n");
                        goto usbhsh_urb_enqueue_error_not_linked;
-
-               udev = new_udev;
+               }
        }
 
        /*
-        * get uep
+        * attach endpoint if needed
+        * see [image of mod_host]
         */
-       uep = usbhsh_ep_to_uep(ep);
-       if (!uep) {
-               uep = usbhsh_endpoint_alloc(hpriv, udev, ep,
-                                           is_dir_in, mem_flags);
-               if (!uep)
+       if (!usbhsh_ep_to_uep(ep)) {
+               ret = usbhsh_endpoint_attach(hpriv, urb, mem_flags);
+               if (ret < 0) {
+                       dev_err(dev, "endpoint attach failed\n");
                        goto usbhsh_urb_enqueue_error_free_device;
+               }
        }
-       pipe = usbhsh_uep_to_pipe(uep);
 
        /*
-        * alloc new request
+        * attach pipe to endpoint
+        * see [image of mod_host]
         */
-       ureq = usbhsh_req_alloc(hpriv, urb, mem_flags);
-       if (unlikely(!ureq)) {
-               ret = -ENOMEM;
+       for (i = 0; i < 1024; i++) {
+               ret = usbhsh_pipe_attach(hpriv, urb);
+               if (ret < 0)
+                       msleep(100);
+               else
+                       break;
+       }
+       if (ret < 0) {
+               dev_err(dev, "pipe attach failed\n");
                goto usbhsh_urb_enqueue_error_free_endpoint;
        }
-       usbhsh_urb_to_ureq(urb) = ureq;
 
        /*
         * push packet
         */
        if (usb_pipecontrol(urb->pipe))
-               usbhsh_dcp_queue_push(hcd, hpriv, pipe, urb);
+               ret = usbhsh_dcp_queue_push(hcd, urb, mem_flags);
        else
-               usbhsh_queue_push(hcd, pipe, urb);
+               ret = usbhsh_queue_push(hcd, urb, mem_flags);
 
-       return 0;
+       return ret;
 
 usbhsh_urb_enqueue_error_free_endpoint:
-       usbhsh_endpoint_free(hpriv, ep);
+       usbhsh_endpoint_detach(hpriv, ep);
 usbhsh_urb_enqueue_error_free_device:
        if (new_udev)
-               usbhsh_device_free(hpriv, new_udev);
+               usbhsh_device_detach(hpriv, new_udev);
 usbhsh_urb_enqueue_error_not_linked:
 
        dev_dbg(dev, "%s error\n", __func__);
@@ -807,8 +1027,11 @@ static int usbhsh_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
        struct usbhsh_request *ureq = usbhsh_urb_to_ureq(urb);
 
        if (ureq) {
-               usbhsh_req_free(hpriv, ureq);
-               usbhsh_urb_to_ureq(urb) = NULL;
+               struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv);
+               struct usbhs_pkt *pkt = &ureq->pkt;
+
+               usbhs_pkt_pop(pkt->pipe, pkt);
+               usbhsh_queue_done(priv, pkt);
        }
 
        return 0;
@@ -823,7 +1046,7 @@ static void usbhsh_endpoint_disable(struct usb_hcd *hcd,
 
        /*
         * this function might be called manytimes by same hcd/ep
-        * in-endpoitn == out-endpoint if ep == dcp.
+        * in-endpoint == out-endpoint if ep == dcp.
         */
        if (!uep)
                return;
@@ -831,15 +1054,14 @@ static void usbhsh_endpoint_disable(struct usb_hcd *hcd,
        udev    = usbhsh_uep_to_udev(uep);
        hpriv   = usbhsh_hcd_to_hpriv(hcd);
 
-       usbhsh_endpoint_free(hpriv, ep);
-       ep->hcpriv = NULL;
+       usbhsh_endpoint_detach(hpriv, ep);
 
        /*
         * if there is no endpoint,
         * free device
         */
        if (!usbhsh_device_has_endpoint(udev))
-               usbhsh_device_free(hpriv, udev);
+               usbhsh_device_detach(hpriv, udev);
 }
 
 static int usbhsh_hub_status_data(struct usb_hcd *hcd, char *buf)
@@ -919,6 +1141,8 @@ static int __usbhsh_hub_port_feature(struct usbhsh_hpriv *hpriv,
                                       USB_PORT_STAT_HIGH_SPEED |
                                       USB_PORT_STAT_LOW_SPEED);
 
+               usbhsh_queue_force_pop_all(priv);
+
                usbhs_bus_send_reset(priv);
                msleep(20);
                usbhs_bus_send_sof_enable(priv);
@@ -1082,6 +1306,20 @@ static int usbhsh_irq_attch(struct usbhs_priv *priv,
        usbhsh_port_stat_set(hpriv, USB_PORT_STAT_CONNECTION);
        usbhsh_port_stat_set(hpriv, USB_PORT_STAT_C_CONNECTION << 16);
 
+       /*
+        * attch interrupt might happen infinitely on some device
+        * (on self power USB hub ?)
+        * disable it here.
+        *
+        * usbhsh_is_running() becomes effective
+        * according to this process.
+        * see
+        *      usbhsh_is_running()
+        *      usbhsh_urb_enqueue()
+        */
+       hpriv->mod.irq_attch = NULL;
+       usbhs_irq_callback_update(priv, &hpriv->mod);
+
        return 0;
 }
 
@@ -1096,6 +1334,24 @@ static int usbhsh_irq_dtch(struct usbhs_priv *priv,
        usbhsh_port_stat_clear(hpriv, USB_PORT_STAT_CONNECTION);
        usbhsh_port_stat_set(hpriv, USB_PORT_STAT_C_CONNECTION << 16);
 
+       /*
+        * enable attch interrupt again
+        *
+        * usbhsh_is_running() becomes invalid
+        * according to this process.
+        * see
+        *      usbhsh_is_running()
+        *      usbhsh_urb_enqueue()
+        */
+       hpriv->mod.irq_attch = usbhsh_irq_attch;
+       usbhs_irq_callback_update(priv, &hpriv->mod);
+
+       /*
+        * usbhsh_queue_force_pop_all() should be called
+        * after usbhsh_is_running() becomes invalid.
+        */
+       usbhsh_queue_force_pop_all(priv);
+
        return 0;
 }
 
@@ -1131,7 +1387,6 @@ static int usbhsh_irq_setup_err(struct usbhs_priv *priv,
 static void usbhsh_pipe_init_for_host(struct usbhs_priv *priv)
 {
        struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);
-       struct usbhsh_pipe_info *pipe_info = hpriv->pipe_info;
        struct usbhs_pipe *pipe;
        u32 *pipe_type = usbhs_get_dparam(priv, pipe_type);
        int pipe_size = usbhs_get_dparam(priv, pipe_size);
@@ -1140,7 +1395,6 @@ static void usbhsh_pipe_init_for_host(struct usbhs_priv *priv)
        /* init all pipe */
        old_type = USB_ENDPOINT_XFER_CONTROL;
        for (i = 0; i < pipe_size; i++) {
-               pipe_info[i].usr_cnt    = 0;
 
                /*
                 * data "output" will be finished as soon as possible,
@@ -1174,7 +1428,7 @@ static void usbhsh_pipe_init_for_host(struct usbhs_priv *priv)
                                                 dir_in);
                }
 
-               pipe->mod_private = pipe_info + i;
+               pipe->mod_private = NULL;
        }
 }
 
@@ -1205,9 +1459,7 @@ static int usbhsh_start(struct usbhs_priv *priv)
         * - host
         * - usb module
         */
-       usbhs_sys_hispeed_ctrl(priv, 1);
        usbhs_sys_host_ctrl(priv, 1);
-       usbhs_sys_usb_ctrl(priv, 1);
 
        /*
         * enable irq callback
@@ -1242,9 +1494,7 @@ static int usbhsh_stop(struct usbhs_priv *priv)
        usb_remove_hcd(hcd);
 
        /* disable sys */
-       usbhs_sys_hispeed_ctrl(priv, 0);
        usbhs_sys_host_ctrl(priv, 0);
-       usbhs_sys_usb_ctrl(priv, 0);
 
        dev_dbg(dev, "quit host\n");
 
@@ -1255,10 +1505,8 @@ int usbhs_mod_host_probe(struct usbhs_priv *priv)
 {
        struct usbhsh_hpriv *hpriv;
        struct usb_hcd *hcd;
-       struct usbhsh_pipe_info *pipe_info;
        struct usbhsh_device *udev;
        struct device *dev = usbhs_priv_to_dev(priv);
-       int pipe_size = usbhs_get_dparam(priv, pipe_size);
        int i;
 
        /* initialize hcd */
@@ -1269,12 +1517,6 @@ int usbhs_mod_host_probe(struct usbhs_priv *priv)
        }
        hcd->has_tt = 1; /* for low/full speed */
 
-       pipe_info = kzalloc(sizeof(*pipe_info) * pipe_size, GFP_KERNEL);
-       if (!pipe_info) {
-               dev_err(dev, "Could not allocate pipe_info\n");
-               goto usbhs_mod_host_probe_err;
-       }
-
        /*
         * CAUTION
         *
@@ -1294,9 +1536,6 @@ int usbhs_mod_host_probe(struct usbhs_priv *priv)
        hpriv->mod.name         = "host";
        hpriv->mod.start        = usbhsh_start;
        hpriv->mod.stop         = usbhsh_stop;
-       hpriv->pipe_info        = pipe_info;
-       hpriv->pipe_size        = pipe_size;
-       usbhsh_req_list_init(hpriv);
        usbhsh_port_stat_init(hpriv);
 
        /* init all device */
@@ -1308,11 +1547,6 @@ int usbhs_mod_host_probe(struct usbhs_priv *priv)
        dev_info(dev, "host probed\n");
 
        return 0;
-
-usbhs_mod_host_probe_err:
-       usb_put_hcd(hcd);
-
-       return -ENOMEM;
 }
 
 int usbhs_mod_host_remove(struct usbhs_priv *priv)
@@ -1320,8 +1554,6 @@ int usbhs_mod_host_remove(struct usbhs_priv *priv)
        struct usbhsh_hpriv *hpriv = usbhsh_priv_to_hpriv(priv);
        struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv);
 
-       usbhsh_req_list_quit(hpriv);
-
        usb_put_hcd(hcd);
 
        return 0;
index c74389c..feb06d6 100644 (file)
@@ -257,6 +257,13 @@ void usbhs_pipe_stall(struct usbhs_pipe *pipe)
        }
 }
 
+int usbhs_pipe_is_stall(struct usbhs_pipe *pipe)
+{
+       u16 pid = usbhsp_pipectrl_get(pipe) & PID_MASK;
+
+       return (int)(pid == PID_STALL10 || pid == PID_STALL11);
+}
+
 /*
  *             pipe setup
  */
@@ -323,8 +330,7 @@ static u16 usbhsp_setup_pipecfg(struct usbhs_pipe *pipe,
        if (dir_in)
                usbhsp_flags_set(pipe, IS_DIR_HOST);
 
-       if ((is_host  && !dir_in) ||
-           (!is_host && dir_in))
+       if (!!is_host ^ !!dir_in)
                dir |= DIR_OUT;
 
        if (!dir)
@@ -471,10 +477,27 @@ int usbhs_pipe_is_dir_host(struct usbhs_pipe *pipe)
        return usbhsp_flags_has(pipe, IS_DIR_HOST);
 }
 
-void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int data)
+void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int sequence)
 {
        u16 mask = (SQCLR | SQSET);
-       u16 val = (data) ? SQSET : SQCLR;
+       u16 val;
+
+       /*
+        * sequence
+        *  0  : data0
+        *  1  : data1
+        *  -1 : no change
+        */
+       switch (sequence) {
+       case 0:
+               val = SQCLR;
+               break;
+       case 1:
+               val = SQSET;
+               break;
+       default:
+               return;
+       }
 
        usbhsp_pipectrl_set(pipe, mask, val);
 }
index 6334fc6..fa18b7d 100644 (file)
@@ -87,6 +87,7 @@ int usbhs_pipe_is_accessible(struct usbhs_pipe *pipe);
 void usbhs_pipe_enable(struct usbhs_pipe *pipe);
 void usbhs_pipe_disable(struct usbhs_pipe *pipe);
 void usbhs_pipe_stall(struct usbhs_pipe *pipe);
+int usbhs_pipe_is_stall(struct usbhs_pipe *pipe);
 void usbhs_pipe_select_fifo(struct usbhs_pipe *pipe, struct usbhs_fifo *fifo);
 void usbhs_pipe_config_update(struct usbhs_pipe *pipe, u16 devsel,
                              u16 epnum, u16 maxp);
diff --git a/drivers/usb/serial/ChangeLog.history b/drivers/usb/serial/ChangeLog.history
deleted file mode 100644 (file)
index f13fd48..0000000
+++ /dev/null
@@ -1,730 +0,0 @@
-This is the contents of some of the drivers/usb/serial/ files that had  old
-changelog comments.  They were quite old, and out of date, and we don't keep
-them anymore, so I've put them here, away from the source files, in case
-people still care to see them.
-
-- Greg Kroah-Hartman <greg@kroah.com> October 20, 2005
-
------------------------------------------------------------------------
-usb-serial.h Change Log comments:
-
- (03/26/2002) gkh
-       removed the port->tty check from port_paranoia_check() due to serial
-       consoles not having a tty device assigned to them.
-
- (12/03/2001) gkh
-       removed active from the port structure.
-       added documentation to the usb_serial_device_type structure
-
- (10/10/2001) gkh
-       added vendor and product to serial structure.  Needed to determine device
-       owner when the device is disconnected.
-
- (05/30/2001) gkh
-       added sem to port structure and removed port_lock
-
- (10/05/2000) gkh
-       Added interrupt_in_endpointAddress and bulk_in_endpointAddress to help
-       fix bug with urb->dev not being set properly, now that the usb core
-       needs it.
-
- (09/11/2000) gkh
-       Added usb_serial_debug_data function to help get rid of #DEBUG in the
-       drivers.
-
- (08/28/2000) gkh
-       Added port_lock to port structure.
-
- (08/08/2000) gkh
-       Added open_count to port structure.
-
- (07/23/2000) gkh
-       Added bulk_out_endpointAddress to port structure.
-
- (07/19/2000) gkh, pberger, and borchers
-       Modifications to allow usb-serial drivers to be modules.
-
------------------------------------------------------------------------
-usb-serial.c Change Log comments:
-
- (12/10/2002) gkh
-       Split the ports off into their own struct device, and added a
-       usb-serial bus driver.
-
- (11/19/2002) gkh
-       removed a few #ifdefs for the generic code and cleaned up the failure
-       logic in initialization.
-
- (10/02/2002) gkh
-       moved the console code to console.c and out of this file.
-
- (06/05/2002) gkh
-       moved location of startup() call in serial_probe() until after all
-       of the port information and endpoints are initialized.  This makes
-       things easier for some drivers.
-
- (04/10/2002) gkh
-       added serial_read_proc function which creates a
-       /proc/tty/driver/usb-serial file.
-
- (03/27/2002) gkh
-       Got USB serial console code working properly and merged into the main
-       version of the tree.  Thanks to Randy Dunlap for the initial version
-       of this code, and for pushing me to finish it up.
-       The USB serial console works with any usb serial driver device.
-
- (03/21/2002) gkh
-       Moved all manipulation of port->open_count into the core.  Now the
-       individual driver's open and close functions are called only when the
-       first open() and last close() is called.  Making the drivers a bit
-       smaller and simpler.
-       Fixed a bug if a driver didn't have the owner field set.
-
- (02/26/2002) gkh
-       Moved all locking into the main serial_* functions, instead of having
-       the individual drivers have to grab the port semaphore.  This should
-       reduce races.
-       Reworked the MOD_INC logic a bit to always increment and decrement, even
-       if the generic driver is being used.
-
- (10/10/2001) gkh
-       usb_serial_disconnect() now sets the serial->dev pointer is to NULL to
-       help prevent child drivers from accessing the device since it is now
-       gone.
-
- (09/13/2001) gkh
-       Moved generic driver initialize after we have registered with the USB
-       core.  Thanks to Randy Dunlap for pointing this problem out.
-
- (07/03/2001) gkh
-       Fixed module paramater size.  Thanks to John Brockmeyer for the pointer.
-       Fixed vendor and product getting defined through the MODULE_PARM macro
-       if the Generic driver wasn't compiled in.
-       Fixed problem with generic_shutdown() not being called for drivers that
-       don't have a shutdown() function.
-
- (06/06/2001) gkh
-       added evil hack that is needed for the prolific pl2303 device due to the
-       crazy way its endpoints are set up.
-
- (05/30/2001) gkh
-       switched from using spinlock to a semaphore, which fixes lots of problems.
-
- (04/08/2001) gb
-       Identify version on module load.
-
- 2001_02_05 gkh
-       Fixed buffer overflows bug with the generic serial driver.  Thanks to
-       Todd Squires <squirest@ct0.com> for fixing this.
-
- (01/10/2001) gkh
-       Fixed bug where the generic serial adaptor grabbed _any_ device that was
-       offered to it.
-
- (12/12/2000) gkh
-       Removed MOD_INC and MOD_DEC from poll and disconnect functions, and
-       moved them to the serial_open and serial_close functions.
-       Also fixed bug with there not being a MOD_DEC for the generic driver
-       (thanks to Gary Brubaker for finding this.)
-
- (11/29/2000) gkh
-       Small NULL pointer initialization cleanup which saves a bit of disk image
-
- (11/01/2000) Adam J. Richter
-       instead of using idVendor/idProduct pairs, usb serial drivers
-       now identify their hardware interest with usb_device_id tables,
-       which they usually have anyhow for use with MODULE_DEVICE_TABLE.
-
- (10/05/2000) gkh
-       Fixed bug with urb->dev not being set properly, now that the usb
-       core needs it.
-
- (09/11/2000) gkh
-       Removed DEBUG #ifdefs with call to usb_serial_debug_data
-
- (08/28/2000) gkh
-       Added port_lock to port structure.
-       Added locks for SMP safeness to generic driver
-       Fixed the ability to open a generic device's port more than once.
-
- (07/23/2000) gkh
-       Added bulk_out_endpointAddress to port structure.
-
- (07/19/2000) gkh, pberger, and borchers
-       Modifications to allow usb-serial drivers to be modules.
-
- (07/03/2000) gkh
-       Added more debugging to serial_ioctl call
-
- (06/25/2000) gkh
-       Changed generic_write_bulk_callback to not call wake_up_interruptible
-       directly, but to have port_softint do it at a safer time.
-
- (06/23/2000) gkh
-       Cleaned up debugging statements in a quest to find UHCI timeout bug.
-
- (05/22/2000) gkh
-       Changed the makefile, enabling the big CONFIG_USB_SERIAL_SOMTHING to be
-       removed from the individual device source files.
-
- (05/03/2000) gkh
-       Added the Digi Acceleport driver from Al Borchers and Peter Berger.
-
- (05/02/2000) gkh
-       Changed devfs and tty register code to work properly now. This was based on
-       the ACM driver changes by Vojtech Pavlik.
-
- (04/27/2000) Ryan VanderBijl
-       Put calls to *_paranoia_checks into one function.
-
- (04/23/2000) gkh
-       Fixed bug that Randy Dunlap found for Generic devices with no bulk out ports.
-       Moved when the startup code printed out the devices that are supported.
-
- (04/19/2000) gkh
-       Added driver for ZyXEL omni.net lcd plus ISDN TA
-       Made startup info message specify which drivers were compiled in.
-
- (04/03/2000) gkh
-       Changed the probe process to remove the module unload races.
-       Changed where the tty layer gets initialized to have devfs work nicer.
-       Added initial devfs support.
-
- (03/26/2000) gkh
-       Split driver up into device specific pieces.
-
- (03/19/2000) gkh
-       Fixed oops that could happen when device was removed while a program
-       was talking to the device.
-       Removed the static urbs and now all urbs are created and destroyed
-       dynamically.
-       Reworked the internal interface. Now everything is based on the
-       usb_serial_port structure instead of the larger usb_serial structure.
-       This fixes the bug that a multiport device could not have more than
-       one port open at one time.
-
- (03/17/2000) gkh
-       Added config option for debugging messages.
-       Added patch for keyspan pda from Brian Warner.
-
- (03/06/2000) gkh
-       Added the keyspan pda code from Brian Warner <warner@lothar.com>
-       Moved a bunch of the port specific stuff into its own structure. This
-       is in anticipation of the true multiport devices (there's a bug if you
-       try to access more than one port of any multiport device right now)
-
- (02/21/2000) gkh
-       Made it so that any serial devices only have to specify which functions
-       they want to overload from the generic function calls (great,
-       inheritance in C, in a driver, just what I wanted...)
-       Added support for set_termios and ioctl function calls. No drivers take
-       advantage of this yet.
-       Removed the #ifdef MODULE, now there is no module specific code.
-       Cleaned up a few comments in usb-serial.h that were wrong (thanks again
-       to Miles Lott).
-       Small fix to get_free_serial.
-
- (02/14/2000) gkh
-       Removed the Belkin and Peracom functionality from the driver due to
-       the lack of support from the vendor, and me not wanting people to
-       accidenatly buy the device, expecting it to work with Linux.
-       Added read_bulk_callback and write_bulk_callback to the type structure
-       for the needs of the FTDI and WhiteHEAT driver.
-       Changed all reverences to FTDI to FTDI_SIO at the request of Bill
-       Ryder.
-       Changed the output urb size back to the max endpoint size to make
-       the ftdi_sio driver have it easier, and due to the fact that it didn't
-       really increase the speed any.
-
- (02/11/2000) gkh
-       Added VISOR_FUNCTION_CONSOLE to the visor startup function. This was a
-       patch from Miles Lott (milos@insync.net).
-       Fixed bug with not restoring the minor range that a device grabs, if
-       the startup function fails (thanks Miles for finding this).
-
- (02/05/2000) gkh
-       Added initial framework for the Keyspan PDA serial converter so that
-       Brian Warner has a place to put his code.
-       Made the ezusb specific functions generic enough that different
-       devices can use them (whiteheat and keyspan_pda both need them).
-       Split out a whole bunch of structure and other stuff to a separate
-       usb-serial.h file.
-       Made the Visor connection messages a little more understandable, now
-       that Miles Lott (milos@insync.net) has gotten the Generic channel to
-       work. Also made them always show up in the log file.
-
- (01/25/2000) gkh
-       Added initial framework for FTDI serial converter so that Bill Ryder
-       has a place to put his code.
-       Added the vendor specific info from Handspring. Now we can print out
-       informational debug messages as well as understand what is happening.
-
- (01/23/2000) gkh
-       Fixed problem of crash when trying to open a port that didn't have a
-       device assigned to it. Made the minor node finding a little smarter,
-       now it looks to find a continuous space for the new device.
-
- (01/21/2000) gkh
-       Fixed bug in visor_startup with patch from Miles Lott (milos@insync.net)
-       Fixed get_serial_by_minor which was all messed up for multi port
-       devices. Fixed multi port problem for generic devices. Now the number
-       of ports is determined by the number of bulk out endpoints for the
-       generic device.
-
- (01/19/2000) gkh
-       Removed lots of cruft that was around from the old (pre urb) driver
-       interface.
-       Made the serial_table dynamic. This should save lots of memory when
-       the number of minor nodes goes up to 256.
-       Added initial support for devices that have more than one port.
-       Added more debugging comments for the Visor, and added a needed
-       set_configuration call.
-
- (01/17/2000) gkh
-       Fixed the WhiteHEAT firmware (my processing tool had a bug)
-       and added new debug loader firmware for it.
-       Removed the put_char function as it isn't really needed.
-       Added visor startup commands as found by the Win98 dump.
-
- (01/13/2000) gkh
-       Fixed the vendor id for the generic driver to the one I meant it to be.
-
- (01/12/2000) gkh
-       Forget the version numbering...that's pretty useless...
-       Made the driver able to be compiled so that the user can select which
-       converter they want to use. This allows people who only want the Visor
-       support to not pay the memory size price of the WhiteHEAT.
-       Fixed bug where the generic driver (idVendor=0000 and idProduct=0000)
-       grabbed the root hub. Not good.
-
- version 0.4.0 (01/10/2000) gkh
-       Added whiteheat.h containing the firmware for the ConnectTech WhiteHEAT
-       device. Added startup function to allow firmware to be downloaded to
-       a device if it needs to be.
-       Added firmware download logic to the WhiteHEAT device.
-       Started to add #defines to split up the different drivers for potential
-       configuration option.
-
- version 0.3.1 (12/30/99) gkh
-      Fixed problems with urb for bulk out.
-      Added initial support for multiple sets of endpoints. This enables
-      the Handspring Visor to be attached successfully. Only the first
-      bulk in / bulk out endpoint pair is being used right now.
-
- version 0.3.0 (12/27/99) gkh
-       Added initial support for the Handspring Visor based on a patch from
-       Miles Lott (milos@sneety.insync.net)
-       Cleaned up the code a bunch and converted over to using urbs only.
-
- version 0.2.3 (12/21/99) gkh
-       Added initial support for the Connect Tech WhiteHEAT converter.
-       Incremented the number of ports in expectation of getting the
-       WhiteHEAT to work properly (4 ports per connection).
-       Added notification on insertion and removal of what port the
-       device is/was connected to (and what kind of device it was).
-
- version 0.2.2 (12/16/99) gkh
-       Changed major number to the new allocated number. We're legal now!
-
- version 0.2.1 (12/14/99) gkh
-       Fixed bug that happens when device node is opened when there isn't a
-       device attached to it. Thanks to marek@webdesign.no for noticing this.
-
- version 0.2.0 (11/10/99) gkh
-       Split up internals to make it easier to add different types of serial
-       converters to the code.
-       Added a "generic" driver that gets it's vendor and product id
-       from when the module is loaded. Thanks to David E. Nelson (dnelson@jump.net)
-       for the idea and sample code (from the usb scanner driver.)
-       Cleared up any licensing questions by releasing it under the GNU GPL.
-
- version 0.1.2 (10/25/99) gkh
-       Fixed bug in detecting device.
-
- version 0.1.1 (10/05/99) gkh
-       Changed the major number to not conflict with anything else.
-
- version 0.1 (09/28/99) gkh
-       Can recognize the two different devices and start up a read from
-       device when asked to. Writes also work. No control signals yet, this
-       all is vendor specific data (i.e. no spec), also no control for
-       different baud rates or other bit settings.
-       Currently we are using the same devid as the acm driver. This needs
-       to change.
-
------------------------------------------------------------------------
-visor.c Change Log comments:
-
- (06/03/2003) Judd Montgomery <judd at jpilot.org>
-     Added support for module parameter options for untested/unknown
-     devices.
-
- (03/09/2003) gkh
-       Added support for the Sony Clie NZ90V device.  Thanks to Martin Brachtl
-       <brachtl@redgrep.cz> for the information.
-
- (03/05/2003) gkh
-       Think Treo support is now working.
-
- (04/03/2002) gkh
-       Added support for the Sony OS 4.1 devices.  Thanks to Hiroyuki ARAKI
-       <hiro@zob.ne.jp> for the information.
-
- (03/27/2002) gkh
-       Removed assumptions that port->tty was always valid (is not true
-       for usb serial console devices.)
-
- (03/23/2002) gkh
-       Added support for the Palm i705 device, thanks to Thomas Riemer
-       <tom@netmech.com> for the information.
-
- (03/21/2002) gkh
-       Added support for the Palm m130 device, thanks to Udo Eisenbarth
-       <udo.eisenbarth@web.de> for the information.
-
- (02/27/2002) gkh
-       Reworked the urb handling logic.  We have no more pool, but dynamically
-       allocate the urb and the transfer buffer on the fly.  In testing this
-       does not incure any measurable overhead.  This also relies on the fact
-       that we have proper reference counting logic for urbs.
-
- (02/21/2002) SilaS
-  Added initial support for the Palm m515 devices.
-
- (02/14/2002) gkh
-       Added support for the Clie S-360 device.
-
- (12/18/2001) gkh
-       Added better Clie support for 3.5 devices.  Thanks to Geoffrey Levand
-       for the patch.
-
- (11/11/2001) gkh
-       Added support for the m125 devices, and added check to prevent oopses
-       for Clié devices that lie about the number of ports they have.
-
- (08/30/2001) gkh
-       Added support for the Clie devices, both the 3.5 and 4.0 os versions.
-       Many thanks to Daniel Burke, and Bryan Payne for helping with this.
-
- (08/23/2001) gkh
-       fixed a few potential bugs pointed out by Oliver Neukum.
-
- (05/30/2001) gkh
-       switched from using spinlock to a semaphore, which fixes lots of problems.
-
- (05/28/2000) gkh
-       Added initial support for the Palm m500 and Palm m505 devices.
-
- (04/08/2001) gb
-       Identify version on module load.
-
- (01/21/2000) gkh
-       Added write_room and chars_in_buffer, as they were previously using the
-       generic driver versions which is all wrong now that we are using an urb
-       pool.  Thanks to Wolfgang Grandegger for pointing this out to me.
-       Removed count assignment in the write function, which was not needed anymore
-       either.  Thanks to Al Borchers for pointing this out.
-
- (12/12/2000) gkh
-       Moved MOD_DEC to end of visor_close to be nicer, as the final write
-       message can sleep.
-
- (11/12/2000) gkh
-       Fixed bug with data being dropped on the floor by forcing tty->low_latency
-       to be on.  Hopefully this fixes the OHCI issue!
-
- (11/01/2000) Adam J. Richter
-       usb_device_id table support
-
- (10/05/2000) gkh
-       Fixed bug with urb->dev not being set properly, now that the usb
-       core needs it.
-
- (09/11/2000) gkh
-       Got rid of always calling kmalloc for every urb we wrote out to the
-       device.
-       Added visor_read_callback so we can keep track of bytes in and out for
-       those people who like to know the speed of their device.
-       Removed DEBUG #ifdefs with call to usb_serial_debug_data
-
- (09/06/2000) gkh
-       Fixed oops in visor_exit.  Need to uncomment usb_unlink_urb call _after_
-       the host controller drivers set urb->dev = NULL when the urb is finished.
-
- (08/28/2000) gkh
-       Added locks for SMP safeness.
-
- (08/08/2000) gkh
-       Fixed endian problem in visor_startup.
-       Fixed MOD_INC and MOD_DEC logic and the ability to open a port more
-       than once.
-
- (07/23/2000) gkh
-       Added pool of write urbs to speed up transfers to the visor.
-
- (07/19/2000) gkh
-       Added module_init and module_exit functions to handle the fact that this
-       driver is a loadable module now.
-
- (07/03/2000) gkh
-       Added visor_set_ioctl and visor_set_termios functions (they don't do much
-       of anything, but are good for debugging.)
-
- (06/25/2000) gkh
-       Fixed bug in visor_unthrottle that should help with the disconnect in PPP
-       bug that people have been reporting.
-
- (06/23/2000) gkh
-       Cleaned up debugging statements in a quest to find UHCI timeout bug.
-
- (04/27/2000) Ryan VanderBijl
-       Fixed memory leak in visor_close
-
- (03/26/2000) gkh
-       Split driver up into device specific pieces.
-
------------------------------------------------------------------------
-pl2303.c Change Log comments:
-
- 2002_Mar_26 gkh
-       allowed driver to work properly if there is no tty assigned to a port
-       (this happens for serial console devices.)
-
- 2001_Oct_06 gkh
-       Added RTS and DTR line control.  Thanks to joe@bndlg.de for parts of it.
-
- 2001_Sep_19 gkh
-       Added break support.
-
- 2001_Aug_30 gkh
-       fixed oops in write_bulk_callback.
-
- 2001_Aug_28 gkh
-       reworked buffer logic to be like other usb-serial drivers.  Hopefully
-       removing some reported problems.
-
- 2001_Jun_06 gkh
-       finished porting to 2.4 format.
-
-
------------------------------------------------------------------------
-io_edgeport.c Change Log comments:
-
- 2003_04_03 al borchers
-  - fixed a bug (that shows up with dosemu) where the tty struct is
-    used in a callback after it has been freed
-
- 2.3 2002_03_08 greg kroah-hartman
-       - fixed bug when multiple devices were attached at the same time.
-
- 2.2 2001_11_14 greg kroah-hartman
-       - fixed bug in edge_close that kept the port from being used more
-         than once.
-       - fixed memory leak on device removal.
-       - fixed potential double free of memory when command urb submitting
-         failed.
-       - other small cleanups when the device is removed
-
- 2.1 2001_07_09 greg kroah-hartman
-       - added support for TIOCMBIS and TIOCMBIC.
-
-     (04/08/2001) gb
-       - Identify version on module load.
-
- 2.0 2001_03_05 greg kroah-hartman
-       - reworked entire driver to fit properly in with the other usb-serial
-         drivers.  Occasional oopses still happen, but it's a good start.
-
- 1.2.3 (02/23/2001) greg kroah-hartman
-       - changed device table to work properly for 2.4.x final format.
-       - fixed problem with dropping data at high data rates.
-
- 1.2.2 (11/27/2000) greg kroah-hartman
-       - cleaned up more NTisms.
-       - Added device table for 2.4.0-test11
-
- 1.2.1 (11/08/2000) greg kroah-hartman
-       - Started to clean up NTisms.
-       - Fixed problem with dev field of urb for kernels >= 2.4.0-test9
-
- 1.2 (10/17/2000) David Iacovelli
-       Remove all EPIC code and GPL source
-  Fix RELEVANT_IFLAG macro to include flow control
-  changes port configuration changes.
-  Fix redefinition of SERIAL_MAGIC
-  Change all timeout values to 5 seconds
-  Tried to fix the UHCI multiple urb submission, but failed miserably.
-  it seems to work fine with OHCI.
-  ( Greg take a look at the #if 0 at end of WriteCmdUsb() we must
-    find a way to work arount this UHCI bug )
-
- 1.1 (10/11/2000) David Iacovelli
-  Fix XON/XOFF flow control to support both IXON and IXOFF
-
- 0.9.27 (06/30/2000) David Iacovelli
-  Added transmit queue and now allocate urb for command writes.
-
- 0.9.26 (06/29/2000) David Iacovelli
-  Add support for 80251 based edgeport
-
- 0.9.25 (06/27/2000) David Iacovelli
-  Do not close the port if it has multiple opens.
-
- 0.9.24 (05/26/2000) David Iacovelli
-  Add IOCTLs to support RXTX and JAVA POS
-  and first cut at running BlackBox Demo
-
- 0.9.23 (05/24/2000) David Iacovelli
-  Add IOCTLs to support RXTX and JAVA POS
-
- 0.9.22 (05/23/2000) David Iacovelli
-  fixed bug in enumeration.  If epconfig turns on mapping by
-  path after a device is already plugged in, we now update
-  the mapping correctly
-
- 0.9.21 (05/16/2000) David Iacovelli
-  Added BlockUntilChaseResp() to also wait for txcredits
-  Updated the way we allocate and handle write URBs
-       Add debug code to dump buffers
-
- 0.9.20 (05/01/2000) David Iacovelli
-       change driver to use usb/tts/
-
- 0.9.19 (05/01/2000) David Iacovelli
-  Update code to compile if DEBUG is off
-
- 0.9.18 (04/28/2000) David Iacovelli
-  cleanup and test tty_register with devfs
-
- 0.9.17 (04/27/2000) greg kroah-hartman
-       changed tty_register around to be like the way it
-       was before, but now it works properly with devfs.
-
- 0.9.16 (04/26/2000) david iacovelli
-  Fixed bug in GetProductInfo()
-
- 0.9.15 (04/25/2000) david iacovelli
-       Updated enumeration
-
- 0.9.14 (04/24/2000) david iacovelli
-  Removed all config/status IOCTLS and
-  converted to using /proc/edgeport
-  still playing with devfs
-
- 0.9.13 (04/24/2000) david iacovelli
-  Removed configuration based on ttyUSB0
-  Added support for configuration using /prod/edgeport
-  first attempt at using devfs (not working yet!)
-  Added IOCTL to GetProductInfo()
-  Added support for custom baud rates
-       Add support for random port numbers
-
- 0.9.12 (04/18/2000) david iacovelli
-       added additional configuration IOCTLs
-  use ttyUSB0 for configuration
-
- 0.9.11 (04/17/2000) greg kroah-hartman
-       fixed module initialization race conditions.
-       made all urbs dynamically allocated.
-       made driver devfs compatible. now it only registers the tty device
-       when the device is actually plugged in.
-
- 0.9.10 (04/13/2000) greg kroah-hartman
-       added proc interface framework.
-
- 0.9.9 (04/13/2000) david iacovelli
-       added enumeration code and ioctls to configure the device
-
- 0.9.8 (04/12/2000) david iacovelli
-  Change interrupt read start when device is plugged in
-  and stop when device is removed
-       process interrupt reads when all ports are closed
-  (keep value of rxBytesAvail consistent with the edgeport)
-  set the USB_BULK_QUEUE flag so that we can shove a bunch
-  of urbs at once down the pipe
-
- 0.9.7 (04/10/2000) david iacovelli
-       start to add enumeration code.
-  generate serial number for epic devices
-  add support for kdb
-
- 0.9.6 (03/30/2000) david iacovelli
-  add IOCTL to get string, manufacture, and boot descriptors
-
- 0.9.5 (03/14/2000) greg kroah-hartman
-       more error checking added to SerialOpen to try to fix UHCI open problem
-
- 0.9.4 (03/09/2000) greg kroah-hartman
-       added more error checking to handle oops when data is hanging
-       around and tty is abruptly closed.
-
- 0.9.3 (03/09/2000) david iacovelli
-       Add epic support for xon/xoff chars
-       play with performance
-
- 0.9.2 (03/08/2000) greg kroah-hartman
-       changed most "info" calls to "dbg"
-       implemented flow control properly in the termios call
-
- 0.9.1 (03/08/2000) david iacovelli
-       added EPIC support
-       enabled bootloader update
-
- 0.9 (03/08/2000) greg kroah-hartman
-       Release to IO networks.
-       Integrated changes that David made
-  made getting urbs for writing SMP safe
-
- 0.8 (03/07/2000) greg kroah-hartman
-       Release to IO networks.
-       Fixed problems that were seen in code by David.
-  Now both Edgeport/4 and Edgeport/2 works properly.
-  Changed most of the functions to use port instead of serial.
-
- 0.7 (02/27/2000) greg kroah-hartman
-       Milestone 3 release.
-       Release to IO Networks
-       ioctl for waiting on line change implemented.
-       ioctl for getting statistics implemented.
-       multiport support working.
-       lsr and msr registers are now handled properly.
-       change break now hooked up and working.
-       support for all known Edgeport devices.
-
- 0.6 (02/22/2000) greg kroah-hartman
-       Release to IO networks.
-       CHASE is implemented correctly when port is closed.
-       SerialOpen now blocks correctly until port is fully opened.
-
- 0.5 (02/20/2000) greg kroah-hartman
-       Release to IO networks.
-       Known problems:
-               modem status register changes are not sent on to the user
-               CHASE is not implemented when the port is closed.
-
- 0.4 (02/16/2000) greg kroah-hartman
-       Second cut at the CeBit demo.
-       Doesn't leak memory on every write to the port
-       Still small leaks on startup.
-       Added support for Edgeport/2 and Edgeport/8
-
- 0.3 (02/15/2000) greg kroah-hartman
-       CeBit demo release.
-       Force the line settings to 4800, 8, 1, e for the demo.
-       Warning! This version leaks memory like crazy!
-
- 0.2 (01/30/2000) greg kroah-hartman
-       Milestone 1 release.
-       Device is found by USB subsystem, enumerated, firmware is downloaded
-       and the descriptors are printed to the debug log, config is set, and
-       green light starts to blink. Open port works, and data can be sent
-       and received at the default settings of the UART. Loopback connector
-       and debug log confirms this.
-
- 0.1 (01/23/2000) greg kroah-hartman
-       Initial release to help IO Networks try to set up their test system.
-       Edgeport4 is recognized, firmware is downloaded, config is set so
-       device blinks green light every 3 sec. Port is bound, but opening,
-       closing, and sending data do not work properly.
-
-
index d6921fa..f9f29b2 100644 (file)
  * TODO:
  * -- Add true modem contol line query capability.  Currently we track the
  *    states reported by the interrupt and the states we request.
- * -- Add error reporting back to application for UART error conditions.
- *    Just point me at how to implement this and I'll do it. I've put the
- *    framework in, but haven't analyzed the "tty_flip" interface yet.
  * -- Add support for flush commands
- * -- Add everything that is missing :)
- *
- * 27-Nov-2001 gkh
- *     compressed all the differnent device entries into 1.
- *
- * 30-May-2001 gkh
- *     switched from using spinlock to a semaphore, which fixes lots of
- *     problems.
- *
- * 08-Apr-2001 gb
- *     - Identify version on module load.
- *
- * 12-Mar-2001 gkh
- *     - Added support for the GoHubs GO-COM232 device which is the same as the
- *       Peracom device.
- *
- * 06-Nov-2000 gkh
- *     - Added support for the old Belkin and Peracom devices.
- *     - Made the port able to be opened multiple times.
- *     - Added some defaults incase the line settings are things these devices
- *       can't support.
- *
- * 18-Oct-2000 William Greathouse
- *    Released into the wild (linux-usb-devel)
- *
- * 17-Oct-2000 William Greathouse
- *    Add code to recognize firmware version and set hardware flow control
- *    appropriately.  Belkin states that firmware prior to 3.05 does not
- *    operate correctly in hardware handshake mode.  I have verified this
- *    on firmware 2.05 -- for both RTS and DTR input flow control, the control
- *    line is not reset.  The test performed by the Belkin Win* driver is
- *    to enable hardware flow control for firmware 2.06 or greater and
- *    for 1.00 or prior.  I am only enabling for 2.06 or greater.
- *
- * 12-Oct-2000 William Greathouse
- *    First cut at supporting Belkin USB Serial Adapter F5U103
- *    I did not have a copy of the original work to support this
- *    adapter, so pardon any stupid mistakes.  All of the information
- *    I am using to write this driver was acquired by using a modified
- *    UsbSnoop on Windows2000 and from examining the other USB drivers.
  */
 
 #include <linux/kernel.h>
index 6ae1c06..0e77511 100644 (file)
@@ -335,13 +335,12 @@ static int ch341_open(struct tty_struct *tty, struct usb_serial_port *port)
                goto out;
 
        dbg("%s - submitting interrupt urb", __func__);
-       port->interrupt_in_urb->dev = serial->dev;
        r = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
        if (r) {
                dev_err(&port->dev, "%s - failed submitting interrupt urb,"
                        " error %d\n", __func__, r);
                ch341_close(port);
-               return -EPROTO;
+               goto out;
        }
 
        r = usb_serial_generic_open(tty, port);
index fd67cc5..adfe660 100644 (file)
@@ -92,6 +92,7 @@ static const struct usb_device_id id_table[] = {
        { USB_DEVICE(0x10C4, 0x818B) }, /* AVIT Research USB to TTL */
        { USB_DEVICE(0x10C4, 0x819F) }, /* MJS USB Toslink Switcher */
        { USB_DEVICE(0x10C4, 0x81A6) }, /* ThinkOptics WavIt */
+       { USB_DEVICE(0x10C4, 0x81A9) }, /* Multiplex RC Interface */
        { USB_DEVICE(0x10C4, 0x81AC) }, /* MSD Dash Hawk */
        { USB_DEVICE(0x10C4, 0x81AD) }, /* INSYS USB Modem */
        { USB_DEVICE(0x10C4, 0x81C8) }, /* Lipowsky Industrie Elektronik GmbH, Baby-JTAG */
@@ -280,7 +281,10 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request,
                dbg("%s - Unable to send config request, "
                                "request=0x%x size=%d result=%d\n",
                                __func__, request, size, result);
-               return -EPROTO;
+               if (result > 0)
+                       result = -EPROTO;
+
+               return result;
        }
 
        return 0;
@@ -331,7 +335,10 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request,
                dbg("%s - Unable to send request, "
                                "request=0x%x size=%d result=%d\n",
                                __func__, request, size, result);
-               return -EPROTO;
+               if (result > 0)
+                       result = -EPROTO;
+
+               return result;
        }
 
        return 0;
@@ -395,10 +402,11 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port)
 
        dbg("%s - port %d", __func__, port->number);
 
-       if (cp210x_set_config_single(port, CP210X_IFC_ENABLE, UART_ENABLE)) {
-               dev_err(&port->dev, "%s - Unable to enable UART\n",
-                               __func__);
-               return -EPROTO;
+       result = cp210x_set_config_single(port, CP210X_IFC_ENABLE,
+                                                               UART_ENABLE);
+       if (result) {
+               dev_err(&port->dev, "%s - Unable to enable UART\n", __func__);
+               return result;
        }
 
        result = usb_serial_generic_open(tty, port);
@@ -520,18 +528,13 @@ static void cp210x_get_termios_port(struct usb_serial_port *port,
                cflag |= PARENB;
                break;
        case BITS_PARITY_MARK:
-               dbg("%s - parity = MARK (not supported, disabling parity)",
-                               __func__);
-               cflag &= ~PARENB;
-               bits &= ~BITS_PARITY_MASK;
-               cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
+               dbg("%s - parity = MARK", __func__);
+               cflag |= (PARENB|PARODD|CMSPAR);
                break;
        case BITS_PARITY_SPACE:
-               dbg("%s - parity = SPACE (not supported, disabling parity)",
-                               __func__);
-               cflag &= ~PARENB;
-               bits &= ~BITS_PARITY_MASK;
-               cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2);
+               dbg("%s - parity = SPACE", __func__);
+               cflag &= ~PARODD;
+               cflag |= (PARENB|CMSPAR);
                break;
        default:
                dbg("%s - Unknown parity mode, disabling parity", __func__);
@@ -588,7 +591,6 @@ static void cp210x_set_termios(struct tty_struct *tty,
        if (!tty)
                return;
 
-       tty->termios->c_cflag &= ~CMSPAR;
        cflag = tty->termios->c_cflag;
        old_cflag = old_termios->c_cflag;
        baud = cp210x_quantise_baudrate(tty_get_baud_rate(tty));
@@ -643,16 +645,27 @@ static void cp210x_set_termios(struct tty_struct *tty,
                                        "not supported by device\n");
        }
 
-       if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))) {
+       if ((cflag     & (PARENB|PARODD|CMSPAR)) !=
+           (old_cflag & (PARENB|PARODD|CMSPAR))) {
                cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2);
                bits &= ~BITS_PARITY_MASK;
                if (cflag & PARENB) {
-                       if (cflag & PARODD) {
-                               bits |= BITS_PARITY_ODD;
-                               dbg("%s - parity = ODD", __func__);
+                       if (cflag & CMSPAR) {
+                           if (cflag & PARODD) {
+                                   bits |= BITS_PARITY_MARK;
+                                   dbg("%s - parity = MARK", __func__);
+                           } else {
+                                   bits |= BITS_PARITY_SPACE;
+                                   dbg("%s - parity = SPACE", __func__);
+                           }
                        } else {
-                               bits |= BITS_PARITY_EVEN;
-                               dbg("%s - parity = EVEN", __func__);
+                           if (cflag & PARODD) {
+                                   bits |= BITS_PARITY_ODD;
+                                   dbg("%s - parity = ODD", __func__);
+                           } else {
+                                   bits |= BITS_PARITY_EVEN;
+                                   dbg("%s - parity = EVEN", __func__);
+                           }
                        }
                }
                if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
index f744ab7..98bf833 100644 (file)
@@ -138,7 +138,6 @@ static int cyberjack_startup(struct usb_serial *serial)
 
        for (i = 0; i < serial->num_ports; ++i) {
                int result;
-               serial->port[i]->interrupt_in_urb->dev = serial->dev;
                result = usb_submit_urb(serial->port[i]->interrupt_in_urb,
                                        GFP_KERNEL);
                if (result)
@@ -208,7 +207,6 @@ static void cyberjack_close(struct usb_serial_port *port)
 static int cyberjack_write(struct tty_struct *tty,
        struct usb_serial_port *port, const unsigned char *buf, int count)
 {
-       struct usb_serial *serial = port->serial;
        struct cyberjack_private *priv = usb_get_serial_port_data(port);
        unsigned long flags;
        int result;
@@ -221,22 +219,18 @@ static int cyberjack_write(struct tty_struct *tty,
                return 0;
        }
 
-       spin_lock_bh(&port->lock);
-       if (port->write_urb_busy) {
-               spin_unlock_bh(&port->lock);
+       if (!test_and_clear_bit(0, &port->write_urbs_free)) {
                dbg("%s - already writing", __func__);
                return 0;
        }
-       port->write_urb_busy = 1;
-       spin_unlock_bh(&port->lock);
 
        spin_lock_irqsave(&priv->lock, flags);
 
        if (count+priv->wrfilled > sizeof(priv->wrbuf)) {
                /* To much data for buffer. Reset buffer. */
                priv->wrfilled = 0;
-               port->write_urb_busy = 0;
                spin_unlock_irqrestore(&priv->lock, flags);
+               set_bit(0, &port->write_urbs_free);
                return 0;
        }
 
@@ -265,13 +259,7 @@ static int cyberjack_write(struct tty_struct *tty,
                priv->wrsent = length;
 
                /* set up our urb */
-               usb_fill_bulk_urb(port->write_urb, serial->dev,
-                             usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress),
-                             port->write_urb->transfer_buffer, length,
-                             ((serial->type->write_bulk_callback) ?
-                              serial->type->write_bulk_callback :
-                              cyberjack_write_bulk_callback),
-                             port);
+               port->write_urb->transfer_buffer_length = length;
 
                /* send the data out the bulk port */
                result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
@@ -283,7 +271,7 @@ static int cyberjack_write(struct tty_struct *tty,
                        priv->wrfilled = 0;
                        priv->wrsent = 0;
                        spin_unlock_irqrestore(&priv->lock, flags);
-                       port->write_urb_busy = 0;
+                       set_bit(0, &port->write_urbs_free);
                        return 0;
                }
 
@@ -351,7 +339,6 @@ static void cyberjack_read_int_callback(struct urb *urb)
                spin_unlock(&priv->lock);
 
                if (!old_rdtodo) {
-                       port->read_urb->dev = port->serial->dev;
                        result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
                        if (result)
                                dev_err(&port->dev, "%s - failed resubmitting "
@@ -362,7 +349,6 @@ static void cyberjack_read_int_callback(struct urb *urb)
        }
 
 resubmit:
-       port->interrupt_in_urb->dev = port->serial->dev;
        result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
        if (result)
                dev_err(&port->dev, "usb_submit_urb(read int) failed\n");
@@ -415,7 +401,6 @@ static void cyberjack_read_bulk_callback(struct urb *urb)
 
        /* Continue to read if we have still urbs to do. */
        if (todo /* || (urb->actual_length==port->bulk_in_endpointAddress)*/) {
-               port->read_urb->dev = port->serial->dev;
                result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
                if (result)
                        dev_err(&port->dev, "%s - failed resubmitting read "
@@ -432,7 +417,7 @@ static void cyberjack_write_bulk_callback(struct urb *urb)
 
        dbg("%s - port %d", __func__, port->number);
 
-       port->write_urb_busy = 0;
+       set_bit(0, &port->write_urbs_free);
        if (status) {
                dbg("%s - nonzero write bulk status received: %d",
                    __func__, status);
@@ -455,13 +440,7 @@ static void cyberjack_write_bulk_callback(struct urb *urb)
                priv->wrsent += length;
 
                /* set up our urb */
-               usb_fill_bulk_urb(port->write_urb, port->serial->dev,
-                             usb_sndbulkpipe(port->serial->dev, port->bulk_out_endpointAddress),
-                             port->write_urb->transfer_buffer, length,
-                             ((port->serial->type->write_bulk_callback) ?
-                              port->serial->type->write_bulk_callback :
-                              cyberjack_write_bulk_callback),
-                             port);
+               port->write_urb->transfer_buffer_length = length;
 
                /* send the data out the bulk port */
                result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
index d9906eb..07680d6 100644 (file)
  *
  * See http://geocities.com/i0xox0i for information on this driver and the
  * earthmate usb device.
- *
- *  Lonnie Mendez <dignome@gmail.com>
- *  4-29-2005
- *     Fixed problem where setting or retreiving the serial config would fail
- *     with EPIPE.  Removed CRTS toggling so the driver behaves more like
- *     other usbserial adapters.  Issued new interval of 1ms instead of the
- *     default 10ms.  As a result, transfer speed has been substantially
- *     increased from avg. 850bps to avg. 3300bps.  initial termios has also
- *     been modified.  Cleaned up code and formatting issues so it is more
- *     readable.  Replaced the C++ style comments.
- *
- *  Lonnie Mendez <dignome@gmail.com>
- *  12-15-2004
- *     Incorporated write buffering from pl2303 driver.  Fixed bug with line
- *     handling so both lines are raised in cypress_open. (was dropping rts)
- *      Various code cleanups made as well along with other misc bug fixes.
- *
- *  Lonnie Mendez <dignome@gmail.com>
- *  04-10-2004
- *     Driver modified to support dynamic line settings.  Various improvements
- *      and features.
- *
- *  Neil Whelchel
- *  10-2003
- *     Driver first released.
- *
  */
 
 /* Thanks to Neil Whelchel for writing the first cypress m8 implementation
@@ -1162,8 +1136,6 @@ static void cypress_unthrottle(struct tty_struct *tty)
                return;
 
        if (actually_throttled) {
-               port->interrupt_in_urb->dev = port->serial->dev;
-
                result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
                if (result) {
                        dev_err(&port->dev, "%s - failed submitting read urb, "
@@ -1352,7 +1324,6 @@ static void cypress_write_int_callback(struct urb *urb)
                dbg("%s - nonzero write bulk status received: %d",
                        __func__, status);
                port->interrupt_out_urb->transfer_buffer_length = 1;
-               port->interrupt_out_urb->dev = port->serial->dev;
                result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
                if (!result)
                        return;
index e92cbef..6d26a77 100644 (file)
 *
 *  Peter Berger (pberger@brimson.com)
 *  Al Borchers (borchers@steinerpoint.com)
-* 
-* (12/03/2001) gkh
-*      switched to using port->port.count instead of private version.
-*      Removed port->active
-*
-* (04/08/2001) gb
-*      Identify version on module load.
-*
-* (11/01/2000) Adam J. Richter
-*      usb_device_id table support
-* 
-* (11/01/2000) pberger and borchers
-*    -- Turned off the USB_DISABLE_SPD flag for write bulk urbs--it caused
-*       USB 4 ports to hang on startup.
-*    -- Serialized access to write urbs by adding the dp_write_urb_in_use
-*       flag; otherwise, the driver caused SMP system hangs.  Watching the
-*       urb status is not sufficient.
-*
-* (10/05/2000) gkh
-*    -- Fixed bug with urb->dev not being set properly, now that the usb
-*      core needs it.
-* 
-*  (8/8/2000) pberger and borchers
-*    -- Fixed close so that 
-*       - it can timeout while waiting for transmit idle, if needed;
-*       - it ignores interrupts when flushing the port, turning
-*         of modem signalling, and so on;
-*       - it waits for the flush to really complete before returning.
-*    -- Read_bulk_callback and write_bulk_callback check for a closed
-*       port before using the tty struct or writing to the port.
-*    -- The two changes above fix the oops caused by interrupted closes.
-*    -- Added interruptible args to write_oob_command and set_modem_signals
-*       and added a timeout arg to transmit_idle; needed for fixes to
-*       close.
-*    -- Added code for rx_throttle and rx_unthrottle so that input flow
-*       control works.
-*    -- Added code to set overrun, parity, framing, and break errors
-*       (untested).
-*    -- Set USB_DISABLE_SPD flag for write bulk urbs, so no 0 length
-*       bulk writes are done.  These hung the Digi USB device.  The
-*       0 length bulk writes were a new feature of usb-uhci added in
-*       the 2.4.0-test6 kernels.
-*    -- Fixed mod inc race in open; do mod inc before sleeping to wait
-*       for a close to finish.
-*
-*  (7/31/2000) pberger
-*    -- Fixed bugs with hardware handshaking:
-*       - Added code to set/clear tty->hw_stopped in digi_read_oob_callback()
-*         and digi_set_termios()
-*    -- Added code in digi_set_termios() to
-*       - add conditional in code handling transition from B0 to only
-*         set RTS if RTS/CTS flow control is either not in use or if
-*         the port is not currently throttled.
-*       - handle turning off CRTSCTS.
-*
-*  (7/30/2000) borchers
-*    -- Added support for more than one Digi USB device by moving
-*       globals to a private structure in the pointed to from the
-*       usb_serial structure.
-*    -- Moved the modem change and transmit idle wait queues into
-*       the port private structure, so each port has its own queue
-*       rather than sharing global queues.
-*    -- Added support for break signals.
-*
-*  (7/25/2000) pberger
-*    -- Added USB-2 support.  Note: the USB-2 supports 3 devices: two
-*       serial and a parallel port.  The parallel port is implemented
-*       as a serial-to-parallel converter.  That is, the driver actually
-*       presents all three USB-2 interfaces as serial ports, but the third
-*       one physically connects to a parallel device.  Thus, for example,
-*       one could plug a parallel printer into the USB-2's third port,
-*       but from the kernel's (and userland's) point of view what's
-*       actually out there is a serial device.
-*
-*  (7/15/2000) borchers
-*    -- Fixed race in open when a close is in progress.
-*    -- Keep count of opens and dec the module use count for each
-*       outstanding open when shutdown is called (on disconnect).
-*    -- Fixed sanity checks in read_bulk_callback and write_bulk_callback
-*       so pointers are checked before use.
-*    -- Split read bulk callback into in band and out of band
-*       callbacks, and no longer restart read chains if there is
-*       a status error or a sanity error.  This fixed the seg
-*       faults and other errors we used to get on disconnect.
-*    -- Port->active is once again a flag as usb-serial intended it
-*       to be, not a count.  Since it was only a char it would
-*       have been limited to 256 simultaneous opens.  Now the open
-*       count is kept in the port private structure in dp_open_count.
-*    -- Added code for modularization of the digi_acceleport driver.
-*
-*  (6/27/2000) pberger and borchers
-*    -- Zeroed out sync field in the wakeup_task before first use;
-*       otherwise the uninitialized value might prevent the task from
-*       being scheduled.
-*    -- Initialized ret value to 0 in write_bulk_callback, otherwise
-*       the uninitialized value could cause a spurious debugging message.
-*
-*  (6/22/2000) pberger and borchers
-*    -- Made cond_wait_... inline--apparently on SPARC the flags arg
-*       to spin_lock_irqsave cannot be passed to another function
-*       to call spin_unlock_irqrestore.  Thanks to Pauline Middelink.
-*    -- In digi_set_modem_signals the inner nested spin locks use just
-*       spin_lock() rather than spin_lock_irqsave().  The old code
-*       mistakenly left interrupts off.  Thanks to Pauline Middelink.
-*    -- copy_from_user (which can sleep) is no longer called while a
-*       spinlock is held.  We copy to a local buffer before getting
-*       the spinlock--don't like the extra copy but the code is simpler.
-*    -- Printk and dbg are no longer called while a spin lock is held.
-*
-*  (6/4/2000) pberger and borchers
-*    -- Replaced separate calls to spin_unlock_irqrestore and
-*       interruptible_sleep_on_timeout with a new function
-*       cond_wait_interruptible_timeout_irqrestore.  This eliminates
-*       the race condition where the wake up could happen after
-*       the unlock and before the sleep.
-*    -- Close now waits for output to drain.
-*    -- Open waits until any close in progress is finished.
-*    -- All out of band responses are now processed, not just the
-*       first in a USB packet.
-*    -- Fixed a bug that prevented the driver from working when the
-*       first Digi port was not the first USB serial port--the driver
-*       was mistakenly using the external USB serial port number to
-*       try to index into its internal ports.
-*    -- Fixed an SMP bug -- write_bulk_callback is called directly from
-*       an interrupt, so spin_lock_irqsave/spin_unlock_irqrestore are
-*       needed for locks outside write_bulk_callback that are also
-*       acquired by write_bulk_callback to prevent deadlocks.
-*    -- Fixed support for select() by making digi_chars_in_buffer()
-*       return 256 when -EINPROGRESS is set, as the line discipline
-*       code in n_tty.c expects.
-*    -- Fixed an include file ordering problem that prevented debugging
-*       messages from working.
-*    -- Fixed an intermittent timeout problem that caused writes to
-*       sometimes get stuck on some machines on some kernels.  It turns
-*       out in these circumstances write_chan() (in n_tty.c) was
-*       asleep waiting for our wakeup call.  Even though we call
-*       wake_up_interruptible() in digi_write_bulk_callback(), there is
-*       a race condition that could cause the wakeup to fail: if our
-*       wake_up_interruptible() call occurs between the time that our
-*       driver write routine finishes and write_chan() sets current->state
-*       to TASK_INTERRUPTIBLE, the effect of our wakeup setting the state
-*       to TASK_RUNNING will be lost and write_chan's subsequent call to
-*       schedule() will never return (unless it catches a signal).
-*       This race condition occurs because write_bulk_callback() (and thus
-*       the wakeup) are called asynchronously from an interrupt, rather than
-*       from the scheduler.  We can avoid the race by calling the wakeup
-*       from the scheduler queue and that's our fix:  Now, at the end of
-*       write_bulk_callback() we queue up a wakeup call on the scheduler
-*       task queue.  We still also invoke the wakeup directly since that
-*       squeezes a bit more performance out of the driver, and any lost
-*       race conditions will get cleaned up at the next scheduler run.
-*
-*       NOTE:  The problem also goes away if you comment out
-*       the two code lines in write_chan() where current->state
-*       is set to TASK_RUNNING just before calling driver.write() and to
-*       TASK_INTERRUPTIBLE immediately afterwards.  This is why the
-*       problem did not show up with the 2.2 kernels -- they do not
-*       include that code.
-*
-*  (5/16/2000) pberger and borchers
-*    -- Added timeouts to sleeps, to defend against lost wake ups.
-*    -- Handle transition to/from B0 baud rate in digi_set_termios.
-*
-*  (5/13/2000) pberger and borchers
-*    -- All commands now sent on out of band port, using
-*       digi_write_oob_command.
-*    -- Get modem control signals whenever they change, support TIOCMGET/
-*       SET/BIS/BIC ioctls.
-*    -- digi_set_termios now supports parity, word size, stop bits, and
-*       receive enable.
-*    -- Cleaned up open and close, use digi_set_termios and
-*       digi_write_oob_command to set port parameters.
-*    -- Added digi_startup_device to start read chains on all ports.
-*    -- Write buffer is only used when count==1, to be sure put_char can
-*       write a char (unless the buffer is full).
-*
-*  (5/10/2000) pberger and borchers
-*    -- Added MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT calls on open/close.
-*    -- Fixed problem where the first incoming character is lost on
-*       port opens after the first close on that port.  Now we keep
-*       the read_urb chain open until shutdown.
-*    -- Added more port conditioning calls in digi_open and digi_close.
-*    -- Convert port->active to a use count so that we can deal with multiple
-*       opens and closes properly.
-*    -- Fixed some problems with the locking code.
-*
-*  (5/3/2000) pberger and borchers
-*    -- First alpha version of the driver--many known limitations and bugs.
-*
-*
-*  Locking and SMP
-*
-*  - Each port, including the out-of-band port, has a lock used to
-*    serialize all access to the port's private structure.
-*  - The port lock is also used to serialize all writes and access to
-*    the port's URB.
-*  - The port lock is also used for the port write_wait condition
-*    variable.  Holding the port lock will prevent a wake up on the
-*    port's write_wait; this can be used with cond_wait_... to be sure
-*    the wake up is not lost in a race when dropping the lock and
-*    sleeping waiting for the wakeup.
-*  - digi_write() does not sleep, since it is sometimes called on
-*    interrupt time.
-*  - digi_write_bulk_callback() and digi_read_bulk_callback() are
-*    called directly from interrupts.  Hence spin_lock_irqsave()
-*    and spin_unlock_irqrestore() are used in the rest of the code
-*    for any locks they acquire.
-*  - digi_write_bulk_callback() gets the port lock before waking up
-*    processes sleeping on the port write_wait.  It also schedules
-*    wake ups so they happen from the scheduler, because the tty
-*    system can miss wake ups from interrupts.
-*  - All sleeps use a timeout of DIGI_RETRY_TIMEOUT before looping to
-*    recheck the condition they are sleeping on.  This is defensive,
-*    in case a wake up is lost.
-*  - Following Documentation/DocBook/kernel-locking.tmpl no spin locks
-*    are held when calling copy_to/from_user or printk.
 */
 
 #include <linux/kernel.h>
@@ -654,7 +438,6 @@ static int digi_write_oob_command(struct usb_serial_port *port,
                        len &= ~3;
                memcpy(oob_port->write_urb->transfer_buffer, buf, len);
                oob_port->write_urb->transfer_buffer_length = len;
-               oob_port->write_urb->dev = port->serial->dev;
                ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC);
                if (ret == 0) {
                        oob_priv->dp_write_urb_in_use = 1;
@@ -732,7 +515,6 @@ static int digi_write_inb_command(struct usb_serial_port *port,
                        memcpy(data, buf, len);
                        port->write_urb->transfer_buffer_length = len;
                }
-               port->write_urb->dev = port->serial->dev;
 
                ret = usb_submit_urb(port->write_urb, GFP_ATOMIC);
                if (ret == 0) {
@@ -803,7 +585,6 @@ static int digi_set_modem_signals(struct usb_serial_port *port,
        data[7] = 0;
 
        oob_port->write_urb->transfer_buffer_length = 8;
-       oob_port->write_urb->dev = port->serial->dev;
 
        ret = usb_submit_urb(oob_port->write_urb, GFP_ATOMIC);
        if (ret == 0) {
@@ -899,10 +680,8 @@ static void digi_rx_unthrottle(struct tty_struct *tty)
        spin_lock_irqsave(&priv->dp_port_lock, flags);
 
        /* restart read chain */
-       if (priv->dp_throttle_restart) {
-               port->read_urb->dev = port->serial->dev;
+       if (priv->dp_throttle_restart)
                ret = usb_submit_urb(port->read_urb, GFP_ATOMIC);
-       }
 
        /* turn throttle off */
        priv->dp_throttled = 0;
@@ -1195,7 +974,6 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
        }
 
        port->write_urb->transfer_buffer_length = data_len+2;
-       port->write_urb->dev = port->serial->dev;
 
        *data++ = DIGI_CMD_SEND_DATA;
        *data++ = data_len;
@@ -1271,7 +1049,6 @@ static void digi_write_bulk_callback(struct urb *urb)
                        = (unsigned char)priv->dp_out_buf_len;
                port->write_urb->transfer_buffer_length =
                                                priv->dp_out_buf_len + 2;
-               port->write_urb->dev = serial->dev;
                memcpy(port->write_urb->transfer_buffer + 2, priv->dp_out_buf,
                        priv->dp_out_buf_len);
                ret = usb_submit_urb(port->write_urb, GFP_ATOMIC);
@@ -1473,7 +1250,6 @@ static int digi_startup_device(struct usb_serial *serial)
        /* set USB_DISABLE_SPD flag for write bulk urbs */
        for (i = 0; i < serial->type->num_ports + 1; i++) {
                port = serial->port[i];
-               port->write_urb->dev = port->serial->dev;
                ret = usb_submit_urb(port->read_urb, GFP_KERNEL);
                if (ret != 0) {
                        dev_err(&port->dev,
@@ -1616,7 +1392,6 @@ 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 && ret != -EPERM) {
                dev_err(&port->dev,
index ff3db5d..c290df9 100644 (file)
@@ -2105,6 +2105,9 @@ static void ftdi_set_termios(struct tty_struct *tty,
 
        cflag = termios->c_cflag;
 
+       if (old_termios == 0)
+               goto no_skip;
+
        if (old_termios->c_cflag == termios->c_cflag
            && old_termios->c_ispeed == termios->c_ispeed
            && old_termios->c_ospeed == termios->c_ospeed)
@@ -2118,6 +2121,7 @@ static void ftdi_set_termios(struct tty_struct *tty,
            (termios->c_cflag & (CSIZE|PARODD|PARENB|CMSPAR|CSTOPB)))
                goto no_data_parity_stop_changes;
 
+no_skip:
        /* Set number of data bits, parity, stop bits */
 
        urb_value = 0;
index 1a49ca9..bf12565 100644 (file)
@@ -901,7 +901,6 @@ static int garmin_init_session(struct usb_serial_port *port)
                usb_kill_urb(port->interrupt_in_urb);
 
                dbg("%s - adding interrupt input", __func__);
-               port->interrupt_in_urb->dev = serial->dev;
                status = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
                if (status)
                        dev_err(&serial->dev->dev,
@@ -1277,7 +1276,6 @@ static void garmin_read_int_callback(struct urb *urb)
        unsigned long flags;
        int retval;
        struct usb_serial_port *port = urb->context;
-       struct usb_serial *serial = port->serial;
        struct garmin_data *garmin_data_p = usb_get_serial_port_data(port);
        unsigned char *data = urb->transfer_buffer;
        int status = urb->status;
@@ -1311,12 +1309,6 @@ static void garmin_read_int_callback(struct urb *urb)
                if (0 == (garmin_data_p->flags & FLAGS_BULK_IN_ACTIVE)) {
 
                        /* bulk data available */
-                       usb_fill_bulk_urb(port->read_urb, serial->dev,
-                                       usb_rcvbulkpipe(serial->dev,
-                                               port->bulk_in_endpointAddress),
-                                       port->read_urb->transfer_buffer,
-                                       port->read_urb->transfer_buffer_length,
-                                       garmin_read_bulk_callback, port);
                        retval = usb_submit_urb(port->read_urb, GFP_ATOMIC);
                        if (retval) {
                                dev_err(&port->dev,
@@ -1353,7 +1345,6 @@ static void garmin_read_int_callback(struct urb *urb)
 
        garmin_read_process(garmin_data_p, data, urb->actual_length, 0);
 
-       port->interrupt_in_urb->dev = port->serial->dev;
        retval = usb_submit_urb(urb, GFP_ATOMIC);
        if (retval)
                dev_err(&urb->dev->dev,
index e4db5ad..f740357 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * USB Serial Converter Generic functions
  *
- * Copyright (C) 2010 Johan Hovold (jhovold@gmail.com)
+ * Copyright (C) 2010 - 2011 Johan Hovold (jhovold@gmail.com)
  * Copyright (C) 1999 - 2002 Greg Kroah-Hartman (greg@kroah.com)
  *
  *     This program is free software; you can redistribute it and/or
@@ -132,7 +132,7 @@ int usb_serial_generic_open(struct tty_struct *tty, struct usb_serial_port *port
 
        /* if we have a bulk endpoint, start reading from it */
        if (port->bulk_in_size)
-               result = usb_serial_generic_submit_read_urb(port, GFP_KERNEL);
+               result = usb_serial_generic_submit_read_urbs(port, GFP_KERNEL);
 
        return result;
 }
@@ -157,8 +157,10 @@ static void generic_cleanup(struct usb_serial_port *port)
                        kfifo_reset_out(&port->write_fifo);
                        spin_unlock_irqrestore(&port->lock, flags);
                }
-               if (port->bulk_in_size)
-                       usb_kill_urb(port->read_urb);
+               if (port->bulk_in_size) {
+                       for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
+                               usb_kill_urb(port->read_urbs[i]);
+               }
        }
 }
 
@@ -308,19 +310,52 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty)
        return chars;
 }
 
-int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
+static int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
+                                               int index, gfp_t mem_flags)
+{
+       int res;
+
+       if (!test_and_clear_bit(index, &port->read_urbs_free))
+               return 0;
+
+       dbg("%s - port %d, urb %d\n", __func__, port->number, index);
+
+       res = usb_submit_urb(port->read_urbs[index], mem_flags);
+       if (res) {
+               if (res != -EPERM) {
+                       dev_err(&port->dev,
+                                       "%s - usb_submit_urb failed: %d\n",
+                                       __func__, res);
+               }
+               set_bit(index, &port->read_urbs_free);
+               return res;
+       }
+
+       return 0;
+}
+
+int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port,
                                        gfp_t mem_flags)
 {
-       int result;
+       int res;
+       int i;
 
-       result = usb_submit_urb(port->read_urb, mem_flags);
-       if (result && result != -EPERM) {
-               dev_err(&port->dev, "%s - error submitting urb: %d\n",
-                                                       __func__, result);
+       dbg("%s - port %d", __func__, port->number);
+
+       for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
+               res = usb_serial_generic_submit_read_urb(port, i, mem_flags);
+               if (res)
+                       goto err;
        }
-       return result;
+
+       return 0;
+err:
+       for (; i >= 0; --i)
+               usb_kill_urb(port->read_urbs[i]);
+
+       return res;
 }
-EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urb);
+EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urbs);
 
 void usb_serial_generic_process_read_urb(struct urb *urb)
 {
@@ -356,14 +391,19 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)
 {
        struct usb_serial_port *port = urb->context;
        unsigned char *data = urb->transfer_buffer;
-       int status = urb->status;
        unsigned long flags;
+       int i;
 
-       dbg("%s - port %d", __func__, port->number);
+       for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
+               if (urb == port->read_urbs[i])
+                       break;
+       }
+       set_bit(i, &port->read_urbs_free);
 
-       if (unlikely(status != 0)) {
-               dbg("%s - nonzero read bulk status received: %d",
-                   __func__, status);
+       dbg("%s - port %d, urb %d, len %d\n", __func__, port->number, i,
+                                                       urb->actual_length);
+       if (urb->status) {
+               dbg("%s - non-zero urb status: %d\n", __func__, urb->status);
                return;
        }
 
@@ -376,7 +416,7 @@ void usb_serial_generic_read_bulk_callback(struct urb *urb)
        port->throttled = port->throttle_req;
        if (!port->throttled) {
                spin_unlock_irqrestore(&port->lock, flags);
-               usb_serial_generic_submit_read_urb(port, GFP_ATOMIC);
+               usb_serial_generic_submit_read_urb(port, i, GFP_ATOMIC);
        } else
                spin_unlock_irqrestore(&port->lock, flags);
 }
@@ -443,7 +483,7 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty)
        spin_unlock_irq(&port->lock);
 
        if (was_throttled)
-               usb_serial_generic_submit_read_urb(port, GFP_KERNEL);
+               usb_serial_generic_submit_read_urbs(port, GFP_KERNEL);
 }
 EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle);
 
@@ -509,8 +549,9 @@ int usb_serial_generic_resume(struct usb_serial *serial)
                if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags))
                        continue;
 
-               if (port->read_urb) {
-                       r = usb_submit_urb(port->read_urb, GFP_NOIO);
+               if (port->bulk_in_size) {
+                       r = usb_serial_generic_submit_read_urbs(port,
+                                                               GFP_NOIO);
                        if (r < 0)
                                c++;
                }
index 2ee8075..abd2ee2 100644 (file)
@@ -610,7 +610,6 @@ static void edge_interrupt_callback(struct urb *urb)
 
                                        /* we have pending bytes on the
                                           bulk in pipe, send a request */
-                                       edge_serial->read_urb->dev = edge_serial->serial->dev;
                                        result = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
                                        if (result) {
                                                dev_err(&edge_serial->serial->dev->dev, "%s - usb_submit_urb(read bulk) failed with result = %d\n", __func__, result);
@@ -711,7 +710,6 @@ static void edge_bulk_in_callback(struct urb *urb)
        /* check to see if there's any more data for us to read */
        if (edge_serial->rxBytesAvail > 0) {
                dbg("%s - posting a read", __func__);
-               edge_serial->read_urb->dev = edge_serial->serial->dev;
                retval = usb_submit_urb(edge_serial->read_urb, GFP_ATOMIC);
                if (retval) {
                        dev_err(&urb->dev->dev,
@@ -1330,7 +1328,6 @@ static void send_more_port_data(struct edgeport_serial *edge_serial,
        edge_port->txCredits -= count;
        edge_port->icount.tx += count;
 
-       urb->dev = edge_serial->serial->dev;
        status = usb_submit_urb(urb, GFP_ATOMIC);
        if (status) {
                /* something went wrong */
index 0aac00a..e44d375 100644 (file)
  * For questions or problems with this driver, contact Inside Out
  * Networks technical support, or Peter Berger <pberger@brimson.com>,
  * or Al Borchers <alborchers@steinerpoint.com>.
- *
- * Version history:
- *
- *     July 11, 2002   Removed 4 port device structure since all TI UMP
- *                     chips have only 2 ports
- *                     David Iacovelli (davidi@ionetworks.com)
- *
  */
 
 #include <linux/kernel.h>
@@ -1777,12 +1770,11 @@ static void edge_bulk_in_callback(struct urb *urb)
 exit:
        /* continue read unless stopped */
        spin_lock(&edge_port->ep_lock);
-       if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING) {
-               urb->dev = edge_port->port->serial->dev;
+       if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING)
                retval = usb_submit_urb(urb, GFP_ATOMIC);
-       } else if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPING) {
+       else if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPING)
                edge_port->ep_read_urb_state = EDGE_READ_URB_STOPPED;
-       }
+
        spin_unlock(&edge_port->ep_lock);
        if (retval)
                dev_err(&urb->dev->dev,
@@ -1959,9 +1951,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
                        status = -EINVAL;
                        goto release_es_lock;
                }
-               urb->complete = edge_interrupt_callback;
                urb->context = edge_serial;
-               urb->dev = dev;
                status = usb_submit_urb(urb, GFP_KERNEL);
                if (status) {
                        dev_err(&port->dev,
@@ -1987,9 +1977,7 @@ static int edge_open(struct tty_struct *tty, struct usb_serial_port *port)
                goto unlink_int_urb;
        }
        edge_port->ep_read_urb_state = EDGE_READ_URB_RUNNING;
-       urb->complete = edge_bulk_in_callback;
        urb->context = edge_port;
-       urb->dev = dev;
        status = usb_submit_urb(urb, GFP_KERNEL);
        if (status) {
                dev_err(&port->dev,
@@ -2118,12 +2106,7 @@ static void edge_send(struct tty_struct *tty)
                                port->write_urb->transfer_buffer);
 
        /* set up our urb */
-       usb_fill_bulk_urb(port->write_urb, port->serial->dev,
-                          usb_sndbulkpipe(port->serial->dev,
-                                           port->bulk_out_endpointAddress),
-                          port->write_urb->transfer_buffer, count,
-                          edge_bulk_out_callback,
-                          port);
+       port->write_urb->transfer_buffer_length = count;
 
        /* send the data out the bulk port */
        result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
@@ -2267,9 +2250,6 @@ static int restart_read(struct edgeport_port *edge_port)
 
        if (edge_port->ep_read_urb_state == EDGE_READ_URB_STOPPED) {
                urb = edge_port->port->read_urb;
-               urb->complete = edge_bulk_in_callback;
-               urb->context = edge_port;
-               urb->dev = edge_port->port->serial->dev;
                status = usb_submit_urb(urb, GFP_ATOMIC);
        }
        edge_port->ep_read_urb_state = EDGE_READ_URB_RUNNING;
index 4735931..36f5cbe 100644 (file)
@@ -8,40 +8,6 @@
  *     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.
- *
- * (12/12/2002) ganesh
- *     Added support for practically all devices supported by ActiveSync
- *     on Windows. Thanks to Wes Cilldhaire <billybobjoehenrybob@hotmail.com>.
- *
- * (26/11/2002) ganesh
- *     Added insmod options to specify product and vendor id.
- *     Use modprobe ipaq vendor=0xfoo product=0xbar
- *
- * (26/7/2002) ganesh
- *     Fixed up broken error handling in ipaq_open. Retry the "kickstart"
- *     packet much harder - this drastically reduces connection failures.
- *
- * (30/4/2002) ganesh
- *     Added support for the Casio EM500. Completely untested. Thanks
- *     to info from Nathan <wfilardo@fuse.net>
- *
- * (19/3/2002) ganesh
- *     Don't submit urbs while holding spinlocks. Not strictly necessary
- *     in 2.5.x.
- *
- * (8/3/2002) ganesh
- *     The ipaq sometimes emits a '\0' before the CLIENT string. At this
- *     point of time, the ppp ldisc is not yet attached to the tty, so
- *     n_tty echoes "^ " to the ipaq, which messes up the chat. In 2.5.6-pre2
- *     this causes a panic because echo_char() tries to sleep in interrupt
- *     context.
- *     The fix is to tell the upper layers that this is a raw device so that
- *     echoing is suppressed. Thanks to Lyle Lindholm for a detailed bug
- *     report.
- *
- * (25/2/2002) ganesh
- *     Added support for the HP Jornada 548 and 568. Completely untested.
- *     Thanks to info from Heath Robinson and Arieh Davidoff.
  */
 
 #include <linux/kernel.h>
index ccbce40..0c537da 100644 (file)
  *
  * See Documentation/usb/usb-serial.txt for more information on using this
  * driver
- *
- * 2008_Jun_02  Felipe Balbi <me@felipebalbi.com>
- *     Introduced common header to be used also in USB Gadget Framework.
- *     Still needs some other style fixes.
- *
- * 2007_Jun_21  Alan Cox <alan@lxorguk.ukuu.org.uk>
- *     Minimal cleanups for some of the driver problens and tty layer abuse.
- *     Still needs fixing to allow multiple dongles.
- *
- * 2002_Mar_07 greg kh
- *     moved some needed structures and #define values from the
- *     net/irda/irda-usb.h file into our file, as we don't want to depend on
- *     that codebase compiling correctly :)
- *
- * 2002_Jan_14  gb
- *     Added module parameter to force specific number of XBOFs.
- *     Added ir_xbof_change().
- *     Reorganized read_bulk_callback error handling.
- *     Switched from FILL_BULK_URB() to usb_fill_bulk_urb().
- *
- * 2001_Nov_08  greg kh
- *     Changed the irda_usb_find_class_desc() function based on comments and
- *     code from Martin Diehl.
- *
- * 2001_Nov_01 greg kh
- *     Added support for more IrDA USB devices.
- *     Added support for zero packet.  Added buffer override paramater, so
- *     users can transfer larger packets at once if they wish.  Both patches
- *     came from Dag Brattli <dag@obexcode.com>.
- *
- * 2001_Oct_07 greg kh
- *     initial version released.
  */
 
 #include <linux/kernel.h>
index 6aca631..64d0ffd 100644 (file)
@@ -1168,15 +1168,14 @@ static int iuu_open(struct tty_struct *tty, struct usb_serial_port *port)
                          port->write_urb->transfer_buffer, 1,
                          read_rxcmd_callback, port);
        result = usb_submit_urb(port->write_urb, GFP_KERNEL);
-
        if (result) {
                dev_err(&port->dev, "%s - failed submitting read urb,"
                        " error %d\n", __func__, result);
                iuu_close(port);
-               return -EPROTO;
        } else {
                dbg("%s - rxcmd OK", __func__);
        }
+
        return result;
 }
 
index a442352..bc8dc20 100644 (file)
 
   Tip 'o the hat to IBM (and previously Linuxcare :) for supporting
   staff in their work on open source projects.
-
-  Change History
-
-    2003sep04  LPM (Keyspan) add support for new single port product USA19HS.
-                               Improve setup message handling for all devices.
-
-    Wed Feb 19 22:00:00 PST 2003 (Jeffrey S. Laing <keyspan@jsl.com>)
-      Merged the current (1/31/03) Keyspan code with the current (2.4.21-pre4)
-      Linux source tree.  The Linux tree lacked support for the 49WLC and
-      others.  The Keyspan patches didn't work with the current kernel.
-
-    2003jan30  LPM     add support for the 49WLC and MPR
-
-    Wed Apr 25 12:00:00 PST 2002 (Keyspan)
-      Started with Hugh Blemings' code dated Jan 17, 2002.  All adapters
-      now supported (including QI and QW).  Modified port open, port
-      close, and send setup() logic to fix various data and endpoint
-      synchronization bugs and device LED status bugs.  Changed keyspan_
-      write_room() to accurately return transmit buffer availability.
-      Changed forwardingLength from 1 to 16 for all adapters.
-
-    Fri Oct 12 16:45:00 EST 2001
-      Preliminary USA-19QI and USA-28 support (both test OK for me, YMMV)
-
-    Wed Apr 25 12:00:00 PST 2002 (Keyspan)
-      Started with Hugh Blemings' code dated Jan 17, 2002.  All adapters
-      now supported (including QI and QW).  Modified port open, port
-      close, and send setup() logic to fix various data and endpoint
-      synchronization bugs and device LED status bugs.  Changed keyspan_
-      write_room() to accurately return transmit buffer availability.
-      Changed forwardingLength from 1 to 16 for all adapters.
-
-    Fri Oct 12 16:45:00 EST 2001
-      Preliminary USA-19QI and USA-28 support (both test OK for me, YMMV)
-
-    Mon Oct  8 14:29:00 EST 2001 hugh
-      Fixed bug that prevented mulitport devices operating correctly
-      if they weren't the first unit attached.
-
-    Sat Oct  6 12:31:21 EST 2001 hugh
-      Added support for USA-28XA and -28XB, misc cleanups, break support
-      for usa26 based models thanks to David Gibson.
-
-    Thu May 31 11:56:42 PDT 2001 gkh
-      switched from using spinlock to a semaphore
-
-    (04/08/2001) gb
-       Identify version on module load.
-
-    (11/01/2000) Adam J. Richter
-       usb_device_id table support.
-
-    Tue Oct 10 23:15:33 EST 2000 Hugh
-      Merged Paul's changes with my USA-49W mods.  Work in progress
-      still...
-
-    Wed Jul 19 14:00:42 EST 2000 gkh
-      Added module_init and module_exit functions to handle the fact that
-      this driver is a loadable module now.
-
-    Tue Jul 18 16:14:52 EST 2000 Hugh
-      Basic character input/output for USA-19 now mostly works,
-      fixed at 9600 baud for the moment.
-
-    Sat Jul  8 11:11:48 EST 2000 Hugh
-      First public release - nothing works except the firmware upload.
-      Tested on PPC and x86 architectures, seems to behave...
 */
 
 
@@ -397,7 +330,6 @@ static int keyspan_write(struct tty_struct *tty,
                /* send the data out the bulk port */
                this_urb->transfer_buffer_length = todo + dataOffset;
 
-               this_urb->dev = port->serial->dev;
                err = usb_submit_urb(this_urb, GFP_ATOMIC);
                if (err != 0)
                        dbg("usb_submit_urb(write bulk) failed (%d)", err);
@@ -463,7 +395,6 @@ static void usa26_indat_callback(struct urb *urb)
        tty_kref_put(tty);
 
        /* Resubmit urb so we continue receiving */
-       urb->dev = port->serial->dev;
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err != 0)
                dbg("%s - resubmit read urb failed. (%d)", __func__, err);
@@ -559,7 +490,6 @@ static void usa26_instat_callback(struct urb *urb)
        }
 
        /* Resubmit urb so we continue receiving */
-       urb->dev = serial->dev;
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err != 0)
                dbg("%s - resubmit read urb failed. (%d)", __func__, err);
@@ -609,7 +539,6 @@ static void usa28_indat_callback(struct urb *urb)
                tty_kref_put(tty);
 
                /* Resubmit urb so we continue receiving */
-               urb->dev = port->serial->dev;
                err = usb_submit_urb(urb, GFP_ATOMIC);
                if (err != 0)
                        dbg("%s - resubmit read urb failed. (%d)",
@@ -694,7 +623,6 @@ static void usa28_instat_callback(struct urb *urb)
        }
 
                /* Resubmit urb so we continue receiving */
-       urb->dev = serial->dev;
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err != 0)
                dbg("%s - resubmit read urb failed. (%d)", __func__, err);
@@ -789,8 +717,6 @@ static void usa49_instat_callback(struct urb *urb)
        }
 
        /* Resubmit urb so we continue receiving */
-       urb->dev = serial->dev;
-
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err != 0)
                dbg("%s - resubmit read urb failed. (%d)", __func__, err);
@@ -848,7 +774,6 @@ static void usa49_indat_callback(struct urb *urb)
        tty_kref_put(tty);
 
        /* Resubmit urb so we continue receiving */
-       urb->dev = port->serial->dev;
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err != 0)
                dbg("%s - resubmit read urb failed. (%d)", __func__, err);
@@ -919,8 +844,6 @@ static void usa49wg_indat_callback(struct urb *urb)
        }
 
        /* Resubmit urb so we continue receiving */
-       urb->dev = serial->dev;
-
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err != 0)
                dbg("%s - resubmit read urb failed. (%d)", __func__, err);
@@ -996,7 +919,6 @@ static void usa90_indat_callback(struct urb *urb)
        }
 
        /* Resubmit urb so we continue receiving */
-       urb->dev = port->serial->dev;
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err != 0)
                dbg("%s - resubmit read urb failed. (%d)", __func__, err);
@@ -1047,7 +969,6 @@ static void        usa90_instat_callback(struct urb *urb)
        }
 
        /* Resubmit urb so we continue receiving */
-       urb->dev = serial->dev;
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err != 0)
                dbg("%s - resubmit read urb failed. (%d)", __func__, err);
@@ -1123,7 +1044,6 @@ static void       usa67_instat_callback(struct urb *urb)
        }
 
        /* Resubmit urb so we continue receiving */
-       urb->dev = serial->dev;
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err != 0)
                dbg("%s - resubmit read urb failed. (%d)", __func__, err);
@@ -1223,7 +1143,6 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
                urb = p_priv->in_urbs[i];
                if (urb == NULL)
                        continue;
-               urb->dev = serial->dev;
 
                /* make sure endpoint data toggle is synchronized
                   with the device */
@@ -1239,7 +1158,6 @@ static int keyspan_open(struct tty_struct *tty, struct usb_serial_port *port)
                urb = p_priv->out_urbs[i];
                if (urb == NULL)
                        continue;
-               urb->dev = serial->dev;
                /* usb_settoggle(urb->dev, usb_pipeendpoint(urb->pipe),
                                                usb_pipeout(urb->pipe), 0); */
        }
@@ -1956,7 +1874,6 @@ static int keyspan_usa26_send_setup(struct usb_serial *serial,
        /* send the data out the device on control endpoint */
        this_urb->transfer_buffer_length = sizeof(msg);
 
-       this_urb->dev = serial->dev;
        err = usb_submit_urb(this_urb, GFP_ATOMIC);
        if (err != 0)
                dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err);
@@ -2084,7 +2001,6 @@ static int keyspan_usa28_send_setup(struct usb_serial *serial,
        /* send the data out the device on control endpoint */
        this_urb->transfer_buffer_length = sizeof(msg);
 
-       this_urb->dev = serial->dev;
        err = usb_submit_urb(this_urb, GFP_ATOMIC);
        if (err != 0)
                dbg("%s - usb_submit_urb(setup) failed", __func__);
@@ -2271,8 +2187,6 @@ static int keyspan_usa49_send_setup(struct usb_serial *serial,
 
                /* send the data out the device on control endpoint */
                this_urb->transfer_buffer_length = sizeof(msg);
-
-               this_urb->dev = serial->dev;
        }
        err = usb_submit_urb(this_urb, GFP_ATOMIC);
        if (err != 0)
@@ -2415,7 +2329,6 @@ static int keyspan_usa90_send_setup(struct usb_serial *serial,
        /* send the data out the device on control endpoint */
        this_urb->transfer_buffer_length = sizeof(msg);
 
-       this_urb->dev = serial->dev;
        err = usb_submit_urb(this_urb, GFP_ATOMIC);
        if (err != 0)
                dbg("%s - usb_submit_urb(setup) failed (%d)", __func__, err);
@@ -2561,7 +2474,6 @@ static int keyspan_usa67_send_setup(struct usb_serial *serial,
 
        /* send the data out the device on control endpoint */
        this_urb->transfer_buffer_length = sizeof(msg);
-       this_urb->dev = serial->dev;
 
        err = usb_submit_urb(this_urb, GFP_ATOMIC);
        if (err != 0)
@@ -2650,14 +2562,12 @@ static int keyspan_startup(struct usb_serial *serial)
        keyspan_setup_urbs(serial);
 
        if (s_priv->instat_urb != NULL) {
-               s_priv->instat_urb->dev = serial->dev;
                err = usb_submit_urb(s_priv->instat_urb, GFP_KERNEL);
                if (err != 0)
                        dbg("%s - submit instat urb failed %d", __func__,
                                err);
        }
        if (s_priv->indat_urb != NULL) {
-               s_priv->indat_urb->dev = serial->dev;
                err = usb_submit_urb(s_priv->indat_urb, GFP_KERNEL);
                if (err != 0)
                        dbg("%s - submit indat urb failed %d", __func__,
index d5c0c6a..a406156 100644 (file)
  *
  * See Documentation/usb/usb-serial.txt for more information on using this
  * driver
- *
- * (09/07/2001) gkh
- *     cleaned up the Xircom support.  Added ids for Entregra device which is
- *     the same as the Xircom device.  Enabled the code to be compiled for
- *     either Xircom or Keyspan devices.
- *
- * (08/11/2001) Cristian M. Craciunescu
- *     support for Xircom PGSDB9
- *
- * (05/31/2001) gkh
- *     switched from using spinlock to a semaphore, which fixes lots of
- *     problems.
- *
- * (04/08/2001) gb
- *     Identify version on module load.
- *
- * (11/01/2000) Adam J. Richter
- *     usb_device_id table support
- *
- * (10/05/2000) gkh
- *     Fixed bug with urb->dev not being set properly, now that the usb
- *     core needs it.
- *
- * (08/28/2000) gkh
- *     Added locks for SMP safeness.
- *     Fixed MOD_INC and MOD_DEC logic and the ability to open a port more
- *     than once.
- *
- * (07/20/2000) borchers
- *     - keyspan_pda_write no longer sleeps if it is called on interrupt time;
- *       PPP and the line discipline with stty echo on can call write on
- *       interrupt time and this would cause an oops if write slept
- *     - if keyspan_pda_write is in an interrupt, it will not call
- *       usb_control_msg (which sleeps) to query the room in the device
- *       buffer, it simply uses the current room value it has
- *     - if the urb is busy or if it is throttled keyspan_pda_write just
- *       returns 0, rather than sleeping to wait for this to change; the
- *       write_chan code in n_tty.c will sleep if needed before calling
- *       keyspan_pda_write again
- *     - if the device needs to be unthrottled, write now queues up the
- *       call to usb_control_msg (which sleeps) to unthrottle the device
- *     - the wakeups from keyspan_pda_write_bulk_callback are queued rather
- *       than done directly from the callback to avoid the race in write_chan
- *     - keyspan_pda_chars_in_buffer also indicates its buffer is full if the
- *       urb status is -EINPROGRESS, meaning it cannot write at the moment
- *
- * (07/19/2000) gkh
- *     Added module_init and module_exit functions to handle the fact that this
- *     driver is a loadable module now.
- *
- * (03/26/2000) gkh
- *     Split driver up into device specific pieces.
- *
  */
 
 
@@ -290,7 +237,6 @@ static void keyspan_pda_rx_unthrottle(struct tty_struct *tty)
        struct usb_serial_port *port = tty->driver_data;
        /* just restart the receive interrupt URB */
        dbg("keyspan_pda_rx_unthrottle port %d", port->number);
-       port->interrupt_in_urb->dev = port->serial->dev;
        if (usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL))
                dbg(" usb_submit_urb(read urb) failed");
 }
@@ -532,11 +478,11 @@ static int keyspan_pda_write(struct tty_struct *tty,
           the device is full (wait until it says there is room)
        */
        spin_lock_bh(&port->lock);
-       if (port->write_urb_busy || priv->tx_throttled) {
+       if (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled) {
                spin_unlock_bh(&port->lock);
                return 0;
        }
-       port->write_urb_busy = 1;
+       clear_bit(0, &port->write_urbs_free);
        spin_unlock_bh(&port->lock);
 
        /* At this point the URB is in our control, nobody else can submit it
@@ -598,7 +544,6 @@ static int keyspan_pda_write(struct tty_struct *tty,
 
                priv->tx_room -= count;
 
-               port->write_urb->dev = port->serial->dev;
                rc = usb_submit_urb(port->write_urb, GFP_ATOMIC);
                if (rc) {
                        dbg(" usb_submit_urb(write bulk) failed");
@@ -618,7 +563,7 @@ static int keyspan_pda_write(struct tty_struct *tty,
        rc = count;
 exit:
        if (rc < 0)
-               port->write_urb_busy = 0;
+               set_bit(0, &port->write_urbs_free);
        return rc;
 }
 
@@ -628,7 +573,7 @@ static void keyspan_pda_write_bulk_callback(struct urb *urb)
        struct usb_serial_port *port = urb->context;
        struct keyspan_pda_private *priv;
 
-       port->write_urb_busy = 0;
+       set_bit(0, &port->write_urbs_free);
        priv = usb_get_serial_port_data(port);
 
        /* queue up a wakeup at scheduler time */
@@ -661,7 +606,7 @@ static int keyspan_pda_chars_in_buffer(struct tty_struct *tty)
           n_tty.c:normal_poll() ) that we're not writeable. */
 
        spin_lock_irqsave(&port->lock, flags);
-       if (port->write_urb_busy || priv->tx_throttled)
+       if (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled)
                ret = 256;
        spin_unlock_irqrestore(&port->lock, flags);
        return ret;
@@ -717,7 +662,6 @@ static int keyspan_pda_open(struct tty_struct *tty,
        priv->tx_throttled = *room ? 0 : 1;
 
        /*Start reading from the device*/
-       port->interrupt_in_urb->dev = serial->dev;
        rc = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
        if (rc) {
                dbg("%s - usb_submit_urb(read int) failed", __func__);
index ddd1463..5d3beee 100644 (file)
  *
  * Supported readers: USB TWIN, KAAN Standard Plus and SecOVID Reader Plus
  * (Adapter K), B1 Professional and KAAN Professional (Adapter B)
- *
- * (21/05/2004) tw
- *      Fix bug with P'n'P readers
- *
- * (28/05/2003) tw
- *      Add support for KAAN SIM
- *
- * (12/09/2002) tw
- *      Adapted to 2.5.
- *
- * (11/08/2002) tw
- *      Initial version.
  */
 
 
@@ -231,9 +219,6 @@ static int kobil_open(struct tty_struct *tty, struct usb_serial_port *port)
        dbg("%s - port %d", __func__, port->number);
        priv = usb_get_serial_port_data(port);
 
-       /* someone sets the dev to 0 if the close method has been called */
-       port->interrupt_in_urb->dev = port->serial->dev;
-
        /* allocate memory for transfer buffer */
        transfer_buffer = kzalloc(transfer_buffer_length, GFP_KERNEL);
        if (!transfer_buffer)
@@ -393,8 +378,6 @@ static void kobil_read_int_callback(struct urb *urb)
                tty_flip_buffer_push(tty);
        }
        tty_kref_put(tty);
-       /* someone sets the dev to 0 if the close method has been called */
-       port->interrupt_in_urb->dev = port->serial->dev;
 
        result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
        dbg("%s - port %d Send read URB returns: %i",
@@ -475,17 +458,9 @@ static int kobil_write(struct tty_struct *tty, struct usb_serial_port *port,
                priv->filled = 0;
                priv->cur_pos = 0;
 
-               /* someone sets the dev to 0 if the close method
-                  has been called */
-               port->interrupt_in_urb->dev = port->serial->dev;
-
                /* start reading (except TWIN and KAAN SIM) */
                if (priv->device_type == KOBIL_ADAPTER_B_PRODUCT_ID ||
                        priv->device_type == KOBIL_ADAPTER_K_PRODUCT_ID) {
-                       /* someone sets the dev to 0 if the close method has
-                          been called */
-                       port->interrupt_in_urb->dev = port->serial->dev;
-
                        result = usb_submit_urb(port->interrupt_in_urb,
                                                                GFP_NOIO);
                        dbg("%s - port %d Send read URB returns: %i",
index ba0d287..a975bb8 100644 (file)
  *   DTR/RTS signal handling may be incomplete or incorrect. I have mainly
  *   implemented what I have seen with SniffUSB or found in belkin_sa.c.
  *   For further TODOs check also belkin_sa.c.
- *
- * TEST STATUS:
- *   Basic tests have been performed with minicom/zmodem transfers and
- *   modem dialing under Linux 2.4.0-test10 (for me it works fine).
- *
- * 04-Nov-2003 Bill Marr <marr at flex dot com>
- *   - Mimic Windows driver by sending 2 USB 'device request' messages
- *     following normal 'baud rate change' message.  This allows data to be
- *     transmitted to RS-232 devices which don't assert the 'CTS' signal.
- *
- * 10-Nov-2001 Wolfgang Grandegger
- *   - Fixed an endianess problem with the baudrate selection for PowerPC.
- *
- * 06-Dec-2001 Martin Hamilton <martinh@gnu.org>
- *   - Added support for the Belkin F5U109 DB9 adaptor
- *
- * 30-May-2001 Greg Kroah-Hartman
- *   - switched from using spinlock to a semaphore, which fixes lots of
- *     problems.
- *
- * 04-May-2001 Stelian Pop
- *   - Set the maximum bulk output size for Sitecom U232-P25 model to 16 bytes
- *     instead of the device reported 32 (using 32 bytes causes many data
- *     loss, Windows driver uses 16 too).
- *
- * 02-May-2001 Stelian Pop
- *   - Fixed the baud calculation for Sitecom U232-P25 model
- *
- * 08-Apr-2001 gb
- *   - Identify version on module load.
- *
- * 06-Jan-2001 Cornel Ciocirlan
- *   - Added support for Sitecom U232-P25 model (Product Id 0x0230)
- *   - Added support for D-Link DU-H3SP USB BAY (Product Id 0x0200)
- *
- * 29-Nov-2000 Greg Kroah-Hartman
- *   - Added device id table to fit with 2.4.0-test11 structure.
- *   - took out DEAL_WITH_TWO_INT_IN_ENDPOINTS #define as it's not needed
- *     (lots of things will change if/when the usb-serial core changes to
- *     handle these issues.
- *
- * 27-Nov-2000 Wolfgang Grandegge
- *   A version for kernel 2.4.0-test10 released to the Linux community
- *   (via linux-usb-devel).
  */
 
 #include <linux/kernel.h>
@@ -526,7 +482,6 @@ static int  mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port)
        mct_u232_msr_to_state(&priv->control_state, priv->last_msr);
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       port->read_urb->dev = port->serial->dev;
        retval = usb_submit_urb(port->read_urb, GFP_KERNEL);
        if (retval) {
                dev_err(&port->dev,
@@ -535,7 +490,6 @@ static int  mct_u232_open(struct tty_struct *tty, struct usb_serial_port *port)
                goto error;
        }
 
-       port->interrupt_in_urb->dev = port->serial->dev;
        retval = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
        if (retval) {
                usb_kill_urb(port->read_urb);
index 3524a10..19d112f 100644 (file)
@@ -939,14 +939,7 @@ static void mos7720_bulk_in_callback(struct urb *urb)
        }
        tty_kref_put(tty);
 
-       if (!port->read_urb) {
-               dbg("URB KILLED !!!");
-               return;
-       }
-
        if (port->read_urb->status != -EINPROGRESS) {
-               port->read_urb->dev = port->serial->dev;
-
                retval = usb_submit_urb(port->read_urb, GFP_ATOMIC);
                if (retval)
                        dbg("usb_submit_urb(read bulk) failed, retval = %d",
@@ -1014,7 +1007,6 @@ static int mos77xx_calc_num_ports(struct usb_serial *serial)
 static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)
 {
        struct usb_serial *serial;
-       struct usb_serial_port *port0;
        struct urb *urb;
        struct moschip_port *mos7720_port;
        int response;
@@ -1029,8 +1021,6 @@ static int mos7720_open(struct tty_struct *tty, struct usb_serial_port *port)
        if (mos7720_port == NULL)
                return -ENODEV;
 
-       port0 = serial->port[0];
-
        usb_clear_halt(serial->dev, port->write_urb->pipe);
        usb_clear_halt(serial->dev, port->read_urb->pipe);
 
@@ -1735,8 +1725,6 @@ static void change_port_settings(struct tty_struct *tty,
        write_mos_reg(serial, port_number, IER, 0x0c);
 
        if (port->read_urb->status != -EINPROGRESS) {
-               port->read_urb->dev = serial->dev;
-
                status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
                if (status)
                        dbg("usb_submit_urb(read bulk) failed, status = %d",
@@ -1786,13 +1774,7 @@ static void mos7720_set_termios(struct tty_struct *tty,
        /* change the port settings to the new ones specified */
        change_port_settings(tty, mos7720_port, old_termios);
 
-       if (!port->read_urb) {
-               dbg("%s", "URB KILLED !!!!!");
-               return;
-       }
-
        if (port->read_urb->status != -EINPROGRESS) {
-               port->read_urb->dev = serial->dev;
                status = usb_submit_urb(port->read_urb, GFP_ATOMIC);
                if (status)
                        dbg("usb_submit_urb(read bulk) failed, status = %d",
index c72abd5..55cfd62 100644 (file)
@@ -792,8 +792,6 @@ static void mos7840_bulk_in_callback(struct urb *urb)
        }
 
 
-       mos7840_port->read_urb->dev = serial->dev;
-
        mos7840_port->read_urb_busy = true;
        retval = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
 
@@ -2058,7 +2056,6 @@ static void mos7840_change_port_settings(struct tty_struct *tty,
        mos7840_set_uart_reg(port, INTERRUPT_ENABLE_REGISTER, Data);
 
        if (mos7840_port->read_urb_busy == false) {
-               mos7840_port->read_urb->dev = serial->dev;
                mos7840_port->read_urb_busy = true;
                status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
                if (status) {
@@ -2130,7 +2127,6 @@ static void mos7840_set_termios(struct tty_struct *tty,
        }
 
        if (mos7840_port->read_urb_busy == false) {
-               mos7840_port->read_urb->dev = serial->dev;
                mos7840_port->read_urb_busy = true;
                status = usb_submit_urb(mos7840_port->read_urb, GFP_ATOMIC);
                if (status) {
index 60f38d5..45a8c55 100644 (file)
@@ -9,31 +9,6 @@
  * driver
  *
  * Please report both successes and troubles to the author at omninet@kroah.com
- *
- * (05/30/2001) gkh
- *     switched from using spinlock to a semaphore, which fixes lots of
- *     problems.
- *
- * (04/08/2001) gb
- *     Identify version on module load.
- *
- * (11/01/2000) Adam J. Richter
- *     usb_device_id table support
- *
- * (10/05/2000) gkh
- *     Fixed bug with urb->dev not being set properly, now that the usb
- *     core needs it.
- *
- * (08/28/2000) gkh
- *     Added locks for SMP safeness.
- *     Fixed MOD_INC and MOD_DEC logic and the ability to open a port more
- *     than once.
- *     Fixed potential race in omninet_write_bulk_callback
- *
- * (07/19/2000) gkh
- *     Added module_init and module_exit functions to handle the fact that this
- *     driver is a loadable module now.
- *
  */
 
 #include <linux/kernel.h>
@@ -44,7 +19,6 @@
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
 #include <linux/module.h>
-#include <linux/spinlock.h>
 #include <linux/uaccess.h>
 #include <linux/usb.h>
 #include <linux/usb/serial.h>
@@ -174,12 +148,6 @@ static int omninet_open(struct tty_struct *tty, struct usb_serial_port *port)
        tty_port_tty_set(&wport->port, tty);
 
        /* Start reading from the device */
-       usb_fill_bulk_urb(port->read_urb, serial->dev,
-                       usb_rcvbulkpipe(serial->dev,
-                               port->bulk_in_endpointAddress),
-                       port->read_urb->transfer_buffer,
-                       port->read_urb->transfer_buffer_length,
-                       omninet_read_bulk_callback, port);
        result = usb_submit_urb(port->read_urb, GFP_KERNEL);
        if (result)
                dev_err(&port->dev,
@@ -236,11 +204,6 @@ static void omninet_read_bulk_callback(struct urb *urb)
        }
 
        /* Continue trying to always read  */
-       usb_fill_bulk_urb(urb, port->serial->dev,
-                       usb_rcvbulkpipe(port->serial->dev,
-                                       port->bulk_in_endpointAddress),
-                       urb->transfer_buffer, urb->transfer_buffer_length,
-                       omninet_read_bulk_callback, port);
        result = usb_submit_urb(urb, GFP_ATOMIC);
        if (result)
                dev_err(&port->dev,
@@ -267,14 +230,10 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
                return 0;
        }
 
-       spin_lock_bh(&wport->lock);
-       if (wport->write_urb_busy) {
-               spin_unlock_bh(&wport->lock);
+       if (!test_and_clear_bit(0, &port->write_urbs_free)) {
                dbg("%s - already writing", __func__);
                return 0;
        }
-       wport->write_urb_busy = 1;
-       spin_unlock_bh(&wport->lock);
 
        count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count;
 
@@ -292,10 +251,9 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
        /* send the data out the bulk port, always 64 bytes */
        wport->write_urb->transfer_buffer_length = 64;
 
-       wport->write_urb->dev = serial->dev;
        result = usb_submit_urb(wport->write_urb, GFP_ATOMIC);
        if (result) {
-               wport->write_urb_busy = 0;
+               set_bit(0, &wport->write_urbs_free);
                dev_err(&port->dev,
                        "%s - failed submitting write urb, error %d\n",
                        __func__, result);
@@ -314,8 +272,7 @@ static int omninet_write_room(struct tty_struct *tty)
 
        int room = 0; /* Default: no room */
 
-       /* FIXME: no consistent locking for write_urb_busy */
-       if (wport->write_urb_busy)
+       if (test_bit(0, &wport->write_urbs_free))
                room = wport->bulk_out_size - OMNINET_HEADERLEN;
 
        dbg("%s - returns %d", __func__, room);
@@ -332,7 +289,7 @@ static void omninet_write_bulk_callback(struct urb *urb)
 
        dbg("%s - port %0x", __func__, port->number);
 
-       port->write_urb_busy = 0;
+       set_bit(0, &port->write_urbs_free);
        if (status) {
                dbg("%s - nonzero write bulk status received: %d",
                    __func__, status);
index c248a91..691f57a 100644 (file)
@@ -384,7 +384,6 @@ static void opticon_unthrottle(struct tty_struct *tty)
        priv->actually_throttled = false;
        spin_unlock_irqrestore(&priv->lock, flags);
 
-       priv->bulk_read_urb->dev = port->serial->dev;
        if (was_throttled) {
                result = usb_submit_urb(priv->bulk_read_urb, GFP_ATOMIC);
                if (result)
index 6dd6453..c96b6b6 100644 (file)
@@ -476,6 +476,10 @@ static void option_instat_callback(struct urb *urb);
 #define VIETTEL_VENDOR_ID                      0x2262
 #define VIETTEL_PRODUCT_VT1000                 0x0002
 
+/* ZD Incorporated */
+#define ZD_VENDOR_ID                           0x0685
+#define ZD_PRODUCT_7000                                0x7000
+
 /* some devices interfaces need special handling due to a number of reasons */
 enum option_blacklist_reason {
                OPTION_BLACKLIST_NONE = 0,
@@ -1178,6 +1182,7 @@ static const struct usb_device_id option_ids[] = {
        { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU528) },
        { USB_DEVICE(YUGA_VENDOR_ID, YUGA_PRODUCT_CLU526) },
        { USB_DEVICE_AND_INTERFACE_INFO(VIETTEL_VENDOR_ID, VIETTEL_PRODUCT_VT1000, 0xff, 0xff, 0xff) },
+       { USB_DEVICE_AND_INTERFACE_INFO(ZD_VENDOR_ID, ZD_PRODUCT_7000, 0xff, 0xff, 0xff) },
        { } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
index 4c29e6c..2161d1c 100644 (file)
@@ -264,7 +264,6 @@ static void setup_line(struct work_struct *work)
        spin_unlock_irqrestore(&priv->lock, flags);
 
        dbg("%s(): submitting interrupt urb", __func__);
-       port->interrupt_in_urb->dev = port->serial->dev;
        result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
        if (result != 0) {
                dev_err(&port->dev, "%s(): usb_submit_urb() failed"
@@ -321,7 +320,6 @@ static void send_data(struct work_struct *work)
                priv->flags.write_urb_in_use = 0;
 
                dbg("%s(): submitting interrupt urb", __func__);
-               port->interrupt_in_urb->dev = port->serial->dev;
                result = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
                if (result != 0) {
                        dev_err(&port->dev, "%s(): usb_submit_urb() failed"
@@ -334,7 +332,6 @@ static void send_data(struct work_struct *work)
                                        port->write_urb->transfer_buffer,
                                        count, &port->lock);
        port->write_urb->transfer_buffer_length = count;
-       port->write_urb->dev = port->serial->dev;
        result = usb_submit_urb(port->write_urb, GFP_NOIO);
        if (result != 0) {
                dev_err(&port->dev, "%s(): usb_submit_urb() failed"
@@ -583,13 +580,12 @@ static int oti6858_open(struct tty_struct *tty, struct usb_serial_port *port)
        kfree(buf);
 
        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 != 0) {
                dev_err(&port->dev, "%s(): usb_submit_urb() failed"
                               " with error %d\n", __func__, result);
                oti6858_close(port);
-               return -EPROTO;
+               return result;
        }
 
        /* setup termios */
@@ -837,7 +833,6 @@ static void oti6858_read_int_callback(struct urb *urb)
        if (can_recv) {
                int result;
 
-               port->read_urb->dev = port->serial->dev;
                result = usb_submit_urb(port->read_urb, GFP_ATOMIC);
                if (result != 0) {
                        priv->flags.read_urb_in_use = 0;
@@ -866,7 +861,6 @@ static void oti6858_read_int_callback(struct urb *urb)
                int result;
 
 /*             dbg("%s(): submitting interrupt urb", __func__); */
-               urb->dev = port->serial->dev;
                result = usb_submit_urb(urb, GFP_ATOMIC);
                if (result != 0) {
                        dev_err(&urb->dev->dev,
@@ -894,18 +888,6 @@ static void oti6858_read_bulk_callback(struct urb *urb)
        spin_unlock_irqrestore(&priv->lock, flags);
 
        if (status != 0) {
-               /*
-               if (status == -EPROTO) {
-                       * PL2303 mysteriously fails with -EPROTO reschedule
-                          the read *
-                       dbg("%s - caught -EPROTO, resubmitting the urb",
-                                                               __func__);
-                       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;
-               }
-               */
                dbg("%s(): unable to handle the error, exiting", __func__);
                return;
        }
@@ -918,7 +900,6 @@ static void oti6858_read_bulk_callback(struct urb *urb)
        tty_kref_put(tty);
 
        /* 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,"
@@ -955,7 +936,6 @@ static void oti6858_write_bulk_callback(struct urb *urb)
                dbg("%s(): overflow in write", __func__);
 
                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(&port->dev, "%s(): usb_submit_urb() failed,"
@@ -968,7 +948,6 @@ static void oti6858_write_bulk_callback(struct urb *urb)
        priv->flags.write_urb_in_use = 0;
 
        /* schedule the interrupt urb if we are still open */
-       port->interrupt_in_urb->dev = port->serial->dev;
        dbg("%s(): submitting interrupt urb", __func__);
        result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
        if (result != 0) {
index fc2d66f..3292956 100644 (file)
@@ -502,21 +502,20 @@ static int pl2303_open(struct tty_struct *tty, struct usb_serial_port *port)
        if (tty)
                pl2303_set_termios(tty, port, &tmp_termios);
 
-       dbg("%s - submitting read urb", __func__);
-       result = usb_serial_generic_submit_read_urb(port, GFP_KERNEL);
-       if (result) {
-               pl2303_close(port);
-               return -EPROTO;
-       }
-
        dbg("%s - submitting interrupt urb", __func__);
        result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
        if (result) {
                dev_err(&port->dev, "%s - failed submitting interrupt urb,"
                        " error %d\n", __func__, result);
-               pl2303_close(port);
-               return -EPROTO;
+               return result;
        }
+
+       result = usb_serial_generic_open(tty, port);
+       if (result) {
+               usb_kill_urb(port->interrupt_in_urb);
+               return result;
+       }
+
        port->port.drain_delay = 256;
        return 0;
 }
index b18179b..f248542 100644 (file)
@@ -681,7 +681,6 @@ static void sierra_instat_callback(struct urb *urb)
        /* Resubmit urb so we continue receiving IRQ data */
        if (status != -ESHUTDOWN && status != -ENOENT) {
                usb_mark_last_busy(serial->dev);
-               urb->dev = serial->dev;
                err = usb_submit_urb(urb, GFP_ATOMIC);
                if (err && err != -EPERM)
                        dev_err(&port->dev, "%s: resubmit intr urb "
index 7096f79..c70cc01 100644 (file)
@@ -182,7 +182,6 @@ static void symbol_unthrottle(struct tty_struct *tty)
        priv->actually_throttled = false;
        spin_unlock_irq(&priv->lock);
 
-       priv->int_urb->dev = port->serial->dev;
        if (was_throttled) {
                result = usb_submit_urb(priv->int_urb, GFP_KERNEL);
                if (result)
index ea84456..4af21f4 100644 (file)
@@ -535,9 +535,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
                        status = -EINVAL;
                        goto release_lock;
                }
-               urb->complete = ti_interrupt_callback;
                urb->context = tdev;
-               urb->dev = dev;
                status = usb_submit_urb(urb, GFP_KERNEL);
                if (status) {
                        dev_err(&port->dev,
@@ -619,9 +617,7 @@ static int ti_open(struct tty_struct *tty, struct usb_serial_port *port)
                goto unlink_int_urb;
        }
        tport->tp_read_urb_state = TI_READ_URB_RUNNING;
-       urb->complete = ti_bulk_in_callback;
        urb->context = tport;
-       urb->dev = dev;
        status = usb_submit_urb(urb, GFP_KERNEL);
        if (status) {
                dev_err(&port->dev, "%s - submit read urb failed, %d\n",
@@ -1236,12 +1232,11 @@ static void ti_bulk_in_callback(struct urb *urb)
 exit:
        /* continue to read unless stopping */
        spin_lock(&tport->tp_lock);
-       if (tport->tp_read_urb_state == TI_READ_URB_RUNNING) {
-               urb->dev = port->serial->dev;
+       if (tport->tp_read_urb_state == TI_READ_URB_RUNNING)
                retval = usb_submit_urb(urb, GFP_ATOMIC);
-       } else if (tport->tp_read_urb_state == TI_READ_URB_STOPPING) {
+       else if (tport->tp_read_urb_state == TI_READ_URB_STOPPING)
                tport->tp_read_urb_state = TI_READ_URB_STOPPED;
-       }
+
        spin_unlock(&tport->tp_lock);
        if (retval)
                dev_err(dev, "%s - resubmit read urb failed, %d\n",
@@ -1574,9 +1569,7 @@ static int ti_restart_read(struct ti_port *tport, struct tty_struct *tty)
                tport->tp_read_urb_state = TI_READ_URB_RUNNING;
                urb = tport->tp_port->read_urb;
                spin_unlock_irqrestore(&tport->tp_lock, flags);
-               urb->complete = ti_bulk_in_callback;
                urb->context = tport;
-               urb->dev = tport->tp_port->serial->dev;
                status = usb_submit_urb(urb, GFP_KERNEL);
        } else  {
                tport->tp_read_urb_state = TI_READ_URB_RUNNING;
index cc274fd..ce6c1a6 100644 (file)
@@ -50,7 +50,7 @@ static struct usb_driver usb_serial_driver = {
        .disconnect =   usb_serial_disconnect,
        .suspend =      usb_serial_suspend,
        .resume =       usb_serial_resume,
-       .no_dynamic_id =        1,
+       .no_dynamic_id =        1,
        .supports_autosuspend = 1,
 };
 
@@ -260,6 +260,10 @@ static int serial_activate(struct tty_port *tport, struct tty_struct *tty)
        else
                retval = port->serial->type->open(tty, port);
        mutex_unlock(&serial->disc_mutex);
+
+       if (retval < 0)
+               retval = usb_translate_errors(retval);
+
        return retval;
 }
 
@@ -360,7 +364,8 @@ static int serial_write(struct tty_struct *tty, const unsigned char *buf,
 
        /* pass on to the driver specific version of this function */
        retval = port->serial->type->write(tty, port, buf, count);
-
+       if (retval < 0)
+               retval = usb_translate_errors(retval);
 exit:
        return retval;
 }
@@ -562,8 +567,8 @@ static void kill_traffic(struct usb_serial_port *port)
 {
        int i;
 
-       usb_kill_urb(port->read_urb);
-       usb_kill_urb(port->write_urb);
+       for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i)
+               usb_kill_urb(port->read_urbs[i]);
        for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i)
                usb_kill_urb(port->write_urbs[i]);
        /*
@@ -595,17 +600,17 @@ static void port_release(struct device *dev)
        kill_traffic(port);
        cancel_work_sync(&port->work);
 
-       usb_free_urb(port->read_urb);
-       usb_free_urb(port->write_urb);
        usb_free_urb(port->interrupt_in_urb);
        usb_free_urb(port->interrupt_out_urb);
+       for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) {
+               usb_free_urb(port->read_urbs[i]);
+               kfree(port->bulk_in_buffers[i]);
+       }
        for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) {
                usb_free_urb(port->write_urbs[i]);
                kfree(port->bulk_out_buffers[i]);
        }
        kfifo_free(&port->write_fifo);
-       kfree(port->bulk_in_buffer);
-       kfree(port->bulk_out_buffer);
        kfree(port->interrupt_in_buffer);
        kfree(port->interrupt_out_buffer);
        kfree(port);
@@ -686,16 +691,18 @@ static int serial_carrier_raised(struct tty_port *port)
 {
        struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
        struct usb_serial_driver *drv = p->serial->type;
+
        if (drv->carrier_raised)
                return drv->carrier_raised(p);
        /* No carrier control - don't block */
-       return 1;       
+       return 1;
 }
 
 static void serial_dtr_rts(struct tty_port *port, int on)
 {
        struct usb_serial_port *p = container_of(port, struct usb_serial_port, port);
        struct usb_serial_driver *drv = p->serial->type;
+
        if (drv->dtr_rts)
                drv->dtr_rts(p, on);
 }
@@ -724,6 +731,7 @@ int usb_serial_probe(struct usb_interface *interface,
        unsigned int minor;
        int buffer_size;
        int i;
+       int j;
        int num_interrupt_in = 0;
        int num_interrupt_out = 0;
        int num_bulk_in = 0;
@@ -906,38 +914,41 @@ int usb_serial_probe(struct usb_interface *interface,
        for (i = 0; i < num_bulk_in; ++i) {
                endpoint = bulk_in_endpoint[i];
                port = serial->port[i];
-               port->read_urb = usb_alloc_urb(0, GFP_KERNEL);
-               if (!port->read_urb) {
-                       dev_err(&interface->dev, "No free urbs available\n");
-                       goto probe_error;
-               }
                buffer_size = max_t(int, serial->type->bulk_in_size,
                                usb_endpoint_maxp(endpoint));
                port->bulk_in_size = buffer_size;
                port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
-               port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
-               if (!port->bulk_in_buffer) {
-                       dev_err(&interface->dev,
+
+               for (j = 0; j < ARRAY_SIZE(port->read_urbs); ++j) {
+                       set_bit(j, &port->read_urbs_free);
+                       port->read_urbs[j] = usb_alloc_urb(0, GFP_KERNEL);
+                       if (!port->read_urbs[j]) {
+                               dev_err(&interface->dev,
+                                               "No free urbs available\n");
+                               goto probe_error;
+                       }
+                       port->bulk_in_buffers[j] = kmalloc(buffer_size,
+                                                               GFP_KERNEL);
+                       if (!port->bulk_in_buffers[j]) {
+                               dev_err(&interface->dev,
                                        "Couldn't allocate bulk_in_buffer\n");
-                       goto probe_error;
-               }
-               usb_fill_bulk_urb(port->read_urb, dev,
-                               usb_rcvbulkpipe(dev,
+                               goto probe_error;
+                       }
+                       usb_fill_bulk_urb(port->read_urbs[j], dev,
+                                       usb_rcvbulkpipe(dev,
                                                endpoint->bEndpointAddress),
-                               port->bulk_in_buffer, buffer_size,
-                               serial->type->read_bulk_callback, port);
+                                       port->bulk_in_buffers[j], buffer_size,
+                                       serial->type->read_bulk_callback,
+                                       port);
+               }
+
+               port->read_urb = port->read_urbs[0];
+               port->bulk_in_buffer = port->bulk_in_buffers[0];
        }
 
        for (i = 0; i < num_bulk_out; ++i) {
-               int j;
-
                endpoint = bulk_out_endpoint[i];
                port = serial->port[i];
-               port->write_urb = usb_alloc_urb(0, GFP_KERNEL);
-               if (!port->write_urb) {
-                       dev_err(&interface->dev, "No free urbs available\n");
-                       goto probe_error;
-               }
                if (kfifo_alloc(&port->write_fifo, PAGE_SIZE, GFP_KERNEL))
                        goto probe_error;
                buffer_size = serial->type->bulk_out_size;
@@ -945,17 +956,7 @@ int usb_serial_probe(struct usb_interface *interface,
                        buffer_size = usb_endpoint_maxp(endpoint);
                port->bulk_out_size = buffer_size;
                port->bulk_out_endpointAddress = endpoint->bEndpointAddress;
-               port->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
-               if (!port->bulk_out_buffer) {
-                       dev_err(&interface->dev,
-                                       "Couldn't allocate bulk_out_buffer\n");
-                       goto probe_error;
-               }
-               usb_fill_bulk_urb(port->write_urb, dev,
-                               usb_sndbulkpipe(dev,
-                                       endpoint->bEndpointAddress),
-                               port->bulk_out_buffer, buffer_size,
-                               serial->type->write_bulk_callback, port);
+
                for (j = 0; j < ARRAY_SIZE(port->write_urbs); ++j) {
                        set_bit(j, &port->write_urbs_free);
                        port->write_urbs[j] = usb_alloc_urb(0, GFP_KERNEL);
@@ -978,6 +979,9 @@ int usb_serial_probe(struct usb_interface *interface,
                                        serial->type->write_bulk_callback,
                                        port);
                }
+
+               port->write_urb = port->write_urbs[0];
+               port->bulk_out_buffer = port->bulk_out_buffers[0];
        }
 
        if (serial->type->read_int_callback) {
@@ -1196,7 +1200,7 @@ static const struct tty_operations serial_ops = {
        .open =                 serial_open,
        .close =                serial_close,
        .write =                serial_write,
-       .hangup =               serial_hangup,
+       .hangup =               serial_hangup,
        .write_room =           serial_write_room,
        .ioctl =                serial_ioctl,
        .set_termios =          serial_set_termios,
@@ -1206,9 +1210,9 @@ static const struct tty_operations serial_ops = {
        .chars_in_buffer =      serial_chars_in_buffer,
        .tiocmget =             serial_tiocmget,
        .tiocmset =             serial_tiocmset,
-       .get_icount =           serial_get_icount,
-       .cleanup =              serial_cleanup,
-       .install =              serial_install,
+       .get_icount =           serial_get_icount,
+       .cleanup =              serial_cleanup,
+       .install =              serial_install,
        .proc_fops =            &serial_proc_fops,
 };
 
@@ -1237,7 +1241,7 @@ static int __init usb_serial_init(void)
 
        usb_serial_tty_driver->owner = THIS_MODULE;
        usb_serial_tty_driver->driver_name = "usbserial";
-       usb_serial_tty_driver->name =   "ttyUSB";
+       usb_serial_tty_driver->name = "ttyUSB";
        usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
        usb_serial_tty_driver->minor_start = 0;
        usb_serial_tty_driver->type = TTY_DRIVER_TYPE_SERIAL;
@@ -1336,7 +1340,6 @@ static void fixup_generic(struct usb_serial_driver *device)
 
 int usb_serial_register(struct usb_serial_driver *driver)
 {
-       /* must be called with BKL held */
        int retval;
 
        if (usb_disabled())
@@ -1374,7 +1377,6 @@ EXPORT_SYMBOL_GPL(usb_serial_register);
 
 void usb_serial_deregister(struct usb_serial_driver *device)
 {
-       /* must be called with BKL held */
        printk(KERN_INFO "USB Serial deregistering driver %s\n",
               device->description);
        mutex_lock(&table_lock);
index 95a8214..9b632e7 100644 (file)
@@ -40,7 +40,7 @@ static struct usb_driver debug_driver = {
        .probe =        usb_serial_probe,
        .disconnect =   usb_serial_disconnect,
        .id_table =     id_table,
-       .no_dynamic_id =        1,
+       .no_dynamic_id =        1,
 };
 
 /* This HW really does not support a serial break, so one will be
@@ -54,19 +54,18 @@ static void usb_debug_break_ctl(struct tty_struct *tty, int break_state)
        usb_serial_generic_write(tty, port, USB_DEBUG_BRK, USB_DEBUG_BRK_SIZE);
 }
 
-static void usb_debug_read_bulk_callback(struct urb *urb)
+static void usb_debug_process_read_urb(struct urb *urb)
 {
        struct usb_serial_port *port = urb->context;
 
        if (urb->actual_length == USB_DEBUG_BRK_SIZE &&
-           memcmp(urb->transfer_buffer, USB_DEBUG_BRK,
-                  USB_DEBUG_BRK_SIZE) == 0) {
+               memcmp(urb->transfer_buffer, USB_DEBUG_BRK,
+                                               USB_DEBUG_BRK_SIZE) == 0) {
                usb_serial_handle_break(port);
-               usb_serial_generic_submit_read_urb(port, GFP_ATOMIC);
                return;
        }
 
-       usb_serial_generic_read_bulk_callback(urb);
+       usb_serial_generic_process_read_urb(urb);
 }
 
 static struct usb_serial_driver debug_device = {
@@ -79,7 +78,7 @@ static struct usb_serial_driver debug_device = {
        .num_ports =            1,
        .bulk_out_size =        USB_DEBUG_MAX_PACKET_SIZE,
        .break_ctl =            usb_debug_break_ctl,
-       .read_bulk_callback =   usb_debug_read_bulk_callback,
+       .process_read_urb =     usb_debug_process_read_urb,
 };
 
 static int __init debug_init(void)
index 5b073bc..11af903 100644 (file)
  *
  * See Documentation/usb/usb-serial.txt for more information on using this
  * driver
- *
- * (10/09/2002) Stuart MacDonald (stuartm@connecttech.com)
- *     Upgrade to full working driver
- *
- * (05/30/2001) gkh
- *     switched from using spinlock to a semaphore, which fixes lots of
- *     problems.
- *
- * (04/08/2001) gb
- *     Identify version on module load.
- *
- * 2001_Mar_19 gkh
- *     Fixed MOD_INC and MOD_DEC logic, the ability to open a port more
- *     than once, and the got the proper usb_device_id table entries so
- *     the driver works again.
- *
- * (11/01/2000) Adam J. Richter
- *     usb_device_id table support
- *
- * (10/05/2000) gkh
- *     Fixed bug with urb->dev not being set properly, now that the usb
- *     core needs it.
- *
- * (10/03/2000) smd
- *     firmware is improved to guard against crap sent to device
- *     firmware now replies CMD_FAILURE on bad things
- *     read_callback fix you provided for private info struct
- *     command_finished now indicates success or fail
- *     setup_port struct now packed to avoid gcc padding
- *     firmware uses 1 based port numbering, driver now handles that
- *
- * (09/11/2000) gkh
- *     Removed DEBUG #ifdefs with call to usb_serial_debug_data
- *
- * (07/19/2000) gkh
- *     Added module_init and module_exit functions to handle the fact that this
- *     driver is a loadable module now.
- *     Fixed bug with port->minor that was found by Al Borchers
- *
- * (07/04/2000) gkh
- *     Added support for port settings. Baud rate can now be changed. Line
- *     signals are not transferred to and from the tty layer yet, but things
- *     seem to be working well now.
- *
- * (05/04/2000) gkh
- *     First cut at open and close commands. Data can flow through the ports at
- *     default speeds now.
- *
- * (03/26/2000) gkh
- *     Split driver up into device specific pieces.
- *
  */
 
 #include <linux/kernel.h>
@@ -753,7 +702,6 @@ static void whiteheat_close(struct usb_serial_port *port)
 static int whiteheat_write(struct tty_struct *tty,
        struct usb_serial_port *port, const unsigned char *buf, int count)
 {
-       struct usb_serial *serial = port->serial;
        struct whiteheat_private *info = usb_get_serial_port_data(port);
        struct whiteheat_urb_wrap *wrap;
        struct urb *urb;
@@ -789,7 +737,6 @@ static int whiteheat_write(struct tty_struct *tty,
                usb_serial_debug_data(debug, &port->dev,
                                __func__, bytes, urb->transfer_buffer);
 
-               urb->dev = serial->dev;
                urb->transfer_buffer_length = bytes;
                result = usb_submit_urb(urb, GFP_ATOMIC);
                if (result) {
@@ -1035,7 +982,6 @@ static void command_port_read_callback(struct urb *urb)
                dbg("%s - bad reply from firmware", __func__);
 
        /* Continue trying to always read */
-       command_port->read_urb->dev = command_port->serial->dev;
        result = usb_submit_urb(command_port->read_urb, GFP_ATOMIC);
        if (result)
                dbg("%s - failed resubmitting read urb, error %d",
@@ -1141,7 +1087,6 @@ static int firm_send_command(struct usb_serial_port *port, __u8 command,
        transfer_buffer[0] = command;
        memcpy(&transfer_buffer[1], data, datasize);
        command_port->write_urb->transfer_buffer_length = datasize + 1;
-       command_port->write_urb->dev = port->serial->dev;
        retval = usb_submit_urb(command_port->write_urb, GFP_NOIO);
        if (retval) {
                dbg("%s - submit urb failed", __func__);
@@ -1362,7 +1307,6 @@ static int start_command_port(struct usb_serial *serial)
                /* Work around HCD bugs */
                usb_clear_halt(serial->dev, command_port->read_urb->pipe);
 
-               command_port->read_urb->dev = serial->dev;
                retval = usb_submit_urb(command_port->read_urb, GFP_KERNEL);
                if (retval) {
                        dev_err(&serial->dev->dev,
@@ -1410,7 +1354,6 @@ static int start_port_read(struct usb_serial_port *port)
                list_del(tmp);
                wrap = list_entry(tmp, struct whiteheat_urb_wrap, list);
                urb = wrap->urb;
-               urb->dev = port->serial->dev;
                spin_unlock_irqrestore(&info->lock, flags);
                retval = usb_submit_urb(urb, GFP_KERNEL);
                if (retval) {
@@ -1490,7 +1433,6 @@ static void rx_data_softint(struct work_struct *work)
                        sent += tty_insert_flip_string(tty,
                                urb->transfer_buffer, urb->actual_length);
 
-               urb->dev = port->serial->dev;
                result = usb_submit_urb(urb, GFP_ATOMIC);
                if (result) {
                        dev_err(&port->dev,
index 3ca87a8..51af2fe 100644 (file)
@@ -139,7 +139,7 @@ static int init_alauda(struct us_data *us);
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id alauda_usb_ids[] = {
+static struct usb_device_id alauda_usb_ids[] = {
 #      include "unusual_alauda.h"
        { }             /* Terminating entry */
 };
index c7909df..387cbd4 100644 (file)
@@ -43,7 +43,7 @@ MODULE_LICENSE("GPL");
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id cypress_usb_ids[] = {
+static struct usb_device_id cypress_usb_ids[] = {
 #      include "unusual_cypress.h"
        { }             /* Terminating entry */
 };
index a99be85..15d41f2 100644 (file)
@@ -88,7 +88,7 @@ static int datafab_determine_lun(struct us_data *us,
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id datafab_usb_ids[] = {
+static struct usb_device_id datafab_usb_ids[] = {
 #      include "unusual_datafab.h"
        { }             /* Terminating entry */
 };
index b0a1687..a6ade40 100644 (file)
@@ -42,7 +42,7 @@ MODULE_LICENSE("GPL");
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
        .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id ene_ub6250_usb_ids[] = {
+static struct usb_device_id ene_ub6250_usb_ids[] = {
 #      include "unusual_ene_ub6250.h"
        { }             /* Terminating entry */
 };
@@ -607,8 +607,8 @@ static int sd_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb)
 
 static int sd_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb)
 {
-       u32   bl_num;
-       u16    bl_len;
+       u32     bl_num;
+       u32     bl_len;
        unsigned int offset = 0;
        unsigned char    buf[8];
        struct scatterlist *sg = NULL;
@@ -622,7 +622,7 @@ static int sd_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb)
                else
                        bl_num = (info->HC_C_SIZE + 1) * 1024 - 1;
        } else {
-               bl_len = 1<<(info->SD_READ_BL_LEN);
+               bl_len = 1 << (info->SD_READ_BL_LEN);
                bl_num = info->SD_Block_Mult * (info->SD_C_SIZE + 1)
                                * (1 << (info->SD_C_SIZE_MULT + 2)) - 1;
        }
@@ -777,7 +777,7 @@ static int ms_lib_free_logicalmap(struct us_data *us)
        return 0;
 }
 
-int ms_lib_alloc_logicalmap(struct us_data *us)
+static int ms_lib_alloc_logicalmap(struct us_data *us)
 {
        u32  i;
        struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
@@ -2248,7 +2248,7 @@ static int sd_scsi_irp(struct us_data *us, struct scsi_cmnd *srb)
 /*
  * ms_scsi_irp()
  */
-int ms_scsi_irp(struct us_data *us, struct scsi_cmnd *srb)
+static int ms_scsi_irp(struct us_data *us, struct scsi_cmnd *srb)
 {
        int result;
        struct ene_ub6250_info *info = (struct ene_ub6250_info *)us->extra;
index 03d4a87..fa16157 100644 (file)
@@ -119,7 +119,7 @@ static int init_freecom(struct us_data *us);
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id freecom_usb_ids[] = {
+static struct usb_device_id freecom_usb_ids[] = {
 #      include "unusual_freecom.h"
        { }             /* Terminating entry */
 };
index 93d359f..bd55027 100644 (file)
@@ -76,7 +76,7 @@ static int isd200_Initialization(struct us_data *us);
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id isd200_usb_ids[] = {
+static struct usb_device_id isd200_usb_ids[] = {
 #      include "unusual_isd200.h"
        { }             /* Terminating entry */
 };
index 54b7165..a19211b 100644 (file)
@@ -71,7 +71,7 @@ MODULE_LICENSE("GPL");
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id jumpshot_usb_ids[] = {
+static struct usb_device_id jumpshot_usb_ids[] = {
 #      include "unusual_jumpshot.h"
        { }             /* Terminating entry */
 };
index 35181e2..e720f8e 100644 (file)
@@ -59,7 +59,7 @@ static int rio_karma_init(struct us_data *us);
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id karma_usb_ids[] = {
+static struct usb_device_id karma_usb_ids[] = {
 #      include "unusual_karma.h"
        { }             /* Terminating entry */
 };
index 721c8c5..d75155c 100644 (file)
@@ -69,7 +69,7 @@ struct usb_onetouch {
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id onetouch_usb_ids[] = {
+static struct usb_device_id onetouch_usb_ids[] = {
 #      include "unusual_onetouch.h"
        { }             /* Terminating entry */
 };
index c41cd30..1f62723 100644 (file)
@@ -398,10 +398,9 @@ static int rts51x_write_mem(struct us_data *us, u16 addr, u8 *data, u16 len)
        u8 cmnd[12] = { 0 };
        u8 *buf;
 
-       buf = kmalloc(len, GFP_NOIO);
+       buf = kmemdup(data, len, GFP_NOIO);
        if (buf == NULL)
                return USB_STOR_TRANSPORT_ERROR;
-       memcpy(buf, data, len);
 
        US_DEBUGP("%s, addr = 0x%x, len = %d\n", __func__, addr, len);
 
@@ -507,15 +506,14 @@ static int enable_oscillator(struct us_data *us)
 static int __do_config_autodelink(struct us_data *us, u8 *data, u16 len)
 {
        int retval;
-       u16 addr = 0xFE47;
        u8 cmnd[12] = {0};
 
-       US_DEBUGP("%s, addr = 0x%x, len = %d\n", __FUNCTION__, addr, len);
+       US_DEBUGP("%s, addr = 0xfe47, len = %d\n", __FUNCTION__, len);
 
        cmnd[0] = 0xF0;
        cmnd[1] = 0x0E;
-       cmnd[2] = (u8)(addr >> 8);
-       cmnd[3] = (u8)addr;
+       cmnd[2] = 0xfe;
+       cmnd[3] = 0x47;
        cmnd[4] = (u8)(len >> 8);
        cmnd[5] = (u8)len;
 
@@ -818,7 +816,7 @@ static inline int working_scsi(struct scsi_cmnd *srb)
        return 1;
 }
 
-void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
+static void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us)
 {
        struct rts51x_chip *chip = (struct rts51x_chip *)(us->extra);
        static int card_first_show = 1;
@@ -977,7 +975,7 @@ static void realtek_cr_destructor(void *extra)
 }
 
 #ifdef CONFIG_PM
-int realtek_cr_suspend(struct usb_interface *iface, pm_message_t message)
+static int realtek_cr_suspend(struct usb_interface *iface, pm_message_t message)
 {
        struct us_data *us = usb_get_intfdata(iface);
 
index 83ee49e..425df7d 100644 (file)
@@ -71,7 +71,7 @@ static int usb_stor_sddr09_init(struct us_data *us);
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id sddr09_usb_ids[] = {
+static struct usb_device_id sddr09_usb_ids[] = {
 #      include "unusual_sddr09.h"
        { }             /* Terminating entry */
 };
index 8983ec2..e4ca5fc 100644 (file)
@@ -48,7 +48,7 @@ MODULE_LICENSE("GPL");
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id sddr55_usb_ids[] = {
+static struct usb_device_id sddr55_usb_ids[] = {
 #      include "unusual_sddr55.h"
        { }             /* Terminating entry */
 };
index a4c0275..1369d25 100644 (file)
@@ -170,7 +170,7 @@ static int init_usbat_flash(struct us_data *us);
 { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
   .driver_info = (flags)|(USB_US_TYPE_STOR<<24) }
 
-struct usb_device_id usbat_usb_ids[] = {
+static struct usb_device_id usbat_usb_ids[] = {
 #      include "unusual_usbat.h"
        { }             /* Terminating entry */
 };
index aa84b3d..3dd7da9 100644 (file)
@@ -1074,6 +1074,7 @@ static struct usb_driver usb_storage_driver = {
        .id_table =     usb_storage_usb_ids,
        .supports_autosuspend = 1,
        .soft_unbind =  1,
+       .no_dynamic_id = 1,
 };
 
 static int __init usb_stor_init(void)
index 5c6c1bd..8efeae2 100644 (file)
@@ -27,6 +27,8 @@
 #define USB_SKEL_VENDOR_ID     0xfff0
 #define USB_SKEL_PRODUCT_ID    0xfff0
 
+static DEFINE_MUTEX(skel_mutex);
+
 /* table of devices that work with this driver */
 static const struct usb_device_id skel_table[] = {
        { USB_DEVICE(USB_SKEL_VENDOR_ID, USB_SKEL_PRODUCT_ID) },
@@ -60,7 +62,6 @@ struct usb_skel {
        __u8                    bulk_in_endpointAddr;   /* the address of the bulk in endpoint */
        __u8                    bulk_out_endpointAddr;  /* the address of the bulk out endpoint */
        int                     errors;                 /* the last request tanked */
-       int                     open_count;             /* count the number of openers */
        bool                    ongoing_read;           /* a read is going on */
        bool                    processed_urb;          /* indicates we haven't processed the urb */
        spinlock_t              err_lock;               /* lock for errors */
@@ -100,39 +101,37 @@ static int skel_open(struct inode *inode, struct file *file)
                goto exit;
        }
 
+       mutex_lock(&skel_mutex);
        dev = usb_get_intfdata(interface);
        if (!dev) {
+               mutex_unlock(&skel_mutex);
                retval = -ENODEV;
                goto exit;
        }
 
        /* increment our usage count for the device */
        kref_get(&dev->kref);
+       mutex_unlock(&skel_mutex);
 
        /* lock the device to allow correctly handling errors
         * in resumption */
        mutex_lock(&dev->io_mutex);
+       if (!dev->interface) {
+               retval = -ENODEV;
+               goto out_err;
+       }
 
-       if (!dev->open_count++) {
-               retval = usb_autopm_get_interface(interface);
-                       if (retval) {
-                               dev->open_count--;
-                               mutex_unlock(&dev->io_mutex);
-                               kref_put(&dev->kref, skel_delete);
-                               goto exit;
-                       }
-       } /* else { //uncomment this block if you want exclusive open
-               retval = -EBUSY;
-               dev->open_count--;
-               mutex_unlock(&dev->io_mutex);
-               kref_put(&dev->kref, skel_delete);
-               goto exit;
-       } */
-       /* prevent the device from being autosuspended */
+       retval = usb_autopm_get_interface(interface);
+       if (retval)
+               goto out_err;
 
        /* save our object in the file's private structure */
        file->private_data = dev;
+
+out_err:
        mutex_unlock(&dev->io_mutex);
+       if (retval)
+               kref_put(&dev->kref, skel_delete);
 
 exit:
        return retval;
@@ -148,7 +147,7 @@ static int skel_release(struct inode *inode, struct file *file)
 
        /* allow the device to be autosuspended */
        mutex_lock(&dev->io_mutex);
-       if (!--dev->open_count && dev->interface)
+       if (dev->interface)
                usb_autopm_put_interface(dev->interface);
        mutex_unlock(&dev->io_mutex);
 
@@ -612,7 +611,6 @@ static void skel_disconnect(struct usb_interface *interface)
        int minor = interface->minor;
 
        dev = usb_get_intfdata(interface);
-       usb_set_intfdata(interface, NULL);
 
        /* give back our minor */
        usb_deregister_dev(interface, &skel_class);
@@ -624,8 +622,12 @@ static void skel_disconnect(struct usb_interface *interface)
 
        usb_kill_anchored_urbs(&dev->submitted);
 
+       mutex_lock(&skel_mutex);
+       usb_set_intfdata(interface, NULL);
+
        /* decrement our usage count */
        kref_put(&dev->kref, skel_delete);
+       mutex_unlock(&skel_mutex);
 
        dev_info(&interface->dev, "USB Skeleton #%d now disconnected", minor);
 }
index eb09a0a..0ead882 100644 (file)
@@ -5,6 +5,7 @@ config USB_WUSB
        tristate "Enable Wireless USB extensions (EXPERIMENTAL)"
        depends on EXPERIMENTAL
        depends on USB
+       depends on PCI
         select UWB
         select CRYPTO
         select CRYPTO_BLKCIPHER
index 371f617..fa810a8 100644 (file)
@@ -354,7 +354,7 @@ int wusb_dev_4way_handshake(struct wusbhc *wusbhc, struct wusb_dev *wusb_dev,
        struct wusb_keydvt_in keydvt_in;
        struct wusb_keydvt_out keydvt_out;
 
-       hs = kzalloc(3*sizeof(hs[0]), GFP_KERNEL);
+       hs = kcalloc(3, sizeof(hs[0]), GFP_KERNEL);
        if (hs == NULL) {
                dev_err(dev, "can't allocate handshake data\n");
                goto error_kzalloc;
index de81ebf..86ed7e6 100644 (file)
@@ -184,7 +184,7 @@ int uwb_est_create(void)
 
        uwb_est_size = 2;
        uwb_est_used = 0;
-       uwb_est = kzalloc(uwb_est_size * sizeof(uwb_est[0]), GFP_KERNEL);
+       uwb_est = kcalloc(uwb_est_size, sizeof(uwb_est[0]), GFP_KERNEL);
        if (uwb_est == NULL)
                return -ENOMEM;
 
index 3a444b4..a81eb23 100644 (file)
@@ -512,7 +512,8 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname,
        int charlen;
 
        if (utf8) {
-               *outlen = utf8s_to_utf16s(name, len, (wchar_t *)outname);
+               *outlen = utf8s_to_utf16s(name, len, UTF16_HOST_ENDIAN,
+                               (wchar_t *) outname, FAT_LFN_LEN + 2);
                if (*outlen < 0)
                        return *outlen;
                else if (*outlen > FAT_LFN_LEN)
index 44a88a9..fea6bd5 100644 (file)
@@ -52,7 +52,7 @@ static const struct utf8_table utf8_table[] =
 #define SURROGATE_LOW  0x00000400
 #define SURROGATE_BITS 0x000003ff
 
-int utf8_to_utf32(const u8 *s, int len, unicode_t *pu)
+int utf8_to_utf32(const u8 *s, int inlen, unicode_t *pu)
 {
        unsigned long l;
        int c0, c, nc;
@@ -71,7 +71,7 @@ int utf8_to_utf32(const u8 *s, int len, unicode_t *pu)
                        *pu = (unicode_t) l;
                        return nc;
                }
-               if (len <= nc)
+               if (inlen <= nc)
                        return -1;
                s++;
                c = (*s ^ 0x80) & 0xFF;
@@ -83,7 +83,7 @@ int utf8_to_utf32(const u8 *s, int len, unicode_t *pu)
 }
 EXPORT_SYMBOL(utf8_to_utf32);
 
-int utf32_to_utf8(unicode_t u, u8 *s, int maxlen)
+int utf32_to_utf8(unicode_t u, u8 *s, int maxout)
 {
        unsigned long l;
        int c, nc;
@@ -97,7 +97,7 @@ int utf32_to_utf8(unicode_t u, u8 *s, int maxlen)
                return -1;
 
        nc = 0;
-       for (t = utf8_table; t->cmask && maxlen; t++, maxlen--) {
+       for (t = utf8_table; t->cmask && maxout; t++, maxout--) {
                nc++;
                if (l <= t->lmask) {
                        c = t->shift;
@@ -114,34 +114,57 @@ int utf32_to_utf8(unicode_t u, u8 *s, int maxlen)
 }
 EXPORT_SYMBOL(utf32_to_utf8);
 
-int utf8s_to_utf16s(const u8 *s, int len, wchar_t *pwcs)
+static inline void put_utf16(wchar_t *s, unsigned c, enum utf16_endian endian)
+{
+       switch (endian) {
+       default:
+               *s = (wchar_t) c;
+               break;
+       case UTF16_LITTLE_ENDIAN:
+               *s = __cpu_to_le16(c);
+               break;
+       case UTF16_BIG_ENDIAN:
+               *s = __cpu_to_be16(c);
+               break;
+       }
+}
+
+int utf8s_to_utf16s(const u8 *s, int inlen, enum utf16_endian endian,
+               wchar_t *pwcs, int maxout)
 {
        u16 *op;
        int size;
        unicode_t u;
 
        op = pwcs;
-       while (*s && len > 0) {
+       while (inlen > 0 && maxout > 0 && *s) {
                if (*s & 0x80) {
-                       size = utf8_to_utf32(s, len, &u);
+                       size = utf8_to_utf32(s, inlen, &u);
                        if (size < 0)
                                return -EINVAL;
+                       s += size;
+                       inlen -= size;
 
                        if (u >= PLANE_SIZE) {
+                               if (maxout < 2)
+                                       break;
                                u -= PLANE_SIZE;
-                               *op++ = (wchar_t) (SURROGATE_PAIR |
-                                               ((u >> 10) & SURROGATE_BITS));
-                               *op++ = (wchar_t) (SURROGATE_PAIR |
+                               put_utf16(op++, SURROGATE_PAIR |
+                                               ((u >> 10) & SURROGATE_BITS),
+                                               endian);
+                               put_utf16(op++, SURROGATE_PAIR |
                                                SURROGATE_LOW |
-                                               (u & SURROGATE_BITS));
+                                               (u & SURROGATE_BITS),
+                                               endian);
+                               maxout -= 2;
                        } else {
-                               *op++ = (wchar_t) u;
+                               put_utf16(op++, u, endian);
+                               maxout--;
                        }
-                       s += size;
-                       len -= size;
                } else {
-                       *op++ = *s++;
-                       len--;
+                       put_utf16(op++, *s++, endian);
+                       inlen--;
+                       maxout--;
                }
        }
        return op - pwcs;
@@ -160,27 +183,27 @@ static inline unsigned long get_utf16(unsigned c, enum utf16_endian endian)
        }
 }
 
-int utf16s_to_utf8s(const wchar_t *pwcs, int len, enum utf16_endian endian,
-               u8 *s, int maxlen)
+int utf16s_to_utf8s(const wchar_t *pwcs, int inlen, enum utf16_endian endian,
+               u8 *s, int maxout)
 {
        u8 *op;
        int size;
        unsigned long u, v;
 
        op = s;
-       while (len > 0 && maxlen > 0) {
+       while (inlen > 0 && maxout > 0) {
                u = get_utf16(*pwcs, endian);
                if (!u)
                        break;
                pwcs++;
-               len--;
+               inlen--;
                if (u > 0x7f) {
                        if ((u & SURROGATE_MASK) == SURROGATE_PAIR) {
                                if (u & SURROGATE_LOW) {
                                        /* Ignore character and move on */
                                        continue;
                                }
-                               if (len <= 0)
+                               if (inlen <= 0)
                                        break;
                                v = get_utf16(*pwcs, endian);
                                if ((v & SURROGATE_MASK) != SURROGATE_PAIR ||
@@ -191,18 +214,18 @@ int utf16s_to_utf8s(const wchar_t *pwcs, int len, enum utf16_endian endian,
                                u = PLANE_SIZE + ((u & SURROGATE_BITS) << 10)
                                                + (v & SURROGATE_BITS);
                                pwcs++;
-                               len--;
+                               inlen--;
                        }
-                       size = utf32_to_utf8(u, op, maxlen);
+                       size = utf32_to_utf8(u, op, maxout);
                        if (size == -1) {
                                /* Ignore character and move on */
                        } else {
                                op += size;
-                               maxlen -= size;
+                               maxout -= size;
                        }
                } else {
                        *op++ = (u8) u;
-                       maxlen--;
+                       maxout--;
                }
        }
        return op - s;
index d47beef..5dc635f 100644 (file)
@@ -43,7 +43,7 @@ enum utf16_endian {
        UTF16_BIG_ENDIAN
 };
 
-/* nls.c */
+/* nls_base.c */
 extern int register_nls(struct nls_table *);
 extern int unregister_nls(struct nls_table *);
 extern struct nls_table *load_nls(char *);
@@ -52,7 +52,8 @@ extern struct nls_table *load_nls_default(void);
 
 extern int utf8_to_utf32(const u8 *s, int len, unicode_t *pu);
 extern int utf32_to_utf8(unicode_t u, u8 *s, int maxlen);
-extern int utf8s_to_utf16s(const u8 *s, int len, wchar_t *pwcs);
+extern int utf8s_to_utf16s(const u8 *s, int len,
+               enum utf16_endian endian, wchar_t *pwcs, int maxlen);
 extern int utf16s_to_utf8s(const wchar_t *pwcs, int len,
                enum utf16_endian endian, u8 *s, int maxlen);
 
index e9d9149..d94804a 100644 (file)
@@ -42,9 +42,23 @@ struct mv_usb_platform_data {
        /* only valid for HCD. OTG or Host only*/
        unsigned int            mode;
 
-       int     (*phy_init)(unsigned int regbase);
-       void    (*phy_deinit)(unsigned int regbase);
+       /* This flag is used for that needs id pin checked by otg */
+       unsigned int    disable_otg_clock_gating:1;
+       /* Force a_bus_req to be asserted */
+        unsigned int    otg_force_a_bus_req:1;
+
+       int     (*phy_init)(void __iomem *regbase);
+       void    (*phy_deinit)(void __iomem *regbase);
        int     (*set_vbus)(unsigned int vbus);
+       int     (*private_init)(void __iomem *opregs, void __iomem *phyregs);
 };
 
+#ifndef CONFIG_HAVE_CLK
+/* Dummy stub for clk framework */
+#define clk_get(dev, id)       NULL
+#define clk_put(clock)         do {} while (0)
+#define clk_enable(clock)      do {} while (0)
+#define clk_disable(clock)     do {} while (0)
+#endif
+
 #endif
diff --git a/include/linux/platform_data/s3c-hsudc.h b/include/linux/platform_data/s3c-hsudc.h
new file mode 100644 (file)
index 0000000..6fa1093
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * S3C24XX USB 2.0 High-speed USB controller gadget driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * The S3C24XX USB 2.0 high-speed USB controller supports upto 9 endpoints.
+ * Each endpoint can be configured as either in or out endpoint. Endpoints
+ * can be configured for Bulk or Interrupt transfer mode.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#ifndef __LINUX_USB_S3C_HSUDC_H
+#define __LINUX_USB_S3C_HSUDC_H
+
+/**
+ * s3c24xx_hsudc_platdata - Platform data for USB High-Speed gadget controller.
+ * @epnum: Number of endpoints to be instantiated by the controller driver.
+ * @gpio_init: Platform specific USB related GPIO initialization.
+ * @gpio_uninit: Platform specific USB releted GPIO uninitialzation.
+ *
+ * Representation of platform data for the S3C24XX USB 2.0 High Speed gadget
+ * controllers.
+ */
+struct s3c24xx_hsudc_platdata {
+       unsigned int    epnum;
+       void            (*gpio_init)(void);
+       void            (*gpio_uninit)(void);
+};
+
+#endif /* __LINUX_USB_S3C_HSUDC_H */
index 7f8d4d6..27a4e16 100644 (file)
@@ -1233,6 +1233,7 @@ struct urb {
        void *transfer_buffer;          /* (in) associated data buffer */
        dma_addr_t transfer_dma;        /* (in) dma addr for transfer_buffer */
        struct scatterlist *sg;         /* (in) scatter gather buffer list */
+       int num_mapped_sgs;             /* (internal) mapped sg entries */
        int num_sgs;                    /* (in) number of entries in the sg list */
        u32 transfer_buffer_length;     /* (in) data buffer length */
        u32 actual_length;              /* (return) actual transfer length */
@@ -1610,6 +1611,19 @@ usb_maxpacket(struct usb_device *udev, int pipe, int is_out)
 
 /* ----------------------------------------------------------------------- */
 
+/* translate USB error codes to codes user space understands */
+static inline int usb_translate_errors(int error_code)
+{
+       switch (error_code) {
+       case 0:
+       case -ENOMEM:
+       case -ENODEV:
+               return error_code;
+       default:
+               return -EIO;
+       }
+}
+
 /* Events from the usb core */
 #define USB_DEVICE_ADD         0x0001
 #define USB_DEVICE_REMOVE      0x0002
index 4ebaf08..31fdb4c 100644 (file)
@@ -26,7 +26,6 @@
 #define HUB_RESET_TT           9
 #define HUB_GET_TT_STATE       10
 #define HUB_STOP_TT            11
-#define HUB_SET_DEPTH          12
 
 /*
  * Hub class additional requests defined by USB 3.0 spec
@@ -165,11 +164,20 @@ struct usb_port_status {
  * wHubCharacteristics (masks)
  * See USB 2.0 spec Table 11-13, offset 3
  */
-#define HUB_CHAR_LPSM          0x0003 /* D1 .. D0 */
-#define HUB_CHAR_COMPOUND      0x0004 /* D2       */
-#define HUB_CHAR_OCPM          0x0018 /* D4 .. D3 */
-#define HUB_CHAR_TTTT           0x0060 /* D6 .. D5 */
-#define HUB_CHAR_PORTIND        0x0080 /* D7       */
+#define HUB_CHAR_LPSM          0x0003 /* Logical Power Switching Mode mask */
+#define HUB_CHAR_COMMON_LPSM   0x0000 /* All ports power control at once */
+#define HUB_CHAR_INDV_PORT_LPSM        0x0001 /* per-port power control */
+#define HUB_CHAR_NO_LPSM       0x0002 /* no power switching */
+
+#define HUB_CHAR_COMPOUND      0x0004 /* hub is part of a compound device */
+
+#define HUB_CHAR_OCPM          0x0018 /* Over-Current Protection Mode mask */
+#define HUB_CHAR_COMMON_OCPM   0x0000 /* All ports Over-Current reporting */
+#define HUB_CHAR_INDV_PORT_OCPM        0x0008 /* per-port Over-current reporting */
+#define HUB_CHAR_NO_OCPM       0x0010 /* No Over-current Protection support */
+
+#define HUB_CHAR_TTTT          0x0060 /* TT Think Time mask */
+#define HUB_CHAR_PORTIND       0x0080 /* per-port indicators (LEDs) */
 
 struct usb_hub_status {
        __le16 wHubStatus;
@@ -198,6 +206,17 @@ struct usb_hub_status {
 #define USB_DT_HUB_NONVAR_SIZE         7
 #define USB_DT_SS_HUB_SIZE              12
 
+/*
+ * Hub Device descriptor
+ * USB Hub class device protocols
+ */
+
+#define USB_HUB_PR_FS          0 /* Full speed hub */
+#define USB_HUB_PR_HS_NO_TT    0 /* Hi-speed hub without TT */
+#define USB_HUB_PR_HS_SINGLE_TT        1 /* Hi-speed hub with single TT */
+#define USB_HUB_PR_HS_MULTI_TT 2 /* Hi-speed hub with multiple TT */
+#define USB_HUB_PR_SS          3 /* Super speed hub */
+
 struct usb_hub_descriptor {
        __u8  bDescLength;
        __u8  bDescriptorType;
index d5da6c6..61b2905 100644 (file)
@@ -605,8 +605,26 @@ struct usb_ss_ep_comp_descriptor {
 } __attribute__ ((packed));
 
 #define USB_DT_SS_EP_COMP_SIZE         6
+
 /* Bits 4:0 of bmAttributes if this is a bulk endpoint */
-#define USB_SS_MAX_STREAMS(p)          (1 << ((p) & 0x1f))
+static inline int
+usb_ss_max_streams(const struct usb_ss_ep_comp_descriptor *comp)
+{
+       int             max_streams;
+
+       if (!comp)
+               return 0;
+
+       max_streams = comp->bmAttributes & 0x1f;
+
+       if (!max_streams)
+               return 0;
+
+       max_streams = 1 << max_streams;
+
+       return max_streams;
+}
+
 /* Bits 1:0 of bmAttributes if this is an isoc endpoint */
 #define USB_SS_MULT(p)                 (1 + ((p) & 0x3))
 
index 1d3a675..da653b5 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/init.h>
 #include <linux/list.h>
 #include <linux/slab.h>
+#include <linux/scatterlist.h>
 #include <linux/types.h>
 #include <linux/usb/ch9.h>
 
@@ -32,6 +33,9 @@ struct usb_ep;
  * @dma: DMA address corresponding to 'buf'.  If you don't set this
  *     field, and the usb controller needs one, it is responsible
  *     for mapping and unmapping the buffer.
+ * @sg: a scatterlist for SG-capable controllers.
+ * @num_sgs: number of SG entries
+ * @num_mapped_sgs: number of SG entries mapped to DMA (internal)
  * @length: Length of that data
  * @stream_id: The stream id, when USB3.0 bulk streams are being used
  * @no_interrupt: If true, hints that no completion irq is needed.
@@ -88,6 +92,10 @@ struct usb_request {
        unsigned                length;
        dma_addr_t              dma;
 
+       struct scatterlist      *sg;
+       unsigned                num_sgs;
+       unsigned                num_mapped_sgs;
+
        unsigned                stream_id:16;
        unsigned                no_interrupt:1;
        unsigned                zero:1;
@@ -164,7 +172,7 @@ struct usb_ep {
        unsigned                maxpacket:16;
        unsigned                max_streams:16;
        unsigned                mult:2;
-       unsigned                maxburst:4;
+       unsigned                maxburst:5;
        u8                      address;
        const struct usb_endpoint_descriptor    *desc;
        const struct usb_ss_ep_comp_descriptor  *comp_desc;
@@ -477,8 +485,9 @@ struct usb_gadget_ops {
  *     driver setup() requests
  * @ep_list: List of other endpoints supported by the device.
  * @speed: Speed of current connection to USB host.
- * @is_dualspeed: True if the controller supports both high and full speed
- *     operation.  If it does, the gadget driver must also support both.
+ * @max_speed: Maximal speed the UDC can handle.  UDC must support this
+ *      and all slower speeds.
+ * @sg_supported: true if we can handle scatter-gather
  * @is_otg: True if the USB device port uses a Mini-AB jack, so that the
  *     gadget driver must provide a USB OTG descriptor.
  * @is_a_peripheral: False unless is_otg, the "A" end of a USB cable
@@ -518,7 +527,8 @@ struct usb_gadget {
        struct usb_ep                   *ep0;
        struct list_head                ep_list;        /* of usb_ep */
        enum usb_device_speed           speed;
-       unsigned                        is_dualspeed:1;
+       enum usb_device_speed           max_speed;
+       unsigned                        sg_supported:1;
        unsigned                        is_otg:1;
        unsigned                        is_a_peripheral:1;
        unsigned                        b_hnp_enable:1;
@@ -549,7 +559,7 @@ static inline struct usb_gadget *dev_to_usb_gadget(struct device *dev)
 static inline int gadget_is_dualspeed(struct usb_gadget *g)
 {
 #ifdef CONFIG_USB_GADGET_DUALSPEED
-       /* runtime test would check "g->is_dualspeed" ... that might be
+       /* runtime test would check "g->max_speed" ... that might be
         * useful to work around hardware bugs, but is mostly pointless
         */
        return 1;
@@ -567,7 +577,7 @@ static inline int gadget_is_superspeed(struct usb_gadget *g)
 {
 #ifdef CONFIG_USB_GADGET_SUPERSPEED
        /*
-        * runtime test would check "g->is_superspeed" ... that might be
+        * runtime test would check "g->max_speed" ... that might be
         * useful to work around hardware bugs, but is mostly pointless
         */
        return 1;
@@ -760,7 +770,7 @@ static inline int usb_gadget_disconnect(struct usb_gadget *gadget)
 /**
  * struct usb_gadget_driver - driver for usb 'slave' devices
  * @function: String describing the gadget's function
- * @speed: Highest speed the driver handles.
+ * @max_speed: Highest speed the driver handles.
  * @setup: Invoked for ep0 control requests that aren't handled by
  *     the hardware level driver. Most calls must be handled by
  *     the gadget driver, including descriptor and configuration
@@ -824,7 +834,7 @@ static inline int usb_gadget_disconnect(struct usb_gadget *gadget)
  */
 struct usb_gadget_driver {
        char                    *function;
-       enum usb_device_speed   speed;
+       enum usb_device_speed   max_speed;
        void                    (*unbind)(struct usb_gadget *);
        int                     (*setup)(struct usb_gadget *,
                                        const struct usb_ctrlrequest *);
index 03354d5..b2f62f3 100644 (file)
@@ -99,7 +99,6 @@ struct usb_hcd {
         */
        unsigned long           flags;
 #define HCD_FLAG_HW_ACCESSIBLE         0       /* at full power */
-#define HCD_FLAG_SAW_IRQ               1
 #define HCD_FLAG_POLL_RH               2       /* poll for rh status? */
 #define HCD_FLAG_POLL_PENDING          3       /* status has changed? */
 #define HCD_FLAG_WAKEUP_PENDING                4       /* root hub is resuming? */
@@ -110,7 +109,6 @@ struct usb_hcd {
         * be slightly faster than test_bit().
         */
 #define HCD_HW_ACCESSIBLE(hcd) ((hcd)->flags & (1U << HCD_FLAG_HW_ACCESSIBLE))
-#define HCD_SAW_IRQ(hcd)       ((hcd)->flags & (1U << HCD_FLAG_SAW_IRQ))
 #define HCD_POLL_RH(hcd)       ((hcd)->flags & (1U << HCD_FLAG_POLL_RH))
 #define HCD_POLL_PENDING(hcd)  ((hcd)->flags & (1U << HCD_FLAG_POLL_PENDING))
 #define HCD_WAKEUP_PENDING(hcd)        ((hcd)->flags & (1U << HCD_FLAG_WAKEUP_PENDING))
index e5a40c3..0d3f988 100644 (file)
@@ -64,6 +64,14 @@ struct renesas_usbhs_platform_callback {
         */
        void (*hardware_exit)(struct platform_device *pdev);
 
+       /*
+        * option:
+        *
+        * for board specific clock control
+        */
+       void (*power_ctrl)(struct platform_device *pdev,
+                          void __iomem *base, int enable);
+
        /*
         * option:
         *
@@ -118,7 +126,7 @@ struct renesas_usbhs_driver_param {
         *
         * delay time from notify_hotplug callback
         */
-       int detection_delay;
+       int detection_delay; /* msec */
 
        /*
         * option:
index b29f70b..4267a9c 100644 (file)
@@ -58,11 +58,13 @@ enum port_dev_state {
  * @read_urb: pointer to the bulk in struct urb for this port.
  * @bulk_in_endpointAddress: endpoint address for the bulk in pipe for this
  *     port.
+ * @bulk_in_buffers: pointers to the bulk in buffers for this port
+ * @read_urbs: pointers to the bulk in urbs for this port
+ * @read_urbs_free: status bitmap the for bulk in urbs
  * @bulk_out_buffer: pointer to the bulk out buffer for this port.
  * @bulk_out_size: the size of the bulk_out_buffer, in bytes.
  * @write_urb: pointer to the bulk out struct urb for this port.
  * @write_fifo: kfifo used to buffer outgoing data
- * @write_urb_busy: port`s writing status
  * @bulk_out_buffers: pointers to the bulk out buffers for this port
  * @write_urbs: pointers to the bulk out urbs for this port
  * @write_urbs_free: status bitmap the for bulk out urbs
@@ -99,11 +101,14 @@ struct usb_serial_port {
        struct urb              *read_urb;
        __u8                    bulk_in_endpointAddress;
 
+       unsigned char           *bulk_in_buffers[2];
+       struct urb              *read_urbs[2];
+       unsigned long           read_urbs_free;
+
        unsigned char           *bulk_out_buffer;
        int                     bulk_out_size;
        struct urb              *write_urb;
        struct kfifo            write_fifo;
-       int                     write_urb_busy;
 
        unsigned char           *bulk_out_buffers[2];
        struct urb              *write_urbs[2];
@@ -340,7 +345,7 @@ extern void usb_serial_generic_disconnect(struct usb_serial *serial);
 extern void usb_serial_generic_release(struct usb_serial *serial);
 extern int usb_serial_generic_register(int debug);
 extern void usb_serial_generic_deregister(void);
-extern int usb_serial_generic_submit_read_urb(struct usb_serial_port *port,
+extern int usb_serial_generic_submit_read_urbs(struct usb_serial_port *port,
                                                 gfp_t mem_flags);
 extern void usb_serial_generic_process_read_urb(struct urb *urb);
 extern int usb_serial_generic_prepare_write_buffer(struct usb_serial_port *port,