From 34eea6ca1f80ed6f4dcc1d2c443556a30b12ea32 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Mon, 19 Dec 2011 22:01:54 +0200 Subject: [PATCH] --- yaml --- r: 280906 b: refs/heads/master c: 772aed45b604c5ff171f0f12c12392d868333f79 h: refs/heads/master v: v3 --- [refs] | 2 +- trunk/Documentation/ABI/testing/sysfs-bus-usb | 25 - .../feature-removal-schedule.txt | 14 - trunk/Documentation/kernel-parameters.txt | 4 - trunk/drivers/hv/hv_kvp.c | 10 +- trunk/drivers/usb/Makefile | 3 +- trunk/drivers/usb/c67x00/c67x00-drv.c | 15 +- trunk/drivers/usb/c67x00/c67x00-hcd.c | 1 + trunk/drivers/usb/class/cdc-acm.c | 334 +++--- trunk/drivers/usb/class/cdc-acm.h | 1 - trunk/drivers/usb/core/devio.c | 186 ++-- trunk/drivers/usb/core/driver.c | 8 +- trunk/drivers/usb/core/hcd-pci.c | 4 + trunk/drivers/usb/core/hcd.c | 31 +- trunk/drivers/usb/core/hub.c | 89 +- trunk/drivers/usb/core/usb.h | 14 + trunk/drivers/usb/dwc3/Kconfig | 5 +- trunk/drivers/usb/dwc3/Makefile | 6 +- trunk/drivers/usb/dwc3/core.c | 209 +--- trunk/drivers/usb/dwc3/core.h | 62 +- trunk/drivers/usb/dwc3/debugfs.c | 83 +- trunk/drivers/usb/dwc3/dwc3-omap.c | 43 +- trunk/drivers/usb/dwc3/dwc3-pci.c | 49 +- trunk/drivers/usb/dwc3/ep0.c | 160 +-- trunk/drivers/usb/dwc3/gadget.c | 199 +--- trunk/drivers/usb/dwc3/gadget.h | 29 +- trunk/drivers/usb/dwc3/host.c | 102 -- trunk/drivers/usb/dwc3/io.h | 2 +- trunk/drivers/usb/gadget/Kconfig | 14 +- trunk/drivers/usb/gadget/amd5536udc.c | 4 +- trunk/drivers/usb/gadget/at91_udc.c | 2 +- trunk/drivers/usb/gadget/atmel_usba_udc.c | 2 +- trunk/drivers/usb/gadget/ci13xxx_udc.c | 36 +- trunk/drivers/usb/gadget/ci13xxx_udc.h | 2 +- trunk/drivers/usb/gadget/composite.c | 8 +- trunk/drivers/usb/gadget/dbgp.c | 2 +- trunk/drivers/usb/gadget/dummy_hcd.c | 15 +- trunk/drivers/usb/gadget/epautoconf.c | 6 +- trunk/drivers/usb/gadget/f_fs.c | 2 +- trunk/drivers/usb/gadget/f_mass_storage.c | 60 +- trunk/drivers/usb/gadget/file_storage.c | 64 +- trunk/drivers/usb/gadget/fsl_qe_udc.c | 19 +- trunk/drivers/usb/gadget/fsl_udc_core.c | 4 +- trunk/drivers/usb/gadget/fusb300_udc.c | 4 +- trunk/drivers/usb/gadget/goku_udc.c | 3 +- trunk/drivers/usb/gadget/imx_udc.c | 2 +- trunk/drivers/usb/gadget/inode.c | 6 +- trunk/drivers/usb/gadget/langwell_udc.c | 2 +- trunk/drivers/usb/gadget/m66592-udc.c | 4 +- trunk/drivers/usb/gadget/mv_udc.h | 5 +- trunk/drivers/usb/gadget/mv_udc_core.c | 160 +-- trunk/drivers/usb/gadget/net2272.c | 4 +- trunk/drivers/usb/gadget/net2280.c | 4 +- trunk/drivers/usb/gadget/omap_udc.c | 3 +- trunk/drivers/usb/gadget/pch_udc.c | 4 +- trunk/drivers/usb/gadget/printer.c | 6 +- trunk/drivers/usb/gadget/pxa25x_udc.c | 2 +- trunk/drivers/usb/gadget/pxa27x_udc.c | 2 +- trunk/drivers/usb/gadget/r8a66597-udc.c | 4 +- trunk/drivers/usb/gadget/s3c-hsotg.c | 17 +- trunk/drivers/usb/gadget/s3c-hsudc.c | 19 +- trunk/drivers/usb/gadget/s3c2410_udc.c | 4 +- trunk/drivers/usb/gadget/udc-core.c | 26 +- trunk/drivers/usb/gadget/usbstring.c | 73 +- trunk/drivers/usb/host/ehci-au1xxx.c | 1 - trunk/drivers/usb/host/ehci-hcd.c | 64 +- trunk/drivers/usb/host/ehci-octeon.c | 2 - trunk/drivers/usb/host/ehci-omap.c | 2 - trunk/drivers/usb/host/ehci-ps3.c | 30 - trunk/drivers/usb/host/ehci-pxa168.c | 2 +- trunk/drivers/usb/host/ehci-q.c | 13 +- trunk/drivers/usb/host/ehci-s5p.c | 4 +- trunk/drivers/usb/host/ehci-vt8500.c | 2 - trunk/drivers/usb/host/ehci-w90x900.c | 2 - trunk/drivers/usb/host/ehci-xls.c | 2 +- trunk/drivers/usb/host/fhci-hcd.c | 12 +- trunk/drivers/usb/host/fsl-mph-dr-of.c | 12 +- trunk/drivers/usb/host/hwa-hc.c | 1 + trunk/drivers/usb/host/imx21-hcd.c | 13 +- trunk/drivers/usb/host/isp1760-hcd.c | 74 +- trunk/drivers/usb/host/isp1760-if.c | 6 +- trunk/drivers/usb/host/ohci-au1xxx.c | 5 +- trunk/drivers/usb/host/ohci-dbg.c | 18 +- trunk/drivers/usb/host/ohci-ep93xx.c | 2 + trunk/drivers/usb/host/ohci-hcd.c | 28 +- trunk/drivers/usb/host/ohci-hub.c | 7 +- trunk/drivers/usb/host/ohci-omap.c | 1 + trunk/drivers/usb/host/ohci-pci.c | 5 +- trunk/drivers/usb/host/ohci-pxa27x.c | 2 + trunk/drivers/usb/host/ohci-q.c | 8 +- trunk/drivers/usb/host/ohci-s3c2410.c | 55 +- trunk/drivers/usb/host/ohci-sh.c | 1 + trunk/drivers/usb/host/ohci-sm501.c | 1 + trunk/drivers/usb/host/ohci-spear.c | 1 + trunk/drivers/usb/host/ohci-tmio.c | 3 + trunk/drivers/usb/host/ohci-xls.c | 2 +- trunk/drivers/usb/host/ohci.h | 14 +- trunk/drivers/usb/host/oxu210hp-hcd.c | 19 +- trunk/drivers/usb/host/uhci-q.c | 2 +- trunk/drivers/usb/host/whci/qset.c | 4 +- trunk/drivers/usb/host/xhci-hub.c | 18 +- trunk/drivers/usb/host/xhci-ring.c | 16 +- trunk/drivers/usb/misc/isight_firmware.c | 6 +- trunk/drivers/usb/misc/usbtest.c | 1 + trunk/drivers/usb/musb/musb_core.c | 3 +- trunk/drivers/usb/musb/musb_gadget.c | 4 +- trunk/drivers/usb/otg/Kconfig | 20 +- trunk/drivers/usb/otg/fsl_otg.c | 13 +- trunk/drivers/usb/renesas_usbhs/common.c | 52 +- trunk/drivers/usb/renesas_usbhs/common.h | 9 +- trunk/drivers/usb/renesas_usbhs/fifo.c | 9 +- trunk/drivers/usb/renesas_usbhs/fifo.h | 3 +- trunk/drivers/usb/renesas_usbhs/mod.c | 4 +- trunk/drivers/usb/renesas_usbhs/mod_gadget.c | 193 +--- trunk/drivers/usb/renesas_usbhs/mod_host.c | 953 +++++++----------- trunk/drivers/usb/renesas_usbhs/pipe.c | 28 +- trunk/drivers/usb/renesas_usbhs/pipe.h | 1 - trunk/drivers/usb/serial/ChangeLog.history | 730 ++++++++++++++ trunk/drivers/usb/serial/belkin_sa.c | 43 + trunk/drivers/usb/serial/ch341.c | 3 +- trunk/drivers/usb/serial/cp210x.c | 58 +- trunk/drivers/usb/serial/cyberjack.c | 33 +- trunk/drivers/usb/serial/cypress_m8.c | 29 + trunk/drivers/usb/serial/digi_acceleport.c | 227 ++++- trunk/drivers/usb/serial/ftdi_sio.c | 4 - trunk/drivers/usb/serial/garmin_gps.c | 9 + trunk/drivers/usb/serial/generic.c | 83 +- trunk/drivers/usb/serial/io_edgeport.c | 3 + trunk/drivers/usb/serial/io_ti.c | 28 +- trunk/drivers/usb/serial/ipaq.c | 34 + trunk/drivers/usb/serial/ir-usb.c | 32 + trunk/drivers/usb/serial/iuu_phoenix.c | 3 +- trunk/drivers/usb/serial/keyspan.c | 90 ++ trunk/drivers/usb/serial/keyspan_pda.c | 66 +- trunk/drivers/usb/serial/kobil_sct.c | 25 + trunk/drivers/usb/serial/mct_u232.c | 46 + trunk/drivers/usb/serial/mos7720.c | 18 + trunk/drivers/usb/serial/mos7840.c | 4 + trunk/drivers/usb/serial/omninet.c | 51 +- trunk/drivers/usb/serial/opticon.c | 1 + trunk/drivers/usb/serial/oti6858.c | 23 +- trunk/drivers/usb/serial/pl2303.c | 17 +- trunk/drivers/usb/serial/sierra.c | 1 + trunk/drivers/usb/serial/symbolserial.c | 1 + trunk/drivers/usb/serial/ti_usb_3410_5052.c | 13 +- trunk/drivers/usb/serial/usb-serial.c | 98 +- trunk/drivers/usb/serial/usb_debug.c | 13 +- trunk/drivers/usb/serial/whiteheat.c | 58 ++ trunk/drivers/usb/storage/alauda.c | 2 +- trunk/drivers/usb/storage/cypress_atacb.c | 2 +- trunk/drivers/usb/storage/datafab.c | 2 +- trunk/drivers/usb/storage/ene_ub6250.c | 12 +- trunk/drivers/usb/storage/freecom.c | 2 +- trunk/drivers/usb/storage/isd200.c | 2 +- trunk/drivers/usb/storage/jumpshot.c | 2 +- trunk/drivers/usb/storage/karma.c | 2 +- trunk/drivers/usb/storage/onetouch.c | 2 +- trunk/drivers/usb/storage/realtek_cr.c | 14 +- trunk/drivers/usb/storage/sddr09.c | 2 +- trunk/drivers/usb/storage/sddr55.c | 2 +- trunk/drivers/usb/storage/shuttle_usbat.c | 2 +- trunk/drivers/usb/wusbcore/security.c | 2 +- trunk/drivers/uwb/est.c | 2 +- trunk/fs/fat/namei_vfat.c | 3 +- trunk/fs/nls/nls_base.c | 73 +- trunk/include/linux/nls.h | 5 +- trunk/include/linux/usb.h | 14 - trunk/include/linux/usb/ch11.h | 31 +- trunk/include/linux/usb/gadget.h | 14 +- trunk/include/linux/usb/hcd.h | 2 + trunk/include/linux/usb/renesas_usbhs.h | 10 +- trunk/include/linux/usb/serial.h | 11 +- 172 files changed, 3240 insertions(+), 2856 deletions(-) delete mode 100644 trunk/drivers/usb/dwc3/host.c create mode 100644 trunk/drivers/usb/serial/ChangeLog.history diff --git a/[refs] b/[refs] index e77fefbf44fe..9bc7d6d3f7ab 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 06e298b46417bc729b996396a068daf462e2ab62 +refs/heads/master: 772aed45b604c5ff171f0f12c12392d868333f79 diff --git a/trunk/Documentation/ABI/testing/sysfs-bus-usb b/trunk/Documentation/ABI/testing/sysfs-bus-usb index b4f548792e32..e647378e9e88 100644 --- a/trunk/Documentation/ABI/testing/sysfs-bus-usb +++ b/trunk/Documentation/ABI/testing/sysfs-bus-usb @@ -119,31 +119,6 @@ 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 diff --git a/trunk/Documentation/feature-removal-schedule.txt b/trunk/Documentation/feature-removal-schedule.txt index a7e4ac1202d6..3d849122b5b1 100644 --- a/trunk/Documentation/feature-removal-schedule.txt +++ b/trunk/Documentation/feature-removal-schedule.txt @@ -535,20 +535,6 @@ Why: In 3.0, we can now autodetect internal 3G device and already have information log when acer-wmi initial. Who: Lee, Chun-Yi ---------------------------- - -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 . -Who: Michal Nazarewicz - ---------------------------- What: The XFS nodelaylog mount option diff --git a/trunk/Documentation/kernel-parameters.txt b/trunk/Documentation/kernel-parameters.txt index 60cfc2531f1f..81c287fad79d 100644 --- a/trunk/Documentation/kernel-parameters.txt +++ b/trunk/Documentation/kernel-parameters.txt @@ -2632,10 +2632,6 @@ 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). diff --git a/trunk/drivers/hv/hv_kvp.c b/trunk/drivers/hv/hv_kvp.c index 0e8343f585bb..89f52440fcf4 100644 --- a/trunk/drivers/hv/hv_kvp.c +++ b/trunk/drivers/hv/hv_kvp.c @@ -212,13 +212,11 @@ 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), UTF16_HOST_ENDIAN, - (wchar_t *) kvp_data->data.key, - HV_KVP_EXCHANGE_MAX_KEY_SIZE / 2); + keylen = utf8s_to_utf16s(key_name, strlen(key_name), + (wchar_t *)kvp_data->data.key); kvp_data->data.key_size = 2*(keylen + 1); /* utf16 encoding */ - valuelen = utf8s_to_utf16s(value, strlen(value), UTF16_HOST_ENDIAN, - (wchar_t *) kvp_data->data.value, - HV_KVP_EXCHANGE_MAX_VALUE_SIZE / 2); + valuelen = utf8s_to_utf16s(value, strlen(value), + (wchar_t *)kvp_data->data.value); kvp_data->data.value_size = 2*(valuelen + 1); /* utf16 encoding */ kvp_data->data.value_type = REG_SZ; /* all our values are strings */ diff --git a/trunk/drivers/usb/Makefile b/trunk/drivers/usb/Makefile index 53a7bc07dd8d..75eca7645227 100644 --- a/trunk/drivers/usb/Makefile +++ b/trunk/drivers/usb/Makefile @@ -6,8 +6,6 @@ obj-$(CONFIG_USB) += core/ -obj-$(CONFIG_USB_OTG_UTILS) += otg/ - obj-$(CONFIG_USB_DWC3) += dwc3/ obj-$(CONFIG_USB_MON) += mon/ @@ -53,6 +51,7 @@ 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 diff --git a/trunk/drivers/usb/c67x00/c67x00-drv.c b/trunk/drivers/usb/c67x00/c67x00-drv.c index 6f3b6e267398..57ae44cd0b88 100644 --- a/trunk/drivers/usb/c67x00/c67x00-drv.c +++ b/trunk/drivers/usb/c67x00/c67x00-drv.c @@ -225,10 +225,21 @@ static struct platform_driver c67x00_driver = { .name = "c67x00", }, }; +MODULE_ALIAS("platform:c67x00"); + +static int __init c67x00_init(void) +{ + return platform_driver_register(&c67x00_driver); +} -module_platform_driver(c67x00_driver); +static void __exit c67x00_exit(void) +{ + platform_driver_unregister(&c67x00_driver); +} + +module_init(c67x00_init); +module_exit(c67x00_exit); MODULE_AUTHOR("Peter Korsgaard, Jan Veldeman, Grant Likely"); MODULE_DESCRIPTION("Cypress C67X00 USB Controller Driver"); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:c67x00"); diff --git a/trunk/drivers/usb/c67x00/c67x00-hcd.c b/trunk/drivers/usb/c67x00/c67x00-hcd.c index 75e47b860a53..d3e1356d091e 100644 --- a/trunk/drivers/usb/c67x00/c67x00-hcd.c +++ b/trunk/drivers/usb/c67x00/c67x00-hcd.c @@ -271,6 +271,7 @@ 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); } } diff --git a/trunk/drivers/usb/class/cdc-acm.c b/trunk/drivers/usb/class/cdc-acm.c index d9d9340abe60..e8c564a53346 100644 --- a/trunk/drivers/usb/class/cdc-acm.c +++ b/trunk/drivers/usb/class/cdc-acm.c @@ -58,62 +58,12 @@ static struct usb_driver acm_driver; static struct tty_driver *acm_tty_driver; static struct acm *acm_table[ACM_TTY_MINORS]; -static DEFINE_MUTEX(acm_table_lock); +static DEFINE_MUTEX(open_mutex); -/* - * acm_table accessors - */ - -/* - * 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); +#define ACM_READY(acm) (acm && acm->dev && acm->port.count) - 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); -} +static const struct tty_port_operations acm_port_ops = { +}; /* * Functions for ACM control messages. @@ -317,6 +267,9 @@ 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); @@ -476,7 +429,8 @@ 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); - schedule_work(&acm->work); + if (ACM_READY(acm)) + schedule_work(&acm->work); } static void acm_softint(struct work_struct *work) @@ -486,6 +440,8 @@ 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; @@ -497,122 +453,93 @@ static void acm_softint(struct work_struct *work) * TTY handlers */ -static int acm_tty_install(struct tty_driver *driver, struct tty_struct *tty) +static int acm_tty_open(struct tty_struct *tty, struct file *filp) { struct acm *acm; - int retval; - - dev_dbg(tty->dev, "%s\n", __func__); - - acm = acm_get_by_index(tty->index); - if (!acm) - return -ENODEV; + int rv = -ENODEV; - retval = tty_init_termios(tty); - if (retval) - goto error_init_termios; + mutex_lock(&open_mutex); - tty->driver_data = acm; + acm = acm_table[tty->index]; + if (!acm || !acm->dev) + goto out; + else + rv = 0; - /* 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__); + dev_dbg(&acm->control->dev, "%s\n", __func__); - return tty_port_open(&acm->port, tty, filp); -} + set_bit(TTY_NO_WRITE_SPLIT, &tty->flags); -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; + tty->driver_data = acm; + tty_port_tty_set(&acm->port, tty); - dev_dbg(&acm->control->dev, "%s\n", __func__); + if (usb_autopm_get_interface(acm->control) < 0) + goto early_bail; + else + acm->control->needs_remote_wakeup = 1; mutex_lock(&acm->mutex); - 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; + if (acm->port.count++) { + mutex_unlock(&acm->mutex); + usb_autopm_put_interface(acm->control); + goto out; + } 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 error_submit_urb; + goto bail_out; } - acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS; - if (acm_set_control(acm, acm->ctrlout) < 0 && + if (0 > acm_set_control(acm, acm->ctrlout = ACM_CTRL_DTR | ACM_CTRL_RTS) && (acm->ctrl_caps & USB_CDC_CAP_LINE)) - goto error_set_control; + goto bail_out; usb_autopm_put_interface(acm->control); if (acm_submit_read_urbs(acm, GFP_KERNEL)) - goto error_submit_read_urbs; + goto bail_out; - mutex_unlock(&acm->mutex); + set_bit(ASYNCB_INITIALIZED, &acm->port.flags); + rv = tty_port_block_til_ready(&acm->port, tty, filp); - return 0; + mutex_unlock(&acm->mutex); +out: + mutex_unlock(&open_mutex); + return rv; -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); -error_get_interface: -disconnected: +bail_out: + acm->port.count--; mutex_unlock(&acm->mutex); - return retval; + usb_autopm_put_interface(acm->control); +early_bail: + mutex_unlock(&open_mutex); + tty_port_tty_set(&acm->port, NULL); + return -EIO; } -static void acm_port_destruct(struct tty_port *port) +static void acm_tty_unregister(struct acm *acm) { - struct acm *acm = container_of(port, struct acm, port); - - dev_dbg(&acm->control->dev, "%s\n", __func__); + int i; 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_shutdown(struct tty_port *port) +static void acm_port_down(struct acm *acm) { - struct acm *acm = container_of(port, struct acm, port); int i; - dev_dbg(&acm->control->dev, "%s\n", __func__); - - mutex_lock(&acm->mutex); - if (!acm->disconnected) { + if (acm->dev) { usb_autopm_get_interface(acm->control); acm_set_control(acm, acm->ctrlout = 0); usb_kill_urb(acm->ctrlurb); @@ -623,28 +550,40 @@ static void acm_port_shutdown(struct tty_port *port) 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; - dev_dbg(&acm->control->dev, "%s\n", __func__); - tty_port_close(&acm->port, tty, filp); + + /* 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); } static int acm_tty_write(struct tty_struct *tty, @@ -656,6 +595,8 @@ 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; @@ -684,6 +625,8 @@ 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. @@ -694,11 +637,7 @@ 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 the device was unplugged then any remaining characters fell out - * of the connector ;) - */ - if (acm->disconnected) + if (!ACM_READY(acm)) return 0; /* * This is inaccurate (overcounts), but it works. @@ -710,6 +649,9 @@ 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); @@ -720,6 +662,9 @@ 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; @@ -734,7 +679,8 @@ 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", @@ -746,6 +692,9 @@ 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) | @@ -760,6 +709,9 @@ 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); @@ -776,6 +728,11 @@ 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; } @@ -799,6 +756,9 @@ 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 ? @@ -828,12 +788,6 @@ 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. */ @@ -1093,6 +1047,12 @@ static int acm_probe(struct usb_interface *intf, } 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) { @@ -1100,13 +1060,6 @@ static int acm_probe(struct usb_interface *intf, 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); @@ -1265,6 +1218,8 @@ static int acm_probe(struct usb_interface *intf, 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++) @@ -1279,7 +1234,6 @@ static int acm_probe(struct usb_interface *intf, 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; @@ -1305,16 +1259,12 @@ 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(&acm->mutex); - acm->disconnected = true; + mutex_lock(&open_mutex); if (acm->country_codes) { device_remove_file(&acm->control->dev, &dev_attr_wCountryCodes); @@ -1322,32 +1272,33 @@ 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); - tty_port_put(&acm->port); + 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); + } } #ifdef CONFIG_PM @@ -1374,10 +1325,16 @@ 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 (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) + if (acm->port.count) stop_data_traffic(acm); + mutex_unlock(&acm->mutex); return 0; } @@ -1396,7 +1353,8 @@ static int acm_resume(struct usb_interface *intf) if (cnt) return 0; - if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { + mutex_lock(&acm->mutex); + if (acm->port.count) { rv = usb_submit_urb(acm->ctrlurb, GFP_NOIO); spin_lock_irq(&acm->write_lock); @@ -1420,6 +1378,7 @@ static int acm_resume(struct usb_interface *intf) } err_out: + mutex_unlock(&acm->mutex); return rv; } @@ -1428,14 +1387,15 @@ static int acm_reset_resume(struct usb_interface *intf) struct acm *acm = usb_get_intfdata(intf); struct tty_struct *tty; - if (test_bit(ASYNCB_INITIALIZED, &acm->port.flags)) { + mutex_lock(&acm->mutex); + if (acm->port.count) { tty = tty_port_tty_get(&acm->port); if (tty) { tty_hangup(tty); tty_kref_put(tty); } } - + mutex_unlock(&acm->mutex); return acm_resume(intf); } @@ -1634,10 +1594,8 @@ 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, diff --git a/trunk/drivers/usb/class/cdc-acm.h b/trunk/drivers/usb/class/cdc-acm.h index 35ef887b7417..ca7937f26e27 100644 --- a/trunk/drivers/usb/class/cdc-acm.h +++ b/trunk/drivers/usb/class/cdc-acm.h @@ -101,7 +101,6 @@ 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) */ diff --git a/trunk/drivers/usb/core/devio.c b/trunk/drivers/usb/core/devio.c index d8cf06f186f2..e3beaf229ee3 100644 --- a/trunk/drivers/usb/core/devio.c +++ b/trunk/drivers/usb/core/devio.c @@ -86,7 +86,6 @@ struct async { void __user *userbuffer; void __user *userurb; struct urb *urb; - unsigned int mem_usage; int status; u32 secid; u8 bulk_addr; @@ -109,44 +108,8 @@ enum snoop_when { #define USB_DEVICE_DEV MKDEV(USB_DEVICE_MAJOR, 0) -/* 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)"); +#define MAX_USBFS_BUFFER_SIZE 16384 -/* 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) { @@ -290,7 +253,6 @@ static void free_async(struct async *as) kfree(as->urb->transfer_buffer); kfree(as->urb->setup_packet); usb_free_urb(as->urb); - usbfs_decrease_memory_usage(as->mem_usage); kfree(as); } @@ -830,15 +792,9 @@ 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) { - ret = -ENOMEM; - goto done; - } + if (!tbuf) + return -ENOMEM; tmo = ctrl.timeout; snoop(&dev->dev, "control urb: bRequestType=%02x " "bRequest=%02x wValue=%04x " @@ -850,8 +806,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)) { - ret = -EINVAL; - goto done; + free_page((unsigned long)tbuf); + return -EINVAL; } pipe = usb_rcvctrlpipe(dev, 0); snoop_urb(dev, NULL, pipe, ctrl.wLength, tmo, SUBMIT, NULL, 0); @@ -865,15 +821,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)) { - ret = -EFAULT; - goto done; + free_page((unsigned long)tbuf); + return -EFAULT; } } } else { if (ctrl.wLength) { if (copy_from_user(tbuf, ctrl.data, ctrl.wLength)) { - ret = -EFAULT; - goto done; + free_page((unsigned long)tbuf); + return -EFAULT; } } pipe = usb_sndctrlpipe(dev, 0); @@ -887,18 +843,14 @@ 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); } - ret = i; - done: - free_page((unsigned long) tbuf); - usbfs_decrease_memory_usage(PAGE_SIZE + sizeof(struct urb) + - sizeof(struct usb_ctrlrequest)); - return ret; + return i; } static int proc_bulk(struct dev_state *ps, void __user *arg) @@ -925,20 +877,15 @@ 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 >= USBFS_XFER_MAX) + if (len1 > MAX_USBFS_BUFFER_SIZE) return -EINVAL; - ret = usbfs_increase_memory_usage(len1 + sizeof(struct urb)); - if (ret) - return ret; - if (!(tbuf = kmalloc(len1, GFP_KERNEL))) { - ret = -ENOMEM; - goto done; - } + if (!(tbuf = kmalloc(len1, GFP_KERNEL))) + return -ENOMEM; tmo = bulk.timeout; if (bulk.ep & 0x80) { if (len1 && !access_ok(VERIFY_WRITE, bulk.data, len1)) { - ret = -EINVAL; - goto done; + kfree(tbuf); + return -EINVAL; } snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, NULL, 0); @@ -949,15 +896,15 @@ static int proc_bulk(struct dev_state *ps, void __user *arg) if (!i && len2) { if (copy_to_user(bulk.data, tbuf, len2)) { - ret = -EFAULT; - goto done; + kfree(tbuf); + return -EFAULT; } } } else { if (len1) { if (copy_from_user(tbuf, bulk.data, len1)) { - ret = -EFAULT; - goto done; + kfree(tbuf); + return -EFAULT; } } snoop_urb(dev, NULL, pipe, len1, tmo, SUBMIT, tbuf, len1); @@ -967,11 +914,10 @@ 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); - usbfs_decrease_memory_usage(len1 + sizeof(struct urb)); - return ret; + if (i < 0) + return i; + return len2; } static int proc_resetep(struct dev_state *ps, void __user *arg) @@ -1116,7 +1062,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 = NULL; + struct async *as; struct usb_ctrlrequest *dr = NULL; unsigned int u, totlen, isofrmlen; int ret, ifnum = -1; @@ -1149,30 +1095,32 @@ 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 */ - if (uurb->buffer_length < 8) + /* 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)) return -EINVAL; dr = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL); if (!dr) return -ENOMEM; if (copy_from_user(dr, uurb->buffer, 8)) { - ret = -EFAULT; - goto error; + kfree(dr); + return -EFAULT; } if (uurb->buffer_length < (le16_to_cpup(&dr->wLength) + 8)) { - ret = -EINVAL; - goto error; + kfree(dr); + return -EINVAL; } ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest, le16_to_cpup(&dr->wIndex)); - if (ret) - goto error; + if (ret) { + kfree(dr); + return ret; + } uurb->number_of_packets = 0; uurb->buffer_length = le16_to_cpup(&dr->wLength); uurb->buffer += 8; @@ -1190,7 +1138,6 @@ 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: @@ -1204,6 +1151,8 @@ 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: @@ -1211,6 +1160,8 @@ 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: @@ -1225,53 +1176,50 @@ 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)) { - ret = -EFAULT; - goto error; + kfree(isopkt); + return -EFAULT; } 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) { - ret = -EINVAL; - goto error; + kfree(isopkt); + return -EINVAL; } totlen += isopkt[u].length; } - u *= sizeof(struct usb_iso_packet_descriptor); + /* 3072 * 64 microframes */ + if (totlen > 196608) { + kfree(isopkt); + return -EINVAL; + } 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)) { - ret = -EFAULT; - goto error; + kfree(isopkt); + kfree(dr); + return -EFAULT; } as = alloc_async(uurb->number_of_packets); if (!as) { - ret = -ENOMEM; - goto error; + kfree(isopkt); + kfree(dr); + return -ENOMEM; } - 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) { - ret = -ENOMEM; - goto error; + kfree(isopkt); + kfree(dr); + free_async(as); + return -ENOMEM; } /* Isochronous input data may end up being discontiguous * if some of the packets are short. Clear the buffer so @@ -1305,7 +1253,6 @@ 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 || @@ -1321,7 +1268,6 @@ 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) @@ -1336,8 +1282,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)) { - ret = -EFAULT; - goto error; + free_async(as); + return -EFAULT; } } snoop_urb(ps->dev, as->userurb, as->urb->pipe, @@ -1383,16 +1329,10 @@ 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); - goto error; + free_async(as); + return ret; } 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) diff --git a/trunk/drivers/usb/core/driver.c b/trunk/drivers/usb/core/driver.c index 73abd8a0647d..45887a0ff873 100644 --- a/trunk/drivers/usb/core/driver.c +++ b/trunk/drivers/usb/core/driver.c @@ -45,12 +45,10 @@ 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 %x", &idVendor, &idProduct, - &bInterfaceClass); + fields = sscanf(buf, "%x %x", &idVendor, &idProduct); if (fields < 2) return -EINVAL; @@ -62,10 +60,6 @@ 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); diff --git a/trunk/drivers/usb/core/hcd-pci.c b/trunk/drivers/usb/core/hcd-pci.c index d136b8f4c8a7..a004db35f6d0 100644 --- a/trunk/drivers/usb/core/hcd-pci.c +++ b/trunk/drivers/usb/core/hcd-pci.c @@ -453,6 +453,10 @@ 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); diff --git a/trunk/drivers/usb/core/hcd.c b/trunk/drivers/usb/core/hcd.c index eb19cba34ac9..13222d352a61 100644 --- a/trunk/drivers/usb/core/hcd.c +++ b/trunk/drivers/usb/core/hcd.c @@ -658,7 +658,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb) len > offsetof(struct usb_device_descriptor, bDeviceProtocol)) ((struct usb_device_descriptor *) ubuf)-> - bDeviceProtocol = USB_HUB_PR_HS_SINGLE_TT; + bDeviceProtocol = 1; } /* any errors get returned through the urb completion */ @@ -1168,6 +1168,20 @@ 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); @@ -1398,10 +1412,11 @@ int usb_hcd_map_urb_for_dma(struct usb_hcd *hcd, struct urb *urb, ret = -EAGAIN; else urb->transfer_flags |= URB_DMA_MAP_SG; - urb->num_mapped_sgs = n; - if (n != urb->num_sgs) + if (n != urb->num_sgs) { + urb->num_sgs = n; urb->transfer_flags |= URB_DMA_SG_COMBINED; + } } else if (urb->sg) { struct scatterlist *sg = urb->sg; urb->transfer_dma = dma_map_page( @@ -2133,12 +2148,16 @@ 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 + } else { + set_bit(HCD_FLAG_SAW_IRQ, &hcd->flags); + if (hcd->shared_hcd) + set_bit(HCD_FLAG_SAW_IRQ, &hcd->shared_hcd->flags); rc = IRQ_HANDLED; + } local_irq_restore(flags); return rc; diff --git a/trunk/drivers/usb/core/hub.c b/trunk/drivers/usb/core/hub.c index 79d339e2e700..79781461eec9 100644 --- a/trunk/drivers/usb/core/hub.c +++ b/trunk/drivers/usb/core/hub.c @@ -84,7 +84,7 @@ struct usb_hub { static inline int hub_is_superspeed(struct usb_device *hdev) { - return (hdev->descriptor.bDeviceProtocol == USB_HUB_PR_SS); + return (hdev->descriptor.bDeviceProtocol == 3); } /* 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 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; + 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; } switch (wHubCharacteristics & HUB_CHAR_OCPM) { - 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; + 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; } 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 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; + 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; } /* Note 8 FS bit times == (8 bits / 12000000 bps) ~= 666ns */ @@ -1360,6 +1360,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id) return -ENODEV; } +/* No BKL needed */ static int hub_ioctl(struct usb_interface *intf, unsigned int code, void *user_data) { diff --git a/trunk/drivers/usb/core/usb.h b/trunk/drivers/usb/core/usb.h index 45e8479c377d..3888778582c4 100644 --- a/trunk/drivers/usb/core/usb.h +++ b/trunk/drivers/usb/core/usb.h @@ -132,6 +132,20 @@ 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; diff --git a/trunk/drivers/usb/dwc3/Kconfig b/trunk/drivers/usb/dwc3/Kconfig index d8f741f9e56e..3c1d67d324fd 100644 --- a/trunk/drivers/usb/dwc3/Kconfig +++ b/trunk/drivers/usb/dwc3/Kconfig @@ -1,10 +1,7 @@ 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. diff --git a/trunk/drivers/usb/dwc3/Makefile b/trunk/drivers/usb/dwc3/Makefile index 900ae74357f1..593d1dbc465b 100644 --- a/trunk/drivers/usb/dwc3/Makefile +++ b/trunk/drivers/usb/dwc3/Makefile @@ -4,8 +4,10 @@ ccflags-$(CONFIG_USB_DWC3_VERBOSE) += -DVERBOSE_DEBUG obj-$(CONFIG_USB_DWC3) += dwc3.o dwc3-y := core.o -dwc3-y += host.o -dwc3-y += gadget.o ep0.o + +ifneq ($(CONFIG_USB_GADGET_DWC3),) + dwc3-y += gadget.o ep0.o +endif ifneq ($(CONFIG_DEBUG_FS),) dwc3-y += debugfs.o diff --git a/trunk/drivers/usb/dwc3/core.c b/trunk/drivers/usb/dwc3/core.c index 455bb1e748d7..717ebc9ff941 100644 --- a/trunk/drivers/usb/dwc3/core.c +++ b/trunk/drivers/usb/dwc3/core.c @@ -59,60 +59,6 @@ #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 @@ -204,7 +150,7 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc) struct dwc3_event_buffer *evt; int i; - for (i = 0; i < dwc->num_event_buffers; i++) { + for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) { evt = dwc->ev_buffs[i]; if (evt) { dwc3_free_one_event_buffer(dwc, evt); @@ -216,25 +162,17 @@ 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 length) +static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned num, + 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; @@ -260,7 +198,7 @@ static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc) struct dwc3_event_buffer *evt; int n; - for (n = 0; n < dwc->num_event_buffers; n++) { + for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; 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, @@ -283,7 +221,7 @@ static void dwc3_event_buffers_cleanup(struct dwc3 *dwc) struct dwc3_event_buffer *evt; int n; - for (n = 0; n < dwc->num_event_buffers; n++) { + for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) { evt = dwc->ev_buffs[n]; dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0); dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0); @@ -347,32 +285,8 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc) cpu_relax(); } while (true); - 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); + ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_NUM, + DWC3_EVENT_BUFFERS_SIZE); if (ret) { dev_err(dwc->dev, "failed to allocate event buffers\n"); ret = -ENOMEM; @@ -385,6 +299,8 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc) goto err1; } + dwc3_cache_hwparams(dwc); + return 0; err1: @@ -404,17 +320,15 @@ 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"); @@ -429,8 +343,6 @@ 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) { @@ -458,17 +370,6 @@ 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); @@ -479,44 +380,13 @@ static int __devinit dwc3_probe(struct platform_device *pdev) goto err3; } - mode = DWC3_MODE(dwc->hwparams.hwparams0); - - switch (mode) { - case DWC3_MODE_DEVICE: - dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE); + if (features & DWC3_HAS_PERIPHERAL) { ret = dwc3_gadget_init(dwc); if (ret) { - dev_err(&pdev->dev, "failed to initialize gadget\n"); + dev_err(&pdev->dev, "failed to initialized 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) { @@ -529,21 +399,8 @@ static int __devinit dwc3_probe(struct platform_device *pdev) return 0; err5: - 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); + if (features & DWC3_HAS_PERIPHERAL) dwc3_gadget_exit(dwc); - break; - default: - /* do nothing */ - break; - } err4: dwc3_core_exit(dwc); @@ -563,8 +420,10 @@ static int __devinit dwc3_probe(struct platform_device *pdev) 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); @@ -573,21 +432,8 @@ static int __devexit dwc3_remove(struct platform_device *pdev) dwc3_debugfs_exit(dwc); - 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); + if (features & DWC3_HAS_PERIPHERAL) dwc3_gadget_exit(dwc); - break; - default: - /* do nothing */ - break; - } dwc3_core_exit(dwc); release_mem_region(res->start, resource_size(res)); @@ -597,15 +443,30 @@ 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 "); MODULE_LICENSE("Dual BSD/GPL"); MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver"); diff --git a/trunk/drivers/usb/dwc3/core.h b/trunk/drivers/usb/dwc3/core.h index 9e57f8e9bf17..29a8e1679e12 100644 --- a/trunk/drivers/usb/dwc3/core.h +++ b/trunk/drivers/usb/dwc3/core.h @@ -41,7 +41,6 @@ #include #include -#include #include #include #include @@ -53,6 +52,7 @@ /* 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 @@ -153,7 +153,6 @@ #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 @@ -348,7 +347,6 @@ 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; @@ -538,31 +536,6 @@ 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 @@ -576,24 +549,19 @@ struct dwc3_request { * @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 @@ -611,15 +579,12 @@ struct dwc3 { dma_addr_t ep0_trb_addr; dma_addr_t setup_buf_addr; dma_addr_t ep0_bounce_addr; - struct dwc3_request ep0_usb_req; + struct usb_request ep0_usb_req; /* device lock */ spinlock_t lock; struct device *dev; - struct platform_device *xhci; - struct resource *res; - - struct dwc3_event_buffer **ev_buffs; + struct dwc3_event_buffer *ev_buffs[DWC3_EVENT_BUFFERS_NUM]; struct dwc3_ep *eps[DWC3_ENDPOINTS_NUM]; struct usb_gadget gadget; @@ -630,11 +595,7 @@ 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 @@ -646,11 +607,10 @@ 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; @@ -805,16 +765,4 @@ 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 */ diff --git a/trunk/drivers/usb/dwc3/debugfs.c b/trunk/drivers/usb/dwc3/debugfs.c index 87d403df1f3f..da1ad77d8d51 100644 --- a/trunk/drivers/usb/dwc3/debugfs.c +++ b/trunk/drivers/usb/dwc3/debugfs.c @@ -44,12 +44,12 @@ #include #include #include -#include + +#include #include "core.h" #include "gadget.h" #include "io.h" -#include "debug.h" struct dwc3_register { const char *name; @@ -405,75 +405,6 @@ 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; @@ -481,7 +412,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; } @@ -494,14 +425,6 @@ 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: diff --git a/trunk/drivers/usb/dwc3/dwc3-omap.c b/trunk/drivers/usb/dwc3/dwc3-omap.c index 3274ac8f1200..062552b5fc8a 100644 --- a/trunk/drivers/usb/dwc3/dwc3-omap.c +++ b/trunk/drivers/usb/dwc3/dwc3-omap.c @@ -48,7 +48,6 @@ #include #include -#include "core.h" #include "io.h" /* @@ -201,7 +200,6 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) struct dwc3_omap *omap; struct resource *res; - int devid; int ret = -ENOMEM; int irq; @@ -238,20 +236,16 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev) goto err1; } - devid = dwc3_get_device_id(); - if (devid < 0) - goto err2; - - dwc3 = platform_device_alloc("dwc3", devid); + dwc3 = platform_device_alloc("dwc3-omap", -1); if (!dwc3) { dev_err(&pdev->dev, "couldn't allocate dwc3 device\n"); - goto err3; + goto err2; } context = kzalloc(resource_size(res), GFP_KERNEL); if (!context) { dev_err(&pdev->dev, "couldn't allocate dwc3 context memory\n"); - goto err4; + goto err3; } spin_lock_init(&omap->lock); @@ -305,7 +299,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 err5; + goto err4; } /* enable all IRQs */ @@ -328,28 +322,25 @@ 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 err6; + goto err5; } ret = platform_device_add(dwc3); if (ret) { dev_err(&pdev->dev, "failed to register dwc3 device\n"); - goto err6; + goto err5; } return 0; -err6: - free_irq(omap->irq, omap); - err5: - kfree(omap->context); + free_irq(omap->irq, omap); err4: - platform_device_put(dwc3); + kfree(omap->context); err3: - dwc3_put_device_id(devid); + platform_device_put(dwc3); err2: iounmap(base); @@ -367,7 +358,6 @@ 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); @@ -394,9 +384,18 @@ static struct platform_driver dwc3_omap_driver = { }, }; -module_platform_driver(dwc3_omap_driver); - -MODULE_ALIAS("platform:omap-dwc3"); MODULE_AUTHOR("Felipe Balbi "); 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); diff --git a/trunk/drivers/usb/dwc3/dwc3-pci.c b/trunk/drivers/usb/dwc3/dwc3-pci.c index cd1429f168c2..f77c00042685 100644 --- a/trunk/drivers/usb/dwc3/dwc3-pci.c +++ b/trunk/drivers/usb/dwc3/dwc3-pci.c @@ -42,17 +42,52 @@ #include #include -#include "core.h" - /* FIXME define these in */ #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) { @@ -79,11 +114,11 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci, pci_set_power_state(pci, PCI_D0); pci_set_master(pci); - devid = dwc3_get_device_id(); + devid = dwc3_pci_get_device_id(glue); if (devid < 0) goto err2; - dwc3 = platform_device_alloc("dwc3", devid); + dwc3 = platform_device_alloc("dwc3-pci", devid); if (!dwc3) { dev_err(&pci->dev, "couldn't allocate dwc3 device\n"); goto err3; @@ -128,7 +163,7 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci, platform_device_put(dwc3); err3: - dwc3_put_device_id(devid); + dwc3_pci_put_device_id(glue, devid); err2: pci_disable_device(pci); @@ -144,7 +179,7 @@ static void __devexit dwc3_pci_remove(struct pci_dev *pci) { struct dwc3_pci *glue = pci_get_drvdata(pci); - dwc3_put_device_id(glue->dwc3->id); + dwc3_pci_put_device_id(glue, glue->dwc3->id); platform_device_unregister(glue->dwc3); pci_set_drvdata(pci, NULL); pci_disable_device(pci); @@ -161,7 +196,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 = "dwc3-pci", + .name = "pci-dwc3", .id_table = dwc3_pci_id_table, .probe = dwc3_pci_probe, .remove = __devexit_p(dwc3_pci_remove), diff --git a/trunk/drivers/usb/dwc3/ep0.c b/trunk/drivers/usb/dwc3/ep0.c index 2f51de57593a..69a4e43ddf59 100644 --- a/trunk/drivers/usb/dwc3/ep0.c +++ b/trunk/drivers/usb/dwc3/ep0.c @@ -48,13 +48,13 @@ #include #include -#include #include "core.h" #include "gadget.h" #include "io.h" -static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum); +static void dwc3_ep0_inspect_setup(struct dwc3 *dwc, + const struct dwc3_event_depevt *event); static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state) { @@ -125,8 +125,6 @@ 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; @@ -145,7 +143,9 @@ 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,13 +165,6 @@ 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; @@ -197,7 +190,9 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, } /* we share one TRB for ep0/1 */ - if (!list_empty(&dep->request_list)) { + if (!list_empty(&dwc->eps[0]->request_list) || + !list_empty(&dwc->eps[1]->request_list) || + dwc->ep0_status_pending) { ret = -EBUSY; goto out; } @@ -219,9 +214,8 @@ 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(dep, 1); - dep->flags = DWC3_EP_ENABLED; - dwc->delayed_status = false; + __dwc3_gadget_ep_set_halt(dwc->eps[0], 1); + dwc->eps[0]->flags = DWC3_EP_ENABLED; if (!list_empty(&dep->request_list)) { struct dwc3_request *req; @@ -260,14 +254,17 @@ static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le) return NULL; } -static void dwc3_ep0_status_cmpl(struct usb_ep *ep, struct usb_request *req) +static void dwc3_ep0_send_status_response(struct dwc3 *dwc) { + 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; @@ -294,7 +291,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, 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; @@ -305,14 +302,10 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc, 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; - 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); + return 0; } static int dwc3_ep0_handle_feature(struct dwc3 *dwc, @@ -403,7 +396,8 @@ 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, wIndex); + + dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex); if (!dep) return -EINVAL; ret = __dwc3_gadget_ep_set_halt(dep, set); @@ -428,15 +422,8 @@ static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) u32 reg; addr = le16_to_cpu(ctrl->wValue); - if (addr > 127) { - dev_dbg(dwc->dev, "invalid device address %d\n", addr); + if (addr > 127) 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); @@ -486,10 +473,8 @@ 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 ret; + return 0; } static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl) @@ -552,9 +537,6 @@ 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; @@ -568,21 +550,27 @@ 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 *ep0; + struct dwc3_ep *dep; u32 transferred; u8 epnum; epnum = event->endpoint_number; - ep0 = dwc->eps[0]; + dep = dwc->eps[epnum]; dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS; - r = next_request(&ep0->request_list); - ur = &r->request; + 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; + } 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); @@ -603,7 +591,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(ep0, r, 0); + dwc3_gadget_giveback(dep, r, 0); } } @@ -631,7 +619,6 @@ 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: @@ -656,6 +643,7 @@ 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); } @@ -667,6 +655,12 @@ 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"); @@ -680,6 +674,7 @@ 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, @@ -711,79 +706,35 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc, WARN_ON(ret < 0); } -static int dwc3_ep0_start_control_status(struct dwc3_ep *dep) +static void dwc3_ep0_do_control_status(struct dwc3 *dwc, + const struct dwc3_event_depevt *event) { - 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; - return dwc3_ep0_start_trans(dwc, dep->number, + ret = dwc3_ep0_start_trans(dwc, event->endpoint_number, dwc->ctrl_req_addr, 0, type); -} - -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)); + WARN_ON(ret < 0); } 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, @@ -813,8 +764,6 @@ 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, @@ -823,19 +772,12 @@ static void dwc3_ep0_xfernotready(struct dwc3 *dwc, dwc3_ep0_stall_and_restart(dwc); return; } - - 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); + dwc3_ep0_do_control_status(dwc, event); } } void dwc3_ep0_interrupt(struct dwc3 *dwc, - const struct dwc3_event_depevt *event) + const const struct dwc3_event_depevt *event) { u8 epnum = event->endpoint_number; diff --git a/trunk/drivers/usb/dwc3/gadget.c b/trunk/drivers/usb/dwc3/gadget.c index 36c61e80f323..25dbd8614e72 100644 --- a/trunk/drivers/usb/dwc3/gadget.c +++ b/trunk/drivers/usb/dwc3/gadget.c @@ -251,8 +251,7 @@ 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_ss_ep_comp_descriptor *comp_desc) + const struct usb_endpoint_descriptor *desc) { struct dwc3_gadget_ep_cmd_params params; @@ -265,8 +264,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 (comp_desc && USB_SS_MAX_STREAMS(comp_desc->bmAttributes) - && usb_endpoint_xfer_bulk(desc)) { + if (usb_endpoint_xfer_bulk(desc) && dep->endpoint.max_streams) { params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE | DWC3_DEPCFG_STREAM_EVENT_EN; dep->stream_capable = true; @@ -319,8 +317,7 @@ 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_ss_ep_comp_descriptor *comp_desc) + const struct usb_endpoint_descriptor *desc) { struct dwc3 *dwc = dep->dwc; u32 reg; @@ -332,7 +329,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep, return ret; } - ret = dwc3_gadget_set_ep_config(dwc, dep, desc, comp_desc); + ret = dwc3_gadget_set_ep_config(dwc, dep, desc); if (ret) return ret; @@ -346,7 +343,6 @@ 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; @@ -409,7 +405,6 @@ 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; @@ -478,7 +473,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, ep->comp_desc); + ret = __dwc3_gadget_ep_enable(dep, desc); spin_unlock_irqrestore(&dwc->lock, flags); return ret; @@ -750,9 +745,8 @@ 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); - - WARN_ON_ONCE(!dep->res_trans_idx); - + if (!dep->res_trans_idx) + printk_once(KERN_ERR "%s() res_trans_idx is invalid\n", __func__); return 0; } @@ -1161,9 +1155,35 @@ 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 |= dwc->maximum_speed; + reg |= DWC3_DCFG_SUPERSPEED; dwc3_writel(dwc->regs, DWC3_DCFG, reg); dwc->start_config_issued = false; @@ -1172,14 +1192,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, NULL); + ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc); 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, NULL); + ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); goto err1; @@ -1270,10 +1290,11 @@ static int __devinit dwc3_gadget_init_endpoints(struct dwc3 *dwc) &dwc->gadget.ep_list); ret = dwc3_alloc_trb_pool(dep); - if (ret) + if (ret) { + dev_err(dwc->dev, "%s: failed to allocate TRB pool\n", dep->name); return ret; + } } - INIT_LIST_HEAD(&dep->request_list); INIT_LIST_HEAD(&dep->req_queued); } @@ -1313,10 +1334,8 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep, do { req = next_request(&dep->req_queued); - if (!req) { - WARN_ON_ONCE(1); - return 1; - } + if (!req) + break; dwc3_trb_to_nat(req->trb, &trb); @@ -1381,31 +1400,6 @@ 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, @@ -1645,7 +1639,6 @@ 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) @@ -1682,37 +1675,6 @@ 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); - } - /* Enable PHYs */ dwc3_gadget_usb2_phy_power(dwc, true); dwc3_gadget_usb3_phy_power(dwc, true); @@ -1793,22 +1755,6 @@ 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; @@ -1835,14 +1781,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, NULL); + ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc); 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, NULL); + ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc); if (ret) { dev_err(dwc->dev, "failed to enable %s\n", dep->name); return; @@ -1872,55 +1818,8 @@ static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc) static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc, unsigned int evtinfo) { - 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; + /* The fith bit says SuperSpeed yes or no. */ + dwc->link_state = evtinfo & DWC3_LINK_STATE_MASK; dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state); } @@ -2026,7 +1925,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc) spin_lock(&dwc->lock); - for (i = 0; i < dwc->num_event_buffers; i++) { + for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) { irqreturn_t status; status = dwc3_process_event_buf(dwc, i); @@ -2087,7 +1986,7 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) dev_set_name(&dwc->gadget.dev, "gadget"); dwc->gadget.ops = &dwc3_gadget_ops; - dwc->gadget.max_speed = USB_SPEED_SUPER; + dwc->gadget.is_dualspeed = true; dwc->gadget.speed = USB_SPEED_UNKNOWN; dwc->gadget.dev.parent = dwc->dev; @@ -2177,6 +2076,7 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc) 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); @@ -2184,6 +2084,9 @@ 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, diff --git a/trunk/drivers/usb/dwc3/gadget.h b/trunk/drivers/usb/dwc3/gadget.h index d97f467d41cc..71145a449d99 100644 --- a/trunk/drivers/usb/dwc3/gadget.h +++ b/trunk/drivers/usb/dwc3/gadget.h @@ -79,6 +79,19 @@ 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) @@ -97,11 +110,23 @@ 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/trunk/drivers/usb/dwc3/host.c b/trunk/drivers/usb/dwc3/host.c deleted file mode 100644 index 7cfe211b6c37..000000000000 --- a/trunk/drivers/usb/dwc3/host.c +++ /dev/null @@ -1,102 +0,0 @@ -/** - * host.c - DesignWare USB3 DRD Controller Host Glue - * - * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com - * - * Authors: Felipe Balbi , - * - * 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 - -#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); -} diff --git a/trunk/drivers/usb/dwc3/io.h b/trunk/drivers/usb/dwc3/io.h index 071d561f3e68..bc957db1ea4b 100644 --- a/trunk/drivers/usb/dwc3/io.h +++ b/trunk/drivers/usb/dwc3/io.h @@ -39,7 +39,7 @@ #ifndef __DRIVERS_USB_DWC3_IO_H #define __DRIVERS_USB_DWC3_IO_H -#include +#include static inline u32 dwc3_readl(void __iomem *base, u32 offset) { diff --git a/trunk/drivers/usb/gadget/Kconfig b/trunk/drivers/usb/gadget/Kconfig index 93f6c808f570..23a447373c51 100644 --- a/trunk/drivers/usb/gadget/Kconfig +++ b/trunk/drivers/usb/gadget/Kconfig @@ -15,7 +15,6 @@ 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. @@ -235,6 +234,7 @@ 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 @@ -318,6 +318,18 @@ config USB_PXA_U2O 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. + # # Controllers available in both integrated and discrete versions # diff --git a/trunk/drivers/usb/gadget/amd5536udc.c b/trunk/drivers/usb/gadget/amd5536udc.c index e9a2c5c44454..45f422ac103f 100644 --- a/trunk/drivers/usb/gadget/amd5536udc.c +++ b/trunk/drivers/usb/gadget/amd5536udc.c @@ -1959,7 +1959,7 @@ static int amd5536_start(struct usb_gadget_driver *driver, u32 tmp; if (!driver || !bind || !driver->setup - || driver->max_speed < USB_SPEED_HIGH) + || driver->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.max_speed = USB_SPEED_HIGH; + dev->gadget.is_dualspeed = 1; /* init registers, interrupts, ... */ startup_registers(dev); diff --git a/trunk/drivers/usb/gadget/at91_udc.c b/trunk/drivers/usb/gadget/at91_udc.c index ac41f71bf9ca..8efe0fa9228d 100644 --- a/trunk/drivers/usb/gadget/at91_udc.c +++ b/trunk/drivers/usb/gadget/at91_udc.c @@ -1633,7 +1633,7 @@ static int at91_start(struct usb_gadget_driver *driver, unsigned long flags; if (!driver - || driver->max_speed < USB_SPEED_FULL + || driver->speed < USB_SPEED_FULL || !bind || !driver->setup) { DBG("bad parameter.\n"); diff --git a/trunk/drivers/usb/gadget/atmel_usba_udc.c b/trunk/drivers/usb/gadget/atmel_usba_udc.c index e2fb6d583bd9..271a9d873608 100644 --- a/trunk/drivers/usb/gadget/atmel_usba_udc.c +++ b/trunk/drivers/usb/gadget/atmel_usba_udc.c @@ -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), - .max_speed = USB_SPEED_HIGH, + .is_dualspeed = 1, .name = "atmel_usba_udc", .dev = { .init_name = "gadget", diff --git a/trunk/drivers/usb/gadget/ci13xxx_udc.c b/trunk/drivers/usb/gadget/ci13xxx_udc.c index 27e313718422..9a0c3979ff43 100644 --- a/trunk/drivers/usb/gadget/ci13xxx_udc.c +++ b/trunk/drivers/usb/gadget/ci13xxx_udc.c @@ -182,16 +182,6 @@ 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 @@ -450,13 +440,12 @@ static int hw_ep_get_halt(int num, int dir) /** * hw_test_and_clear_setup_status: test & clear setup status (execute without * interruption) - * @n: endpoint number + * @n: bit number (endpoint) * * 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)); } @@ -652,13 +641,12 @@ static int hw_register_write(u16 addr, u32 data) /** * hw_test_and_clear_complete: test & clear complete status (execute without * interruption) - * @n: endpoint number + * @n: bit number (endpoint) * * 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)); } @@ -766,11 +754,8 @@ 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)); + gadget->is_dualspeed); 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", @@ -813,7 +798,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->max_speed); + driver->speed); return n; } @@ -2578,7 +2563,9 @@ static int ci13xxx_start(struct usb_gadget_driver *driver, if (driver == NULL || bind == NULL || driver->setup == NULL || - driver->disconnect == NULL) + driver->disconnect == NULL || + driver->suspend == NULL || + driver->resume == NULL) return -EINVAL; else if (udc == NULL) return -ENODEV; @@ -2706,6 +2693,8 @@ 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; @@ -2804,7 +2793,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 && udc->driver->resume) { + if (udc->suspended) { spin_unlock(udc->lock); udc->driver->resume(&udc->gadget); spin_lock(udc->lock); @@ -2818,8 +2807,7 @@ static irqreturn_t udc_irq(void) isr_tr_complete_handler(udc); } if (USBi_SLI & intr) { - if (udc->gadget.speed != USB_SPEED_UNKNOWN && - udc->driver->suspend) { + if (udc->gadget.speed != USB_SPEED_UNKNOWN) { udc->suspended = 1; spin_unlock(udc->lock); udc->driver->suspend(&udc->gadget); @@ -2883,7 +2871,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.max_speed = USB_SPEED_HIGH; + udc->gadget.is_dualspeed = 1; udc->gadget.is_otg = 0; udc->gadget.name = driver->name; diff --git a/trunk/drivers/usb/gadget/ci13xxx_udc.h b/trunk/drivers/usb/gadget/ci13xxx_udc.h index f4871e1fac59..23707775cb43 100644 --- a/trunk/drivers/usb/gadget/ci13xxx_udc.h +++ b/trunk/drivers/usb/gadget/ci13xxx_udc.h @@ -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[hw_ep_max / 2] +#define ep0in ci13xxx_ep[16] u8 remote_wakeup; /* Is remote wakeup feature enabled by the host? */ u8 suspended; /* suspended by the host */ diff --git a/trunk/drivers/usb/gadget/composite.c b/trunk/drivers/usb/gadget/composite.c index a95de6a4a134..f71b0787983f 100644 --- a/trunk/drivers/usb/gadget/composite.c +++ b/trunk/drivers/usb/gadget/composite.c @@ -1535,9 +1535,9 @@ composite_resume(struct usb_gadget *gadget) static struct usb_gadget_driver composite_driver = { #ifdef CONFIG_USB_GADGET_SUPERSPEED - .max_speed = USB_SPEED_SUPER, + .speed = USB_SPEED_SUPER, #else - .max_speed = USB_SPEED_HIGH, + .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.max_speed = - min_t(u8, composite_driver.max_speed, driver->max_speed); + composite_driver.speed = min((u8)composite_driver.speed, + (u8)driver->max_speed); composite = driver; composite_gadget_bind = bind; diff --git a/trunk/drivers/usb/gadget/dbgp.c b/trunk/drivers/usb/gadget/dbgp.c index 19d7bb0df75a..6256420089f3 100644 --- a/trunk/drivers/usb/gadget/dbgp.c +++ b/trunk/drivers/usb/gadget/dbgp.c @@ -404,7 +404,7 @@ static int dbgp_setup(struct usb_gadget *gadget, static struct usb_gadget_driver dbgp_driver = { .function = "dbgp", - .max_speed = USB_SPEED_HIGH, + .speed = USB_SPEED_HIGH, .unbind = dbgp_unbind, .setup = dbgp_setup, .disconnect = dbgp_disconnect, diff --git a/trunk/drivers/usb/gadget/dummy_hcd.c b/trunk/drivers/usb/gadget/dummy_hcd.c index db815c2da7ed..ab8f1b488d54 100644 --- a/trunk/drivers/usb/gadget/dummy_hcd.c +++ b/trunk/drivers/usb/gadget/dummy_hcd.c @@ -823,18 +823,19 @@ 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->max_speed; + dum->gadget.speed = dum->driver->speed; else if (mod_data.is_high_speed) dum->gadget.speed = min_t(u8, USB_SPEED_HIGH, - dum->driver->max_speed); + dum->driver->speed); else dum->gadget.speed = USB_SPEED_FULL; dummy_udc_udpate_ep0(dum); - if (dum->gadget.speed < dum->driver->max_speed) + if (dum->gadget.speed < dum->driver->speed) dev_dbg(udc_dev(dum), "This device can perform faster" - " if you connect it to a %s port...\n", - usb_speed_string(dum->driver->max_speed)); + " if you connect it to a %s port...\n", + (dum->driver->speed == USB_SPEED_SUPER ? + "SuperSpeed" : "HighSpeed")); } dum_hcd = gadget_to_dummy_hcd(_gadget); @@ -897,7 +898,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->max_speed == USB_SPEED_UNKNOWN) + if (driver->speed == USB_SPEED_UNKNOWN) return -EINVAL; /* @@ -976,7 +977,7 @@ static int dummy_udc_probe (struct platform_device *pdev) dum->gadget.name = gadget_name; dum->gadget.ops = &dummy_ops; - dum->gadget.max_speed = USB_SPEED_SUPER; + dum->gadget.is_dualspeed = 1; dev_set_name(&dum->gadget.dev, "gadget"); dum->gadget.dev.parent = &pdev->dev; diff --git a/trunk/drivers/usb/gadget/epautoconf.c b/trunk/drivers/usb/gadget/epautoconf.c index 38bcbfb91f62..596a0b464e61 100644 --- a/trunk/drivers/usb/gadget/epautoconf.c +++ b/trunk/drivers/usb/gadget/epautoconf.c @@ -152,7 +152,7 @@ ep_matches ( switch (type) { case USB_ENDPOINT_XFER_INT: /* INT: limit 64 bytes full speed, 1024 high/super speed */ - if (!gadget_is_dualspeed(gadget) && max > 64) + if (!gadget->is_dualspeed && max > 64) return 0; /* FALLTHROUGH */ @@ -160,12 +160,12 @@ ep_matches ( /* ISO: limit 1023 bytes full speed, 1024 high/super speed */ if (ep->maxpacket < max) return 0; - if (!gadget_is_dualspeed(gadget) && max > 1023) + if (!gadget->is_dualspeed && max > 1023) return 0; /* BOTH: "high bandwidth" works only at high speed */ if ((desc->wMaxPacketSize & cpu_to_le16(3<<11))) { - if (!gadget_is_dualspeed(gadget)) + if (!gadget->is_dualspeed) return 0; /* configure your hardware with enough buffering!! */ } diff --git a/trunk/drivers/usb/gadget/f_fs.c b/trunk/drivers/usb/gadget/f_fs.c index da9d04815ea5..acb38004eec0 100644 --- a/trunk/drivers/usb/gadget/f_fs.c +++ b/trunk/drivers/usb/gadget/f_fs.c @@ -1408,7 +1408,7 @@ static int ffs_epfiles_create(struct ffs_data *ffs) ENTER(); count = ffs->eps_count; - epfiles = kcalloc(count, sizeof(*epfiles), GFP_KERNEL); + epfiles = kzalloc(count * sizeof *epfiles, GFP_KERNEL); if (!epfiles) return -ENOMEM; diff --git a/trunk/drivers/usb/gadget/f_mass_storage.c b/trunk/drivers/usb/gadget/f_mass_storage.c index a18ebeed82b5..c39d58860fa0 100644 --- a/trunk/drivers/usb/gadget/f_mass_storage.c +++ b/trunk/drivers/usb/gadget/f_mass_storage.c @@ -1873,14 +1873,17 @@ static int check_command(struct fsg_common *common, int cmnd_size, common->lun, lun); /* Check the LUN */ - curlun = common->curlun; - if (curlun) { + if (common->lun < common->nluns) { + curlun = &common->luns[common->lun]; + common->curlun = 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; /* @@ -1926,17 +1929,6 @@ 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; @@ -2019,9 +2011,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; - reply = check_command_size_in_blocks(common, 6, - DATA_DIR_TO_HOST, + common->data_size_from_cmnd = (i == 0 ? 256 : i) << + common->curlun->blkbits; + reply = check_command(common, 6, DATA_DIR_TO_HOST, (7<<1) | (1<<4), 1, "READ(6)"); if (reply == 0) @@ -2030,9 +2022,9 @@ static int do_scsi_command(struct fsg_common *common) case READ_10: common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); - reply = check_command_size_in_blocks(common, 10, - DATA_DIR_TO_HOST, + get_unaligned_be16(&common->cmnd[7]) << + common->curlun->blkbits; + reply = check_command(common, 10, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (3<<7), 1, "READ(10)"); if (reply == 0) @@ -2041,9 +2033,9 @@ static int do_scsi_command(struct fsg_common *common) case READ_12: common->data_size_from_cmnd = - get_unaligned_be32(&common->cmnd[6]); - reply = check_command_size_in_blocks(common, 12, - DATA_DIR_TO_HOST, + get_unaligned_be32(&common->cmnd[6]) << + common->curlun->blkbits; + reply = check_command(common, 12, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "READ(12)"); if (reply == 0) @@ -2142,9 +2134,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; - reply = check_command_size_in_blocks(common, 6, - DATA_DIR_FROM_HOST, + common->data_size_from_cmnd = (i == 0 ? 256 : i) << + common->curlun->blkbits; + reply = check_command(common, 6, DATA_DIR_FROM_HOST, (7<<1) | (1<<4), 1, "WRITE(6)"); if (reply == 0) @@ -2153,9 +2145,9 @@ static int do_scsi_command(struct fsg_common *common) case WRITE_10: common->data_size_from_cmnd = - get_unaligned_be16(&common->cmnd[7]); - reply = check_command_size_in_blocks(common, 10, - DATA_DIR_FROM_HOST, + get_unaligned_be16(&common->cmnd[7]) << + common->curlun->blkbits; + reply = check_command(common, 10, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (3<<7), 1, "WRITE(10)"); if (reply == 0) @@ -2164,9 +2156,9 @@ static int do_scsi_command(struct fsg_common *common) case WRITE_12: common->data_size_from_cmnd = - get_unaligned_be32(&common->cmnd[6]); - reply = check_command_size_in_blocks(common, 12, - DATA_DIR_FROM_HOST, + get_unaligned_be32(&common->cmnd[6]) << + common->curlun->blkbits; + reply = check_command(common, 12, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "WRITE(12)"); if (reply == 0) @@ -2281,10 +2273,6 @@ 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; } @@ -2775,7 +2763,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 = kcalloc(nluns, sizeof(*curlun), GFP_KERNEL); + curlun = kzalloc(nluns * sizeof *curlun, GFP_KERNEL); if (unlikely(!curlun)) { rc = -ENOMEM; goto error_release; diff --git a/trunk/drivers/usb/gadget/file_storage.c b/trunk/drivers/usb/gadget/file_storage.c index e0f30fc70e45..11b5196284ae 100644 --- a/trunk/drivers/usb/gadget/file_storage.c +++ b/trunk/drivers/usb/gadget/file_storage.c @@ -2297,17 +2297,19 @@ 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 */ - curlun = fsg->curlun; - if (curlun) { + if (fsg->lun < fsg->nluns) { + fsg->curlun = curlun = &fsg->luns[fsg->lun]; 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 @@ -2349,16 +2351,6 @@ 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) { @@ -2433,27 +2425,26 @@ 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; - if ((reply = check_command_size_in_blocks(fsg, 6, - DATA_DIR_TO_HOST, + fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits; + if ((reply = check_command(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]); - if ((reply = check_command_size_in_blocks(fsg, 10, - DATA_DIR_TO_HOST, + fsg->data_size_from_cmnd = + get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits; + if ((reply = check_command(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]); - if ((reply = check_command_size_in_blocks(fsg, 12, - DATA_DIR_TO_HOST, + fsg->data_size_from_cmnd = + get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits; + if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "READ(12)")) == 0) reply = do_read(fsg); @@ -2538,27 +2529,26 @@ 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; - if ((reply = check_command_size_in_blocks(fsg, 6, - DATA_DIR_FROM_HOST, + fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits; + if ((reply = check_command(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]); - if ((reply = check_command_size_in_blocks(fsg, 10, - DATA_DIR_FROM_HOST, + fsg->data_size_from_cmnd = + get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits; + if ((reply = check_command(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]); - if ((reply = check_command_size_in_blocks(fsg, 12, - DATA_DIR_FROM_HOST, + fsg->data_size_from_cmnd = + get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits; + if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST, (1<<1) | (0xf<<2) | (0xf<<6), 1, "WRITE(12)")) == 0) reply = do_write(fsg); @@ -2725,17 +2715,7 @@ 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; } @@ -3604,7 +3584,7 @@ static void fsg_resume(struct usb_gadget *gadget) /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver fsg_driver = { - .max_speed = USB_SPEED_SUPER, + .speed = USB_SPEED_SUPER, .function = (char *) fsg_string_product, .unbind = fsg_unbind, .disconnect = fsg_disconnect, diff --git a/trunk/drivers/usb/gadget/fsl_qe_udc.c b/trunk/drivers/usb/gadget/fsl_qe_udc.c index b95697c03d07..e00cf92409ce 100644 --- a/trunk/drivers/usb/gadget/fsl_qe_udc.c +++ b/trunk/drivers/usb/gadget/fsl_qe_udc.c @@ -2336,7 +2336,7 @@ static int fsl_qe_start(struct usb_gadget_driver *driver, if (!udc_controller) return -ENODEV; - if (!driver || driver->max_speed < USB_SPEED_FULL + if (!driver || driver->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 = driver->max_speed; + udc_controller->gadget.speed = (enum usb_device_speed)(driver->speed); spin_unlock_irqrestore(&udc_controller->lock, flags); retval = bind(&udc_controller->gadget); @@ -2814,7 +2814,20 @@ static struct platform_driver udc_driver = { #endif }; -module_platform_driver(udc_driver); +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_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR(DRIVER_AUTHOR); diff --git a/trunk/drivers/usb/gadget/fsl_udc_core.c b/trunk/drivers/usb/gadget/fsl_udc_core.c index d7ea6c076ce9..dd28ef3def71 100644 --- a/trunk/drivers/usb/gadget/fsl_udc_core.c +++ b/trunk/drivers/usb/gadget/fsl_udc_core.c @@ -1934,7 +1934,7 @@ static int fsl_start(struct usb_gadget_driver *driver, if (!udc_controller) return -ENODEV; - if (!driver || driver->max_speed < USB_SPEED_FULL + if (!driver || driver->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.max_speed = USB_SPEED_HIGH; + udc_controller->gadget.is_dualspeed = 1; udc_controller->gadget.ep0 = &udc_controller->eps[0].ep; INIT_LIST_HEAD(&udc_controller->gadget.ep_list); udc_controller->gadget.speed = USB_SPEED_UNKNOWN; diff --git a/trunk/drivers/usb/gadget/fusb300_udc.c b/trunk/drivers/usb/gadget/fusb300_udc.c index 5831cb4a0b35..74da206c8406 100644 --- a/trunk/drivers/usb/gadget/fusb300_udc.c +++ b/trunk/drivers/usb/gadget/fusb300_udc.c @@ -1317,7 +1317,7 @@ static int fusb300_udc_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->max_speed < USB_SPEED_FULL + || driver->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.max_speed = USB_SPEED_HIGH; + fusb300->gadget.is_dualspeed = 1; fusb300->gadget.dev.parent = &pdev->dev; fusb300->gadget.dev.dma_mask = pdev->dev.dma_mask; fusb300->gadget.dev.release = pdev->dev.release; diff --git a/trunk/drivers/usb/gadget/goku_udc.c b/trunk/drivers/usb/gadget/goku_udc.c index 5af70fcce139..7f87805cddc4 100644 --- a/trunk/drivers/usb/gadget/goku_udc.c +++ b/trunk/drivers/usb/gadget/goku_udc.c @@ -1357,7 +1357,7 @@ static int goku_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->max_speed < USB_SPEED_FULL + || driver->speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) @@ -1796,7 +1796,6 @@ 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"); diff --git a/trunk/drivers/usb/gadget/imx_udc.c b/trunk/drivers/usb/gadget/imx_udc.c index 8d1c75abd73d..2d978c0e7ced 100644 --- a/trunk/drivers/usb/gadget/imx_udc.c +++ b/trunk/drivers/usb/gadget/imx_udc.c @@ -1336,7 +1336,7 @@ static int imx_udc_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->max_speed < USB_SPEED_FULL + || driver->speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) diff --git a/trunk/drivers/usb/gadget/inode.c b/trunk/drivers/usb/gadget/inode.c index 93612519b53a..6ccae2707e59 100644 --- a/trunk/drivers/usb/gadget/inode.c +++ b/trunk/drivers/usb/gadget/inode.c @@ -1766,9 +1766,9 @@ gadgetfs_suspend (struct usb_gadget *gadget) static struct usb_gadget_driver gadgetfs_driver = { #ifdef CONFIG_USB_GADGET_DUALSPEED - .max_speed = USB_SPEED_HIGH, + .speed = USB_SPEED_HIGH, #else - .max_speed = USB_SPEED_FULL, + .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 = { - .max_speed = USB_SPEED_HIGH, + .speed = USB_SPEED_HIGH, .unbind = gadgetfs_nop, .setup = (void *)gadgetfs_nop, .disconnect = gadgetfs_nop, diff --git a/trunk/drivers/usb/gadget/langwell_udc.c b/trunk/drivers/usb/gadget/langwell_udc.c index fa0fcc11263f..c9fa3bf5b377 100644 --- a/trunk/drivers/usb/gadget/langwell_udc.c +++ b/trunk/drivers/usb/gadget/langwell_udc.c @@ -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.max_speed = USB_SPEED_HIGH; /* support dual speed */ + dev->gadget.is_dualspeed = 1; /* support dual speed */ #ifdef OTG_TRANSCEIVER dev->gadget.is_otg = 1; /* support otg mode */ #endif diff --git a/trunk/drivers/usb/gadget/m66592-udc.c b/trunk/drivers/usb/gadget/m66592-udc.c index 3608b3bd5732..9aa1cbbee45b 100644 --- a/trunk/drivers/usb/gadget/m66592-udc.c +++ b/trunk/drivers/usb/gadget/m66592-udc.c @@ -1472,7 +1472,7 @@ static int m66592_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->max_speed < USB_SPEED_HIGH + || driver->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.max_speed = USB_SPEED_HIGH; + m66592->gadget.is_dualspeed = 1; m66592->gadget.dev.parent = &pdev->dev; m66592->gadget.dev.dma_mask = pdev->dev.dma_mask; m66592->gadget.dev.release = pdev->dev.release; diff --git a/trunk/drivers/usb/gadget/mv_udc.h b/trunk/drivers/usb/gadget/mv_udc.h index 3d8404484613..daa75c12f336 100644 --- a/trunk/drivers/usb/gadget/mv_udc.h +++ b/trunk/drivers/usb/gadget/mv_udc.h @@ -211,14 +211,11 @@ struct mv_udc { softconnected:1, force_fs:1, clock_gating:1, - active:1, - stopped:1; /* stop bit is setted */ + active:1; 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*/ diff --git a/trunk/drivers/usb/gadget/mv_udc_core.c b/trunk/drivers/usb/gadget/mv_udc_core.c index 142a67f06638..892412103dd8 100644 --- a/trunk/drivers/usb/gadget/mv_udc_core.c +++ b/trunk/drivers/usb/gadget/mv_udc_core.c @@ -1056,8 +1056,6 @@ 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; @@ -1074,8 +1072,6 @@ 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); } @@ -1138,11 +1134,11 @@ static int udc_reset(struct mv_udc *udc) return 0; } -static int mv_udc_enable_internal(struct mv_udc *udc) +static int mv_udc_enable(struct mv_udc *udc) { int retval; - if (udc->active) + if (udc->clock_gating == 0 || udc->active) return 0; dev_dbg(&udc->dev->dev, "enable udc\n"); @@ -1161,17 +1157,9 @@ static int mv_udc_enable_internal(struct mv_udc *udc) return 0; } -static int mv_udc_enable(struct mv_udc *udc) -{ - if (udc->clock_gating) - return mv_udc_enable_internal(udc); - - return 0; -} - -static void mv_udc_disable_internal(struct mv_udc *udc) +static void mv_udc_disable(struct mv_udc *udc) { - if (udc->active) { + if (udc->clock_gating && udc->active) { dev_dbg(&udc->dev->dev, "disable udc\n"); if (udc->pdata->phy_deinit) udc->pdata->phy_deinit(udc->phy_regs); @@ -1180,12 +1168,6 @@ static void mv_udc_disable_internal(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; @@ -1230,11 +1212,10 @@ 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) { @@ -1263,11 +1244,10 @@ 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) { @@ -1427,20 +1407,6 @@ 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); @@ -2060,10 +2026,6 @@ 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); @@ -2147,12 +2109,7 @@ static int __devexit mv_udc_remove(struct platform_device *dev) destroy_workqueue(udc->qwork); } - /* - * 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) + if (udc->pdata && udc->pdata->vbus && udc->clock_gating) free_irq(udc->pdata->vbus->irq, &dev->dev); /* free memory allocated in probe */ @@ -2225,11 +2182,6 @@ 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]); @@ -2269,9 +2221,14 @@ static int __devinit mv_udc_probe(struct platform_device *dev) } /* we will acces controller register, so enable the clk */ - retval = mv_udc_enable_internal(udc); - if (retval) - goto err_iounmap_phyreg; + 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; + } + } udc->op_regs = (struct mv_op_regs __iomem *)((u32)udc->cap_regs + (readl(&udc->cap_regs->caplength_hciversion) @@ -2355,7 +2312,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.max_speed = USB_SPEED_HIGH; /* support dual speed */ + udc->gadget.is_dualspeed = 1; /* support dual speed */ /* the "gadget" abstracts/virtualizes the controller */ dev_set_name(&udc->gadget.dev, "gadget"); @@ -2371,9 +2328,7 @@ static int __devinit mv_udc_probe(struct platform_device *dev) eps_init(udc); /* VBUS detect: we can disable/enable clock on demand.*/ - if (udc->transceiver) - udc->clock_gating = 1; - else if (pdata->vbus) { + if (pdata->vbus) { udc->clock_gating = 1; retval = request_threaded_irq(pdata->vbus->irq, NULL, mv_udc_vbus_irq, IRQF_ONESHOT, "vbus", udc); @@ -2399,9 +2354,11 @@ 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) - mv_udc_disable_internal(udc); - else + if (udc->clock_gating) { + if (udc->pdata->phy_deinit) + udc->pdata->phy_deinit(udc->phy_regs); + udc_clock_disable(udc); + } else udc->vbus_active = 1; retval = usb_add_gadget_udc(&dev->dev, &udc->gadget); @@ -2414,8 +2371,7 @@ static int __devinit mv_udc_probe(struct platform_device *dev) return 0; err_unregister: - if (udc->pdata && udc->pdata->vbus - && udc->clock_gating && udc->transceiver == NULL) + if (udc->pdata && udc->pdata->vbus && udc->clock_gating) free_irq(pdata->vbus->irq, &dev->dev); device_unregister(&udc->gadget.dev); err_free_irq: @@ -2431,7 +2387,9 @@ static int __devinit mv_udc_probe(struct platform_device *dev) dma_free_coherent(&dev->dev, udc->ep_dqh_size, udc->ep_dqh, udc->ep_dqh_dma); err_disable_clock: - mv_udc_disable_internal(udc); + if (udc->pdata->phy_deinit) + udc->pdata->phy_deinit(udc->phy_regs); + udc_clock_disable(udc); err_iounmap_phyreg: iounmap((void *)udc->phy_regs); err_iounmap_capreg: @@ -2449,30 +2407,7 @@ static int mv_udc_suspend(struct device *_dev) { struct mv_udc *udc = the_controller; - /* 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); - } + udc_stop(udc); return 0; } @@ -2482,22 +2417,20 @@ static int mv_udc_resume(struct device *_dev) struct mv_udc *udc = the_controller; int 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) + 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); 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; } @@ -2530,11 +2463,24 @@ static struct platform_driver udc_driver = { #endif }, }; - -module_platform_driver(udc_driver); +MODULE_ALIAS("platform:pxa-u2o"); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_AUTHOR("Chao Xie "); MODULE_VERSION(DRIVER_VERSION); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:pxa-u2o"); + + +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); + diff --git a/trunk/drivers/usb/gadget/net2272.c b/trunk/drivers/usb/gadget/net2272.c index 4c81d540bc26..d1b76368472f 100644 --- a/trunk/drivers/usb/gadget/net2272.c +++ b/trunk/drivers/usb/gadget/net2272.c @@ -1459,7 +1459,7 @@ static int net2272_start(struct usb_gadget *_gadget, unsigned i; if (!driver || !driver->unbind || !driver->setup || - driver->max_speed != USB_SPEED_HIGH) + driver->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.max_speed = USB_SPEED_HIGH; + ret->gadget.is_dualspeed = 1; /* the "gadget" abstracts/virtualizes the controller */ dev_set_name(&ret->gadget.dev, "gadget"); diff --git a/trunk/drivers/usb/gadget/net2280.c b/trunk/drivers/usb/gadget/net2280.c index cf1f36454d08..da2b9d0be3ca 100644 --- a/trunk/drivers/usb/gadget/net2280.c +++ b/trunk/drivers/usb/gadget/net2280.c @@ -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->max_speed < USB_SPEED_HIGH + if (!driver || driver->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.max_speed = USB_SPEED_HIGH; + dev->gadget.is_dualspeed = 1; /* the "gadget" abstracts/virtualizes the controller */ dev_set_name(&dev->gadget.dev, "gadget"); diff --git a/trunk/drivers/usb/gadget/omap_udc.c b/trunk/drivers/usb/gadget/omap_udc.c index 7db5bbe6251b..788989a10223 100644 --- a/trunk/drivers/usb/gadget/omap_udc.c +++ b/trunk/drivers/usb/gadget/omap_udc.c @@ -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->max_speed < USB_SPEED_FULL + || driver->speed < USB_SPEED_FULL || !bind || !driver->setup) return -EINVAL; @@ -2676,7 +2676,6 @@ 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); diff --git a/trunk/drivers/usb/gadget/pch_udc.c b/trunk/drivers/usb/gadget/pch_udc.c index dd2313cce1d3..5048a0c07640 100644 --- a/trunk/drivers/usb/gadget/pch_udc.c +++ b/trunk/drivers/usb/gadget/pch_udc.c @@ -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->max_speed == USB_SPEED_UNKNOWN) || !bind || + if (!driver || (driver->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.max_speed = USB_SPEED_HIGH; + dev->gadget.is_dualspeed = 1; retval = device_register(&dev->gadget.dev); if (retval) diff --git a/trunk/drivers/usb/gadget/printer.c b/trunk/drivers/usb/gadget/printer.c index d83134b0f78a..65a8834f274b 100644 --- a/trunk/drivers/usb/gadget/printer.c +++ b/trunk/drivers/usb/gadget/printer.c @@ -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(gadget)) + if (!gadget->is_dualspeed) 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(gadget)) + if (!gadget->is_dualspeed) break; /* FALLTHROUGH */ #endif /* CONFIG_USB_GADGET_DUALSPEED */ @@ -1535,7 +1535,7 @@ printer_bind(struct usb_gadget *gadget) /*-------------------------------------------------------------------------*/ static struct usb_gadget_driver printer_driver = { - .max_speed = DEVSPEED, + .speed = DEVSPEED, .function = (char *) driver_desc, .unbind = printer_unbind, diff --git a/trunk/drivers/usb/gadget/pxa25x_udc.c b/trunk/drivers/usb/gadget/pxa25x_udc.c index dd470635f4f7..c090a7e3ecf8 100644 --- a/trunk/drivers/usb/gadget/pxa25x_udc.c +++ b/trunk/drivers/usb/gadget/pxa25x_udc.c @@ -1264,7 +1264,7 @@ static int pxa25x_start(struct usb_gadget_driver *driver, int retval; if (!driver - || driver->max_speed < USB_SPEED_FULL + || driver->speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) diff --git a/trunk/drivers/usb/gadget/pxa27x_udc.c b/trunk/drivers/usb/gadget/pxa27x_udc.c index f4c44eb806c3..18b6b091f2a6 100644 --- a/trunk/drivers/usb/gadget/pxa27x_udc.c +++ b/trunk/drivers/usb/gadget/pxa27x_udc.c @@ -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->max_speed < USB_SPEED_FULL || !bind + if (!driver || driver->speed < USB_SPEED_FULL || !bind || !driver->disconnect || !driver->setup) return -EINVAL; if (!udc) diff --git a/trunk/drivers/usb/gadget/r8a66597-udc.c b/trunk/drivers/usb/gadget/r8a66597-udc.c index f5b8d215e1d5..fc719a3f8557 100644 --- a/trunk/drivers/usb/gadget/r8a66597-udc.c +++ b/trunk/drivers/usb/gadget/r8a66597-udc.c @@ -1746,7 +1746,7 @@ static int r8a66597_start(struct usb_gadget *gadget, struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget); if (!driver - || driver->max_speed < USB_SPEED_HIGH + || driver->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.max_speed = USB_SPEED_HIGH; + r8a66597->gadget.is_dualspeed = 1; r8a66597->gadget.dev.parent = &pdev->dev; r8a66597->gadget.dev.dma_mask = pdev->dev.dma_mask; r8a66597->gadget.dev.release = pdev->dev.release; diff --git a/trunk/drivers/usb/gadget/s3c-hsotg.c b/trunk/drivers/usb/gadget/s3c-hsotg.c index 69295ba9d99a..b31448229f0b 100644 --- a/trunk/drivers/usb/gadget/s3c-hsotg.c +++ b/trunk/drivers/usb/gadget/s3c-hsotg.c @@ -2586,7 +2586,7 @@ static int s3c_hsotg_start(struct usb_gadget_driver *driver, return -EINVAL; } - if (driver->max_speed < USB_SPEED_FULL) + if (driver->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.max_speed = USB_SPEED_HIGH; + hsotg->gadget.is_dualspeed = 1; hsotg->gadget.ops = &s3c_hsotg_gadget_ops; hsotg->gadget.name = dev_name(dev); @@ -3467,7 +3467,18 @@ static struct platform_driver s3c_hsotg_driver = { .resume = s3c_hsotg_resume, }; -module_platform_driver(s3c_hsotg_driver); +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_DESCRIPTION("Samsung S3C USB High-speed/OtG device"); MODULE_AUTHOR("Ben Dooks "); diff --git a/trunk/drivers/usb/gadget/s3c-hsudc.c b/trunk/drivers/usb/gadget/s3c-hsudc.c index 6f2a0419350d..20a553b46aed 100644 --- a/trunk/drivers/usb/gadget/s3c-hsudc.c +++ b/trunk/drivers/usb/gadget/s3c-hsudc.c @@ -1142,7 +1142,7 @@ static int s3c_hsudc_start(struct usb_gadget_driver *driver, int ret; if (!driver - || driver->max_speed < USB_SPEED_FULL + || driver->speed < USB_SPEED_FULL || !bind || !driver->unbind || !driver->disconnect || !driver->setup) return -EINVAL; @@ -1310,7 +1310,7 @@ static int s3c_hsudc_probe(struct platform_device *pdev) device_initialize(&hsudc->gadget.dev); dev_set_name(&hsudc->gadget.dev, "gadget"); - hsudc->gadget.max_speed = USB_SPEED_HIGH; + hsudc->gadget.is_dualspeed = 1; hsudc->gadget.ops = &s3c_hsudc_gadget_ops; hsudc->gadget.name = dev_name(dev); hsudc->gadget.dev.parent = dev; @@ -1377,10 +1377,21 @@ 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); +} -module_platform_driver(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_DESCRIPTION("Samsung S3C24XX USB high-speed controller driver"); MODULE_AUTHOR("Thomas Abraham "); MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:s3c-hsudc"); diff --git a/trunk/drivers/usb/gadget/s3c2410_udc.c b/trunk/drivers/usb/gadget/s3c2410_udc.c index 4d860e9460a4..b8643771fa80 100644 --- a/trunk/drivers/usb/gadget/s3c2410_udc.c +++ b/trunk/drivers/usb/gadget/s3c2410_udc.c @@ -1683,9 +1683,9 @@ static int s3c2410_udc_start(struct usb_gadget_driver *driver, if (udc->driver) return -EBUSY; - if (!bind || !driver->setup || driver->max_speed < USB_SPEED_FULL) { + if (!bind || !driver->setup || driver->speed < USB_SPEED_FULL) { printk(KERN_ERR "Invalid driver: bind %p setup %p speed %d\n", - bind, driver->setup, driver->max_speed); + bind, driver->setup, driver->speed); return -EINVAL; } #if defined(MODULE) diff --git a/trunk/drivers/usb/gadget/udc-core.c b/trunk/drivers/usb/gadget/udc-core.c index 0b0d12ccc487..6939e17f4580 100644 --- a/trunk/drivers/usb/gadget/udc-core.c +++ b/trunk/drivers/usb/gadget/udc-core.c @@ -371,28 +371,14 @@ static ssize_t usb_udc_softconn_store(struct device *dev, } static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store); -#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, +static ssize_t usb_udc_speed_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, "%d\n", - gadget_is_dualspeed(udc->gadget)); + return snprintf(buf, PAGE_SIZE, "%s\n", + usb_speed_string(udc->gadget->speed)); } -static DEVICE_ATTR(is_dualspeed, S_IRUSR, usb_udc_is_dualspeed_show, NULL); +static DEVICE_ATTR(speed, S_IRUGO, usb_udc_speed_show, NULL); #define USB_UDC_ATTR(name) \ ssize_t usb_udc_##name##_show(struct device *dev, \ @@ -405,6 +391,7 @@ 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); @@ -414,8 +401,7 @@ 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_current_speed.attr, - &dev_attr_maximum_speed.attr, + &dev_attr_speed.attr, &dev_attr_is_dualspeed.attr, &dev_attr_is_otg.attr, diff --git a/trunk/drivers/usb/gadget/usbstring.c b/trunk/drivers/usb/gadget/usbstring.c index 4d25b9009edf..58c4d37d312a 100644 --- a/trunk/drivers/usb/gadget/usbstring.c +++ b/trunk/drivers/usb/gadget/usbstring.c @@ -13,17 +13,82 @@ #include #include #include -#include #include #include +#include + + +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, must be 16-bit aligned + * @buf: at least 256 bytes * * Finds the UTF-8 string matching the ID, and converts it into a * string descriptor in utf16-le. @@ -60,8 +125,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)); - len = utf8s_to_utf16s(s->s, len, UTF16_LITTLE_ENDIAN, - (wchar_t *) &buf[2], 126); + memset (buf + 2, 0, 2 * len); /* zero all the bytes */ + len = utf8_to_utf16le(s->s, (__le16 *)&buf[2], len); if (len < 0) return -EINVAL; buf [0] = (len + 1) * 2; diff --git a/trunk/drivers/usb/host/ehci-au1xxx.c b/trunk/drivers/usb/host/ehci-au1xxx.c index bf7441afed16..18bafa99fe57 100644 --- a/trunk/drivers/usb/host/ehci-au1xxx.c +++ b/trunk/drivers/usb/host/ehci-au1xxx.c @@ -23,7 +23,6 @@ static int au1xxx_ehci_setup(struct usb_hcd *hcd) int ret = ehci_init(hcd); ehci->need_io_watchdog = 0; - ehci_reset(ehci); return ret; } diff --git a/trunk/drivers/usb/host/ehci-hcd.c b/trunk/drivers/usb/host/ehci-hcd.c index c4c76ab204c1..3ff9f82f7263 100644 --- a/trunk/drivers/usb/host/ehci-hcd.c +++ b/trunk/drivers/usb/host/ehci-hcd.c @@ -48,10 +48,6 @@ #include #include -#if defined(CONFIG_PPC_PS3) -#include -#endif - /*-------------------------------------------------------------------------*/ /* @@ -234,58 +230,12 @@ 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; @@ -670,7 +620,6 @@ 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; @@ -728,13 +677,22 @@ 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); @@ -1366,7 +1324,7 @@ MODULE_LICENSE ("GPL"); #define PLATFORM_DRIVER ehci_pxa168_driver #endif -#ifdef CONFIG_CPU_XLR +#ifdef CONFIG_NLM_XLR #include "ehci-xls.c" #define PLATFORM_DRIVER ehci_xls_driver #endif diff --git a/trunk/drivers/usb/host/ehci-octeon.c b/trunk/drivers/usb/host/ehci-octeon.c index c0104882c72d..ba1f51361134 100644 --- a/trunk/drivers/usb/host/ehci-octeon.c +++ b/trunk/drivers/usb/host/ehci-octeon.c @@ -155,8 +155,6 @@ 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); diff --git a/trunk/drivers/usb/host/ehci-omap.c b/trunk/drivers/usb/host/ehci-omap.c index e33baf9052cb..e39b0297bad1 100644 --- a/trunk/drivers/usb/host/ehci-omap.c +++ b/trunk/drivers/usb/host/ehci-omap.c @@ -228,8 +228,6 @@ 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); diff --git a/trunk/drivers/usb/host/ehci-ps3.c b/trunk/drivers/usb/host/ehci-ps3.c index a20e496eb479..2dc32da75cfc 100644 --- a/trunk/drivers/usb/host/ehci-ps3.c +++ b/trunk/drivers/usb/host/ehci-ps3.c @@ -21,34 +21,6 @@ #include #include -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; @@ -77,8 +49,6 @@ static int ps3_ehci_hc_reset(struct usb_hcd *hcd) ehci_reset(ehci); - ps3_ehci_setup_insnreg(ehci); - return result; } diff --git a/trunk/drivers/usb/host/ehci-pxa168.c b/trunk/drivers/usb/host/ehci-pxa168.c index 8d0e7a22e711..ac0c16e8f539 100644 --- a/trunk/drivers/usb/host/ehci-pxa168.c +++ b/trunk/drivers/usb/host/ehci-pxa168.c @@ -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, ehci_readl(ehci, &ehci->caps->hc_capbase)); + HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase)); ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params); hcd->has_tt = 1; ehci->sbrn = 0x20; diff --git a/trunk/drivers/usb/host/ehci-q.c b/trunk/drivers/usb/host/ehci-q.c index 36ca5077cdf7..4e4066c35a09 100644 --- a/trunk/drivers/usb/host/ehci-q.c +++ b/trunk/drivers/usb/host/ehci-q.c @@ -373,17 +373,6 @@ 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. */ @@ -658,7 +647,7 @@ qh_urb_transaction ( /* * data transfer stage: buffer setup */ - i = urb->num_mapped_sgs; + i = urb->num_sgs; if (len > 0 && i > 0) { sg = urb->sg; buf = sg_dma_address(sg); diff --git a/trunk/drivers/usb/host/ehci-s5p.c b/trunk/drivers/usb/host/ehci-s5p.c index 293f7412992e..024b65c4990d 100644 --- a/trunk/drivers/usb/host/ehci-s5p.c +++ b/trunk/drivers/usb/host/ehci-s5p.c @@ -14,6 +14,8 @@ #include #include +#include +#include #include #include @@ -134,8 +136,6 @@ 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"); diff --git a/trunk/drivers/usb/host/ehci-vt8500.c b/trunk/drivers/usb/host/ehci-vt8500.c index c1eda73916cd..54d1ab8aec49 100644 --- a/trunk/drivers/usb/host/ehci-vt8500.c +++ b/trunk/drivers/usb/host/ehci-vt8500.c @@ -132,8 +132,6 @@ 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) { diff --git a/trunk/drivers/usb/host/ehci-w90x900.c b/trunk/drivers/usb/host/ehci-w90x900.c index 3d2e26cbb34c..d661cf7de140 100644 --- a/trunk/drivers/usb/host/ehci-w90x900.c +++ b/trunk/drivers/usb/host/ehci-w90x900.c @@ -78,8 +78,6 @@ 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; diff --git a/trunk/drivers/usb/host/ehci-xls.c b/trunk/drivers/usb/host/ehci-xls.c index 72f08196f8cd..b4fb511d24bc 100644 --- a/trunk/drivers/usb/host/ehci-xls.c +++ b/trunk/drivers/usb/host/ehci-xls.c @@ -69,7 +69,7 @@ int ehci_xls_probe_internal(const struct hc_driver *driver, } hcd->rsrc_start = res->start; - hcd->rsrc_len = resource_size(res); + hcd->rsrc_len = res->end - res->start + 1; if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, driver->description)) { diff --git a/trunk/drivers/usb/host/fhci-hcd.c b/trunk/drivers/usb/host/fhci-hcd.c index d2623747b489..4ed6d19f2a54 100644 --- a/trunk/drivers/usb/host/fhci-hcd.c +++ b/trunk/drivers/usb/host/fhci-hcd.c @@ -824,7 +824,17 @@ static struct platform_driver of_fhci_driver = { .remove = __devexit_p(of_fhci_remove), }; -module_platform_driver(of_fhci_driver); +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_DESCRIPTION("USB Freescale Host Controller Interface Driver"); MODULE_AUTHOR("Shlomi Gridish , " diff --git a/trunk/drivers/usb/host/fsl-mph-dr-of.c b/trunk/drivers/usb/host/fsl-mph-dr-of.c index 7916e56a725e..9037035ad1e4 100644 --- a/trunk/drivers/usb/host/fsl-mph-dr-of.c +++ b/trunk/drivers/usb/host/fsl-mph-dr-of.c @@ -297,7 +297,17 @@ static struct platform_driver fsl_usb2_mph_dr_driver = { .remove = __devexit_p(fsl_usb2_mph_dr_of_remove), }; -module_platform_driver(fsl_usb2_mph_dr_driver); +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_DESCRIPTION("FSL MPH DR OF devices driver"); MODULE_AUTHOR("Anatolij Gustschin "); diff --git a/trunk/drivers/usb/host/hwa-hc.c b/trunk/drivers/usb/host/hwa-hc.c index 565d79f06e6f..9bfac657572e 100644 --- a/trunk/drivers/usb/host/hwa-hc.c +++ b/trunk/drivers/usb/host/hwa-hc.c @@ -776,6 +776,7 @@ 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); diff --git a/trunk/drivers/usb/host/imx21-hcd.c b/trunk/drivers/usb/host/imx21-hcd.c index 6923bcb8aa68..2ee18cfa1efe 100644 --- a/trunk/drivers/usb/host/imx21-hcd.c +++ b/trunk/drivers/usb/host/imx21-hcd.c @@ -1924,7 +1924,18 @@ static struct platform_driver imx21_hcd_driver = { .resume = NULL, }; -module_platform_driver(imx21_hcd_driver); +static int __init imx21_hcd_init(void) +{ + return platform_driver_register(&imx21_hcd_driver); +} + +static void __exit imx21_hcd_cleanup(void) +{ + platform_driver_unregister(&imx21_hcd_driver); +} + +module_init(imx21_hcd_init); +module_exit(imx21_hcd_cleanup); MODULE_DESCRIPTION("i.MX21 USB Host controller"); MODULE_AUTHOR("Martin Fuzzey"); diff --git a/trunk/drivers/usb/host/isp1760-hcd.c b/trunk/drivers/usb/host/isp1760-hcd.c index fc72d44bf787..27dfab80ed8f 100644 --- a/trunk/drivers/usb/host/isp1760-hcd.c +++ b/trunk/drivers/usb/host/isp1760-hcd.c @@ -32,13 +32,6 @@ 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; @@ -47,7 +40,7 @@ struct isp1760_hcd { struct slotinfo int_slots[32]; int int_done_map; struct memory_chunk memory_pool[BLOCKS]; - struct list_head qh_list[QH_END]; + struct list_head controlqhs, bulkqhs, interruptqhs; /* periodic schedule support */ #define DEFAULT_I_TDPS 1024 @@ -413,12 +406,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); - for (i = 0; i < QH_END; i++) - INIT_LIST_HEAD(&priv->qh_list[i]); + INIT_LIST_HEAD(&priv->interruptqhs); + INIT_LIST_HEAD(&priv->controlqhs); + INIT_LIST_HEAD(&priv->bulkqhs); /* * hw default: 1K periodic list heads, one per frame. @@ -937,9 +930,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); @@ -951,13 +944,28 @@ void schedule_ptds(struct usb_hcd *hcd) /* * check finished/retired xfers, transfer payloads, call urb_done() */ - for (i = 0; i < QH_END; i++) { - ep_queue = &priv->qh_list[i]; + ep_queue = &priv->interruptqhs; + while (ep_queue) { 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, @@ -990,10 +998,17 @@ void schedule_ptds(struct usb_hcd *hcd) * * I'm sure this scheme could be improved upon! */ - for (i = 0; i < QH_END; i++) { - ep_queue = &priv->qh_list[i]; + ep_queue = &priv->controlqhs; + while (ep_queue) { 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; } } @@ -1528,16 +1543,16 @@ static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, switch (usb_pipetype(urb->pipe)) { case PIPE_CONTROL: - ep_queue = &priv->qh_list[QH_CONTROL]; + ep_queue = &priv->controlqhs; break; case PIPE_BULK: - ep_queue = &priv->qh_list[QH_BULK]; + ep_queue = &priv->bulkqhs; break; case PIPE_INTERRUPT: if (urb->interval < 0) return -EINVAL; /* FIXME: Check bandwidth */ - ep_queue = &priv->qh_list[QH_INTERRUPT]; + ep_queue = &priv->interruptqhs; break; case PIPE_ISOCHRONOUS: dev_err(hcd->self.controller, "%s: isochronous USB packets " @@ -1699,8 +1714,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, *qh_iter; - int i; + struct isp1760_qh *qh; + struct isp1760_qtd *qtd; spin_lock_irqsave(&priv->lock, spinflags); @@ -1708,17 +1723,14 @@ static void isp1760_endpoint_disable(struct usb_hcd *hcd, if (!qh) goto out; - WARN_ON(!list_empty(&qh->qtd_list)); + 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; + } - 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); diff --git a/trunk/drivers/usb/host/isp1760-if.c b/trunk/drivers/usb/host/isp1760-if.c index b605224fb9e3..a7dc1e1d45f2 100644 --- a/trunk/drivers/usb/host/isp1760-if.c +++ b/trunk/drivers/usb/host/isp1760-if.c @@ -47,9 +47,9 @@ 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) @@ -77,8 +77,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 */ - of_property_read_u32(dp, "bus-width", &bus_width); - if (bus_width == 16) + prop = of_get_property(dp, "bus-width", NULL); + if (prop && *prop == 16) devflags |= ISP1760_FLAG_BUS_WIDTH_16; if (of_get_property(dp, "port1-otg", NULL) != NULL) diff --git a/trunk/drivers/usb/host/ohci-au1xxx.c b/trunk/drivers/usb/host/ohci-au1xxx.c index 40d886adff53..9b66df8278f3 100644 --- a/trunk/drivers/usb/host/ohci-au1xxx.c +++ b/trunk/drivers/usb/host/ohci-au1xxx.c @@ -173,9 +173,12 @@ 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 (ohci->rh_state != OHCI_RH_SUSPENDED) { + if (hcd->state != HC_STATE_SUSPENDED) { rc = -EINVAL; goto bail; } diff --git a/trunk/drivers/usb/host/ohci-dbg.c b/trunk/drivers/usb/host/ohci-dbg.c index 5179fcd73d8a..d7d34492934a 100644 --- a/trunk/drivers/usb/host/ohci-dbg.c +++ b/trunk/drivers/usb/host/ohci-dbg.c @@ -127,19 +127,6 @@ 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) @@ -149,10 +136,9 @@ ohci_dump_status (struct ohci_hcd *controller, char **next, unsigned *size) temp = ohci_readl (controller, ®s->revision) & 0xff; ohci_dbg_sw (controller, next, size, - "OHCI %d.%d, %s legacy support registers, rh state %s\n", + "OHCI %d.%d, %s legacy support registers\n", 0x03 & (temp >> 4), (temp & 0x0f), - (temp & 0x0100) ? "with" : "NO", - rh_state_string(controller)); + (temp & 0x0100) ? "with" : "NO"); temp = ohci_readl (controller, ®s->control); ohci_dbg_sw (controller, next, size, diff --git a/trunk/drivers/usb/host/ohci-ep93xx.c b/trunk/drivers/usb/host/ohci-ep93xx.c index 3d63574d2c7e..dc45d489d00e 100644 --- a/trunk/drivers/usb/host/ohci-ep93xx.c +++ b/trunk/drivers/usb/host/ohci-ep93xx.c @@ -179,6 +179,8 @@ 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; } diff --git a/trunk/drivers/usb/host/ohci-hcd.c b/trunk/drivers/usb/host/ohci-hcd.c index 4fa5d8c4d239..b2639191549e 100644 --- a/trunk/drivers/usb/host/ohci-hcd.c +++ b/trunk/drivers/usb/host/ohci-hcd.c @@ -209,7 +209,7 @@ static int ohci_urb_enqueue ( retval = -ENODEV; goto fail; } - if (ohci->rh_state != OHCI_RH_RUNNING) { + if (!HC_IS_RUNNING(hcd->state)) { 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 (ohci->rh_state == OHCI_RH_RUNNING) { + } else if (HC_IS_RUNNING(hcd->state)) { 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 (ohci->rh_state != OHCI_RH_RUNNING) { + if (!HC_IS_RUNNING (hcd->state)) { sanitize: ed->state = ED_IDLE; if (quirk_zfmicro(ohci) && ed->type == PIPE_INTERRUPT) @@ -377,7 +377,6 @@ 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 @@ -501,7 +500,7 @@ static int ohci_init (struct ohci_hcd *ohci) if (distrust_firmware) ohci->flags |= OHCI_QUIRK_HUB_POWER; - ohci->rh_state = OHCI_RH_HALTED; + disable (ohci); ohci->regs = hcd->regs; /* REVISIT this BIOS handshake is now moved into PCI "quirks", and @@ -576,7 +575,7 @@ static int ohci_run (struct ohci_hcd *ohci) int first = ohci->fminterval == 0; struct usb_hcd *hcd = ohci_to_hcd(ohci); - ohci->rh_state = OHCI_RH_HALTED; + disable (ohci); /* boot firmware should have set this up (5.1.1.3.1) */ if (first) { @@ -689,7 +688,7 @@ static int ohci_run (struct ohci_hcd *ohci) ohci->hc_control &= OHCI_CTRL_RWC; ohci->hc_control |= OHCI_CONTROL_INIT | OHCI_USB_OPER; ohci_writel (ohci, ohci->hc_control, &ohci->regs->control); - ohci->rh_state = OHCI_RH_RUNNING; + hcd->state = HC_STATE_RUNNING; /* wake on ConnectStatusChange, matching external hubs */ ohci_writel (ohci, RH_HS_DRWE, &ohci->regs->roothub.status); @@ -726,6 +725,7 @@ static int ohci_run (struct ohci_hcd *ohci) // 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) { - ohci->rh_state = OHCI_RH_HALTED; + disable (ohci); 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, ®s->intrenable); /* interrupt for some other device? */ - if (ints == 0 || unlikely(ohci->rh_state == OHCI_RH_HALTED)) + if (ints == 0 || unlikely(hcd->state == HC_STATE_HALT)) 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 - && ohci->rh_state == OHCI_RH_RUNNING) + && HC_IS_RUNNING(hcd->state)) ohci_writel (ohci, OHCI_INTR_SF, ®s->intrdisable); spin_unlock (&ohci->lock); - if (ohci->rh_state == OHCI_RH_RUNNING) { + if (HC_IS_RUNNING(hcd->state)) { ohci_writel (ohci, ints, ®s->intrstatus); ohci_writel (ohci, OHCI_INTR_MIE, ®s->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); - ohci->rh_state = OHCI_RH_HALTED; + disable (ohci); /* 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_CPU_XLR +#ifdef CONFIG_NLM_XLR #include "ohci-xls.c" #define PLATFORM_DRIVER ohci_xls_driver #endif diff --git a/trunk/drivers/usb/host/ohci-hub.c b/trunk/drivers/usb/host/ohci-hub.c index 836772dfabd3..2f00040fc408 100644 --- a/trunk/drivers/usb/host/ohci-hub.c +++ b/trunk/drivers/usb/host/ohci-hub.c @@ -111,7 +111,6 @@ __acquires(ohci->lock) if (!autostop) { ohci->next_statechange = jiffies + msecs_to_jiffies (5); ohci->autostop = 0; - ohci->rh_state = OHCI_RH_SUSPENDED; } done: @@ -141,7 +140,7 @@ __acquires(ohci->lock) if (ohci->hc_control & (OHCI_CTRL_IR | OHCI_SCHED_ENABLES)) { /* this can happen after resuming a swsusp snapshot */ - if (ohci->rh_state != OHCI_RH_RUNNING) { + if (hcd->state == HC_STATE_RESUMING) { ohci_dbg (ohci, "BIOS/SMM active, control %03x\n", ohci->hc_control); status = -EBUSY; @@ -275,7 +274,6 @@ __acquires(ohci->lock) (void) ohci_readl (ohci, &ohci->regs->control); } - ohci->rh_state = OHCI_RH_RUNNING; return 0; } @@ -338,8 +336,11 @@ 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); } diff --git a/trunk/drivers/usb/host/ohci-omap.c b/trunk/drivers/usb/host/ohci-omap.c index db3968656d21..e4b8782cc6e2 100644 --- a/trunk/drivers/usb/host/ohci-omap.c +++ b/trunk/drivers/usb/host/ohci-omap.c @@ -516,6 +516,7 @@ 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; } diff --git a/trunk/drivers/usb/host/ohci-pci.c b/trunk/drivers/usb/host/ohci-pci.c index 6109810cc2d3..bc01b064585a 100644 --- a/trunk/drivers/usb/host/ohci-pci.c +++ b/trunk/drivers/usb/host/ohci-pci.c @@ -308,9 +308,12 @@ 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 (ohci->rh_state != OHCI_RH_SUSPENDED) { + if (hcd->state != HC_STATE_SUSPENDED) { rc = -EINVAL; goto bail; } diff --git a/trunk/drivers/usb/host/ohci-pxa27x.c b/trunk/drivers/usb/host/ohci-pxa27x.c index 6313e4439f37..29dfefe1c726 100644 --- a/trunk/drivers/usb/host/ohci-pxa27x.c +++ b/trunk/drivers/usb/host/ohci-pxa27x.c @@ -502,6 +502,8 @@ 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; } diff --git a/trunk/drivers/usb/host/ohci-q.c b/trunk/drivers/usb/host/ohci-q.c index c5a1ea9145fa..15dc51ded61a 100644 --- a/trunk/drivers/usb/host/ohci-q.c +++ b/trunk/drivers/usb/host/ohci-q.c @@ -912,7 +912,7 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick) /* only take off EDs that the HC isn't using, accounting for * frame counter wraps and EDs with partially retired TDs */ - if (likely(ohci->rh_state == OHCI_RH_RUNNING)) { + if (likely (HC_IS_RUNNING(ohci_to_hcd(ohci)->state))) { if (tick_before (tick, ed->tick)) { skip_ed: last = &ed->ed_next; @@ -1012,7 +1012,7 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick) /* but if there's work queued, reschedule */ if (!list_empty (&ed->td_list)) { - if (ohci->rh_state == OHCI_RH_RUNNING) + if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state)) ed_schedule (ohci, ed); } @@ -1021,7 +1021,9 @@ finish_unlinks (struct ohci_hcd *ohci, u16 tick) } /* maybe reenable control and bulk lists */ - if (ohci->rh_state == OHCI_RH_RUNNING && !ohci->ed_rm_list) { + if (HC_IS_RUNNING(ohci_to_hcd(ohci)->state) + && ohci_to_hcd(ohci)->state != HC_STATE_QUIESCING + && !ohci->ed_rm_list) { u32 command = 0, control = 0; if (ohci->ed_controltail) { diff --git a/trunk/drivers/usb/host/ohci-s3c2410.c b/trunk/drivers/usb/host/ohci-s3c2410.c index 56dcf069246d..a1877c47601e 100644 --- a/trunk/drivers/usb/host/ohci-s3c2410.c +++ b/trunk/drivers/usb/host/ohci-s3c2410.c @@ -486,66 +486,15 @@ 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, }, }; diff --git a/trunk/drivers/usb/host/ohci-sh.c b/trunk/drivers/usb/host/ohci-sh.c index 84686d90805b..afc4eb6bb9d0 100644 --- a/trunk/drivers/usb/host/ohci-sh.c +++ b/trunk/drivers/usb/host/ohci-sh.c @@ -29,6 +29,7 @@ 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; } diff --git a/trunk/drivers/usb/host/ohci-sm501.c b/trunk/drivers/usb/host/ohci-sm501.c index 5596ac2ba1ca..968cea2b6d4e 100644 --- a/trunk/drivers/usb/host/ohci-sm501.c +++ b/trunk/drivers/usb/host/ohci-sm501.c @@ -224,6 +224,7 @@ 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; } diff --git a/trunk/drivers/usb/host/ohci-spear.c b/trunk/drivers/usb/host/ohci-spear.c index 95c16489e883..69874654f3b5 100644 --- a/trunk/drivers/usb/host/ohci-spear.c +++ b/trunk/drivers/usb/host/ohci-spear.c @@ -203,6 +203,7 @@ 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; } diff --git a/trunk/drivers/usb/host/ohci-tmio.c b/trunk/drivers/usb/host/ohci-tmio.c index 120bfe6ede38..06331d931171 100644 --- a/trunk/drivers/usb/host/ohci-tmio.c +++ b/trunk/drivers/usb/host/ohci-tmio.c @@ -318,6 +318,9 @@ 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; } diff --git a/trunk/drivers/usb/host/ohci-xls.c b/trunk/drivers/usb/host/ohci-xls.c index a2247867af86..a3a9c6f45b91 100644 --- a/trunk/drivers/usb/host/ohci-xls.c +++ b/trunk/drivers/usb/host/ohci-xls.c @@ -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 = resource_size(res); + hcd->rsrc_len = res->end - res->start + 1; if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, driver->description)) { diff --git a/trunk/drivers/usb/host/ohci.h b/trunk/drivers/usb/host/ohci.h index 8ff6f7ea96fd..0795b934d00c 100644 --- a/trunk/drivers/usb/host/ohci.h +++ b/trunk/drivers/usb/host/ohci.h @@ -344,12 +344,6 @@ 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; @@ -390,7 +384,6 @@ 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 */ @@ -686,6 +679,11 @@ 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) @@ -709,7 +707,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) \ - hc->rh_state = OHCI_RH_HALTED; \ + disable (hc); \ else if (hc->flags & OHCI_QUIRK_AMD756) \ while (temp & mask) \ temp = ohci_readl (hc, &hc->regs->roothub.register); \ diff --git a/trunk/drivers/usb/host/oxu210hp-hcd.c b/trunk/drivers/usb/host/oxu210hp-hcd.c index 6f62de5c6e35..dcd889803f0f 100644 --- a/trunk/drivers/usb/host/oxu210hp-hcd.c +++ b/trunk/drivers/usb/host/oxu210hp-hcd.c @@ -3951,7 +3951,24 @@ static struct platform_driver oxu_driver = { } }; -module_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_DESCRIPTION("Oxford OXU210HP HCD driver - ver. " DRIVER_VERSION); MODULE_AUTHOR("Rodolfo Giometti "); diff --git a/trunk/drivers/usb/host/uhci-q.c b/trunk/drivers/usb/host/uhci-q.c index d2c6f5ac4626..f6ca80ee4cec 100644 --- a/trunk/drivers/usb/host/uhci-q.c +++ b/trunk/drivers/usb/host/uhci-q.c @@ -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_mapped_sgs; + i = urb->num_sgs; if (len > 0 && i > 0) { sg = urb->sg; data = sg_dma_address(sg); diff --git a/trunk/drivers/usb/host/whci/qset.c b/trunk/drivers/usb/host/whci/qset.c index 76083ae92138..a403b53e86b9 100644 --- a/trunk/drivers/usb/host/whci/qset.c +++ b/trunk/drivers/usb/host/whci/qset.c @@ -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_mapped_sgs, i) { + for_each_sg(urb->sg, sg, urb->num_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_mapped_sgs, i) { + for_each_sg(urb->sg, sg, urb->num_sgs, i) { size_t len; size_t sg_remaining; void *orig; diff --git a/trunk/drivers/usb/host/xhci-hub.c b/trunk/drivers/usb/host/xhci-hub.c index 35e257f79c7b..430e88fd3f6c 100644 --- a/trunk/drivers/usb/host/xhci-hub.c +++ b/trunk/drivers/usb/host/xhci-hub.c @@ -57,15 +57,17 @@ 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 per-port power switching, or power always on */ + /* Bits 1:0 - support port power switching, or power always on */ if (HCC_PPC(xhci->hcc_params)) - temp |= HUB_CHAR_INDV_PORT_LPSM; + temp |= 0x0001; else - temp |= HUB_CHAR_NO_LPSM; + temp |= 0x0002; /* Bit 2 - root hubs are not part of a compound device */ /* Bits 4:3 - individual port over current protection */ - temp |= HUB_CHAR_INDV_PORT_OCPM; + temp |= 0x0008; /* Bits 6:5 - no TTs in root ports */ /* Bit 7 - no port indicators */ desc->wHubCharacteristics = cpu_to_le16(temp); @@ -84,9 +86,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 = USB_DT_HUB; + desc->bDescriptorType = 0x29; temp = 1 + (ports / 8); - desc->bDescLength = USB_DT_HUB_NONVAR_SIZE + 2 * temp; + desc->bDescLength = 7 + 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. @@ -135,8 +137,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 = USB_DT_SS_HUB; - desc->bDescLength = USB_DT_SS_HUB_SIZE; + desc->bDescriptorType = 0x2a; + desc->bDescLength = 12; /* header decode latency should be zero for roothubs, * see section 4.23.5.2. diff --git a/trunk/drivers/usb/host/xhci-ring.c b/trunk/drivers/usb/host/xhci-ring.c index d030f0b2bfa2..9f1d4b15d818 100644 --- a/trunk/drivers/usb/host/xhci-ring.c +++ b/trunk/drivers/usb/host/xhci-ring.c @@ -2390,7 +2390,17 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd) irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd) { - return xhci_irq(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; } /**** Endpoint Ring Operations ****/ @@ -2551,7 +2561,7 @@ static unsigned int count_sg_trbs_needed(struct xhci_hcd *xhci, struct urb *urb) struct scatterlist *sg; sg = NULL; - num_sgs = urb->num_mapped_sgs; + num_sgs = urb->num_sgs; temp = urb->transfer_buffer_length; xhci_dbg(xhci, "count sg list trbs: \n"); @@ -2735,7 +2745,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_mapped_sgs; + num_sgs = urb->num_sgs; total_packet_count = roundup(urb->transfer_buffer_length, usb_endpoint_maxp(&urb->ep->desc)); diff --git a/trunk/drivers/usb/misc/isight_firmware.c b/trunk/drivers/usb/misc/isight_firmware.c index 8f725f651915..fe1d44319d0a 100644 --- a/trunk/drivers/usb/misc/isight_firmware.c +++ b/trunk/drivers/usb/misc/isight_firmware.c @@ -55,9 +55,8 @@ 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, buf, 1, + (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\1", 1, 300) != 1) { printk(KERN_ERR "Failed to initialise isight firmware loader\n"); @@ -101,9 +100,8 @@ 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, buf, 1, + (dev, usb_sndctrlpipe(dev, 0), 0xa0, 0x40, 0xe600, 0, "\0", 1, 300) != 1) { printk(KERN_ERR "isight firmware loading completion failed\n"); ret = -ENODEV; diff --git a/trunk/drivers/usb/misc/usbtest.c b/trunk/drivers/usb/misc/usbtest.c index 959145baf3cf..bd6d00802eab 100644 --- a/trunk/drivers/usb/misc/usbtest.c +++ b/trunk/drivers/usb/misc/usbtest.c @@ -1765,6 +1765,7 @@ 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) { diff --git a/trunk/drivers/usb/musb/musb_core.c b/trunk/drivers/usb/musb/musb_core.c index de7405e6d7dc..b35942c56da6 100644 --- a/trunk/drivers/usb/musb/musb_core.c +++ b/trunk/drivers/usb/musb/musb_core.c @@ -661,6 +661,7 @@ 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; @@ -2012,8 +2013,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; diff --git a/trunk/drivers/usb/musb/musb_gadget.c b/trunk/drivers/usb/musb/musb_gadget.c index ac3d2eec20fe..f2c5bcbf2541 100644 --- a/trunk/drivers/usb/musb/musb_gadget.c +++ b/trunk/drivers/usb/musb/musb_gadget.c @@ -1842,7 +1842,7 @@ int __init musb_gadget_setup(struct musb *musb) */ musb->g.ops = &musb_gadget_operations; - musb->g.max_speed = USB_SPEED_HIGH; + musb->g.is_dualspeed = 1; musb->g.speed = USB_SPEED_UNKNOWN; /* this "gadget" abstracts/virtualizes the controller */ @@ -1901,7 +1901,7 @@ static int musb_gadget_start(struct usb_gadget *g, unsigned long flags; int retval = -EINVAL; - if (driver->max_speed < USB_SPEED_HIGH) + if (driver->speed < USB_SPEED_HIGH) goto err0; pm_runtime_get_sync(musb->controller); diff --git a/trunk/drivers/usb/otg/Kconfig b/trunk/drivers/usb/otg/Kconfig index 5e913d72cdab..c66481ad98d7 100644 --- a/trunk/drivers/usb/otg/Kconfig +++ b/trunk/drivers/usb/otg/Kconfig @@ -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" diff --git a/trunk/drivers/usb/otg/fsl_otg.c b/trunk/drivers/usb/otg/fsl_otg.c index 2a52ff1b493d..0f420b25e9a9 100644 --- a/trunk/drivers/usb/otg/fsl_otg.c +++ b/trunk/drivers/usb/otg/fsl_otg.c @@ -1151,7 +1151,18 @@ struct platform_driver fsl_otg_driver = { }, }; -module_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_DESCRIPTION(DRIVER_INFO); MODULE_AUTHOR(DRIVER_AUTHOR); diff --git a/trunk/drivers/usb/renesas_usbhs/common.c b/trunk/drivers/usb/renesas_usbhs/common.c index e9a5b1d2615e..08c679c0dde5 100644 --- a/trunk/drivers/usb/renesas_usbhs/common.c +++ b/trunk/drivers/usb/renesas_usbhs/common.c @@ -95,15 +95,25 @@ struct usbhs_priv *usbhs_pdev_to_priv(struct platform_device *pdev) /* * syscfg functions */ -static void usbhs_sys_clock_ctrl(struct usbhs_priv *priv, int enable) +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 | HSE | USBE; - u16 val = DCFM | DRPD | HSE | USBE; + u16 mask = DCFM | DRPD | DPRPU; + u16 val = DCFM | DRPD; int has_otg = usbhs_get_dparam(priv, has_otg); if (has_otg) @@ -120,8 +130,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 | HSE | USBE; - u16 val = DPRPU | HSE | USBE; + u16 mask = DCFM | DRPD | DPRPU; + u16 val = DPRPU; /* * if enable @@ -132,11 +142,6 @@ 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 */ @@ -224,7 +229,7 @@ static void usbhsc_bus_init(struct usbhs_priv *priv) /* * device configuration */ -int usbhs_set_device_config(struct usbhs_priv *priv, int devnum, +int usbhs_set_device_speed(struct usbhs_priv *priv, int devnum, u16 upphub, u16 hubport, u16 speed) { struct device *dev = usbhs_priv_to_dev(priv); @@ -296,25 +301,18 @@ 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); } @@ -390,7 +388,7 @@ static void usbhsc_notify_hotplug(struct work_struct *work) usbhsc_hotplug(priv); } -static int usbhsc_drvcllbck_notify_hotplug(struct platform_device *pdev) +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); @@ -400,8 +398,7 @@ static 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, - msecs_to_jiffies(delay)); + schedule_delayed_work(&priv->notify_hotplug_work, delay); return 0; } @@ -640,7 +637,18 @@ static struct platform_driver renesas_usbhs_driver = { .remove = __devexit_p(usbhs_remove), }; -module_platform_driver(renesas_usbhs_driver); +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_LICENSE("GPL"); MODULE_DESCRIPTION("Renesas USB driver"); diff --git a/trunk/drivers/usb/renesas_usbhs/common.h b/trunk/drivers/usb/renesas_usbhs/common.h index d79b3e27db95..8729da5c3be6 100644 --- a/trunk/drivers/usb/renesas_usbhs/common.h +++ b/trunk/drivers/usb/renesas_usbhs/common.h @@ -33,7 +33,6 @@ struct usbhs_priv; #define SYSCFG 0x0000 #define BUSWAIT 0x0002 #define DVSTCTR 0x0008 -#define TESTMODE 0x000C #define CFIFO 0x0014 #define CFIFOSEL 0x0020 #define CFIFOCTR 0x0022 @@ -276,15 +275,19 @@ 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 @@ -308,7 +311,7 @@ int usbhs_frame_get_num(struct usbhs_priv *priv); /* * device config */ -int usbhs_set_device_config(struct usbhs_priv *priv, int devnum, u16 upphub, +int usbhs_set_device_speed(struct usbhs_priv *priv, int devnum, u16 upphub, u16 hubport, u16 speed); /* diff --git a/trunk/drivers/usb/renesas_usbhs/fifo.c b/trunk/drivers/usb/renesas_usbhs/fifo.c index b51fcd80d244..ffdf5d15085e 100644 --- a/trunk/drivers/usb/renesas_usbhs/fifo.c +++ b/trunk/drivers/usb/renesas_usbhs/fifo.c @@ -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, int sequence) + void *buf, int len, int zero) { struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe); struct device *dev = usbhs_priv_to_dev(priv); @@ -90,7 +90,6 @@ 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 ******************/ @@ -482,9 +481,6 @@ 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; @@ -588,8 +584,6 @@ 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); @@ -647,7 +641,6 @@ 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; } diff --git a/trunk/drivers/usb/renesas_usbhs/fifo.h b/trunk/drivers/usb/renesas_usbhs/fifo.h index f68609c0f489..32a7b246b28d 100644 --- a/trunk/drivers/usb/renesas_usbhs/fifo.h +++ b/trunk/drivers/usb/renesas_usbhs/fifo.h @@ -59,7 +59,6 @@ struct usbhs_pkt { int trans; int actual; int zero; - int sequence; }; struct usbhs_pkt_handle { @@ -96,7 +95,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, int sequence); + void *buf, int len, int zero); struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt); void usbhs_pkt_start(struct usbhs_pipe *pipe); diff --git a/trunk/drivers/usb/renesas_usbhs/mod.c b/trunk/drivers/usb/renesas_usbhs/mod.c index f382e4314362..053f86d70009 100644 --- a/trunk/drivers/usb/renesas_usbhs/mod.c +++ b/trunk/drivers/usb/renesas_usbhs/mod.c @@ -50,9 +50,7 @@ static int usbhsm_autonomy_irq_vbus(struct usbhs_priv *priv, { struct platform_device *pdev = usbhs_priv_to_pdev(priv); - renesas_usbhs_call_notify_hotplug(pdev); - - return 0; + return usbhsc_drvcllbck_notify_hotplug(pdev); } void usbhs_mod_autonomy_mode(struct usbhs_priv *priv) diff --git a/trunk/drivers/usb/renesas_usbhs/mod_gadget.c b/trunk/drivers/usb/renesas_usbhs/mod_gadget.c index db2a1c6a0866..7f4e80338570 100644 --- a/trunk/drivers/usb/renesas_usbhs/mod_gadget.c +++ b/trunk/drivers/usb/renesas_usbhs/mod_gadget.c @@ -14,7 +14,6 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA * */ -#include #include #include #include @@ -45,6 +44,7 @@ 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,6 +114,16 @@ 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 */ @@ -154,7 +164,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, -1); + req->buf, req->length, req->zero); usbhs_pkt_start(pipe); dev_dbg(dev, "pipe %d : queue push (%d)\n", @@ -261,8 +271,6 @@ 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; } @@ -273,145 +281,6 @@ 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 */ @@ -434,7 +303,8 @@ 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"); - return -EINVAL; + ret = -EINVAL; + goto usbhsg_recip_run_handle_end; } switch (recip) { @@ -457,10 +327,20 @@ 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; } @@ -532,12 +412,6 @@ 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; } } @@ -565,16 +439,14 @@ 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; } @@ -809,7 +681,9 @@ 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 @@ -857,8 +731,9 @@ static int usbhsg_try_stop(struct usbhs_priv *priv, u32 status) gpriv->gadget.speed = USB_SPEED_UNKNOWN; /* disable sys */ - usbhs_sys_set_test_mode(priv, 0); + usbhs_sys_hispeed_ctrl(priv, 0); usbhs_sys_function_ctrl(priv, 0); + usbhs_sys_usb_ctrl(priv, 0); usbhsg_pipe_disable(dcp); @@ -880,7 +755,7 @@ static int usbhsg_gadget_start(struct usb_gadget *gadget, if (!driver || !driver->setup || - driver->max_speed < USB_SPEED_FULL) + driver->speed < USB_SPEED_FULL) return -EINVAL; /* first hook up the driver ... */ @@ -991,7 +866,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.max_speed = USB_SPEED_HIGH; + gpriv->gadget.is_dualspeed = 1; ret = device_register(&gpriv->gadget.dev); if (ret < 0) goto err_add_udc; @@ -1021,6 +896,8 @@ 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; @@ -1049,6 +926,8 @@ void usbhs_mod_gadget_remove(struct usbhs_priv *priv) device_unregister(&gpriv->gadget.dev); + usbhsg_controller_unregister(gpriv); + kfree(gpriv->uep); kfree(gpriv); } diff --git a/trunk/drivers/usb/renesas_usbhs/mod_host.c b/trunk/drivers/usb/renesas_usbhs/mod_host.c index aa50eaaffcb6..bade761a1e52 100644 --- a/trunk/drivers/usb/renesas_usbhs/mod_host.c +++ b/trunk/drivers/usb/renesas_usbhs/mod_host.c @@ -45,34 +45,36 @@ * * +--------+ pipes are reused for each uep. * | udev 1 |-+- [uep 0 (dcp) ] --+ pipe will be switched when - * +--------+ | | other device requested + * +--------+ | | target device was changed * +- [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 { @@ -81,10 +83,11 @@ struct usbhsh_device { }; struct usbhsh_ep { - struct usbhs_pipe *pipe; /* attached pipe */ + struct usbhs_pipe *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 */ @@ -95,9 +98,16 @@ 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; }; @@ -109,6 +119,17 @@ 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; \ @@ -131,20 +152,15 @@ 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_to_uep(p) ((p)->mod_private) +#define usbhsh_pipe_info(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) @@ -154,428 +170,156 @@ 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_ureq(p) \ +#define usbhsh_pkt_to_req(p) \ container_of((void *)p, struct usbhsh_request, pkt) /* * req alloc/free */ -static struct usbhsh_request *usbhsh_ureq_alloc(struct usbhsh_hpriv *hpriv, - struct urb *urb, - gfp_t mem_flags) -{ - struct usbhsh_request *ureq; - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct device *dev = usbhs_priv_to_dev(priv); - - ureq = kzalloc(sizeof(struct usbhsh_request), mem_flags); - if (!ureq) { - dev_err(dev, "ureq alloc fail\n"); - return NULL; - } - - usbhs_pkt_init(&ureq->pkt); - ureq->urb = urb; - usbhsh_urb_to_ureq(urb) = ureq; - - return ureq; -} - -static void usbhsh_ureq_free(struct usbhsh_hpriv *hpriv, - struct usbhsh_request *ureq) -{ - usbhsh_urb_to_ureq(ureq->urb) = NULL; - ureq->urb = NULL; - - kfree(ureq); -} - -/* - * status - */ -static int usbhsh_is_running(struct usbhsh_hpriv *hpriv) +static void usbhsh_req_list_init(struct usbhsh_hpriv *hpriv) { - /* - * we can decide some device is attached or not - * by checking mod.irq_attch - * see - * usbhsh_irq_attch() - * usbhsh_irq_dtch() - */ - return (hpriv->mod.irq_attch == NULL); + INIT_LIST_HEAD(&hpriv->ureq_link_active); + INIT_LIST_HEAD(&hpriv->ureq_link_free); } -/* - * pipe control - */ -static void usbhsh_endpoint_sequence_save(struct usbhsh_hpriv *hpriv, - struct urb *urb, - struct usbhs_pkt *pkt) +static void usbhsh_req_list_quit(struct usbhsh_hpriv *hpriv) { - int len = urb->actual_length; - int maxp = usb_endpoint_maxp(&urb->ep->desc); - int t = 0; - - /* DCP is out of sequence control */ - if (usb_pipecontrol(urb->pipe)) - return; - - /* - * 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] - */ + 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); + } - /* - * next sequence depends on actual_length - * - * ex) actual_length = 1147, maxp = 512 - * data0 : 512 - * data1 : 512 - * data0 : 123 - * data1 is the next sequence - */ - 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)); + /* kfree all free ureq */ + list_for_each_entry_safe(ureq, next, &hpriv->ureq_link_free, ureq_link) + kfree(ureq); } -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) +static struct usbhsh_request *usbhsh_req_alloc(struct usbhsh_hpriv *hpriv, + struct urb *urb, + gfp_t mem_flags) { + struct usbhsh_request *ureq; 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; - } - - usbhs_for_each_pipe_with_dcp(pipe, priv, i) { - - /* check pipe type */ - if (!usbhs_pipe_type_is(pipe, usb_endpoint_type(desc))) - continue; - - /* 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; - } - - /* check pipe is free */ - if (usbhsh_pipe_to_uep(pipe)) - continue; + if (list_empty(&hpriv->ureq_link_free)) { /* - * attach pipe to uep - * - * usbhs_pipe_config_update() should be called after - * usbhs_set_device_config() - * see - * DCPMAXP/PIPEMAXP + * create new one if there is no free ureq */ - usbhsh_uep_to_pipe(uep) = pipe; - usbhsh_pipe_to_uep(pipe) = uep; - - usbhs_pipe_config_update(pipe, - usbhsh_device_number(hpriv, udev), - usb_endpoint_num(desc), - usb_endpoint_maxp(desc)); - - 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"); - - ret = 0; - break; - } - -usbhsh_pipe_attach_done: - usbhs_unlock(priv, flags); - /******************** spin unlock ******************/ - - return ret; -} - -static void usbhsh_pipe_detach(struct usbhsh_hpriv *hpriv, - struct usbhsh_ep *uep) -{ - struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); - struct usbhs_pipe *pipe; - struct device *dev = usbhs_priv_to_dev(priv); - unsigned long flags; - - /******************** spin lock ********************/ - usbhs_lock(priv, flags); - - pipe = usbhsh_uep_to_pipe(uep); - - if (unlikely(!pipe)) { - dev_err(dev, "uep doens't have pipe\n"); + ureq = kzalloc(sizeof(struct usbhsh_request), mem_flags); + if (ureq) + INIT_LIST_HEAD(&ureq->ureq_link); } 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)); + /* + * 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); } - usbhs_unlock(priv, flags); - /******************** spin unlock ******************/ -} - -/* - * endpoint control - */ -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 usbhsh_device *udev = usbhsh_device_get(hpriv, urb); - struct usb_host_endpoint *ep = urb->ep; - struct usbhsh_ep *uep; - struct device *dev = usbhs_priv_to_dev(priv); - struct usb_endpoint_descriptor *desc = &ep->desc; - unsigned long flags; - - uep = kzalloc(sizeof(struct usbhsh_ep), mem_flags); - if (!uep) { - dev_err(dev, "usbhsh_ep alloc fail\n"); - return -ENOMEM; + if (!ureq) { + dev_err(dev, "ureq alloc fail\n"); + return NULL; } - /******************** spin lock ********************/ - usbhs_lock(priv, flags); + usbhs_pkt_init(&ureq->pkt); /* - * init endpoint + * push it to "active" list */ - 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)); + list_add_tail(&ureq->ureq_link, &hpriv->ureq_link_active); + ureq->urb = urb; - return 0; + return ureq; } -static void usbhsh_endpoint_detach(struct usbhsh_hpriv *hpriv, - struct usb_host_endpoint *ep) +static void usbhsh_req_free(struct usbhsh_hpriv *hpriv, + struct usbhsh_request *ureq) { - 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)); + struct usbhs_pkt *pkt = &ureq->pkt; - if (usbhsh_uep_to_pipe(uep)) - usbhsh_pipe_detach(hpriv, uep); + usbhs_pkt_init(pkt); - /******************** 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)); + /* + * removed from "active" list, + * and push it to "free" list + */ + ureq->urb = NULL; + list_del_init(&ureq->ureq_link); + list_add_tail(&ureq->ureq_link, &hpriv->ureq_link_free); } /* * 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, +static struct usbhsh_device *usbhsh_device_alloc(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. + * device 0 */ - if (0 != usb_pipedevice(urb->pipe)) { - dev_err(dev, "%s fail: urb isn't pointing device0\n", __func__); - return NULL; + if (0 == usb_pipedevice(urb->pipe)) { + udev = usbhsh_device0(hpriv); + goto usbhsh_device_find; } - /******************** spin lock ********************/ - usbhs_lock(priv, flags); - /* * find unused device */ - usbhsh_for_each_udev(pos, hpriv, i) { - if (usbhsh_udev_is_used(pos)) + usbhsh_for_each_udev(udev, hpriv, i) { + if (usbhsh_udev_to_usbv(udev)) continue; - udev = pos; - break; + goto usbhsh_device_find; } - if (udev) { - /* - * usbhsh_usbv_to_udev() - * usbhsh_udev_to_usbv() - * will be enable - */ - dev_set_drvdata(&usbv->dev, udev); - udev->usbv = usbv; - } + dev_err(dev, "no free usbhsh_device\n"); - usbhs_unlock(priv, flags); - /******************** spin unlock ******************/ + return NULL; - if (!udev) { - dev_err(dev, "no free usbhsh_device\n"); - return NULL; - } - - if (usbhsh_device_has_endpoint(udev)) { +usbhsh_device_find: + 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); - } /* uep will be attached */ - INIT_LIST_HEAD(&udev0->ep_list_head); INIT_LIST_HEAD(&udev->ep_list_head); /* - * set device0 config - */ - usbhs_set_device_config(priv, - 0, 0, 0, usbv->speed); - - /* - * set new device config + * usbhsh_usbv_to_udev() + * usbhsh_udev_to_usbv() + * will be enable */ - 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); - - upphub = usbhsh_device_number(hpriv, parent); - hubport = usbhsh_device_hubport(udev); + dev_set_drvdata(&usbv->dev, udev); + udev->usbv = usbv; - dev_dbg(dev, "%s connecte to Hub [%d:%d](%p)\n", __func__, - upphub, hubport, parent); - } - - usbhs_set_device_config(priv, + /* set device config */ + usbhs_set_device_speed(priv, + usbhsh_device_number(hpriv, udev), usbhsh_device_number(hpriv, udev), - upphub, hubport, usbv->speed); + 0, /* FIXME no parent */ + usbv->speed); dev_dbg(dev, "%s [%d](%p)\n", __func__, usbhsh_device_number(hpriv, udev), udev); @@ -583,45 +327,152 @@ static struct usbhsh_device *usbhsh_device_attach(struct usbhsh_hpriv *hpriv, return udev; } -static void usbhsh_device_detach(struct usbhsh_hpriv *hpriv, +static void usbhsh_device_free(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 = usbhsh_hcd_to_dev(hcd); struct usb_device *usbv = usbhsh_udev_to_usbv(udev); - unsigned long flags; dev_dbg(dev, "%s [%d](%p)\n", __func__, usbhsh_device_number(hpriv, udev), udev); - if (usbhsh_device_has_endpoint(udev)) { + if (usbhsh_device_has_endpoint(udev)) dev_warn(dev, "udev still have endpoint\n"); - usbhsh_endpoint_detach_all(hpriv, udev); + + /* + * usbhsh_usbv_to_udev() + * usbhsh_udev_to_usbv() + * will be disable + */ + dev_set_drvdata(&usbv->dev, NULL); + udev->usbv = NULL; +} + +/* + * end-point 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) +{ + struct usbhs_priv *priv = usbhsh_hpriv_to_priv(hpriv); + struct usb_hcd *hcd = usbhsh_hpriv_to_hcd(hpriv); + struct usbhsh_ep *uep; + struct usbhsh_pipe_info *info; + struct usbhs_pipe *pipe, *best_pipe; + struct device *dev = usbhsh_hcd_to_dev(hcd); + struct usb_endpoint_descriptor *desc = &ep->desc; + int type, i, dir_in; + unsigned int min_usr; + + dir_in_req = !!dir_in_req; + + uep = kzalloc(sizeof(struct usbhsh_ep), mem_flags); + if (!uep) { + dev_err(dev, "usbhsh_ep alloc fail\n"); + return NULL; + } + + if (usb_endpoint_xfer_control(desc)) { + best_pipe = usbhsh_hpriv_to_dcp(hpriv); + goto usbhsh_endpoint_alloc_find_pipe; } /* - * There is nothing to do if it is device0. + * find best pipe for endpoint * see - * usbhsh_device_attach() - * usbhsh_device_get() + * HARDWARE LIMITATION */ - if (0 == usbhsh_device_number(hpriv, udev)) - return; + 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)) + continue; + + dir_in = !!usbhs_pipe_is_dir_in(pipe); + if (0 != (dir_in - dir_in_req)) + continue; - /******************** spin lock ********************/ - usbhs_lock(priv, flags); + info = usbhsh_pipe_info(pipe); + if (min_usr > info->usr_cnt) { + min_usr = info->usr_cnt; + best_pipe = pipe; + } + } + + if (unlikely(!best_pipe)) { + dev_err(dev, "couldn't find best pipe\n"); + kfree(uep); + return NULL; + } +usbhsh_endpoint_alloc_find_pipe: /* - * usbhsh_usbv_to_udev() - * usbhsh_udev_to_usbv() - * will be disable + * init uep */ - dev_set_drvdata(&usbv->dev, NULL); - udev->usbv = NULL; + uep->pipe = best_pipe; + uep->maxp = usb_endpoint_maxp(desc); + usbhsh_uep_to_udev(uep) = udev; + usbhsh_ep_to_uep(ep) = uep; + + /* + * update pipe user count + */ + info = usbhsh_pipe_info(best_pipe); + info->usr_cnt++; + + /* init this endpoint, and attach it to udev */ + INIT_LIST_HEAD(&uep->ep_list); + list_add_tail(&uep->ep_list, &udev->ep_list_head); - usbhs_unlock(priv, flags); - /******************** spin unlock ******************/ + /* + * 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 [%d-%s](%p)\n", __func__, + usbhsh_device_number(hpriv, udev), + usbhs_pipe_name(uep->pipe), uep); + + return uep; +} + +void usbhsh_endpoint_free(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); + struct usbhsh_pipe_info *info; + + if (!uep) + return; + + dev_dbg(dev, "%s [%d-%s](%p)\n", __func__, + usbhsh_device_number(hpriv, usbhsh_uep_to_udev(uep)), + usbhs_pipe_name(uep->pipe), uep); + + info = usbhsh_pipe_info(uep->pipe); + info->usr_cnt--; + + /* remove this endpoint from udev */ + list_del_init(&uep->ep_list); + + usbhsh_uep_to_udev(uep) = NULL; + usbhsh_ep_to_uep(ep) = NULL; + + kfree(uep); } /* @@ -629,13 +480,11 @@ static void usbhsh_device_detach(struct usbhsh_hpriv *hpriv, */ static void usbhsh_queue_done(struct usbhs_priv *priv, struct usbhs_pkt *pkt) { - struct usbhsh_request *ureq = usbhsh_pkt_to_ureq(pkt); + struct usbhsh_request *ureq = usbhsh_pkt_to_req(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 usbhsh_ep *uep = usbhsh_ep_to_uep(urb->ep); struct device *dev = usbhs_priv_to_dev(priv); - int status = 0; dev_dbg(dev, "%s\n", __func__); @@ -644,43 +493,29 @@ 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_ureq_free(hpriv, ureq); - - usbhsh_endpoint_sequence_save(hpriv, urb, pkt); - usbhsh_pipe_detach(hpriv, uep); + usbhsh_req_free(hpriv, ureq); + usbhsh_urb_to_ureq(urb) = NULL; usb_hcd_unlink_urb_from_ep(hcd, urb); - usb_hcd_giveback_urb(hcd, urb, status); + usb_hcd_giveback_urb(hcd, urb, 0); } static int usbhsh_queue_push(struct usb_hcd *hcd, - struct urb *urb, - gfp_t mem_flags) + struct usbhs_pipe *pipe, + struct urb *urb) { - 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 usbhsh_request *ureq = usbhsh_urb_to_ureq(urb); + struct usbhs_pkt *pkt = &ureq->pkt; struct device *dev = usbhsh_hcd_to_dev(hcd); - struct usbhsh_request *ureq; void *buf; - int len, sequence; + int len; 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 @@ -689,59 +524,25 @@ 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, &ureq->pkt, usbhsh_queue_done, - buf, len, (urb->transfer_flags & URB_ZERO_PACKET), - sequence); - + usbhs_pkt_push(pipe, pkt, usbhsh_queue_done, + buf, len, (urb->transfer_flags & URB_ZERO_PACKET)); 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 *req; + struct usb_ctrlrequest *cmd; - req = (struct usb_ctrlrequest *)urb->setup_packet; + cmd = (struct usb_ctrlrequest *)urb->setup_packet; - if ((DeviceOutRequest == req->bRequestType << 8) && - (USB_REQ_SET_ADDRESS == req->bRequest)) + if ((DeviceOutRequest == cmd->bRequestType << 8) && + (USB_REQ_SET_ADDRESS == cmd->bRequest)) return 1; else return 0; @@ -769,15 +570,11 @@ 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 to use attached device. - * see usbhsh_device_attach() + * modify usb address here. */ if (usbhsh_is_request_address(urb)) { - 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); + /* FIXME */ + req.wValue = 1; dev_dbg(dev, "create new address - %d\n", req.wValue); } @@ -798,80 +595,82 @@ 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_ureq(pkt); + struct usbhsh_request *ureq = usbhsh_pkt_to_req(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_ureq_free(hpriv, ureq); + usbhsh_req_free(hpriv, ureq); + usbhsh_urb_to_ureq(urb) = NULL; } -static int usbhsh_data_stage_packet_push(struct usbhsh_hpriv *hpriv, - struct urb *urb, - struct usbhs_pipe *pipe, - gfp_t mem_flags) - +static void usbhsh_data_stage_packet_push(struct usbhsh_hpriv *hpriv, + struct urb *urb, + struct usbhs_pipe *pipe) { struct usbhsh_request *ureq; + struct usbhs_pkt *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; + /* + * 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; 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, &ureq->pkt, + usbhs_pkt_push(pipe, pkt, usbhsh_data_stage_packet_done, urb->transfer_buffer, urb->transfer_buffer_length, - (urb->transfer_flags & URB_ZERO_PACKET), - -1); - - return 0; + (urb->transfer_flags & URB_ZERO_PACKET)); } /* * DCP status stage */ -static int usbhsh_status_stage_packet_push(struct usbhsh_hpriv *hpriv, +static void usbhsh_status_stage_packet_push(struct usbhsh_hpriv *hpriv, struct urb *urb, - struct usbhs_pipe *pipe, - gfp_t mem_flags) + struct usbhs_pipe *pipe) { struct usbhsh_request *ureq; + struct usbhs_pkt *pkt; - /* This ureq will be freed on usbhsh_queue_done() */ - ureq = usbhsh_ureq_alloc(hpriv, urb, mem_flags); - if (unlikely(!ureq)) - return -ENOMEM; + /* + * 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; 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, &ureq->pkt, + usbhs_pkt_push(pipe, pkt, usbhsh_queue_done, NULL, urb->transfer_buffer_length, - 0, -1); - - return 0; + 0); } static int usbhsh_dcp_queue_push(struct usb_hcd *hcd, - struct urb *urb, - gfp_t mflags) + struct usbhsh_hpriv *hpriv, + struct usbhs_pipe *pipe, + struct urb *urb) { - 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__); @@ -887,22 +686,13 @@ static int usbhsh_dcp_queue_push(struct usb_hcd *hcd, * * It is pushed only when urb has buffer. */ - 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; - } - } + if (urb->transfer_buffer_length) + usbhsh_data_stage_packet_push(hpriv, urb, pipe); /* * status stage */ - ret = usbhsh_status_stage_packet_push(hpriv, urb, pipe, mflags); - if (ret < 0) { - dev_err(dev, "status stage failed\n"); - return ret; - } + usbhsh_status_stage_packet_push(hpriv, urb, pipe); /* * start pushed packets @@ -939,82 +729,71 @@ 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_device *new_udev = NULL; + struct usbhsh_request *ureq; + struct usbhsh_device *udev, *new_udev = NULL; + struct usbhs_pipe *pipe; + struct usbhsh_ep *uep; 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) { - dev_err(dev, "urb link failed\n"); + if (ret) goto usbhsh_urb_enqueue_error_not_linked; - } /* - * attach udev if needed - * see [image of mod_host] + * get 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"); + udev = usbhsh_usbv_to_udev(usbv); + if (!udev) { + new_udev = usbhsh_device_alloc(hpriv, urb); + if (!new_udev) goto usbhsh_urb_enqueue_error_not_linked; - } + + udev = new_udev; } /* - * attach endpoint if needed - * see [image of mod_host] + * get 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"); + uep = usbhsh_ep_to_uep(ep); + if (!uep) { + uep = usbhsh_endpoint_alloc(hpriv, udev, ep, + is_dir_in, mem_flags); + if (!uep) goto usbhsh_urb_enqueue_error_free_device; - } } + pipe = usbhsh_uep_to_pipe(uep); /* - * attach pipe to endpoint - * see [image of mod_host] + * alloc new request */ - 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"); + ureq = usbhsh_req_alloc(hpriv, urb, mem_flags); + if (unlikely(!ureq)) { + ret = -ENOMEM; goto usbhsh_urb_enqueue_error_free_endpoint; } + usbhsh_urb_to_ureq(urb) = ureq; /* * push packet */ if (usb_pipecontrol(urb->pipe)) - ret = usbhsh_dcp_queue_push(hcd, urb, mem_flags); + usbhsh_dcp_queue_push(hcd, hpriv, pipe, urb); else - ret = usbhsh_queue_push(hcd, urb, mem_flags); + usbhsh_queue_push(hcd, pipe, urb); - return ret; + return 0; usbhsh_urb_enqueue_error_free_endpoint: - usbhsh_endpoint_detach(hpriv, ep); + usbhsh_endpoint_free(hpriv, ep); usbhsh_urb_enqueue_error_free_device: if (new_udev) - usbhsh_device_detach(hpriv, new_udev); + usbhsh_device_free(hpriv, new_udev); usbhsh_urb_enqueue_error_not_linked: dev_dbg(dev, "%s error\n", __func__); @@ -1028,11 +807,8 @@ 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) { - 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); + usbhsh_req_free(hpriv, ureq); + usbhsh_urb_to_ureq(urb) = NULL; } return 0; @@ -1047,7 +823,7 @@ static void usbhsh_endpoint_disable(struct usb_hcd *hcd, /* * this function might be called manytimes by same hcd/ep - * in-endpoint == out-endpoint if ep == dcp. + * in-endpoitn == out-endpoint if ep == dcp. */ if (!uep) return; @@ -1055,14 +831,15 @@ static void usbhsh_endpoint_disable(struct usb_hcd *hcd, udev = usbhsh_uep_to_udev(uep); hpriv = usbhsh_hcd_to_hpriv(hcd); - usbhsh_endpoint_detach(hpriv, ep); + usbhsh_endpoint_free(hpriv, ep); + ep->hcpriv = NULL; /* * if there is no endpoint, * free device */ if (!usbhsh_device_has_endpoint(udev)) - usbhsh_device_detach(hpriv, udev); + usbhsh_device_free(hpriv, udev); } static int usbhsh_hub_status_data(struct usb_hcd *hcd, char *buf) @@ -1142,8 +919,6 @@ 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); @@ -1307,20 +1082,6 @@ 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; } @@ -1335,24 +1096,6 @@ 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; } @@ -1388,6 +1131,7 @@ 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); @@ -1396,6 +1140,7 @@ 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, @@ -1429,7 +1174,7 @@ static void usbhsh_pipe_init_for_host(struct usbhs_priv *priv) dir_in); } - pipe->mod_private = NULL; + pipe->mod_private = pipe_info + i; } } @@ -1460,7 +1205,9 @@ 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 @@ -1495,7 +1242,9 @@ 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"); @@ -1506,8 +1255,10 @@ 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 */ @@ -1517,6 +1268,12 @@ int usbhs_mod_host_probe(struct usbhs_priv *priv) return -ENOMEM; } + 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 * @@ -1536,6 +1293,9 @@ 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 */ @@ -1547,6 +1307,11 @@ 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) @@ -1554,6 +1319,8 @@ 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; diff --git a/trunk/drivers/usb/renesas_usbhs/pipe.c b/trunk/drivers/usb/renesas_usbhs/pipe.c index c2559e80d41f..c74389ce2177 100644 --- a/trunk/drivers/usb/renesas_usbhs/pipe.c +++ b/trunk/drivers/usb/renesas_usbhs/pipe.c @@ -257,13 +257,6 @@ 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 */ @@ -478,27 +471,10 @@ 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 sequence) +void usbhs_pipe_data_sequence(struct usbhs_pipe *pipe, int data) { u16 mask = (SQCLR | SQSET); - u16 val; - - /* - * sequence - * 0 : data0 - * 1 : data1 - * -1 : no change - */ - switch (sequence) { - case 0: - val = SQCLR; - break; - case 1: - val = SQSET; - break; - default: - return; - } + u16 val = (data) ? SQSET : SQCLR; usbhsp_pipectrl_set(pipe, mask, val); } diff --git a/trunk/drivers/usb/renesas_usbhs/pipe.h b/trunk/drivers/usb/renesas_usbhs/pipe.h index fa18b7dc2b2a..6334fc644cc0 100644 --- a/trunk/drivers/usb/renesas_usbhs/pipe.h +++ b/trunk/drivers/usb/renesas_usbhs/pipe.h @@ -87,7 +87,6 @@ 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/trunk/drivers/usb/serial/ChangeLog.history b/trunk/drivers/usb/serial/ChangeLog.history new file mode 100644 index 000000000000..f13fd488ebec --- /dev/null +++ b/trunk/drivers/usb/serial/ChangeLog.history @@ -0,0 +1,730 @@ +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 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 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 + 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 + 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 + 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 + 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 + for the information. + + (03/21/2002) gkh + Added support for the Palm m130 device, thanks to Udo Eisenbarth + 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. + + diff --git a/trunk/drivers/usb/serial/belkin_sa.c b/trunk/drivers/usb/serial/belkin_sa.c index f9f29b289f2f..d6921fa1403c 100644 --- a/trunk/drivers/usb/serial/belkin_sa.c +++ b/trunk/drivers/usb/serial/belkin_sa.c @@ -20,7 +20,50 @@ * 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 diff --git a/trunk/drivers/usb/serial/ch341.c b/trunk/drivers/usb/serial/ch341.c index 0e77511060c0..6ae1c0688b5e 100644 --- a/trunk/drivers/usb/serial/ch341.c +++ b/trunk/drivers/usb/serial/ch341.c @@ -335,12 +335,13 @@ 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); - goto out; + return -EPROTO; } r = usb_serial_generic_open(tty, port); diff --git a/trunk/drivers/usb/serial/cp210x.c b/trunk/drivers/usb/serial/cp210x.c index 7175bb107dec..fd67cc53545b 100644 --- a/trunk/drivers/usb/serial/cp210x.c +++ b/trunk/drivers/usb/serial/cp210x.c @@ -280,10 +280,7 @@ 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); - if (result > 0) - result = -EPROTO; - - return result; + return -EPROTO; } return 0; @@ -334,10 +331,7 @@ 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); - if (result > 0) - result = -EPROTO; - - return result; + return -EPROTO; } return 0; @@ -401,11 +395,10 @@ static int cp210x_open(struct tty_struct *tty, struct usb_serial_port *port) dbg("%s - port %d", __func__, port->number); - 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; + 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 = usb_serial_generic_open(tty, port); @@ -527,13 +520,18 @@ static void cp210x_get_termios_port(struct usb_serial_port *port, cflag |= PARENB; break; case BITS_PARITY_MARK: - dbg("%s - parity = MARK", __func__); - cflag |= (PARENB|PARODD|CMSPAR); + 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); break; case BITS_PARITY_SPACE: - dbg("%s - parity = SPACE", __func__); - cflag &= ~PARODD; - cflag |= (PARENB|CMSPAR); + 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); break; default: dbg("%s - Unknown parity mode, disabling parity", __func__); @@ -590,6 +588,7 @@ 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)); @@ -644,27 +643,16 @@ static void cp210x_set_termios(struct tty_struct *tty, "not supported by device\n"); } - if ((cflag & (PARENB|PARODD|CMSPAR)) != - (old_cflag & (PARENB|PARODD|CMSPAR))) { + if ((cflag & (PARENB|PARODD)) != (old_cflag & (PARENB|PARODD))) { cp210x_get_config(port, CP210X_GET_LINE_CTL, &bits, 2); bits &= ~BITS_PARITY_MASK; if (cflag & PARENB) { - 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__); - } + if (cflag & PARODD) { + bits |= BITS_PARITY_ODD; + dbg("%s - parity = ODD", __func__); } else { - if (cflag & PARODD) { - bits |= BITS_PARITY_ODD; - dbg("%s - parity = ODD", __func__); - } else { - bits |= BITS_PARITY_EVEN; - dbg("%s - parity = EVEN", __func__); - } + bits |= BITS_PARITY_EVEN; + dbg("%s - parity = EVEN", __func__); } } if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2)) diff --git a/trunk/drivers/usb/serial/cyberjack.c b/trunk/drivers/usb/serial/cyberjack.c index 98bf83349838..f744ab7a3b19 100644 --- a/trunk/drivers/usb/serial/cyberjack.c +++ b/trunk/drivers/usb/serial/cyberjack.c @@ -138,6 +138,7 @@ 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) @@ -207,6 +208,7 @@ 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; @@ -219,18 +221,22 @@ static int cyberjack_write(struct tty_struct *tty, return 0; } - if (!test_and_clear_bit(0, &port->write_urbs_free)) { + spin_lock_bh(&port->lock); + if (port->write_urb_busy) { + spin_unlock_bh(&port->lock); 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; } @@ -259,7 +265,13 @@ static int cyberjack_write(struct tty_struct *tty, priv->wrsent = length; /* set up our urb */ - port->write_urb->transfer_buffer_length = length; + 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); /* send the data out the bulk port */ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); @@ -271,7 +283,7 @@ static int cyberjack_write(struct tty_struct *tty, priv->wrfilled = 0; priv->wrsent = 0; spin_unlock_irqrestore(&priv->lock, flags); - set_bit(0, &port->write_urbs_free); + port->write_urb_busy = 0; return 0; } @@ -339,6 +351,7 @@ 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 " @@ -349,6 +362,7 @@ 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"); @@ -401,6 +415,7 @@ 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 " @@ -417,7 +432,7 @@ static void cyberjack_write_bulk_callback(struct urb *urb) dbg("%s - port %d", __func__, port->number); - set_bit(0, &port->write_urbs_free); + port->write_urb_busy = 0; if (status) { dbg("%s - nonzero write bulk status received: %d", __func__, status); @@ -440,7 +455,13 @@ static void cyberjack_write_bulk_callback(struct urb *urb) priv->wrsent += length; /* set up our urb */ - port->write_urb->transfer_buffer_length = length; + 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); /* send the data out the bulk port */ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); diff --git a/trunk/drivers/usb/serial/cypress_m8.c b/trunk/drivers/usb/serial/cypress_m8.c index 07680d6b792b..d9906eb9d16a 100644 --- a/trunk/drivers/usb/serial/cypress_m8.c +++ b/trunk/drivers/usb/serial/cypress_m8.c @@ -16,6 +16,32 @@ * * See http://geocities.com/i0xox0i for information on this driver and the * earthmate usb device. + * + * Lonnie Mendez + * 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 + * 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 + * 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 @@ -1136,6 +1162,8 @@ 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, " @@ -1324,6 +1352,7 @@ 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; diff --git a/trunk/drivers/usb/serial/digi_acceleport.c b/trunk/drivers/usb/serial/digi_acceleport.c index 6d26a77d0f2a..e92cbefc0f88 100644 --- a/trunk/drivers/usb/serial/digi_acceleport.c +++ b/trunk/drivers/usb/serial/digi_acceleport.c @@ -13,6 +13,222 @@ * * 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 @@ -438,6 +654,7 @@ 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; @@ -515,6 +732,7 @@ 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) { @@ -585,6 +803,7 @@ 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) { @@ -680,8 +899,10 @@ 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) + if (priv->dp_throttle_restart) { + port->read_urb->dev = port->serial->dev; ret = usb_submit_urb(port->read_urb, GFP_ATOMIC); + } /* turn throttle off */ priv->dp_throttled = 0; @@ -974,6 +1195,7 @@ 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; @@ -1049,6 +1271,7 @@ 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); @@ -1250,6 +1473,7 @@ 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, @@ -1392,6 +1616,7 @@ static void digi_read_bulk_callback(struct urb *urb) } /* continue read */ + urb->dev = port->serial->dev; ret = usb_submit_urb(urb, GFP_ATOMIC); if (ret != 0 && ret != -EPERM) { dev_err(&port->dev, diff --git a/trunk/drivers/usb/serial/ftdi_sio.c b/trunk/drivers/usb/serial/ftdi_sio.c index c290df97108e..ff3db5d056a5 100644 --- a/trunk/drivers/usb/serial/ftdi_sio.c +++ b/trunk/drivers/usb/serial/ftdi_sio.c @@ -2105,9 +2105,6 @@ 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) @@ -2121,7 +2118,6 @@ 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; diff --git a/trunk/drivers/usb/serial/garmin_gps.c b/trunk/drivers/usb/serial/garmin_gps.c index bf12565f8e87..1a49ca9c8ea5 100644 --- a/trunk/drivers/usb/serial/garmin_gps.c +++ b/trunk/drivers/usb/serial/garmin_gps.c @@ -901,6 +901,7 @@ 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, @@ -1276,6 +1277,7 @@ 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; @@ -1309,6 +1311,12 @@ 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, @@ -1345,6 +1353,7 @@ 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, diff --git a/trunk/drivers/usb/serial/generic.c b/trunk/drivers/usb/serial/generic.c index f7403576f99f..e4db5ad2bc55 100644 --- a/trunk/drivers/usb/serial/generic.c +++ b/trunk/drivers/usb/serial/generic.c @@ -1,7 +1,7 @@ /* * USB Serial Converter Generic functions * - * Copyright (C) 2010 - 2011 Johan Hovold (jhovold@gmail.com) + * Copyright (C) 2010 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_urbs(port, GFP_KERNEL); + result = usb_serial_generic_submit_read_urb(port, GFP_KERNEL); return result; } @@ -157,10 +157,8 @@ 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) { - for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) - usb_kill_urb(port->read_urbs[i]); - } + if (port->bulk_in_size) + usb_kill_urb(port->read_urb); } } @@ -310,52 +308,19 @@ int usb_serial_generic_chars_in_buffer(struct tty_struct *tty) return chars; } -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, +int usb_serial_generic_submit_read_urb(struct usb_serial_port *port, gfp_t mem_flags) { - int res; - int i; - - dbg("%s - port %d", __func__, port->number); + int result; - 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; + 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); } - - return 0; -err: - for (; i >= 0; --i) - usb_kill_urb(port->read_urbs[i]); - - return res; + return result; } -EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urbs); +EXPORT_SYMBOL_GPL(usb_serial_generic_submit_read_urb); void usb_serial_generic_process_read_urb(struct urb *urb) { @@ -391,19 +356,14 @@ 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; - for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) { - if (urb == port->read_urbs[i]) - break; - } - set_bit(i, &port->read_urbs_free); + dbg("%s - port %d", __func__, port->number); - 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); + if (unlikely(status != 0)) { + dbg("%s - nonzero read bulk status received: %d", + __func__, status); return; } @@ -416,7 +376,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, i, GFP_ATOMIC); + usb_serial_generic_submit_read_urb(port, GFP_ATOMIC); } else spin_unlock_irqrestore(&port->lock, flags); } @@ -483,7 +443,7 @@ void usb_serial_generic_unthrottle(struct tty_struct *tty) spin_unlock_irq(&port->lock); if (was_throttled) - usb_serial_generic_submit_read_urbs(port, GFP_KERNEL); + usb_serial_generic_submit_read_urb(port, GFP_KERNEL); } EXPORT_SYMBOL_GPL(usb_serial_generic_unthrottle); @@ -549,9 +509,8 @@ int usb_serial_generic_resume(struct usb_serial *serial) if (!test_bit(ASYNCB_INITIALIZED, &port->port.flags)) continue; - if (port->bulk_in_size) { - r = usb_serial_generic_submit_read_urbs(port, - GFP_NOIO); + if (port->read_urb) { + r = usb_submit_urb(port->read_urb, GFP_NOIO); if (r < 0) c++; } diff --git a/trunk/drivers/usb/serial/io_edgeport.c b/trunk/drivers/usb/serial/io_edgeport.c index abd2ee2b2f99..2ee807523f53 100644 --- a/trunk/drivers/usb/serial/io_edgeport.c +++ b/trunk/drivers/usb/serial/io_edgeport.c @@ -610,6 +610,7 @@ 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); @@ -710,6 +711,7 @@ 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, @@ -1328,6 +1330,7 @@ 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 */ diff --git a/trunk/drivers/usb/serial/io_ti.c b/trunk/drivers/usb/serial/io_ti.c index e44d375edaad..0aac00afb5c8 100644 --- a/trunk/drivers/usb/serial/io_ti.c +++ b/trunk/drivers/usb/serial/io_ti.c @@ -15,6 +15,13 @@ * For questions or problems with this driver, contact Inside Out * Networks technical support, or Peter Berger , * or Al Borchers . + * + * 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 @@ -1770,11 +1777,12 @@ 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) + if (edge_port->ep_read_urb_state == EDGE_READ_URB_RUNNING) { + urb->dev = edge_port->port->serial->dev; 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, @@ -1951,7 +1959,9 @@ 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, @@ -1977,7 +1987,9 @@ 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, @@ -2106,7 +2118,12 @@ static void edge_send(struct tty_struct *tty) port->write_urb->transfer_buffer); /* set up our urb */ - port->write_urb->transfer_buffer_length = count; + 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); /* send the data out the bulk port */ result = usb_submit_urb(port->write_urb, GFP_ATOMIC); @@ -2250,6 +2267,9 @@ 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; diff --git a/trunk/drivers/usb/serial/ipaq.c b/trunk/drivers/usb/serial/ipaq.c index 36f5cbe90485..4735931b4c7b 100644 --- a/trunk/drivers/usb/serial/ipaq.c +++ b/trunk/drivers/usb/serial/ipaq.c @@ -8,6 +8,40 @@ * 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 . + * + * (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 + * + * (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 diff --git a/trunk/drivers/usb/serial/ir-usb.c b/trunk/drivers/usb/serial/ir-usb.c index 0c537da0d3cd..ccbce4066d04 100644 --- a/trunk/drivers/usb/serial/ir-usb.c +++ b/trunk/drivers/usb/serial/ir-usb.c @@ -22,6 +22,38 @@ * * See Documentation/usb/usb-serial.txt for more information on using this * driver + * + * 2008_Jun_02 Felipe Balbi + * Introduced common header to be used also in USB Gadget Framework. + * Still needs some other style fixes. + * + * 2007_Jun_21 Alan Cox + * 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 . + * + * 2001_Oct_07 greg kh + * initial version released. */ #include diff --git a/trunk/drivers/usb/serial/iuu_phoenix.c b/trunk/drivers/usb/serial/iuu_phoenix.c index 64d0ffd4440b..6aca631a407a 100644 --- a/trunk/drivers/usb/serial/iuu_phoenix.c +++ b/trunk/drivers/usb/serial/iuu_phoenix.c @@ -1168,14 +1168,15 @@ 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; } diff --git a/trunk/drivers/usb/serial/keyspan.c b/trunk/drivers/usb/serial/keyspan.c index bc8dc203e818..a442352d7b61 100644 --- a/trunk/drivers/usb/serial/keyspan.c +++ b/trunk/drivers/usb/serial/keyspan.c @@ -25,6 +25,73 @@ 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 ) + 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... */ @@ -330,6 +397,7 @@ 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); @@ -395,6 +463,7 @@ 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); @@ -490,6 +559,7 @@ 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); @@ -539,6 +609,7 @@ 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)", @@ -623,6 +694,7 @@ 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); @@ -717,6 +789,8 @@ 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); @@ -774,6 +848,7 @@ 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); @@ -844,6 +919,8 @@ 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); @@ -919,6 +996,7 @@ 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); @@ -969,6 +1047,7 @@ 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); @@ -1044,6 +1123,7 @@ 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); @@ -1143,6 +1223,7 @@ 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 */ @@ -1158,6 +1239,7 @@ 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); */ } @@ -1874,6 +1956,7 @@ 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); @@ -2001,6 +2084,7 @@ 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__); @@ -2187,6 +2271,8 @@ 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) @@ -2329,6 +2415,7 @@ 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); @@ -2474,6 +2561,7 @@ 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) @@ -2562,12 +2650,14 @@ 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__, diff --git a/trunk/drivers/usb/serial/keyspan_pda.c b/trunk/drivers/usb/serial/keyspan_pda.c index a40615674a68..d5c0c6ab4966 100644 --- a/trunk/drivers/usb/serial/keyspan_pda.c +++ b/trunk/drivers/usb/serial/keyspan_pda.c @@ -12,6 +12,59 @@ * * 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. + * */ @@ -237,6 +290,7 @@ 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"); } @@ -478,11 +532,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 (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled) { + if (port->write_urb_busy || priv->tx_throttled) { spin_unlock_bh(&port->lock); return 0; } - clear_bit(0, &port->write_urbs_free); + port->write_urb_busy = 1; spin_unlock_bh(&port->lock); /* At this point the URB is in our control, nobody else can submit it @@ -544,6 +598,7 @@ 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"); @@ -563,7 +618,7 @@ static int keyspan_pda_write(struct tty_struct *tty, rc = count; exit: if (rc < 0) - set_bit(0, &port->write_urbs_free); + port->write_urb_busy = 0; return rc; } @@ -573,7 +628,7 @@ static void keyspan_pda_write_bulk_callback(struct urb *urb) struct usb_serial_port *port = urb->context; struct keyspan_pda_private *priv; - set_bit(0, &port->write_urbs_free); + port->write_urb_busy = 0; priv = usb_get_serial_port_data(port); /* queue up a wakeup at scheduler time */ @@ -606,7 +661,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 (!test_bit(0, &port->write_urbs_free) || priv->tx_throttled) + if (port->write_urb_busy || priv->tx_throttled) ret = 256; spin_unlock_irqrestore(&port->lock, flags); return ret; @@ -662,6 +717,7 @@ 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__); diff --git a/trunk/drivers/usb/serial/kobil_sct.c b/trunk/drivers/usb/serial/kobil_sct.c index 5d3beeeb5fd9..ddd146300ddb 100644 --- a/trunk/drivers/usb/serial/kobil_sct.c +++ b/trunk/drivers/usb/serial/kobil_sct.c @@ -20,6 +20,18 @@ * * 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. */ @@ -219,6 +231,9 @@ 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) @@ -378,6 +393,8 @@ 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", @@ -458,9 +475,17 @@ 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", diff --git a/trunk/drivers/usb/serial/mct_u232.c b/trunk/drivers/usb/serial/mct_u232.c index a975bb80303f..ba0d28727ccb 100644 --- a/trunk/drivers/usb/serial/mct_u232.c +++ b/trunk/drivers/usb/serial/mct_u232.c @@ -19,6 +19,50 @@ * 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 + * - 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 + * - 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 @@ -482,6 +526,7 @@ 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, @@ -490,6 +535,7 @@ 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); diff --git a/trunk/drivers/usb/serial/mos7720.c b/trunk/drivers/usb/serial/mos7720.c index 19d112f51b97..3524a105d042 100644 --- a/trunk/drivers/usb/serial/mos7720.c +++ b/trunk/drivers/usb/serial/mos7720.c @@ -939,7 +939,14 @@ 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", @@ -1007,6 +1014,7 @@ 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; @@ -1021,6 +1029,8 @@ 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); @@ -1725,6 +1735,8 @@ 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", @@ -1774,7 +1786,13 @@ 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", diff --git a/trunk/drivers/usb/serial/mos7840.c b/trunk/drivers/usb/serial/mos7840.c index 55cfd6265b98..c72abd524983 100644 --- a/trunk/drivers/usb/serial/mos7840.c +++ b/trunk/drivers/usb/serial/mos7840.c @@ -792,6 +792,8 @@ 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); @@ -2056,6 +2058,7 @@ 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) { @@ -2127,6 +2130,7 @@ 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) { diff --git a/trunk/drivers/usb/serial/omninet.c b/trunk/drivers/usb/serial/omninet.c index 45a8c55881d3..60f38d5e64fc 100644 --- a/trunk/drivers/usb/serial/omninet.c +++ b/trunk/drivers/usb/serial/omninet.c @@ -9,6 +9,31 @@ * 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 @@ -19,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -148,6 +174,12 @@ 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, @@ -204,6 +236,11 @@ 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, @@ -230,10 +267,14 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port, return 0; } - if (!test_and_clear_bit(0, &port->write_urbs_free)) { + spin_lock_bh(&wport->lock); + if (wport->write_urb_busy) { + spin_unlock_bh(&wport->lock); dbg("%s - already writing", __func__); return 0; } + wport->write_urb_busy = 1; + spin_unlock_bh(&wport->lock); count = (count > OMNINET_BULKOUTSIZE) ? OMNINET_BULKOUTSIZE : count; @@ -251,9 +292,10 @@ 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) { - set_bit(0, &wport->write_urbs_free); + wport->write_urb_busy = 0; dev_err(&port->dev, "%s - failed submitting write urb, error %d\n", __func__, result); @@ -272,7 +314,8 @@ static int omninet_write_room(struct tty_struct *tty) int room = 0; /* Default: no room */ - if (test_bit(0, &wport->write_urbs_free)) + /* FIXME: no consistent locking for write_urb_busy */ + if (wport->write_urb_busy) room = wport->bulk_out_size - OMNINET_HEADERLEN; dbg("%s - returns %d", __func__, room); @@ -289,7 +332,7 @@ static void omninet_write_bulk_callback(struct urb *urb) dbg("%s - port %0x", __func__, port->number); - set_bit(0, &port->write_urbs_free); + port->write_urb_busy = 0; if (status) { dbg("%s - nonzero write bulk status received: %d", __func__, status); diff --git a/trunk/drivers/usb/serial/opticon.c b/trunk/drivers/usb/serial/opticon.c index 691f57a9d712..c248a9147439 100644 --- a/trunk/drivers/usb/serial/opticon.c +++ b/trunk/drivers/usb/serial/opticon.c @@ -384,6 +384,7 @@ 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) diff --git a/trunk/drivers/usb/serial/oti6858.c b/trunk/drivers/usb/serial/oti6858.c index 2161d1c3c089..4c29e6c2bda7 100644 --- a/trunk/drivers/usb/serial/oti6858.c +++ b/trunk/drivers/usb/serial/oti6858.c @@ -264,6 +264,7 @@ 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" @@ -320,6 +321,7 @@ 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" @@ -332,6 +334,7 @@ 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" @@ -580,12 +583,13 @@ 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 result; + return -EPROTO; } /* setup termios */ @@ -833,6 +837,7 @@ 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; @@ -861,6 +866,7 @@ 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, @@ -888,6 +894,18 @@ 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; } @@ -900,6 +918,7 @@ 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," @@ -936,6 +955,7 @@ 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," @@ -948,6 +968,7 @@ 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) { diff --git a/trunk/drivers/usb/serial/pl2303.c b/trunk/drivers/usb/serial/pl2303.c index 329295615d06..fc2d66f7f4eb 100644 --- a/trunk/drivers/usb/serial/pl2303.c +++ b/trunk/drivers/usb/serial/pl2303.c @@ -502,20 +502,21 @@ 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); - return result; + pl2303_close(port); + return -EPROTO; } - - 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; } diff --git a/trunk/drivers/usb/serial/sierra.c b/trunk/drivers/usb/serial/sierra.c index f2485429172f..b18179bda0d8 100644 --- a/trunk/drivers/usb/serial/sierra.c +++ b/trunk/drivers/usb/serial/sierra.c @@ -681,6 +681,7 @@ 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 " diff --git a/trunk/drivers/usb/serial/symbolserial.c b/trunk/drivers/usb/serial/symbolserial.c index c70cc012d03f..7096f799b071 100644 --- a/trunk/drivers/usb/serial/symbolserial.c +++ b/trunk/drivers/usb/serial/symbolserial.c @@ -182,6 +182,7 @@ 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) diff --git a/trunk/drivers/usb/serial/ti_usb_3410_5052.c b/trunk/drivers/usb/serial/ti_usb_3410_5052.c index 4af21f46096e..ea8445689c85 100644 --- a/trunk/drivers/usb/serial/ti_usb_3410_5052.c +++ b/trunk/drivers/usb/serial/ti_usb_3410_5052.c @@ -535,7 +535,9 @@ 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, @@ -617,7 +619,9 @@ 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", @@ -1232,11 +1236,12 @@ 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) + if (tport->tp_read_urb_state == TI_READ_URB_RUNNING) { + urb->dev = port->serial->dev; 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", @@ -1569,7 +1574,9 @@ 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; diff --git a/trunk/drivers/usb/serial/usb-serial.c b/trunk/drivers/usb/serial/usb-serial.c index ce6c1a65a544..cc274fdf2627 100644 --- a/trunk/drivers/usb/serial/usb-serial.c +++ b/trunk/drivers/usb/serial/usb-serial.c @@ -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,10 +260,6 @@ 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; } @@ -364,8 +360,7 @@ 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; } @@ -567,8 +562,8 @@ static void kill_traffic(struct usb_serial_port *port) { int i; - for (i = 0; i < ARRAY_SIZE(port->read_urbs); ++i) - usb_kill_urb(port->read_urbs[i]); + usb_kill_urb(port->read_urb); + usb_kill_urb(port->write_urb); for (i = 0; i < ARRAY_SIZE(port->write_urbs); ++i) usb_kill_urb(port->write_urbs[i]); /* @@ -600,17 +595,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); @@ -691,18 +686,16 @@ 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); } @@ -731,7 +724,6 @@ 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; @@ -914,41 +906,38 @@ 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; - - 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, + port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL); + if (!port->bulk_in_buffer) { + dev_err(&interface->dev, "Couldn't allocate bulk_in_buffer\n"); - goto probe_error; - } - usb_fill_bulk_urb(port->read_urbs[j], dev, - usb_rcvbulkpipe(dev, - endpoint->bEndpointAddress), - port->bulk_in_buffers[j], buffer_size, - serial->type->read_bulk_callback, - port); + goto probe_error; } - - port->read_urb = port->read_urbs[0]; - port->bulk_in_buffer = port->bulk_in_buffers[0]; + usb_fill_bulk_urb(port->read_urb, dev, + usb_rcvbulkpipe(dev, + endpoint->bEndpointAddress), + port->bulk_in_buffer, buffer_size, + serial->type->read_bulk_callback, port); } 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; @@ -956,7 +945,17 @@ 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); @@ -979,9 +978,6 @@ 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) { @@ -1200,7 +1196,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, @@ -1210,9 +1206,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, }; @@ -1241,7 +1237,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; @@ -1340,6 +1336,7 @@ 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()) @@ -1377,6 +1374,7 @@ 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); diff --git a/trunk/drivers/usb/serial/usb_debug.c b/trunk/drivers/usb/serial/usb_debug.c index 9b632e753210..95a82148ee81 100644 --- a/trunk/drivers/usb/serial/usb_debug.c +++ b/trunk/drivers/usb/serial/usb_debug.c @@ -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,18 +54,19 @@ 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_process_read_urb(struct urb *urb) +static void usb_debug_read_bulk_callback(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_process_read_urb(urb); + usb_serial_generic_read_bulk_callback(urb); } static struct usb_serial_driver debug_device = { @@ -78,7 +79,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, - .process_read_urb = usb_debug_process_read_urb, + .read_bulk_callback = usb_debug_read_bulk_callback, }; static int __init debug_init(void) diff --git a/trunk/drivers/usb/serial/whiteheat.c b/trunk/drivers/usb/serial/whiteheat.c index 11af903cb09f..5b073bcc807b 100644 --- a/trunk/drivers/usb/serial/whiteheat.c +++ b/trunk/drivers/usb/serial/whiteheat.c @@ -14,6 +14,57 @@ * * 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 @@ -702,6 +753,7 @@ 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; @@ -737,6 +789,7 @@ 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) { @@ -982,6 +1035,7 @@ 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", @@ -1087,6 +1141,7 @@ 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__); @@ -1307,6 +1362,7 @@ 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, @@ -1354,6 +1410,7 @@ 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) { @@ -1433,6 +1490,7 @@ 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, diff --git a/trunk/drivers/usb/storage/alauda.c b/trunk/drivers/usb/storage/alauda.c index 9ce3bbab6d20..42d0eaed4a01 100644 --- a/trunk/drivers/usb/storage/alauda.c +++ b/trunk/drivers/usb/storage/alauda.c @@ -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) } -static struct usb_device_id alauda_usb_ids[] = { +struct usb_device_id alauda_usb_ids[] = { # include "unusual_alauda.h" { } /* Terminating entry */ }; diff --git a/trunk/drivers/usb/storage/cypress_atacb.c b/trunk/drivers/usb/storage/cypress_atacb.c index 740bfe6b2d23..c84471821183 100644 --- a/trunk/drivers/usb/storage/cypress_atacb.c +++ b/trunk/drivers/usb/storage/cypress_atacb.c @@ -43,7 +43,7 @@ MODULE_LICENSE("GPL"); { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } -static struct usb_device_id cypress_usb_ids[] = { +struct usb_device_id cypress_usb_ids[] = { # include "unusual_cypress.h" { } /* Terminating entry */ }; diff --git a/trunk/drivers/usb/storage/datafab.c b/trunk/drivers/usb/storage/datafab.c index 0d8d97c94f09..ded836b02d7b 100644 --- a/trunk/drivers/usb/storage/datafab.c +++ b/trunk/drivers/usb/storage/datafab.c @@ -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) } -static struct usb_device_id datafab_usb_ids[] = { +struct usb_device_id datafab_usb_ids[] = { # include "unusual_datafab.h" { } /* Terminating entry */ }; diff --git a/trunk/drivers/usb/storage/ene_ub6250.c b/trunk/drivers/usb/storage/ene_ub6250.c index b990726f144a..9fbe742343c6 100644 --- a/trunk/drivers/usb/storage/ene_ub6250.c +++ b/trunk/drivers/usb/storage/ene_ub6250.c @@ -42,7 +42,7 @@ MODULE_LICENSE("GPL"); { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } -static struct usb_device_id ene_ub6250_usb_ids[] = { +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; - u32 bl_len; + u32 bl_num; + u16 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; } -static int ms_lib_alloc_logicalmap(struct us_data *us) +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() */ -static int ms_scsi_irp(struct us_data *us, struct scsi_cmnd *srb) +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; diff --git a/trunk/drivers/usb/storage/freecom.c b/trunk/drivers/usb/storage/freecom.c index 8cf16f89c96c..6542ca40d505 100644 --- a/trunk/drivers/usb/storage/freecom.c +++ b/trunk/drivers/usb/storage/freecom.c @@ -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) } -static struct usb_device_id freecom_usb_ids[] = { +struct usb_device_id freecom_usb_ids[] = { # include "unusual_freecom.h" { } /* Terminating entry */ }; diff --git a/trunk/drivers/usb/storage/isd200.c b/trunk/drivers/usb/storage/isd200.c index 7b813036b485..ffc4193e9505 100644 --- a/trunk/drivers/usb/storage/isd200.c +++ b/trunk/drivers/usb/storage/isd200.c @@ -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) } -static struct usb_device_id isd200_usb_ids[] = { +struct usb_device_id isd200_usb_ids[] = { # include "unusual_isd200.h" { } /* Terminating entry */ }; diff --git a/trunk/drivers/usb/storage/jumpshot.c b/trunk/drivers/usb/storage/jumpshot.c index 5ef55c7d73e1..6168596c5ac6 100644 --- a/trunk/drivers/usb/storage/jumpshot.c +++ b/trunk/drivers/usb/storage/jumpshot.c @@ -71,7 +71,7 @@ MODULE_LICENSE("GPL"); { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } -static struct usb_device_id jumpshot_usb_ids[] = { +struct usb_device_id jumpshot_usb_ids[] = { # include "unusual_jumpshot.h" { } /* Terminating entry */ }; diff --git a/trunk/drivers/usb/storage/karma.c b/trunk/drivers/usb/storage/karma.c index fb5bfb00d797..ba1b78906880 100644 --- a/trunk/drivers/usb/storage/karma.c +++ b/trunk/drivers/usb/storage/karma.c @@ -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) } -static struct usb_device_id karma_usb_ids[] = { +struct usb_device_id karma_usb_ids[] = { # include "unusual_karma.h" { } /* Terminating entry */ }; diff --git a/trunk/drivers/usb/storage/onetouch.c b/trunk/drivers/usb/storage/onetouch.c index d29be3e81134..1943be5a2914 100644 --- a/trunk/drivers/usb/storage/onetouch.c +++ b/trunk/drivers/usb/storage/onetouch.c @@ -69,7 +69,7 @@ struct usb_onetouch { { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } -static struct usb_device_id onetouch_usb_ids[] = { +struct usb_device_id onetouch_usb_ids[] = { # include "unusual_onetouch.h" { } /* Terminating entry */ }; diff --git a/trunk/drivers/usb/storage/realtek_cr.c b/trunk/drivers/usb/storage/realtek_cr.c index 71147679cb11..0ce5f79197e7 100644 --- a/trunk/drivers/usb/storage/realtek_cr.c +++ b/trunk/drivers/usb/storage/realtek_cr.c @@ -398,9 +398,10 @@ static int rts51x_write_mem(struct us_data *us, u16 addr, u8 *data, u16 len) u8 cmnd[12] = { 0 }; u8 *buf; - buf = kmemdup(data, len, GFP_NOIO); + buf = kmalloc(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); @@ -506,14 +507,15 @@ 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 = 0xfe47, len = %d\n", __FUNCTION__, len); + US_DEBUGP("%s, addr = 0x%x, len = %d\n", __FUNCTION__, addr, len); cmnd[0] = 0xF0; cmnd[1] = 0x0E; - cmnd[2] = 0xfe; - cmnd[3] = 0x47; + cmnd[2] = (u8)(addr >> 8); + cmnd[3] = (u8)addr; cmnd[4] = (u8)(len >> 8); cmnd[5] = (u8)len; @@ -816,7 +818,7 @@ static inline int working_scsi(struct scsi_cmnd *srb) return 1; } -static void rts51x_invoke_transport(struct scsi_cmnd *srb, struct us_data *us) +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; @@ -975,7 +977,7 @@ static void realtek_cr_destructor(void *extra) } #ifdef CONFIG_PM -static int realtek_cr_suspend(struct usb_interface *iface, pm_message_t message) +int realtek_cr_suspend(struct usb_interface *iface, pm_message_t message) { struct us_data *us = usb_get_intfdata(iface); diff --git a/trunk/drivers/usb/storage/sddr09.c b/trunk/drivers/usb/storage/sddr09.c index 6ecbf44c7ecb..bcb9a709d349 100644 --- a/trunk/drivers/usb/storage/sddr09.c +++ b/trunk/drivers/usb/storage/sddr09.c @@ -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) } -static struct usb_device_id sddr09_usb_ids[] = { +struct usb_device_id sddr09_usb_ids[] = { # include "unusual_sddr09.h" { } /* Terminating entry */ }; diff --git a/trunk/drivers/usb/storage/sddr55.c b/trunk/drivers/usb/storage/sddr55.c index f2930441a2fa..44dfed7754ed 100644 --- a/trunk/drivers/usb/storage/sddr55.c +++ b/trunk/drivers/usb/storage/sddr55.c @@ -48,7 +48,7 @@ MODULE_LICENSE("GPL"); { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ .driver_info = (flags)|(USB_US_TYPE_STOR<<24) } -static struct usb_device_id sddr55_usb_ids[] = { +struct usb_device_id sddr55_usb_ids[] = { # include "unusual_sddr55.h" { } /* Terminating entry */ }; diff --git a/trunk/drivers/usb/storage/shuttle_usbat.c b/trunk/drivers/usb/storage/shuttle_usbat.c index 7d642c8efed3..0b00091d2ae9 100644 --- a/trunk/drivers/usb/storage/shuttle_usbat.c +++ b/trunk/drivers/usb/storage/shuttle_usbat.c @@ -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) } -static struct usb_device_id usbat_usb_ids[] = { +struct usb_device_id usbat_usb_ids[] = { # include "unusual_usbat.h" { } /* Terminating entry */ }; diff --git a/trunk/drivers/usb/wusbcore/security.c b/trunk/drivers/usb/wusbcore/security.c index fa810a83e830..371f61733f05 100644 --- a/trunk/drivers/usb/wusbcore/security.c +++ b/trunk/drivers/usb/wusbcore/security.c @@ -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 = kcalloc(3, sizeof(hs[0]), GFP_KERNEL); + hs = kzalloc(3*sizeof(hs[0]), GFP_KERNEL); if (hs == NULL) { dev_err(dev, "can't allocate handshake data\n"); goto error_kzalloc; diff --git a/trunk/drivers/uwb/est.c b/trunk/drivers/uwb/est.c index 86ed7e61e597..de81ebf51784 100644 --- a/trunk/drivers/uwb/est.c +++ b/trunk/drivers/uwb/est.c @@ -184,7 +184,7 @@ int uwb_est_create(void) uwb_est_size = 2; uwb_est_used = 0; - uwb_est = kcalloc(uwb_est_size, sizeof(uwb_est[0]), GFP_KERNEL); + uwb_est = kzalloc(uwb_est_size * sizeof(uwb_est[0]), GFP_KERNEL); if (uwb_est == NULL) return -ENOMEM; diff --git a/trunk/fs/fat/namei_vfat.c b/trunk/fs/fat/namei_vfat.c index c25cf151b84b..a87a65663c25 100644 --- a/trunk/fs/fat/namei_vfat.c +++ b/trunk/fs/fat/namei_vfat.c @@ -512,8 +512,7 @@ xlate_to_uni(const unsigned char *name, int len, unsigned char *outname, int charlen; if (utf8) { - *outlen = utf8s_to_utf16s(name, len, UTF16_HOST_ENDIAN, - (wchar_t *) outname, FAT_LFN_LEN + 2); + *outlen = utf8s_to_utf16s(name, len, (wchar_t *)outname); if (*outlen < 0) return *outlen; else if (*outlen > FAT_LFN_LEN) diff --git a/trunk/fs/nls/nls_base.c b/trunk/fs/nls/nls_base.c index fea6bd5831dc..44a88a9fa2c8 100644 --- a/trunk/fs/nls/nls_base.c +++ b/trunk/fs/nls/nls_base.c @@ -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 inlen, unicode_t *pu) +int utf8_to_utf32(const u8 *s, int len, unicode_t *pu) { unsigned long l; int c0, c, nc; @@ -71,7 +71,7 @@ int utf8_to_utf32(const u8 *s, int inlen, unicode_t *pu) *pu = (unicode_t) l; return nc; } - if (inlen <= nc) + if (len <= nc) return -1; s++; c = (*s ^ 0x80) & 0xFF; @@ -83,7 +83,7 @@ int utf8_to_utf32(const u8 *s, int inlen, unicode_t *pu) } EXPORT_SYMBOL(utf8_to_utf32); -int utf32_to_utf8(unicode_t u, u8 *s, int maxout) +int utf32_to_utf8(unicode_t u, u8 *s, int maxlen) { unsigned long l; int c, nc; @@ -97,7 +97,7 @@ int utf32_to_utf8(unicode_t u, u8 *s, int maxout) return -1; nc = 0; - for (t = utf8_table; t->cmask && maxout; t++, maxout--) { + for (t = utf8_table; t->cmask && maxlen; t++, maxlen--) { nc++; if (l <= t->lmask) { c = t->shift; @@ -114,57 +114,34 @@ int utf32_to_utf8(unicode_t u, u8 *s, int maxout) } EXPORT_SYMBOL(utf32_to_utf8); -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) +int utf8s_to_utf16s(const u8 *s, int len, wchar_t *pwcs) { u16 *op; int size; unicode_t u; op = pwcs; - while (inlen > 0 && maxout > 0 && *s) { + while (*s && len > 0) { if (*s & 0x80) { - size = utf8_to_utf32(s, inlen, &u); + size = utf8_to_utf32(s, len, &u); if (size < 0) return -EINVAL; - s += size; - inlen -= size; if (u >= PLANE_SIZE) { - if (maxout < 2) - break; u -= PLANE_SIZE; - put_utf16(op++, SURROGATE_PAIR | - ((u >> 10) & SURROGATE_BITS), - endian); - put_utf16(op++, SURROGATE_PAIR | + *op++ = (wchar_t) (SURROGATE_PAIR | + ((u >> 10) & SURROGATE_BITS)); + *op++ = (wchar_t) (SURROGATE_PAIR | SURROGATE_LOW | - (u & SURROGATE_BITS), - endian); - maxout -= 2; + (u & SURROGATE_BITS)); } else { - put_utf16(op++, u, endian); - maxout--; + *op++ = (wchar_t) u; } + s += size; + len -= size; } else { - put_utf16(op++, *s++, endian); - inlen--; - maxout--; + *op++ = *s++; + len--; } } return op - pwcs; @@ -183,27 +160,27 @@ static inline unsigned long get_utf16(unsigned c, enum utf16_endian endian) } } -int utf16s_to_utf8s(const wchar_t *pwcs, int inlen, enum utf16_endian endian, - u8 *s, int maxout) +int utf16s_to_utf8s(const wchar_t *pwcs, int len, enum utf16_endian endian, + u8 *s, int maxlen) { u8 *op; int size; unsigned long u, v; op = s; - while (inlen > 0 && maxout > 0) { + while (len > 0 && maxlen > 0) { u = get_utf16(*pwcs, endian); if (!u) break; pwcs++; - inlen--; + len--; if (u > 0x7f) { if ((u & SURROGATE_MASK) == SURROGATE_PAIR) { if (u & SURROGATE_LOW) { /* Ignore character and move on */ continue; } - if (inlen <= 0) + if (len <= 0) break; v = get_utf16(*pwcs, endian); if ((v & SURROGATE_MASK) != SURROGATE_PAIR || @@ -214,18 +191,18 @@ int utf16s_to_utf8s(const wchar_t *pwcs, int inlen, enum utf16_endian endian, u = PLANE_SIZE + ((u & SURROGATE_BITS) << 10) + (v & SURROGATE_BITS); pwcs++; - inlen--; + len--; } - size = utf32_to_utf8(u, op, maxout); + size = utf32_to_utf8(u, op, maxlen); if (size == -1) { /* Ignore character and move on */ } else { op += size; - maxout -= size; + maxlen -= size; } } else { *op++ = (u8) u; - maxout--; + maxlen--; } } return op - s; diff --git a/trunk/include/linux/nls.h b/trunk/include/linux/nls.h index 5dc635f8d79e..d47beef08dfd 100644 --- a/trunk/include/linux/nls.h +++ b/trunk/include/linux/nls.h @@ -43,7 +43,7 @@ enum utf16_endian { UTF16_BIG_ENDIAN }; -/* nls_base.c */ +/* nls.c */ extern int register_nls(struct nls_table *); extern int unregister_nls(struct nls_table *); extern struct nls_table *load_nls(char *); @@ -52,8 +52,7 @@ 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, - enum utf16_endian endian, wchar_t *pwcs, int maxlen); +extern int utf8s_to_utf16s(const u8 *s, int len, wchar_t *pwcs); extern int utf16s_to_utf8s(const wchar_t *pwcs, int len, enum utf16_endian endian, u8 *s, int maxlen); diff --git a/trunk/include/linux/usb.h b/trunk/include/linux/usb.h index 4269c3f88148..d3d0c1374334 100644 --- a/trunk/include/linux/usb.h +++ b/trunk/include/linux/usb.h @@ -1221,7 +1221,6 @@ 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 */ @@ -1599,19 +1598,6 @@ 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 diff --git a/trunk/include/linux/usb/ch11.h b/trunk/include/linux/usb/ch11.h index 31fdb4c6ee3d..4ebaf0824179 100644 --- a/trunk/include/linux/usb/ch11.h +++ b/trunk/include/linux/usb/ch11.h @@ -26,6 +26,7 @@ #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 @@ -164,20 +165,11 @@ struct usb_port_status { * wHubCharacteristics (masks) * See USB 2.0 spec Table 11-13, offset 3 */ -#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) */ +#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 */ struct usb_hub_status { __le16 wHubStatus; @@ -206,17 +198,6 @@ 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; diff --git a/trunk/include/linux/usb/gadget.h b/trunk/include/linux/usb/gadget.h index 317d8925387c..1d3a67523ffc 100644 --- a/trunk/include/linux/usb/gadget.h +++ b/trunk/include/linux/usb/gadget.h @@ -477,8 +477,8 @@ 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. - * @max_speed: Maximal speed the UDC can handle. UDC must support this - * and all slower speeds. + * @is_dualspeed: True if the controller supports both high and full speed + * operation. If it does, the gadget driver must also support both. * @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 +518,7 @@ struct usb_gadget { struct usb_ep *ep0; struct list_head ep_list; /* of usb_ep */ enum usb_device_speed speed; - enum usb_device_speed max_speed; + unsigned is_dualspeed:1; unsigned is_otg:1; unsigned is_a_peripheral:1; unsigned b_hnp_enable:1; @@ -549,7 +549,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->max_speed" ... that might be + /* runtime test would check "g->is_dualspeed" ... that might be * useful to work around hardware bugs, but is mostly pointless */ return 1; @@ -567,7 +567,7 @@ static inline int gadget_is_superspeed(struct usb_gadget *g) { #ifdef CONFIG_USB_GADGET_SUPERSPEED /* - * runtime test would check "g->max_speed" ... that might be + * runtime test would check "g->is_superspeed" ... that might be * useful to work around hardware bugs, but is mostly pointless */ return 1; @@ -760,7 +760,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 - * @max_speed: Highest speed the driver handles. + * @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 +824,7 @@ static inline int usb_gadget_disconnect(struct usb_gadget *gadget) */ struct usb_gadget_driver { char *function; - enum usb_device_speed max_speed; + enum usb_device_speed speed; void (*unbind)(struct usb_gadget *); int (*setup)(struct usb_gadget *, const struct usb_ctrlrequest *); diff --git a/trunk/include/linux/usb/hcd.h b/trunk/include/linux/usb/hcd.h index b2f62f3a32af..03354d557b79 100644 --- a/trunk/include/linux/usb/hcd.h +++ b/trunk/include/linux/usb/hcd.h @@ -99,6 +99,7 @@ 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? */ @@ -109,6 +110,7 @@ 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)) diff --git a/trunk/include/linux/usb/renesas_usbhs.h b/trunk/include/linux/usb/renesas_usbhs.h index 0d3f98879256..e5a40c318548 100644 --- a/trunk/include/linux/usb/renesas_usbhs.h +++ b/trunk/include/linux/usb/renesas_usbhs.h @@ -64,14 +64,6 @@ 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: * @@ -126,7 +118,7 @@ struct renesas_usbhs_driver_param { * * delay time from notify_hotplug callback */ - int detection_delay; /* msec */ + int detection_delay; /* * option: diff --git a/trunk/include/linux/usb/serial.h b/trunk/include/linux/usb/serial.h index 4267a9c717ba..b29f70b2ecae 100644 --- a/trunk/include/linux/usb/serial.h +++ b/trunk/include/linux/usb/serial.h @@ -58,13 +58,11 @@ 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 @@ -101,14 +99,11 @@ 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]; @@ -345,7 +340,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_urbs(struct usb_serial_port *port, +extern int usb_serial_generic_submit_read_urb(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,