summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2012-05-24 12:13:01 +0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2012-05-24 12:13:01 +0400
commite644dae645e167d154c0526358940986682a72b0 (patch)
tree972993c6568085b8d407fc7e13de10f4b93c651d /drivers/usb
parent899c612d74d4a242158a4db20367388d6299c028 (diff)
parent86809173ce32ef03bd4d0389dfc72df0c805e9c4 (diff)
downloadlinux-e644dae645e167d154c0526358940986682a72b0.tar.xz
Merge branch 'next' into for-linus
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/Kconfig63
-rw-r--r--drivers/usb/class/cdc-acm.c38
-rw-r--r--drivers/usb/class/cdc-wdm.c352
-rw-r--r--drivers/usb/core/driver.c195
-rw-r--r--drivers/usb/core/hcd-pci.c2
-rw-r--r--drivers/usb/core/hcd.c18
-rw-r--r--drivers/usb/core/hub.c231
-rw-r--r--drivers/usb/core/inode.c33
-rw-r--r--drivers/usb/core/message.c17
-rw-r--r--drivers/usb/core/sysfs.c23
-rw-r--r--drivers/usb/core/urb.c44
-rw-r--r--drivers/usb/core/usb.c2
-rw-r--r--drivers/usb/core/usb.h1
-rw-r--r--drivers/usb/dwc3/Makefile13
-rw-r--r--drivers/usb/dwc3/core.c128
-rw-r--r--drivers/usb/dwc3/core.h200
-rw-r--r--drivers/usb/dwc3/debugfs.c214
-rw-r--r--drivers/usb/dwc3/dwc3-exynos.c151
-rw-r--r--drivers/usb/dwc3/dwc3-omap.c116
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c65
-rw-r--r--drivers/usb/dwc3/ep0.c100
-rw-r--r--drivers/usb/dwc3/gadget.c429
-rw-r--r--drivers/usb/dwc3/gadget.h5
-rw-r--r--drivers/usb/dwc3/host.c2
-rw-r--r--drivers/usb/gadget/Kconfig35
-rw-r--r--drivers/usb/gadget/amd5536udc.c148
-rw-r--r--drivers/usb/gadget/at91_udc.c60
-rw-r--r--drivers/usb/gadget/atmel_usba_udc.c7
-rw-r--r--drivers/usb/gadget/audio.c47
-rw-r--r--drivers/usb/gadget/ci13xxx_msm.c4
-rw-r--r--drivers/usb/gadget/ci13xxx_udc.c18
-rw-r--r--drivers/usb/gadget/ci13xxx_udc.h2
-rw-r--r--drivers/usb/gadget/dummy_hcd.c756
-rw-r--r--drivers/usb/gadget/epautoconf.c16
-rw-r--r--drivers/usb/gadget/f_acm.c52
-rw-r--r--drivers/usb/gadget/f_ecm.c25
-rw-r--r--drivers/usb/gadget/f_fs.c17
-rw-r--r--drivers/usb/gadget/f_mass_storage.c29
-rw-r--r--drivers/usb/gadget/f_midi.c2
-rw-r--r--drivers/usb/gadget/f_phonet.c2
-rw-r--r--drivers/usb/gadget/f_rndis.c3
-rw-r--r--drivers/usb/gadget/f_serial.c42
-rw-r--r--drivers/usb/gadget/f_subset.c34
-rw-r--r--drivers/usb/gadget/f_uac1.c (renamed from drivers/usb/gadget/f_audio.c)25
-rw-r--r--drivers/usb/gadget/f_uac2.c1449
-rw-r--r--drivers/usb/gadget/file_storage.c26
-rw-r--r--drivers/usb/gadget/fsl_qe_udc.c1
-rw-r--r--drivers/usb/gadget/fsl_udc_core.c54
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.h2
-rw-r--r--drivers/usb/gadget/g_ffs.c6
-rw-r--r--drivers/usb/gadget/goku_udc.c20
-rw-r--r--drivers/usb/gadget/hid.c6
-rw-r--r--drivers/usb/gadget/inode.c16
-rw-r--r--drivers/usb/gadget/langwell_udc.c53
-rw-r--r--drivers/usb/gadget/langwell_udc.h2
-rw-r--r--drivers/usb/gadget/mass_storage.c2
-rw-r--r--drivers/usb/gadget/multi.c2
-rw-r--r--drivers/usb/gadget/mv_udc.h2
-rw-r--r--drivers/usb/gadget/mv_udc_core.c10
-rw-r--r--drivers/usb/gadget/net2272.c19
-rw-r--r--drivers/usb/gadget/net2280.c20
-rw-r--r--drivers/usb/gadget/omap_udc.c27
-rw-r--r--drivers/usb/gadget/omap_udc.h2
-rw-r--r--drivers/usb/gadget/pch_udc.c323
-rw-r--r--drivers/usb/gadget/printer.c1
-rw-r--r--drivers/usb/gadget/pxa25x_udc.c16
-rw-r--r--drivers/usb/gadget/pxa25x_udc.h2
-rw-r--r--drivers/usb/gadget/pxa27x_udc.c11
-rw-r--r--drivers/usb/gadget/pxa27x_udc.h2
-rw-r--r--drivers/usb/gadget/r8a66597-udc.c10
-rw-r--r--drivers/usb/gadget/rndis.c1
-rw-r--r--drivers/usb/gadget/s3c-hsotg.c17
-rw-r--r--drivers/usb/gadget/s3c-hsudc.c34
-rw-r--r--drivers/usb/gadget/s3c2410_udc.c3
-rw-r--r--drivers/usb/gadget/serial.c2
-rw-r--r--drivers/usb/gadget/storage_common.c42
-rw-r--r--drivers/usb/gadget/u_serial.c4
-rw-r--r--drivers/usb/gadget/u_uac1.c (renamed from drivers/usb/gadget/u_audio.c)4
-rw-r--r--drivers/usb/gadget/u_uac1.h (renamed from drivers/usb/gadget/u_audio.h)2
-rw-r--r--drivers/usb/gadget/udc-core.c58
-rw-r--r--drivers/usb/gadget/uvc_queue.c4
-rw-r--r--drivers/usb/host/Kconfig45
-rw-r--r--drivers/usb/host/Makefile4
-rw-r--r--drivers/usb/host/ehci-ath79.c208
-rw-r--r--drivers/usb/host/ehci-atmel.c25
-rw-r--r--drivers/usb/host/ehci-dbg.c11
-rw-r--r--drivers/usb/host/ehci-fsl.c63
-rw-r--r--drivers/usb/host/ehci-fsl.h3
-rw-r--r--drivers/usb/host/ehci-hcd.c33
-rw-r--r--drivers/usb/host/ehci-hub.c41
-rw-r--r--drivers/usb/host/ehci-ls1x.c159
-rw-r--r--drivers/usb/host/ehci-msm.c14
-rw-r--r--drivers/usb/host/ehci-mv.c12
-rw-r--r--drivers/usb/host/ehci-mxc.c12
-rw-r--r--drivers/usb/host/ehci-omap.c39
-rw-r--r--drivers/usb/host/ehci-platform.c198
-rw-r--r--drivers/usb/host/ehci-pxa168.c363
-rw-r--r--drivers/usb/host/ehci-s5p.c15
-rw-r--r--drivers/usb/host/ehci-spear.c83
-rw-r--r--drivers/usb/host/ehci-tegra.c17
-rw-r--r--drivers/usb/host/ehci.h4
-rw-r--r--drivers/usb/host/fsl-mph-dr-of.c1
-rw-r--r--drivers/usb/host/imx21-dbg.c2
-rw-r--r--drivers/usb/host/isp116x-hcd.c24
-rw-r--r--drivers/usb/host/isp1362-hcd.c21
-rw-r--r--drivers/usb/host/ohci-at91.c201
-rw-r--r--drivers/usb/host/ohci-ath79.c151
-rw-r--r--drivers/usb/host/ohci-exynos.c6
-rw-r--r--drivers/usb/host/ohci-hcd.c21
-rw-r--r--drivers/usb/host/ohci-nxp.c (renamed from drivers/usb/host/ohci-pnx4008.c)253
-rw-r--r--drivers/usb/host/ohci-omap.c8
-rw-r--r--drivers/usb/host/ohci-platform.c194
-rw-r--r--drivers/usb/host/ohci-pxa27x.c5
-rw-r--r--drivers/usb/host/ohci-sa1111.c297
-rw-r--r--drivers/usb/host/ohci.h2
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c1
-rw-r--r--drivers/usb/host/pci-quirks.c13
-rw-r--r--drivers/usb/host/r8a66597-hcd.c21
-rw-r--r--drivers/usb/host/sl811-hcd.c22
-rw-r--r--drivers/usb/host/u132-hcd.c1
-rw-r--r--drivers/usb/host/uhci-hcd.c4
-rw-r--r--drivers/usb/host/uhci-hub.c5
-rw-r--r--drivers/usb/host/xhci-dbg.c2
-rw-r--r--drivers/usb/host/xhci-ext-caps.h5
-rw-r--r--drivers/usb/host/xhci-hub.c41
-rw-r--r--drivers/usb/host/xhci-mem.c250
-rw-r--r--drivers/usb/host/xhci-pci.c4
-rw-r--r--drivers/usb/host/xhci-plat.c205
-rw-r--r--drivers/usb/host/xhci-ring.c339
-rw-r--r--drivers/usb/host/xhci.c84
-rw-r--r--drivers/usb/host/xhci.h38
-rw-r--r--drivers/usb/misc/usbtest.c9
-rw-r--r--drivers/usb/misc/yurex.c10
-rw-r--r--drivers/usb/musb/am35x.c20
-rw-r--r--drivers/usb/musb/blackfin.c15
-rw-r--r--drivers/usb/musb/da8xx.c20
-rw-r--r--drivers/usb/musb/davinci.c24
-rw-r--r--drivers/usb/musb/musb_core.c117
-rw-r--r--drivers/usb/musb/musb_core.h2
-rw-r--r--drivers/usb/musb/musb_debugfs.c14
-rw-r--r--drivers/usb/musb/musb_gadget.c39
-rw-r--r--drivers/usb/musb/musb_host.c2
-rw-r--r--drivers/usb/musb/musb_virthub.c9
-rw-r--r--drivers/usb/musb/omap2430.c73
-rw-r--r--drivers/usb/musb/tusb6010.c33
-rw-r--r--drivers/usb/musb/ux500.c19
-rw-r--r--drivers/usb/musb/ux500_dma.c4
-rw-r--r--drivers/usb/otg/Kconfig2
-rw-r--r--drivers/usb/otg/ab8500-usb.c95
-rw-r--r--drivers/usb/otg/fsl_otg.c113
-rw-r--r--drivers/usb/otg/fsl_otg.h2
-rw-r--r--drivers/usb/otg/gpio_vbus.c61
-rw-r--r--drivers/usb/otg/isp1301_omap.c234
-rw-r--r--drivers/usb/otg/msm_otg.c398
-rw-r--r--drivers/usb/otg/mv_otg.c110
-rw-r--r--drivers/usb/otg/mv_otg.h2
-rw-r--r--drivers/usb/otg/nop-usb-xceiv.c66
-rw-r--r--drivers/usb/otg/otg.c38
-rw-r--r--drivers/usb/otg/otg_fsm.c22
-rw-r--r--drivers/usb/otg/otg_fsm.h2
-rw-r--r--drivers/usb/otg/twl4030-usb.c83
-rw-r--r--drivers/usb/otg/twl6030-usb.c119
-rw-r--r--drivers/usb/otg/ulpi.c116
-rw-r--r--drivers/usb/otg/ulpi_viewport.c6
-rw-r--r--drivers/usb/renesas_usbhs/common.c11
-rw-r--r--drivers/usb/renesas_usbhs/common.h1
-rw-r--r--drivers/usb/renesas_usbhs/fifo.c34
-rw-r--r--drivers/usb/renesas_usbhs/fifo.h3
-rw-r--r--drivers/usb/renesas_usbhs/mod.c2
-rw-r--r--drivers/usb/renesas_usbhs/mod_gadget.c79
-rw-r--r--drivers/usb/serial/Kconfig17
-rw-r--r--drivers/usb/serial/Makefile2
-rw-r--r--drivers/usb/serial/aircable.c30
-rw-r--r--drivers/usb/serial/ark3116.c30
-rw-r--r--drivers/usb/serial/belkin_sa.c35
-rw-r--r--drivers/usb/serial/bus.c5
-rw-r--r--drivers/usb/serial/ch341.c27
-rw-r--r--drivers/usb/serial/cp210x.c80
-rw-r--r--drivers/usb/serial/cyberjack.c36
-rw-r--r--drivers/usb/serial/cypress_m8.c64
-rw-r--r--drivers/usb/serial/digi_acceleport.c45
-rw-r--r--drivers/usb/serial/empeg.c34
-rw-r--r--drivers/usb/serial/f81232.c405
-rw-r--r--drivers/usb/serial/ftdi_sio.c97
-rw-r--r--drivers/usb/serial/ftdi_sio.h3
-rw-r--r--drivers/usb/serial/ftdi_sio_ids.h19
-rw-r--r--drivers/usb/serial/funsoft.c25
-rw-r--r--drivers/usb/serial/garmin_gps.c40
-rw-r--r--drivers/usb/serial/generic.c19
-rw-r--r--drivers/usb/serial/hp4x.c31
-rw-r--r--drivers/usb/serial/io_edgeport.c66
-rw-r--r--drivers/usb/serial/io_tables.h10
-rw-r--r--drivers/usb/serial/io_ti.c44
-rw-r--r--drivers/usb/serial/ipaq.c28
-rw-r--r--drivers/usb/serial/ipw.c32
-rw-r--r--drivers/usb/serial/ir-usb.c30
-rw-r--r--drivers/usb/serial/iuu_phoenix.c31
-rw-r--r--drivers/usb/serial/keyspan.c48
-rw-r--r--drivers/usb/serial/keyspan.h10
-rw-r--r--drivers/usb/serial/keyspan_pda.c62
-rw-r--r--drivers/usb/serial/kl5kusb105.c37
-rw-r--r--drivers/usb/serial/kobil_sct.c35
-rw-r--r--drivers/usb/serial/mct_u232.c34
-rw-r--r--drivers/usb/serial/metro-usb.c402
-rw-r--r--drivers/usb/serial/mos7720.c46
-rw-r--r--drivers/usb/serial/mos7840.c142
-rw-r--r--drivers/usb/serial/moto_modem.c26
-rw-r--r--drivers/usb/serial/navman.c25
-rw-r--r--drivers/usb/serial/omninet.c38
-rw-r--r--drivers/usb/serial/opticon.c25
-rw-r--r--drivers/usb/serial/option.c60
-rw-r--r--drivers/usb/serial/oti6858.c36
-rw-r--r--drivers/usb/serial/pl2303.c33
-rw-r--r--drivers/usb/serial/qcaux.c26
-rw-r--r--drivers/usb/serial/qcserial.c134
-rw-r--r--drivers/usb/serial/safe_serial.c24
-rw-r--r--drivers/usb/serial/siemens_mpi.c30
-rw-r--r--drivers/usb/serial/sierra.c42
-rw-r--r--drivers/usb/serial/spcp8x5.c31
-rw-r--r--drivers/usb/serial/ssu100.c40
-rw-r--r--drivers/usb/serial/symbolserial.c25
-rw-r--r--drivers/usb/serial/ti_usb_3410_5052.c40
-rw-r--r--drivers/usb/serial/usb-serial.c125
-rw-r--r--drivers/usb/serial/usb_debug.c26
-rw-r--r--drivers/usb/serial/visor.c37
-rw-r--r--drivers/usb/serial/vivopay-serial.c31
-rw-r--r--drivers/usb/serial/whiteheat.c47
-rw-r--r--drivers/usb/serial/zio.c26
-rw-r--r--drivers/usb/storage/Kconfig2
-rw-r--r--drivers/usb/storage/alauda.c1
-rw-r--r--drivers/usb/storage/cypress_atacb.c1
-rw-r--r--drivers/usb/storage/datafab.c1
-rw-r--r--drivers/usb/storage/ene_ub6250.c27
-rw-r--r--drivers/usb/storage/freecom.c1
-rw-r--r--drivers/usb/storage/isd200.c1
-rw-r--r--drivers/usb/storage/jumpshot.c1
-rw-r--r--drivers/usb/storage/karma.c1
-rw-r--r--drivers/usb/storage/onetouch.c1
-rw-r--r--drivers/usb/storage/realtek_cr.c13
-rw-r--r--drivers/usb/storage/scsiglue.c55
-rw-r--r--drivers/usb/storage/sddr09.c1
-rw-r--r--drivers/usb/storage/sddr55.c1
-rw-r--r--drivers/usb/storage/shuttle_usbat.c1
-rw-r--r--drivers/usb/storage/transport.c3
-rw-r--r--drivers/usb/storage/transport.h39
-rw-r--r--drivers/usb/storage/uas.c328
-rw-r--r--drivers/usb/storage/usb.c51
247 files changed, 9342 insertions, 5815 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 75823a1abeb6..76316a33061b 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -2,42 +2,13 @@
# USB device configuration
#
-menuconfig USB_SUPPORT
- bool "USB support"
- depends on HAS_IOMEM
- default y
- ---help---
- This option adds core support for Universal Serial Bus (USB).
- You will also need drivers from the following menu to make use of it.
-
-if USB_SUPPORT
-
-config USB_COMMON
- tristate
- default y
- depends on USB || USB_GADGET
-
-# Host-side USB depends on having a host controller
-# NOTE: dummy_hcd is always an option, but it's ignored here ...
-# NOTE: SL-811 option should be board-specific ...
-config USB_ARCH_HAS_HCD
- boolean
- default y if USB_ARCH_HAS_OHCI
- default y if USB_ARCH_HAS_EHCI
- default y if USB_ARCH_HAS_XHCI
- default y if PCMCIA && !M32R # sl811_cs
- default y if ARM # SL-811
- default y if BLACKFIN # SL-811
- default y if SUPERH # r8a66597-hcd
- default PCI
-
# many non-PCI SOC chips embed OHCI
config USB_ARCH_HAS_OHCI
boolean
# ARM:
default y if SA1111
default y if ARCH_OMAP
- default y if ARCH_S3C2410
+ default y if ARCH_S3C24XX
default y if PXA27x
default y if PXA3xx
default y if ARCH_EP93XX
@@ -65,7 +36,7 @@ config USB_ARCH_HAS_EHCI
default y if PPC_MPC512x
default y if ARCH_IXP4XX
default y if ARCH_W90X900
- default y if ARCH_AT91SAM9G45
+ default y if ARCH_AT91
default y if ARCH_MXC
default y if ARCH_OMAP3
default y if ARCH_CNS3XXX
@@ -76,6 +47,7 @@ config USB_ARCH_HAS_EHCI
default y if MICROBLAZE
default y if SPARC_LEON
default y if ARCH_MMP
+ default y if MACH_LOONGSON1
default PCI
# some non-PCI HCDs implement xHCI
@@ -83,6 +55,35 @@ config USB_ARCH_HAS_XHCI
boolean
default PCI
+menuconfig USB_SUPPORT
+ bool "USB support"
+ depends on HAS_IOMEM
+ default y
+ ---help---
+ This option adds core support for Universal Serial Bus (USB).
+ You will also need drivers from the following menu to make use of it.
+
+if USB_SUPPORT
+
+config USB_COMMON
+ tristate
+ default y
+ depends on USB || USB_GADGET
+
+# Host-side USB depends on having a host controller
+# NOTE: dummy_hcd is always an option, but it's ignored here ...
+# NOTE: SL-811 option should be board-specific ...
+config USB_ARCH_HAS_HCD
+ boolean
+ default y if USB_ARCH_HAS_OHCI
+ default y if USB_ARCH_HAS_EHCI
+ default y if USB_ARCH_HAS_XHCI
+ default y if PCMCIA && !M32R # sl811_cs
+ default y if ARM # SL-811
+ default y if BLACKFIN # SL-811
+ default y if SUPERH # r8a66597-hcd
+ default PCI
+
# ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
config USB
tristate "Support for Host-side USB"
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 9543b19d410c..b32ccb461019 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -39,6 +39,7 @@
#include <linux/serial.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
+#include <linux/serial.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/uaccess.h>
@@ -508,17 +509,12 @@ static int acm_tty_install(struct tty_driver *driver, struct tty_struct *tty)
if (!acm)
return -ENODEV;
- retval = tty_init_termios(tty);
+ retval = tty_standard_install(driver, tty);
if (retval)
goto error_init_termios;
tty->driver_data = acm;
- /* Final install (we use the default method) */
- tty_driver_kref_get(driver);
- tty->count++;
- driver->ttys[tty->index] = tty;
-
return 0;
error_init_termios:
@@ -773,10 +769,37 @@ static int acm_tty_tiocmset(struct tty_struct *tty,
return acm_set_control(acm, acm->ctrlout = newctrl);
}
+static int get_serial_info(struct acm *acm, struct serial_struct __user *info)
+{
+ struct serial_struct tmp;
+
+ if (!info)
+ return -EINVAL;
+
+ memset(&tmp, 0, sizeof(tmp));
+ tmp.flags = ASYNC_LOW_LATENCY;
+ tmp.xmit_fifo_size = acm->writesize;
+ tmp.baud_base = le32_to_cpu(acm->line.dwDTERate);
+
+ if (copy_to_user(info, &tmp, sizeof(tmp)))
+ return -EFAULT;
+ else
+ return 0;
+}
+
static int acm_tty_ioctl(struct tty_struct *tty,
unsigned int cmd, unsigned long arg)
{
- return -ENOIOCTLCMD;
+ struct acm *acm = tty->driver_data;
+ int rv = -ENOIOCTLCMD;
+
+ switch (cmd) {
+ case TIOCGSERIAL: /* gets serial port data */
+ rv = get_serial_info(acm, (struct serial_struct __user *) arg);
+ break;
+ }
+
+ return rv;
}
static const __u32 acm_tty_speed[] = {
@@ -1675,7 +1698,6 @@ static int __init acm_init(void)
acm_tty_driver = alloc_tty_driver(ACM_TTY_MINORS);
if (!acm_tty_driver)
return -ENOMEM;
- acm_tty_driver->owner = THIS_MODULE,
acm_tty_driver->driver_name = "acm",
acm_tty_driver->name = "ttyACM",
acm_tty_driver->major = ACM_TTY_MAJOR,
diff --git a/drivers/usb/class/cdc-wdm.c b/drivers/usb/class/cdc-wdm.c
index d2b3cffca3f7..c6f6560d436c 100644
--- a/drivers/usb/class/cdc-wdm.c
+++ b/drivers/usb/class/cdc-wdm.c
@@ -23,6 +23,7 @@
#include <linux/usb/cdc.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
+#include <linux/usb/cdc-wdm.h>
/*
* Version Information
@@ -31,6 +32,8 @@
#define DRIVER_AUTHOR "Oliver Neukum"
#define DRIVER_DESC "USB Abstract Control Model driver for USB WCM Device Management"
+#define HUAWEI_VENDOR_ID 0x12D1
+
static const struct usb_device_id wdm_ids[] = {
{
.match_flags = USB_DEVICE_ID_MATCH_INT_CLASS |
@@ -38,6 +41,20 @@ static const struct usb_device_id wdm_ids[] = {
.bInterfaceClass = USB_CLASS_COMM,
.bInterfaceSubClass = USB_CDC_SUBCLASS_DMM
},
+ {
+ /*
+ * Huawei E392, E398 and possibly other Qualcomm based modems
+ * embed the Qualcomm QMI protocol inside CDC on CDC ECM like
+ * control interfaces. Userspace access to this is required
+ * to configure the accompanying data interface
+ */
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
+ USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = HUAWEI_VENDOR_ID,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 9, /* NOTE: CDC ECM control interface! */
+ },
{ }
};
@@ -54,6 +71,7 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
#define WDM_POLL_RUNNING 6
#define WDM_RESPONDING 7
#define WDM_SUSPENDING 8
+#define WDM_RESETTING 9
#define WDM_MAX 16
@@ -61,6 +79,8 @@ MODULE_DEVICE_TABLE (usb, wdm_ids);
#define WDM_DEFAULT_BUFSIZE 256
static DEFINE_MUTEX(wdm_mutex);
+static DEFINE_SPINLOCK(wdm_device_list_lock);
+static LIST_HEAD(wdm_device_list);
/* --- method tables --- */
@@ -82,7 +102,6 @@ struct wdm_device {
u16 bufsize;
u16 wMaxCommand;
u16 wMaxPacketSize;
- u16 bMaxPacketSize0;
__le16 inum;
int reslength;
int length;
@@ -96,10 +115,40 @@ struct wdm_device {
struct work_struct rxwork;
int werr;
int rerr;
+
+ struct list_head device_list;
+ int (*manage_power)(struct usb_interface *, int);
};
static struct usb_driver wdm_driver;
+/* return intfdata if we own the interface, else look up intf in the list */
+static struct wdm_device *wdm_find_device(struct usb_interface *intf)
+{
+ struct wdm_device *desc = NULL;
+
+ spin_lock(&wdm_device_list_lock);
+ list_for_each_entry(desc, &wdm_device_list, device_list)
+ if (desc->intf == intf)
+ break;
+ spin_unlock(&wdm_device_list_lock);
+
+ return desc;
+}
+
+static struct wdm_device *wdm_find_device_by_minor(int minor)
+{
+ struct wdm_device *desc = NULL;
+
+ spin_lock(&wdm_device_list_lock);
+ list_for_each_entry(desc, &wdm_device_list, device_list)
+ if (desc->intf->minor == minor)
+ break;
+ spin_unlock(&wdm_device_list_lock);
+
+ return desc;
+}
+
/* --- callbacks --- */
static void wdm_out_callback(struct urb *urb)
{
@@ -162,11 +211,9 @@ static void wdm_int_callback(struct urb *urb)
int rv = 0;
int status = urb->status;
struct wdm_device *desc;
- struct usb_ctrlrequest *req;
struct usb_cdc_notification *dr;
desc = urb->context;
- req = desc->irq;
dr = (struct usb_cdc_notification *)desc->sbuf;
if (status) {
@@ -213,24 +260,6 @@ static void wdm_int_callback(struct urb *urb)
goto exit;
}
- req->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
- req->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
- req->wValue = 0;
- req->wIndex = desc->inum;
- req->wLength = cpu_to_le16(desc->wMaxCommand);
-
- usb_fill_control_urb(
- desc->response,
- interface_to_usbdev(desc->intf),
- /* using common endpoint 0 */
- usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0),
- (unsigned char *)req,
- desc->inbuf,
- desc->wMaxCommand,
- wdm_in_callback,
- desc
- );
- desc->response->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
spin_lock(&desc->iuspin);
clear_bit(WDM_READ, &desc->flags);
set_bit(WDM_RESPONDING, &desc->flags);
@@ -279,14 +308,11 @@ static void free_urbs(struct wdm_device *desc)
static void cleanup(struct wdm_device *desc)
{
- usb_free_coherent(interface_to_usbdev(desc->intf),
- desc->wMaxPacketSize,
- desc->sbuf,
- desc->validity->transfer_dma);
- usb_free_coherent(interface_to_usbdev(desc->intf),
- desc->bMaxPacketSize0,
- desc->inbuf,
- desc->response->transfer_dma);
+ spin_lock(&wdm_device_list_lock);
+ list_del(&desc->device_list);
+ spin_unlock(&wdm_device_list_lock);
+ kfree(desc->sbuf);
+ kfree(desc->inbuf);
kfree(desc->orq);
kfree(desc->irq);
kfree(desc->ubuf);
@@ -351,6 +377,10 @@ static ssize_t wdm_write
else
if (test_bit(WDM_IN_USE, &desc->flags))
r = -EAGAIN;
+
+ if (test_bit(WDM_RESETTING, &desc->flags))
+ r = -EIO;
+
if (r < 0) {
kfree(buf);
goto out;
@@ -397,7 +427,7 @@ outnl:
static ssize_t wdm_read
(struct file *file, char __user *buffer, size_t count, loff_t *ppos)
{
- int rv, cntr = 0;
+ int rv, cntr;
int i = 0;
struct wdm_device *desc = file->private_data;
@@ -406,7 +436,8 @@ static ssize_t wdm_read
if (rv < 0)
return -ERESTARTSYS;
- if (desc->length == 0) {
+ cntr = ACCESS_ONCE(desc->length);
+ if (cntr == 0) {
desc->read = 0;
retry:
if (test_bit(WDM_DISCONNECTING, &desc->flags)) {
@@ -430,6 +461,10 @@ retry:
rv = -ENODEV;
goto err;
}
+ if (test_bit(WDM_RESETTING, &desc->flags)) {
+ rv = -EIO;
+ goto err;
+ }
usb_mark_last_busy(interface_to_usbdev(desc->intf));
if (rv < 0) {
rv = -ERESTARTSYS;
@@ -456,26 +491,30 @@ retry:
spin_unlock_irq(&desc->iuspin);
goto retry;
}
- clear_bit(WDM_READ, &desc->flags);
+ cntr = desc->length;
spin_unlock_irq(&desc->iuspin);
}
- cntr = count > desc->length ? desc->length : count;
+ if (cntr > count)
+ cntr = count;
rv = copy_to_user(buffer, desc->ubuf, cntr);
if (rv > 0) {
rv = -EFAULT;
goto err;
}
+ spin_lock_irq(&desc->iuspin);
+
for (i = 0; i < desc->length - cntr; i++)
desc->ubuf[i] = desc->ubuf[i + cntr];
- spin_lock_irq(&desc->iuspin);
desc->length -= cntr;
- spin_unlock_irq(&desc->iuspin);
/* in case we had outstanding data */
if (!desc->length)
clear_bit(WDM_READ, &desc->flags);
+
+ spin_unlock_irq(&desc->iuspin);
+
rv = cntr;
err:
@@ -529,11 +568,11 @@ static int wdm_open(struct inode *inode, struct file *file)
struct wdm_device *desc;
mutex_lock(&wdm_mutex);
- intf = usb_find_interface(&wdm_driver, minor);
- if (!intf)
+ desc = wdm_find_device_by_minor(minor);
+ if (!desc)
goto out;
- desc = usb_get_intfdata(intf);
+ intf = desc->intf;
if (test_bit(WDM_DISCONNECTING, &desc->flags))
goto out;
file->private_data = desc;
@@ -543,7 +582,6 @@ static int wdm_open(struct inode *inode, struct file *file)
dev_err(&desc->intf->dev, "Error autopm - %d\n", rv);
goto out;
}
- intf->needs_remote_wakeup = 1;
/* using write lock to protect desc->count */
mutex_lock(&desc->wlock);
@@ -560,6 +598,8 @@ static int wdm_open(struct inode *inode, struct file *file)
rv = 0;
}
mutex_unlock(&desc->wlock);
+ if (desc->count == 1)
+ desc->manage_power(intf, 1);
usb_autopm_put_interface(desc->intf);
out:
mutex_unlock(&wdm_mutex);
@@ -581,7 +621,7 @@ static int wdm_release(struct inode *inode, struct file *file)
dev_dbg(&desc->intf->dev, "wdm_release: cleanup");
kill_urbs(desc);
if (!test_bit(WDM_DISCONNECTING, &desc->flags))
- desc->intf->needs_remote_wakeup = 0;
+ desc->manage_power(desc->intf, 0);
}
mutex_unlock(&wdm_mutex);
return 0;
@@ -628,71 +668,31 @@ static void wdm_rxwork(struct work_struct *work)
/* --- hotplug --- */
-static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
+static int wdm_create(struct usb_interface *intf, struct usb_endpoint_descriptor *ep,
+ u16 bufsize, int (*manage_power)(struct usb_interface *, int))
{
- int rv = -EINVAL;
- struct usb_device *udev = interface_to_usbdev(intf);
+ int rv = -ENOMEM;
struct wdm_device *desc;
- struct usb_host_interface *iface;
- struct usb_endpoint_descriptor *ep;
- struct usb_cdc_dmm_desc *dmhd;
- u8 *buffer = intf->altsetting->extra;
- int buflen = intf->altsetting->extralen;
- u16 maxcom = WDM_DEFAULT_BUFSIZE;
-
- if (!buffer)
- goto out;
- while (buflen > 2) {
- if (buffer [1] != USB_DT_CS_INTERFACE) {
- dev_err(&intf->dev, "skipping garbage\n");
- goto next_desc;
- }
-
- switch (buffer [2]) {
- case USB_CDC_HEADER_TYPE:
- break;
- case USB_CDC_DMM_TYPE:
- dmhd = (struct usb_cdc_dmm_desc *)buffer;
- maxcom = le16_to_cpu(dmhd->wMaxCommand);
- dev_dbg(&intf->dev,
- "Finding maximum buffer length: %d", maxcom);
- break;
- default:
- dev_err(&intf->dev,
- "Ignoring extra header, type %d, length %d\n",
- buffer[2], buffer[0]);
- break;
- }
-next_desc:
- buflen -= buffer[0];
- buffer += buffer[0];
- }
-
- rv = -ENOMEM;
desc = kzalloc(sizeof(struct wdm_device), GFP_KERNEL);
if (!desc)
goto out;
+ INIT_LIST_HEAD(&desc->device_list);
mutex_init(&desc->rlock);
mutex_init(&desc->wlock);
spin_lock_init(&desc->iuspin);
init_waitqueue_head(&desc->wait);
- desc->wMaxCommand = maxcom;
+ desc->wMaxCommand = bufsize;
/* this will be expanded and needed in hardware endianness */
desc->inum = cpu_to_le16((u16)intf->cur_altsetting->desc.bInterfaceNumber);
desc->intf = intf;
INIT_WORK(&desc->rxwork, wdm_rxwork);
rv = -EINVAL;
- iface = intf->cur_altsetting;
- if (iface->desc.bNumEndpoints != 1)
- goto err;
- ep = &iface->endpoint[0].desc;
- if (!ep || !usb_endpoint_is_int_in(ep))
+ if (!usb_endpoint_is_int_in(ep))
goto err;
desc->wMaxPacketSize = usb_endpoint_maxp(ep);
- desc->bMaxPacketSize0 = udev->descriptor.bMaxPacketSize0;
desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);
if (!desc->orq)
@@ -717,19 +717,13 @@ next_desc:
if (!desc->ubuf)
goto err;
- desc->sbuf = usb_alloc_coherent(interface_to_usbdev(intf),
- desc->wMaxPacketSize,
- GFP_KERNEL,
- &desc->validity->transfer_dma);
+ desc->sbuf = kmalloc(desc->wMaxPacketSize, GFP_KERNEL);
if (!desc->sbuf)
goto err;
- desc->inbuf = usb_alloc_coherent(interface_to_usbdev(intf),
- desc->wMaxCommand,
- GFP_KERNEL,
- &desc->response->transfer_dma);
+ desc->inbuf = kmalloc(desc->wMaxCommand, GFP_KERNEL);
if (!desc->inbuf)
- goto err2;
+ goto err;
usb_fill_int_urb(
desc->validity,
@@ -741,45 +735,149 @@ next_desc:
desc,
ep->bInterval
);
- desc->validity->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- usb_set_intfdata(intf, desc);
+ desc->irq->bRequestType = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);
+ desc->irq->bRequest = USB_CDC_GET_ENCAPSULATED_RESPONSE;
+ desc->irq->wValue = 0;
+ desc->irq->wIndex = desc->inum;
+ desc->irq->wLength = cpu_to_le16(desc->wMaxCommand);
+
+ usb_fill_control_urb(
+ desc->response,
+ interface_to_usbdev(intf),
+ /* using common endpoint 0 */
+ usb_rcvctrlpipe(interface_to_usbdev(desc->intf), 0),
+ (unsigned char *)desc->irq,
+ desc->inbuf,
+ desc->wMaxCommand,
+ wdm_in_callback,
+ desc
+ );
+
+ desc->manage_power = manage_power;
+
+ spin_lock(&wdm_device_list_lock);
+ list_add(&desc->device_list, &wdm_device_list);
+ spin_unlock(&wdm_device_list_lock);
+
rv = usb_register_dev(intf, &wdm_class);
if (rv < 0)
- goto err3;
+ goto err;
else
- dev_info(&intf->dev, "cdc-wdm%d: USB WDM device\n",
- intf->minor - WDM_MINOR_BASE);
+ dev_info(&intf->dev, "%s: USB WDM device\n", dev_name(intf->usb_dev));
out:
return rv;
-err3:
- usb_set_intfdata(intf, NULL);
- usb_free_coherent(interface_to_usbdev(desc->intf),
- desc->bMaxPacketSize0,
- desc->inbuf,
- desc->response->transfer_dma);
-err2:
- usb_free_coherent(interface_to_usbdev(desc->intf),
- desc->wMaxPacketSize,
- desc->sbuf,
- desc->validity->transfer_dma);
err:
- free_urbs(desc);
- kfree(desc->ubuf);
- kfree(desc->orq);
- kfree(desc->irq);
- kfree(desc);
+ cleanup(desc);
+ return rv;
+}
+
+static int wdm_manage_power(struct usb_interface *intf, int on)
+{
+ /* need autopm_get/put here to ensure the usbcore sees the new value */
+ int rv = usb_autopm_get_interface(intf);
+ if (rv < 0)
+ goto err;
+
+ intf->needs_remote_wakeup = on;
+ usb_autopm_put_interface(intf);
+err:
+ return rv;
+}
+
+static int wdm_probe(struct usb_interface *intf, const struct usb_device_id *id)
+{
+ int rv = -EINVAL;
+ struct usb_host_interface *iface;
+ struct usb_endpoint_descriptor *ep;
+ struct usb_cdc_dmm_desc *dmhd;
+ u8 *buffer = intf->altsetting->extra;
+ int buflen = intf->altsetting->extralen;
+ u16 maxcom = WDM_DEFAULT_BUFSIZE;
+
+ if (!buffer)
+ goto err;
+ while (buflen > 2) {
+ if (buffer[1] != USB_DT_CS_INTERFACE) {
+ dev_err(&intf->dev, "skipping garbage\n");
+ goto next_desc;
+ }
+
+ switch (buffer[2]) {
+ case USB_CDC_HEADER_TYPE:
+ break;
+ case USB_CDC_DMM_TYPE:
+ dmhd = (struct usb_cdc_dmm_desc *)buffer;
+ maxcom = le16_to_cpu(dmhd->wMaxCommand);
+ dev_dbg(&intf->dev,
+ "Finding maximum buffer length: %d", maxcom);
+ break;
+ default:
+ dev_err(&intf->dev,
+ "Ignoring extra header, type %d, length %d\n",
+ buffer[2], buffer[0]);
+ break;
+ }
+next_desc:
+ buflen -= buffer[0];
+ buffer += buffer[0];
+ }
+
+ iface = intf->cur_altsetting;
+ if (iface->desc.bNumEndpoints != 1)
+ goto err;
+ ep = &iface->endpoint[0].desc;
+
+ rv = wdm_create(intf, ep, maxcom, &wdm_manage_power);
+
+err:
return rv;
}
+/**
+ * usb_cdc_wdm_register - register a WDM subdriver
+ * @intf: usb interface the subdriver will associate with
+ * @ep: interrupt endpoint to monitor for notifications
+ * @bufsize: maximum message size to support for read/write
+ *
+ * Create WDM usb class character device and associate it with intf
+ * without binding, allowing another driver to manage the interface.
+ *
+ * The subdriver will manage the given interrupt endpoint exclusively
+ * and will issue control requests referring to the given intf. It
+ * will otherwise avoid interferring, and in particular not do
+ * usb_set_intfdata/usb_get_intfdata on intf.
+ *
+ * The return value is a pointer to the subdriver's struct usb_driver.
+ * The registering driver is responsible for calling this subdriver's
+ * disconnect, suspend, resume, pre_reset and post_reset methods from
+ * its own.
+ */
+struct usb_driver *usb_cdc_wdm_register(struct usb_interface *intf,
+ struct usb_endpoint_descriptor *ep,
+ int bufsize,
+ int (*manage_power)(struct usb_interface *, int))
+{
+ int rv = -EINVAL;
+
+ rv = wdm_create(intf, ep, bufsize, manage_power);
+ if (rv < 0)
+ goto err;
+
+ return &wdm_driver;
+err:
+ return ERR_PTR(rv);
+}
+EXPORT_SYMBOL(usb_cdc_wdm_register);
+
static void wdm_disconnect(struct usb_interface *intf)
{
struct wdm_device *desc;
unsigned long flags;
usb_deregister_dev(intf, &wdm_class);
+ desc = wdm_find_device(intf);
mutex_lock(&wdm_mutex);
- desc = usb_get_intfdata(intf);
/* the spinlock makes sure no new urbs are generated in the callbacks */
spin_lock_irqsave(&desc->iuspin, flags);
@@ -803,7 +901,7 @@ static void wdm_disconnect(struct usb_interface *intf)
#ifdef CONFIG_PM
static int wdm_suspend(struct usb_interface *intf, pm_message_t message)
{
- struct wdm_device *desc = usb_get_intfdata(intf);
+ struct wdm_device *desc = wdm_find_device(intf);
int rv = 0;
dev_dbg(&desc->intf->dev, "wdm%d_suspend\n", intf->minor);
@@ -853,7 +951,7 @@ static int recover_from_urb_loss(struct wdm_device *desc)
#ifdef CONFIG_PM
static int wdm_resume(struct usb_interface *intf)
{
- struct wdm_device *desc = usb_get_intfdata(intf);
+ struct wdm_device *desc = wdm_find_device(intf);
int rv;
dev_dbg(&desc->intf->dev, "wdm%d_resume\n", intf->minor);
@@ -867,11 +965,7 @@ static int wdm_resume(struct usb_interface *intf)
static int wdm_pre_reset(struct usb_interface *intf)
{
- struct wdm_device *desc = usb_get_intfdata(intf);
-
- mutex_lock(&desc->rlock);
- mutex_lock(&desc->wlock);
- kill_urbs(desc);
+ struct wdm_device *desc = wdm_find_device(intf);
/*
* we notify everybody using poll of
@@ -880,17 +974,25 @@ static int wdm_pre_reset(struct usb_interface *intf)
* message from the device is lost
*/
spin_lock_irq(&desc->iuspin);
+ set_bit(WDM_RESETTING, &desc->flags); /* inform read/write */
+ set_bit(WDM_READ, &desc->flags); /* unblock read */
+ clear_bit(WDM_IN_USE, &desc->flags); /* unblock write */
desc->rerr = -EINTR;
spin_unlock_irq(&desc->iuspin);
wake_up_all(&desc->wait);
+ mutex_lock(&desc->rlock);
+ mutex_lock(&desc->wlock);
+ kill_urbs(desc);
+ cancel_work_sync(&desc->rxwork);
return 0;
}
static int wdm_post_reset(struct usb_interface *intf)
{
- struct wdm_device *desc = usb_get_intfdata(intf);
+ struct wdm_device *desc = wdm_find_device(intf);
int rv;
+ clear_bit(WDM_RESETTING, &desc->flags);
rv = recover_from_urb_loss(desc);
mutex_unlock(&desc->wlock);
mutex_unlock(&desc->rlock);
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index d40ff9568813..9a56635dc19c 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -71,10 +71,7 @@ ssize_t usb_store_new_id(struct usb_dynids *dynids,
list_add_tail(&dynid->node, &dynids->list);
spin_unlock(&dynids->lock);
- if (get_driver(driver)) {
- retval = driver_attach(driver);
- put_driver(driver);
- }
+ retval = driver_attach(driver);
if (retval)
return retval;
@@ -132,43 +129,39 @@ store_remove_id(struct device_driver *driver, const char *buf, size_t count)
}
static DRIVER_ATTR(remove_id, S_IWUSR, NULL, store_remove_id);
-static int usb_create_newid_file(struct usb_driver *usb_drv)
+static int usb_create_newid_files(struct usb_driver *usb_drv)
{
int error = 0;
if (usb_drv->no_dynamic_id)
goto exit;
- if (usb_drv->probe != NULL)
+ if (usb_drv->probe != NULL) {
error = driver_create_file(&usb_drv->drvwrap.driver,
&driver_attr_new_id);
+ if (error == 0) {
+ error = driver_create_file(&usb_drv->drvwrap.driver,
+ &driver_attr_remove_id);
+ if (error)
+ driver_remove_file(&usb_drv->drvwrap.driver,
+ &driver_attr_new_id);
+ }
+ }
exit:
return error;
}
-static void usb_remove_newid_file(struct usb_driver *usb_drv)
+static void usb_remove_newid_files(struct usb_driver *usb_drv)
{
if (usb_drv->no_dynamic_id)
return;
- if (usb_drv->probe != NULL)
+ if (usb_drv->probe != NULL) {
driver_remove_file(&usb_drv->drvwrap.driver,
- &driver_attr_new_id);
-}
-
-static int
-usb_create_removeid_file(struct usb_driver *drv)
-{
- int error = 0;
- if (drv->probe != NULL)
- error = driver_create_file(&drv->drvwrap.driver,
&driver_attr_remove_id);
- return error;
-}
-
-static void usb_remove_removeid_file(struct usb_driver *drv)
-{
- driver_remove_file(&drv->drvwrap.driver, &driver_attr_remove_id);
+ driver_remove_file(&usb_drv->drvwrap.driver,
+ &driver_attr_new_id);
+ }
}
static void usb_free_dynids(struct usb_driver *usb_drv)
@@ -183,22 +176,12 @@ static void usb_free_dynids(struct usb_driver *usb_drv)
spin_unlock(&usb_drv->dynids.lock);
}
#else
-static inline int usb_create_newid_file(struct usb_driver *usb_drv)
-{
- return 0;
-}
-
-static void usb_remove_newid_file(struct usb_driver *usb_drv)
-{
-}
-
-static int
-usb_create_removeid_file(struct usb_driver *drv)
+static inline int usb_create_newid_files(struct usb_driver *usb_drv)
{
return 0;
}
-static void usb_remove_removeid_file(struct usb_driver *drv)
+static void usb_remove_newid_files(struct usb_driver *usb_drv)
{
}
@@ -875,22 +858,16 @@ int usb_register_driver(struct usb_driver *new_driver, struct module *owner,
usbfs_update_special();
- retval = usb_create_newid_file(new_driver);
+ retval = usb_create_newid_files(new_driver);
if (retval)
goto out_newid;
- retval = usb_create_removeid_file(new_driver);
- if (retval)
- goto out_removeid;
-
pr_info("%s: registered new interface driver %s\n",
usbcore_name, new_driver->name);
out:
return retval;
-out_removeid:
- usb_remove_newid_file(new_driver);
out_newid:
driver_unregister(&new_driver->drvwrap.driver);
@@ -917,10 +894,9 @@ void usb_deregister(struct usb_driver *driver)
pr_info("%s: deregistering interface driver %s\n",
usbcore_name, driver->name);
- usb_remove_removeid_file(driver);
- usb_remove_newid_file(driver);
- usb_free_dynids(driver);
+ usb_remove_newid_files(driver);
driver_unregister(&driver->drvwrap.driver);
+ usb_free_dynids(driver);
usbfs_update_special();
}
@@ -958,13 +934,8 @@ void usb_rebind_intf(struct usb_interface *intf)
int rc;
/* Delayed unbind of an existing driver */
- if (intf->dev.driver) {
- struct usb_driver *driver =
- to_usb_driver(intf->dev.driver);
-
- dev_dbg(&intf->dev, "forced unbind\n");
- usb_driver_release_interface(driver, intf);
- }
+ if (intf->dev.driver)
+ usb_forced_unbind_intf(intf);
/* Try to rebind the interface */
if (!intf->dev.power.is_prepared) {
@@ -977,15 +948,13 @@ void usb_rebind_intf(struct usb_interface *intf)
#ifdef CONFIG_PM
-#define DO_UNBIND 0
-#define DO_REBIND 1
-
-/* Unbind drivers for @udev's interfaces that don't support suspend/resume,
- * or rebind interfaces that have been unbound, according to @action.
+/* Unbind drivers for @udev's interfaces that don't support suspend/resume
+ * There is no check for reset_resume here because it can be determined
+ * only during resume whether reset_resume is needed.
*
* The caller must hold @udev's device lock.
*/
-static void do_unbind_rebind(struct usb_device *udev, int action)
+static void unbind_no_pm_drivers_interfaces(struct usb_device *udev)
{
struct usb_host_config *config;
int i;
@@ -996,23 +965,53 @@ static void do_unbind_rebind(struct usb_device *udev, int action)
if (config) {
for (i = 0; i < config->desc.bNumInterfaces; ++i) {
intf = config->interface[i];
- switch (action) {
- case DO_UNBIND:
- if (intf->dev.driver) {
- drv = to_usb_driver(intf->dev.driver);
- if (!drv->suspend || !drv->resume)
- usb_forced_unbind_intf(intf);
- }
- break;
- case DO_REBIND:
- if (intf->needs_binding)
- usb_rebind_intf(intf);
- break;
+
+ if (intf->dev.driver) {
+ drv = to_usb_driver(intf->dev.driver);
+ if (!drv->suspend || !drv->resume)
+ usb_forced_unbind_intf(intf);
}
}
}
}
+/* Unbind drivers for @udev's interfaces that failed to support reset-resume.
+ * These interfaces have the needs_binding flag set by usb_resume_interface().
+ *
+ * The caller must hold @udev's device lock.
+ */
+static void unbind_no_reset_resume_drivers_interfaces(struct usb_device *udev)
+{
+ struct usb_host_config *config;
+ int i;
+ struct usb_interface *intf;
+
+ config = udev->actconfig;
+ if (config) {
+ for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+ intf = config->interface[i];
+ if (intf->dev.driver && intf->needs_binding)
+ usb_forced_unbind_intf(intf);
+ }
+ }
+}
+
+static void do_rebind_interfaces(struct usb_device *udev)
+{
+ struct usb_host_config *config;
+ int i;
+ struct usb_interface *intf;
+
+ config = udev->actconfig;
+ if (config) {
+ for (i = 0; i < config->desc.bNumInterfaces; ++i) {
+ intf = config->interface[i];
+ if (intf->needs_binding)
+ usb_rebind_intf(intf);
+ }
+ }
+}
+
static int usb_suspend_device(struct usb_device *udev, pm_message_t msg)
{
struct usb_device_driver *udriver;
@@ -1190,8 +1189,13 @@ static int usb_suspend_both(struct usb_device *udev, pm_message_t msg)
if (status == 0) {
status = usb_suspend_device(udev, msg);
- /* Again, ignore errors during system sleep transitions */
- if (!PMSG_IS_AUTO(msg))
+ /*
+ * Ignore errors from non-root-hub devices during
+ * system sleep transitions. For the most part,
+ * these devices should go to low power anyway when
+ * the entire bus is suspended.
+ */
+ if (udev->parent && !PMSG_IS_AUTO(msg))
status = 0;
}
@@ -1302,35 +1306,48 @@ int usb_suspend(struct device *dev, pm_message_t msg)
{
struct usb_device *udev = to_usb_device(dev);
- do_unbind_rebind(udev, DO_UNBIND);
+ unbind_no_pm_drivers_interfaces(udev);
+
+ /* From now on we are sure all drivers support suspend/resume
+ * but not necessarily reset_resume()
+ * so we may still need to unbind and rebind upon resume
+ */
choose_wakeup(udev, msg);
return usb_suspend_both(udev, msg);
}
/* The device lock is held by the PM core */
+int usb_resume_complete(struct device *dev)
+{
+ struct usb_device *udev = to_usb_device(dev);
+
+ /* For PM complete calls, all we do is rebind interfaces
+ * whose needs_binding flag is set
+ */
+ if (udev->state != USB_STATE_NOTATTACHED)
+ do_rebind_interfaces(udev);
+ return 0;
+}
+
+/* The device lock is held by the PM core */
int usb_resume(struct device *dev, pm_message_t msg)
{
struct usb_device *udev = to_usb_device(dev);
int status;
- /* For PM complete calls, all we do is rebind interfaces */
- if (msg.event == PM_EVENT_ON) {
- if (udev->state != USB_STATE_NOTATTACHED)
- do_unbind_rebind(udev, DO_REBIND);
- status = 0;
-
- /* For all other calls, take the device back to full power and
+ /* For all calls, take the device back to full power and
* tell the PM core in case it was autosuspended previously.
- * Unbind the interfaces that will need rebinding later.
+ * Unbind the interfaces that will need rebinding later,
+ * because they fail to support reset_resume.
+ * (This can't be done in usb_resume_interface()
+ * above because it doesn't own the right set of locks.)
*/
- } else {
- status = usb_resume_both(udev, msg);
- if (status == 0) {
- pm_runtime_disable(dev);
- pm_runtime_set_active(dev);
- pm_runtime_enable(dev);
- do_unbind_rebind(udev, DO_REBIND);
- }
+ status = usb_resume_both(udev, msg);
+ if (status == 0) {
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ unbind_no_reset_resume_drivers_interfaces(udev);
}
/* Avoid PM error messages for devices disconnected while suspended
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index 81e2c0d9c17d..622b4a48e732 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -380,6 +380,7 @@ static int check_root_hub_suspended(struct device *dev)
return 0;
}
+#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME)
static int suspend_common(struct device *dev, bool do_wakeup)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -471,6 +472,7 @@ static int resume_common(struct device *dev, int event)
}
return retval;
}
+#endif /* SLEEP || RUNTIME */
#ifdef CONFIG_PM_SLEEP
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index e1282328fc27..140d3e11f212 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1978,6 +1978,18 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg)
if (status == 0) {
usb_set_device_state(rhdev, USB_STATE_SUSPENDED);
hcd->state = HC_STATE_SUSPENDED;
+
+ /* Did we race with a root-hub wakeup event? */
+ if (rhdev->do_remote_wakeup) {
+ char buffer[6];
+
+ status = hcd->driver->hub_status_data(hcd, buffer);
+ if (status != 0) {
+ dev_dbg(&rhdev->dev, "suspend raced with wakeup event\n");
+ hcd_bus_resume(rhdev, PMSG_AUTO_RESUME);
+ status = -EBUSY;
+ }
+ }
} else {
spin_lock_irq(&hcd_root_hub_lock);
if (!HCD_DEAD(hcd)) {
@@ -2352,7 +2364,7 @@ static int usb_hcd_request_irqs(struct usb_hcd *hcd,
"io mem" : "io base",
(unsigned long long)hcd->rsrc_start);
} else {
- hcd->irq = -1;
+ hcd->irq = 0;
if (hcd->rsrc_start)
dev_info(hcd->self.controller, "%s 0x%08llx\n",
(hcd->driver->flags & HCD_MEMORY) ?
@@ -2508,7 +2520,7 @@ err_register_root_hub:
clear_bit(HCD_FLAG_POLL_RH, &hcd->flags);
del_timer_sync(&hcd->rh_timer);
err_hcd_driver_start:
- if (usb_hcd_is_primary_hcd(hcd) && hcd->irq >= 0)
+ if (usb_hcd_is_primary_hcd(hcd) && hcd->irq > 0)
free_irq(irqnum, hcd);
err_request_irq:
err_hcd_driver_setup:
@@ -2573,7 +2585,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
del_timer_sync(&hcd->rh_timer);
if (usb_hcd_is_primary_hcd(hcd)) {
- if (hcd->irq >= 0)
+ if (hcd->irq > 0)
free_irq(hcd->irq, hcd);
}
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index 265c2f675d04..ec6c97dadbe4 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -62,6 +62,8 @@ struct usb_hub {
resumed */
unsigned long removed_bits[1]; /* ports with a "removed"
device present */
+ unsigned long wakeup_bits[1]; /* ports that have signaled
+ remote wakeup */
#if USB_MAXCHILDREN > 31 /* 8*sizeof(unsigned long) - 1 */
#error event_bits[] is too short!
#endif
@@ -411,6 +413,29 @@ void usb_kick_khubd(struct usb_device *hdev)
kick_khubd(hub);
}
+/*
+ * Let the USB core know that a USB 3.0 device has sent a Function Wake Device
+ * Notification, which indicates it had initiated remote wakeup.
+ *
+ * USB 3.0 hubs do not report the port link state change from U3 to U0 when the
+ * device initiates resume, so the USB core will not receive notice of the
+ * resume through the normal hub interrupt URB.
+ */
+void usb_wakeup_notification(struct usb_device *hdev,
+ unsigned int portnum)
+{
+ struct usb_hub *hub;
+
+ if (!hdev)
+ return;
+
+ hub = hdev_to_hub(hdev);
+ if (hub) {
+ set_bit(portnum, hub->wakeup_bits);
+ kick_khubd(hub);
+ }
+}
+EXPORT_SYMBOL_GPL(usb_wakeup_notification);
/* completion function, fires on port status changes and various faults */
static void hub_irq(struct urb *urb)
@@ -823,12 +848,6 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
clear_port_feature(hub->hdev, port1,
USB_PORT_FEAT_C_ENABLE);
}
- if (portchange & USB_PORT_STAT_C_LINK_STATE) {
- need_debounce_delay = true;
- clear_port_feature(hub->hdev, port1,
- USB_PORT_FEAT_C_PORT_LINK_STATE);
- }
-
if ((portchange & USB_PORT_STAT_C_BH_RESET) &&
hub_is_superspeed(hub->hdev)) {
need_debounce_delay = true;
@@ -850,12 +869,19 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type)
set_bit(port1, hub->change_bits);
} else if (portstatus & USB_PORT_STAT_ENABLE) {
+ bool port_resumed = (portstatus &
+ USB_PORT_STAT_LINK_STATE) ==
+ USB_SS_PORT_LS_U0;
/* The power session apparently survived the resume.
* If there was an overcurrent or suspend change
* (i.e., remote wakeup request), have khubd
- * take care of it.
+ * take care of it. Look at the port link state
+ * for USB 3.0 hubs, since they don't have a suspend
+ * change bit, and they don't set the port link change
+ * bit on device-initiated resume.
*/
- if (portchange)
+ if (portchange || (hub_is_superspeed(hub->hdev) &&
+ port_resumed))
set_bit(port1, hub->change_bits);
} else if (udev->persist_enabled) {
@@ -1021,8 +1047,10 @@ static int hub_configure(struct usb_hub *hub,
dev_info (hub_dev, "%d port%s detected\n", hdev->maxchild,
(hdev->maxchild == 1) ? "" : "s");
+ hdev->children = kzalloc(hdev->maxchild *
+ sizeof(struct usb_device *), GFP_KERNEL);
hub->port_owners = kzalloc(hdev->maxchild * sizeof(void *), GFP_KERNEL);
- if (!hub->port_owners) {
+ if (!hdev->children || !hub->port_owners) {
ret = -ENOMEM;
goto fail;
}
@@ -1253,7 +1281,8 @@ static unsigned highspeed_hubs;
static void hub_disconnect(struct usb_interface *intf)
{
- struct usb_hub *hub = usb_get_intfdata (intf);
+ struct usb_hub *hub = usb_get_intfdata(intf);
+ struct usb_device *hdev = interface_to_usbdev(intf);
/* Take the hub off the event list and don't let it be added again */
spin_lock_irq(&hub_event_lock);
@@ -1275,6 +1304,7 @@ static void hub_disconnect(struct usb_interface *intf)
highspeed_hubs--;
usb_free_urb(hub->urb);
+ kfree(hdev->children);
kfree(hub->port_owners);
kfree(hub->descriptor);
kfree(hub->status);
@@ -1293,14 +1323,8 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
desc = intf->cur_altsetting;
hdev = interface_to_usbdev(intf);
- /* Hubs have proper suspend/resume support. USB 3.0 device suspend is
- * different from USB 2.0/1.1 device suspend, and unfortunately we
- * don't support it yet. So leave autosuspend disabled for USB 3.0
- * external hubs for now. Enable autosuspend for USB 3.0 roothubs,
- * since that isn't a "real" hub.
- */
- if (!hub_is_superspeed(hdev) || !hdev->parent)
- usb_enable_autosuspend(hdev);
+ /* Hubs have proper suspend/resume support. */
+ usb_enable_autosuspend(hdev);
if (hdev->level == MAX_TOPO_LEVEL) {
dev_err(&intf->dev,
@@ -1643,7 +1667,6 @@ void usb_disconnect(struct usb_device **pdev)
{
struct usb_device *udev = *pdev;
int i;
- struct usb_hcd *hcd = bus_to_hcd(udev->bus);
/* mark the device as inactive, so any further urb submissions for
* this device (and any of its children) will fail immediately.
@@ -1656,7 +1679,7 @@ void usb_disconnect(struct usb_device **pdev)
usb_lock_device(udev);
/* Free up all the children before we remove this device */
- for (i = 0; i < USB_MAXCHILDREN; i++) {
+ for (i = 0; i < udev->maxchild; i++) {
if (udev->children[i])
usb_disconnect(&udev->children[i]);
}
@@ -1666,9 +1689,7 @@ void usb_disconnect(struct usb_device **pdev)
* so that the hardware is now fully quiesced.
*/
dev_dbg (&udev->dev, "unregistering device\n");
- mutex_lock(hcd->bandwidth_mutex);
usb_disable_device(udev, 0);
- mutex_unlock(hcd->bandwidth_mutex);
usb_hcd_synchronize_unlinks(udev);
usb_remove_ep_devs(&udev->ep0);
@@ -1842,6 +1863,37 @@ fail:
return err;
}
+static void set_usb_port_removable(struct usb_device *udev)
+{
+ struct usb_device *hdev = udev->parent;
+ struct usb_hub *hub;
+ u8 port = udev->portnum;
+ u16 wHubCharacteristics;
+ bool removable = true;
+
+ if (!hdev)
+ return;
+
+ hub = hdev_to_hub(udev->parent);
+
+ wHubCharacteristics = le16_to_cpu(hub->descriptor->wHubCharacteristics);
+
+ if (!(wHubCharacteristics & HUB_CHAR_COMPOUND))
+ return;
+
+ if (hub_is_superspeed(hdev)) {
+ if (hub->descriptor->u.ss.DeviceRemovable & (1 << port))
+ removable = false;
+ } else {
+ if (hub->descriptor->u.hs.DeviceRemovable[port / 8] & (1 << (port % 8)))
+ removable = false;
+ }
+
+ if (removable)
+ udev->removable = USB_DEVICE_REMOVABLE;
+ else
+ udev->removable = USB_DEVICE_FIXED;
+}
/**
* usb_new_device - perform initial device setup (usbcore-internal)
@@ -1900,6 +1952,15 @@ int usb_new_device(struct usb_device *udev)
announce_device(udev);
device_enable_async_suspend(&udev->dev);
+
+ /*
+ * check whether the hub marks this port as non-removable. Do it
+ * now so that platform-specific data can override it in
+ * device_add()
+ */
+ if (udev->parent)
+ set_usb_port_removable(udev);
+
/* Register the device. The device driver is responsible
* for configuring the device and invoking the add-device
* notifier chain (used by usbfs and possibly others).
@@ -2385,11 +2446,27 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
* we don't explicitly enable it here.
*/
if (udev->do_remote_wakeup) {
- status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
- USB_DEVICE_REMOTE_WAKEUP, 0,
- NULL, 0,
- USB_CTRL_SET_TIMEOUT);
+ if (!hub_is_superspeed(hub->hdev)) {
+ status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
+ USB_DEVICE_REMOTE_WAKEUP, 0,
+ NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ } else {
+ /* Assume there's only one function on the USB 3.0
+ * device and enable remote wake for the first
+ * interface. FIXME if the interface association
+ * descriptor shows there's more than one function.
+ */
+ status = usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
+ USB_REQ_SET_FEATURE,
+ USB_RECIP_INTERFACE,
+ USB_INTRF_FUNC_SUSPEND,
+ USB_INTRF_FUNC_SUSPEND_RW |
+ USB_INTRF_FUNC_SUSPEND_LP,
+ NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
+ }
if (status) {
dev_dbg(&udev->dev, "won't remote wakeup, status %d\n",
status);
@@ -2679,6 +2756,7 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
struct usb_hub *hub = usb_get_intfdata (intf);
struct usb_device *hdev = hub->hdev;
unsigned port1;
+ int status;
/* Warn if children aren't already suspended */
for (port1 = 1; port1 <= hdev->maxchild; port1++) {
@@ -2691,6 +2769,17 @@ static int hub_suspend(struct usb_interface *intf, pm_message_t msg)
return -EBUSY;
}
}
+ if (hub_is_superspeed(hdev) && hdev->do_remote_wakeup) {
+ /* Enable hub to send remote wakeup for all ports. */
+ for (port1 = 1; port1 <= hdev->maxchild; port1++) {
+ status = set_port_feature(hdev,
+ port1 |
+ USB_PORT_FEAT_REMOTE_WAKE_CONNECT |
+ USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT |
+ USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT,
+ USB_PORT_FEAT_REMOTE_WAKE_MASK);
+ }
+ }
dev_dbg(&intf->dev, "%s\n", __func__);
@@ -3071,6 +3160,22 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
if (retval)
goto fail;
+ /*
+ * Some superspeed devices have finished the link training process
+ * and attached to a superspeed hub port, but the device descriptor
+ * got from those devices show they aren't superspeed devices. Warm
+ * reset the port attached by the devices can fix them.
+ */
+ if ((udev->speed == USB_SPEED_SUPER) &&
+ (le16_to_cpu(udev->descriptor.bcdUSB) < 0x0300)) {
+ dev_err(&udev->dev, "got a wrong device descriptor, "
+ "warm reset device\n");
+ hub_port_reset(hub, port1, udev,
+ HUB_BH_RESET_TIME, true);
+ retval = -EINVAL;
+ goto fail;
+ }
+
if (udev->descriptor.bMaxPacketSize0 == 0xff ||
udev->speed == USB_SPEED_SUPER)
i = 512;
@@ -3424,6 +3529,46 @@ done:
hcd->driver->relinquish_port(hcd, port1);
}
+/* Returns 1 if there was a remote wakeup and a connect status change. */
+static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
+ u16 portstatus, u16 portchange)
+{
+ struct usb_device *hdev;
+ struct usb_device *udev;
+ int connect_change = 0;
+ int ret;
+
+ hdev = hub->hdev;
+ udev = hdev->children[port-1];
+ if (!hub_is_superspeed(hdev)) {
+ if (!(portchange & USB_PORT_STAT_C_SUSPEND))
+ return 0;
+ clear_port_feature(hdev, port, USB_PORT_FEAT_C_SUSPEND);
+ } else {
+ if (!udev || udev->state != USB_STATE_SUSPENDED ||
+ (portstatus & USB_PORT_STAT_LINK_STATE) !=
+ USB_SS_PORT_LS_U0)
+ return 0;
+ }
+
+ if (udev) {
+ /* TRSMRCY = 10 msec */
+ msleep(10);
+
+ usb_lock_device(udev);
+ ret = usb_remote_wakeup(udev);
+ usb_unlock_device(udev);
+ if (ret < 0)
+ connect_change = 1;
+ } else {
+ ret = -ENODEV;
+ hub_port_disable(hub, port, 1);
+ }
+ dev_dbg(hub->intfdev, "resume on port %d, status %d\n",
+ port, ret);
+ return connect_change;
+}
+
static void hub_events(void)
{
struct list_head *tmp;
@@ -3436,7 +3581,7 @@ static void hub_events(void)
u16 portstatus;
u16 portchange;
int i, ret;
- int connect_change;
+ int connect_change, wakeup_change;
/*
* We restart the list every time to avoid a deadlock with
@@ -3515,8 +3660,9 @@ static void hub_events(void)
if (test_bit(i, hub->busy_bits))
continue;
connect_change = test_bit(i, hub->change_bits);
+ wakeup_change = test_and_clear_bit(i, hub->wakeup_bits);
if (!test_and_clear_bit(i, hub->event_bits) &&
- !connect_change)
+ !connect_change && !wakeup_change)
continue;
ret = hub_port_status(hub, i,
@@ -3557,31 +3703,10 @@ static void hub_events(void)
}
}
- if (portchange & USB_PORT_STAT_C_SUSPEND) {
- struct usb_device *udev;
+ if (hub_handle_remote_wakeup(hub, i,
+ portstatus, portchange))
+ connect_change = 1;
- clear_port_feature(hdev, i,
- USB_PORT_FEAT_C_SUSPEND);
- udev = hdev->children[i-1];
- if (udev) {
- /* TRSMRCY = 10 msec */
- msleep(10);
-
- usb_lock_device(udev);
- ret = usb_remote_wakeup(hdev->
- children[i-1]);
- usb_unlock_device(udev);
- if (ret < 0)
- connect_change = 1;
- } else {
- ret = -ENODEV;
- hub_port_disable(hub, i, 1);
- }
- dev_dbg (hub_dev,
- "resume on port %d, status %d\n",
- i, ret);
- }
-
if (portchange & USB_PORT_STAT_C_OVERCURRENT) {
u16 status = 0;
u16 unused;
diff --git a/drivers/usb/core/inode.c b/drivers/usb/core/inode.c
index 9e186f3da839..d2b9af59cba9 100644
--- a/drivers/usb/core/inode.c
+++ b/drivers/usb/core/inode.c
@@ -50,7 +50,6 @@
static const struct file_operations default_file_operations;
static struct vfsmount *usbfs_mount;
static int usbfs_mount_count; /* = 0 */
-static int ignore_mount = 0;
static struct dentry *devices_usbfs_dentry;
static int num_buses; /* = 0 */
@@ -256,7 +255,7 @@ static int remount(struct super_block *sb, int *flags, char *data)
* i.e. it's a simple_pin_fs from create_special_files,
* then ignore it.
*/
- if (ignore_mount)
+ if (*flags & MS_KERNMOUNT)
return 0;
if (parse_options(sb, data)) {
@@ -429,18 +428,10 @@ static loff_t default_file_lseek (struct file *file, loff_t offset, int orig)
return retval;
}
-static int default_open (struct inode *inode, struct file *file)
-{
- if (inode->i_private)
- file->private_data = inode->i_private;
-
- return 0;
-}
-
static const struct file_operations default_file_operations = {
.read = default_read_file,
.write = default_write_file,
- .open = default_open,
+ .open = simple_open,
.llseek = default_file_lseek,
};
@@ -454,7 +445,6 @@ static const struct super_operations usbfs_ops = {
static int usbfs_fill_super(struct super_block *sb, void *data, int silent)
{
struct inode *inode;
- struct dentry *root;
sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@@ -462,19 +452,11 @@ static int usbfs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_op = &usbfs_ops;
sb->s_time_gran = 1;
inode = usbfs_get_inode(sb, S_IFDIR | 0755, 0);
-
- if (!inode) {
- dbg("%s: could not get inode!",__func__);
- return -ENOMEM;
- }
-
- root = d_alloc_root(inode);
- if (!root) {
+ sb->s_root = d_make_root(inode);
+ if (!sb->s_root) {
dbg("%s: could not get root dentry!",__func__);
- iput(inode);
return -ENOMEM;
}
- sb->s_root = root;
return 0;
}
@@ -591,11 +573,6 @@ static int create_special_files (void)
struct dentry *parent;
int retval;
- /* the simple_pin_fs calls will call remount with no options
- * without this flag that would overwrite the real mount options (if any)
- */
- ignore_mount = 1;
-
/* create the devices special file */
retval = simple_pin_fs(&usb_fs_type, &usbfs_mount, &usbfs_mount_count);
if (retval) {
@@ -603,8 +580,6 @@ static int create_special_files (void)
goto exit;
}
- ignore_mount = 0;
-
parent = usbfs_mount->mnt_root;
devices_usbfs_dentry = fs_create_file ("devices",
listmode | S_IFREG, parent,
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index b3bdfede45e6..ca717da3be95 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -308,7 +308,8 @@ static void sg_complete(struct urb *urb)
retval = usb_unlink_urb(io->urbs [i]);
if (retval != -EINPROGRESS &&
retval != -ENODEV &&
- retval != -EBUSY)
+ retval != -EBUSY &&
+ retval != -EIDRM)
dev_err(&io->dev->dev,
"%s, unlink --> %d\n",
__func__, retval);
@@ -317,7 +318,6 @@ static void sg_complete(struct urb *urb)
}
spin_lock(&io->lock);
}
- urb->dev = NULL;
/* on the last completion, signal usb_sg_wait() */
io->bytes += urb->actual_length;
@@ -524,7 +524,6 @@ void usb_sg_wait(struct usb_sg_request *io)
case -ENXIO: /* hc didn't queue this one */
case -EAGAIN:
case -ENOMEM:
- io->urbs[i]->dev = NULL;
retval = 0;
yield();
break;
@@ -542,7 +541,6 @@ void usb_sg_wait(struct usb_sg_request *io)
/* fail any uncompleted urbs */
default:
- io->urbs[i]->dev = NULL;
io->urbs[i]->status = retval;
dev_dbg(&io->dev->dev, "%s, submit --> %d\n",
__func__, retval);
@@ -593,7 +591,10 @@ void usb_sg_cancel(struct usb_sg_request *io)
if (!io->urbs [i]->dev)
continue;
retval = usb_unlink_urb(io->urbs [i]);
- if (retval != -EINPROGRESS && retval != -EBUSY)
+ if (retval != -EINPROGRESS
+ && retval != -ENODEV
+ && retval != -EBUSY
+ && retval != -EIDRM)
dev_warn(&io->dev->dev, "%s, unlink --> %d\n",
__func__, retval);
}
@@ -1135,8 +1136,6 @@ void usb_disable_interface(struct usb_device *dev, struct usb_interface *intf,
* Deallocates hcd/hardware state for the endpoints (nuking all or most
* pending urbs) and usbcore state for the interfaces, so that usbcore
* must usb_set_configuration() before any interfaces could be used.
- *
- * Must be called with hcd->bandwidth_mutex held.
*/
void usb_disable_device(struct usb_device *dev, int skip_ep0)
{
@@ -1189,7 +1188,9 @@ void usb_disable_device(struct usb_device *dev, int skip_ep0)
usb_disable_endpoint(dev, i + USB_DIR_IN, false);
}
/* Remove endpoints from the host controller internal state */
+ mutex_lock(hcd->bandwidth_mutex);
usb_hcd_alloc_bandwidth(dev, NULL, NULL, NULL);
+ mutex_unlock(hcd->bandwidth_mutex);
/* Second pass: remove endpoint pointers */
}
for (i = skip_ep0; i < 16; ++i) {
@@ -1749,7 +1750,6 @@ free_interfaces:
/* if it's already configured, clear out old state first.
* getting rid of old interfaces means unbinding their drivers.
*/
- mutex_lock(hcd->bandwidth_mutex);
if (dev->state != USB_STATE_ADDRESS)
usb_disable_device(dev, 1); /* Skip ep0 */
@@ -1762,6 +1762,7 @@ free_interfaces:
* host controller will not allow submissions to dropped endpoints. If
* this call fails, the device state is unchanged.
*/
+ mutex_lock(hcd->bandwidth_mutex);
ret = usb_hcd_alloc_bandwidth(dev, cp, NULL, NULL);
if (ret < 0) {
mutex_unlock(hcd->bandwidth_mutex);
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 9e491ca2e5c4..566d9f94f735 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -230,6 +230,28 @@ show_urbnum(struct device *dev, struct device_attribute *attr, char *buf)
}
static DEVICE_ATTR(urbnum, S_IRUGO, show_urbnum, NULL);
+static ssize_t
+show_removable(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct usb_device *udev;
+ char *state;
+
+ udev = to_usb_device(dev);
+
+ switch (udev->removable) {
+ case USB_DEVICE_REMOVABLE:
+ state = "removable";
+ break;
+ case USB_DEVICE_FIXED:
+ state = "fixed";
+ break;
+ default:
+ state = "unknown";
+ }
+
+ return sprintf(buf, "%s\n", state);
+}
+static DEVICE_ATTR(removable, S_IRUGO, show_removable, NULL);
#ifdef CONFIG_PM
@@ -626,6 +648,7 @@ static struct attribute *dev_attrs[] = {
&dev_attr_avoid_reset_quirk.attr,
&dev_attr_authorized.attr,
&dev_attr_remove.attr,
+ &dev_attr_removable.attr,
NULL,
};
static struct attribute_group dev_attr_grp = {
diff --git a/drivers/usb/core/urb.c b/drivers/usb/core/urb.c
index 909625b91eb3..cd9b3a2cd8a7 100644
--- a/drivers/usb/core/urb.c
+++ b/drivers/usb/core/urb.c
@@ -403,20 +403,17 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
* cause problems in HCDs if they get it wrong.
*/
{
- unsigned int orig_flags = urb->transfer_flags;
unsigned int allowed;
static int pipetypes[4] = {
PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
};
/* Check that the pipe's type matches the endpoint's type */
- if (usb_pipetype(urb->pipe) != pipetypes[xfertype]) {
- dev_err(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n",
+ if (usb_pipetype(urb->pipe) != pipetypes[xfertype])
+ dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n",
usb_pipetype(urb->pipe), pipetypes[xfertype]);
- return -EPIPE; /* The most suitable error code :-) */
- }
- /* enforce simple/standard policy */
+ /* Check against a simple/standard policy */
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT | URB_DIR_MASK |
URB_FREE_BUFFER);
switch (xfertype) {
@@ -435,14 +432,12 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
allowed |= URB_ISO_ASAP;
break;
}
- urb->transfer_flags &= allowed;
+ allowed &= urb->transfer_flags;
- /* fail if submitter gave bogus flags */
- if (urb->transfer_flags != orig_flags) {
- dev_err(&dev->dev, "BOGUS urb flags, %x --> %x\n",
- orig_flags, urb->transfer_flags);
- return -EINVAL;
- }
+ /* warn if submitter gave bogus flags */
+ if (allowed != urb->transfer_flags)
+ dev_WARN(&dev->dev, "BOGUS urb flags, %x --> %x\n",
+ urb->transfer_flags, allowed);
}
#endif
/*
@@ -532,15 +527,22 @@ EXPORT_SYMBOL_GPL(usb_submit_urb);
* a driver's I/O routines to insure that all URB-related activity has
* completed before it returns.
*
- * This request is always asynchronous. Success is indicated by
- * returning -EINPROGRESS, at which time the URB will probably not yet
- * have been given back to the device driver. When it is eventually
- * called, the completion function will see @urb->status == -ECONNRESET.
+ * This request is asynchronous, however the HCD might call the ->complete()
+ * callback during unlink. Therefore when drivers call usb_unlink_urb(), they
+ * must not hold any locks that may be taken by the completion function.
+ * Success is indicated by returning -EINPROGRESS, at which time the URB will
+ * probably not yet have been given back to the device driver. When it is
+ * eventually called, the completion function will see @urb->status ==
+ * -ECONNRESET.
* Failure is indicated by usb_unlink_urb() returning any other value.
* Unlinking will fail when @urb is not currently "linked" (i.e., it was
* never submitted, or it was unlinked before, or the hardware is already
* finished with it), even if the completion handler has not yet run.
*
+ * The URB must not be deallocated while this routine is running. In
+ * particular, when a driver calls this routine, it must insure that the
+ * completion handler cannot deallocate the URB.
+ *
* Unlinking and Endpoint Queues:
*
* [The behaviors and guarantees described below do not apply to virtual
@@ -605,6 +607,10 @@ EXPORT_SYMBOL_GPL(usb_unlink_urb);
* with error -EPERM. Thus even if the URB's completion handler always
* tries to resubmit, it will not succeed and the URB will become idle.
*
+ * The URB must not be deallocated while this routine is running. In
+ * particular, when a driver calls this routine, it must insure that the
+ * completion handler cannot deallocate the URB.
+ *
* This routine may not be used in an interrupt context (such as a bottom
* half or a completion handler), or when holding a spinlock, or in other
* situations where the caller can't schedule().
@@ -642,6 +648,10 @@ EXPORT_SYMBOL_GPL(usb_kill_urb);
* with error -EPERM. Thus even if the URB's completion handler always
* tries to resubmit, it will not succeed and the URB will become idle.
*
+ * The URB must not be deallocated while this routine is running. In
+ * particular, when a driver calls this routine, it must insure that the
+ * completion handler cannot deallocate the URB.
+ *
* This routine may not be used in an interrupt context (such as a bottom
* half or a completion handler), or when holding a spinlock, or in other
* situations where the caller can't schedule().
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 8ca9f994a280..c74ba7bbc748 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -274,7 +274,7 @@ static int usb_dev_prepare(struct device *dev)
static void usb_dev_complete(struct device *dev)
{
/* Currently used only for rebinding interfaces */
- usb_resume(dev, PMSG_ON); /* FIXME: change to PMSG_COMPLETE */
+ usb_resume_complete(dev);
}
static int usb_dev_suspend(struct device *dev)
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index 45e8479c377d..71648dcbe438 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -56,6 +56,7 @@ extern void usb_major_cleanup(void);
extern int usb_suspend(struct device *dev, pm_message_t msg);
extern int usb_resume(struct device *dev, pm_message_t msg);
+extern int usb_resume_complete(struct device *dev);
extern int usb_port_suspend(struct usb_device *dev, pm_message_t msg);
extern int usb_port_resume(struct usb_device *dev, pm_message_t msg);
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index 900ae74357f1..d441fe4c180b 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -28,6 +28,19 @@ endif
obj-$(CONFIG_USB_DWC3) += dwc3-omap.o
+##
+# REVISIT Samsung Exynos platform needs the clk API which isn't
+# defined on all architectures. If we allow dwc3-exynos.c compile
+# always we will fail the linking phase on those architectures
+# which don't provide clk api implementation and that's unnaceptable.
+#
+# When Samsung's platform start supporting pm_runtime, this check
+# for HAVE_CLK should be removed.
+##
+ifneq ($(CONFIG_HAVE_CLK),)
+ obj-$(CONFIG_USB_DWC3) += dwc3-exynos.o
+endif
+
ifneq ($(CONFIG_PCI),)
obj-$(CONFIG_USB_DWC3) += dwc3-pci.o
endif
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 7c9df630dbe4..99b58d84553a 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -48,10 +48,10 @@
#include <linux/list.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
+#include <linux/of.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
-#include <linux/module.h>
#include "core.h"
#include "gadget.h"
@@ -86,7 +86,7 @@ again:
id = -ENOMEM;
}
- return 0;
+ return id;
}
EXPORT_SYMBOL_GPL(dwc3_get_device_id);
@@ -167,11 +167,11 @@ static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
}
/**
- * dwc3_alloc_one_event_buffer - Allocated one event buffer structure
+ * dwc3_alloc_one_event_buffer - Allocates one event buffer structure
* @dwc: Pointer to our controller context structure
* @length: size of the event buffer
*
- * Returns a pointer to the allocated event buffer structure on succes
+ * Returns a pointer to the allocated event buffer structure on success
* otherwise ERR_PTR(errno).
*/
static struct dwc3_event_buffer *__devinit
@@ -206,19 +206,19 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)
for (i = 0; i < dwc->num_event_buffers; i++) {
evt = dwc->ev_buffs[i];
- if (evt) {
+ if (evt)
dwc3_free_one_event_buffer(dwc, evt);
- dwc->ev_buffs[i] = NULL;
- }
}
+
+ kfree(dwc->ev_buffs);
}
/**
* dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
- * @dwc: Pointer to out controller context structure
+ * @dwc: pointer to our controller context structure
* @length: size of event buffer
*
- * Returns 0 on success otherwise negative errno. In error the case, dwc
+ * Returns 0 on success otherwise negative errno. In the error 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)
@@ -251,7 +251,7 @@ static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned length)
/**
* dwc3_event_buffers_setup - setup our allocated event buffers
- * @dwc: Pointer to out controller context structure
+ * @dwc: pointer to our controller context structure
*
* Returns 0 on success otherwise negative errno.
*/
@@ -350,7 +350,7 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
dwc3_cache_hwparams(dwc);
reg = dwc3_readl(dwc->regs, DWC3_GCTL);
- reg &= ~DWC3_GCTL_SCALEDOWN(3);
+ reg &= ~DWC3_GCTL_SCALEDOWN_MASK;
reg &= ~DWC3_GCTL_DISSCRAMBLE;
switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams1)) {
@@ -363,9 +363,9 @@ static int __devinit dwc3_core_init(struct dwc3 *dwc)
/*
* WORKAROUND: DWC3 revisions <1.90a have a bug
- * when The device fails to connect at SuperSpeed
+ * where the device can fail to connect at SuperSpeed
* and falls back to high-speed mode which causes
- * the device to enter in a Connect/Disconnect loop
+ * the device to enter a Connect/Disconnect loop
*/
if (dwc->revision < DWC3_REVISION_190A)
reg |= DWC3_GCTL_U2RSTECN;
@@ -404,8 +404,10 @@ static void dwc3_core_exit(struct dwc3 *dwc)
static int __devinit dwc3_probe(struct platform_device *pdev)
{
+ struct device_node *node = pdev->dev.of_node;
struct resource *res;
struct dwc3 *dwc;
+ struct device *dev = &pdev->dev;
int ret = -ENOMEM;
int irq;
@@ -415,39 +417,39 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
u8 mode;
- mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
+ mem = devm_kzalloc(dev, sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
if (!mem) {
- dev_err(&pdev->dev, "not enough memory\n");
- goto err0;
+ dev_err(dev, "not enough memory\n");
+ return -ENOMEM;
}
dwc = PTR_ALIGN(mem, DWC3_ALIGN_MASK + 1);
dwc->mem = mem;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
- dev_err(&pdev->dev, "missing resource\n");
- goto err1;
+ dev_err(dev, "missing resource\n");
+ return -ENODEV;
}
dwc->res = res;
- res = request_mem_region(res->start, resource_size(res),
- dev_name(&pdev->dev));
+ res = devm_request_mem_region(dev, res->start, resource_size(res),
+ dev_name(dev));
if (!res) {
- dev_err(&pdev->dev, "can't request mem region\n");
- goto err1;
+ dev_err(dev, "can't request mem region\n");
+ return -ENOMEM;
}
- regs = ioremap(res->start, resource_size(res));
+ regs = devm_ioremap(dev, res->start, resource_size(res));
if (!regs) {
- dev_err(&pdev->dev, "ioremap failed\n");
- goto err2;
+ dev_err(dev, "ioremap failed\n");
+ return -ENOMEM;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
- dev_err(&pdev->dev, "missing IRQ\n");
- goto err3;
+ dev_err(dev, "missing IRQ\n");
+ return -ENODEV;
}
spin_lock_init(&dwc->lock);
@@ -455,7 +457,7 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
dwc->regs = regs;
dwc->regs_size = resource_size(res);
- dwc->dev = &pdev->dev;
+ dwc->dev = dev;
dwc->irq = irq;
if (!strncmp("super", maximum_speed, 5))
@@ -469,14 +471,17 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
else
dwc->maximum_speed = DWC3_DCFG_SUPERSPEED;
- pm_runtime_enable(&pdev->dev);
- pm_runtime_get_sync(&pdev->dev);
- pm_runtime_forbid(&pdev->dev);
+ if (of_get_property(node, "tx-fifo-resize", NULL))
+ dwc->needs_fifo_resize = true;
+
+ pm_runtime_enable(dev);
+ pm_runtime_get_sync(dev);
+ pm_runtime_forbid(dev);
ret = dwc3_core_init(dwc);
if (ret) {
- dev_err(&pdev->dev, "failed to initialize core\n");
- goto err3;
+ dev_err(dev, "failed to initialize core\n");
+ return ret;
}
mode = DWC3_MODE(dwc->hwparams.hwparams0);
@@ -486,49 +491,49 @@ static int __devinit dwc3_probe(struct platform_device *pdev)
dwc3_set_mode(dwc, DWC3_GCTL_PRTCAP_DEVICE);
ret = dwc3_gadget_init(dwc);
if (ret) {
- dev_err(&pdev->dev, "failed to initialize gadget\n");
- goto err4;
+ dev_err(dev, "failed to initialize gadget\n");
+ goto err1;
}
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;
+ dev_err(dev, "failed to initialize host\n");
+ goto err1;
}
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;
+ dev_err(dev, "failed to initialize host\n");
+ goto err1;
}
ret = dwc3_gadget_init(dwc);
if (ret) {
- dev_err(&pdev->dev, "failed to initialize gadget\n");
- goto err4;
+ dev_err(dev, "failed to initialize gadget\n");
+ goto err1;
}
break;
default:
- dev_err(&pdev->dev, "Unsupported mode of operation %d\n", mode);
- goto err4;
+ dev_err(dev, "Unsupported mode of operation %d\n", mode);
+ goto err1;
}
dwc->mode = mode;
ret = dwc3_debugfs_init(dwc);
if (ret) {
- dev_err(&pdev->dev, "failed to initialize debugfs\n");
- goto err5;
+ dev_err(dev, "failed to initialize debugfs\n");
+ goto err2;
}
- pm_runtime_allow(&pdev->dev);
+ pm_runtime_allow(dev);
return 0;
-err5:
+err2:
switch (mode) {
case DWC3_MODE_DEVICE:
dwc3_gadget_exit(dwc);
@@ -545,19 +550,9 @@ err5:
break;
}
-err4:
- dwc3_core_exit(dwc);
-
-err3:
- iounmap(regs);
-
-err2:
- release_mem_region(res->start, resource_size(res));
-
err1:
- kfree(dwc->mem);
+ dwc3_core_exit(dwc);
-err0:
return ret;
}
@@ -590,9 +585,6 @@ static int __devexit dwc3_remove(struct platform_device *pdev)
}
dwc3_core_exit(dwc);
- release_mem_region(res->start, resource_size(res));
- iounmap(dwc->regs);
- kfree(dwc->mem);
return 0;
}
@@ -605,19 +597,9 @@ static struct platform_driver dwc3_driver = {
},
};
+module_platform_driver(dwc3_driver);
+
MODULE_ALIAS("platform:dwc3");
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("DesignWare USB3 DRD Controller Driver");
-
-static int __devinit dwc3_init(void)
-{
- return platform_driver_register(&dwc3_driver);
-}
-module_init(dwc3_init);
-
-static void __exit dwc3_exit(void)
-{
- platform_driver_unregister(&dwc3_driver);
-}
-module_exit(dwc3_exit);
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 9e57f8e9bf17..6c7945b4cad3 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -145,22 +145,23 @@
/* Bit fields */
/* Global Configuration Register */
-#define DWC3_GCTL_PWRDNSCALE(n) (n << 19)
+#define DWC3_GCTL_PWRDNSCALE(n) ((n) << 19)
#define DWC3_GCTL_U2RSTECN (1 << 16)
-#define DWC3_GCTL_RAMCLKSEL(x) ((x & DWC3_GCTL_CLK_MASK) << 6)
+#define DWC3_GCTL_RAMCLKSEL(x) (((x) & DWC3_GCTL_CLK_MASK) << 6)
#define DWC3_GCTL_CLK_BUS (0)
#define DWC3_GCTL_CLK_PIPE (1)
#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_PRTCAPDIR(n) ((n) << 12)
#define DWC3_GCTL_PRTCAP_HOST 1
#define DWC3_GCTL_PRTCAP_DEVICE 2
#define DWC3_GCTL_PRTCAP_OTG 3
#define DWC3_GCTL_CORESOFTRESET (1 << 11)
-#define DWC3_GCTL_SCALEDOWN(n) (n << 4)
+#define DWC3_GCTL_SCALEDOWN(n) ((n) << 4)
+#define DWC3_GCTL_SCALEDOWN_MASK DWC3_GCTL_SCALEDOWN(3)
#define DWC3_GCTL_DISSCRAMBLE (1 << 3)
#define DWC3_GCTL_DSBLCLKGTNG (1 << 0)
@@ -172,8 +173,12 @@
#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
+/* Global TX Fifo Size Register */
+#define DWC3_GTXFIFOSIZ_TXFDEF(n) ((n) & 0xffff)
+#define DWC3_GTXFIFOSIZ_TXFSTADDR(n) ((n) & 0xffff0000)
+
/* Global HWPARAMS1 Register */
-#define DWC3_GHWPARAMS1_EN_PWROPT(n) ((n & (3 << 24)) >> 24)
+#define DWC3_GHWPARAMS1_EN_PWROPT(n) (((n) & (3 << 24)) >> 24)
#define DWC3_GHWPARAMS1_EN_PWROPT_NO 0
#define DWC3_GHWPARAMS1_EN_PWROPT_CLK 1
@@ -198,6 +203,15 @@
#define DWC3_DCTL_APPL1RES (1 << 23)
+#define DWC3_DCTL_TRGTULST_MASK (0x0f << 17)
+#define DWC3_DCTL_TRGTULST(n) ((n) << 17)
+
+#define DWC3_DCTL_TRGTULST_U2 (DWC3_DCTL_TRGTULST(2))
+#define DWC3_DCTL_TRGTULST_U3 (DWC3_DCTL_TRGTULST(3))
+#define DWC3_DCTL_TRGTULST_SS_DIS (DWC3_DCTL_TRGTULST(4))
+#define DWC3_DCTL_TRGTULST_RX_DET (DWC3_DCTL_TRGTULST(5))
+#define DWC3_DCTL_TRGTULST_SS_INACT (DWC3_DCTL_TRGTULST(6))
+
#define DWC3_DCTL_INITU2ENA (1 << 12)
#define DWC3_DCTL_ACCEPTU2ENA (1 << 11)
#define DWC3_DCTL_INITU1ENA (1 << 10)
@@ -260,10 +274,10 @@
/* Device Endpoint Command Register */
#define DWC3_DEPCMD_PARAM_SHIFT 16
-#define DWC3_DEPCMD_PARAM(x) (x << DWC3_DEPCMD_PARAM_SHIFT)
-#define DWC3_DEPCMD_GET_RSC_IDX(x) ((x >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
+#define DWC3_DEPCMD_PARAM(x) ((x) << DWC3_DEPCMD_PARAM_SHIFT)
+#define DWC3_DEPCMD_GET_RSC_IDX(x) (((x) >> DWC3_DEPCMD_PARAM_SHIFT) & 0x7f)
#define DWC3_DEPCMD_STATUS_MASK (0x0f << 12)
-#define DWC3_DEPCMD_STATUS(x) ((x & DWC3_DEPCMD_STATUS_MASK) >> 12)
+#define DWC3_DEPCMD_STATUS(x) (((x) & DWC3_DEPCMD_STATUS_MASK) >> 12)
#define DWC3_DEPCMD_HIPRI_FORCERM (1 << 11)
#define DWC3_DEPCMD_CMDACT (1 << 10)
#define DWC3_DEPCMD_CMDIOC (1 << 8)
@@ -288,7 +302,7 @@
/* Structures */
-struct dwc3_trb_hw;
+struct dwc3_trb;
/**
* struct dwc3_event_buffer - Software event buffer representation
@@ -343,7 +357,7 @@ struct dwc3_ep {
struct list_head request_list;
struct list_head req_queued;
- struct dwc3_trb_hw *trb_pool;
+ struct dwc3_trb *trb_pool;
dma_addr_t trb_pool_dma;
u32 free_slot;
u32 busy_slot;
@@ -418,102 +432,49 @@ enum dwc3_device_state {
DWC3_CONFIGURED_STATE,
};
-/**
- * struct dwc3_trb - transfer request block
- * @bpl: lower 32bit of the buffer
- * @bph: higher 32bit of the buffer
- * @length: buffer size (up to 16mb - 1)
- * @pcm1: packet count m1
- * @trbsts: trb status
- * 0 = ok
- * 1 = missed isoc
- * 2 = setup pending
- * @hwo: hardware owner of descriptor
- * @lst: last trb
- * @chn: chain buffers
- * @csp: continue on short packets (only supported on isoc eps)
- * @trbctl: trb control
- * 1 = normal
- * 2 = control-setup
- * 3 = control-status-2
- * 4 = control-status-3
- * 5 = control-data (first trb of data stage)
- * 6 = isochronous-first (first trb of service interval)
- * 7 = isochronous
- * 8 = link trb
- * others = reserved
- * @isp_imi: interrupt on short packet / interrupt on missed isoc
- * @ioc: interrupt on complete
- * @sid_sofn: Stream ID / SOF Number
- */
-struct dwc3_trb {
- u64 bplh;
-
- union {
- struct {
- u32 length:24;
- u32 pcm1:2;
- u32 reserved27_26:2;
- u32 trbsts:4;
-#define DWC3_TRB_STS_OKAY 0
-#define DWC3_TRB_STS_MISSED_ISOC 1
-#define DWC3_TRB_STS_SETUP_PENDING 2
- };
- u32 len_pcm;
- };
-
- union {
- struct {
- u32 hwo:1;
- u32 lst:1;
- u32 chn:1;
- u32 csp:1;
- u32 trbctl:6;
- u32 isp_imi:1;
- u32 ioc:1;
- u32 reserved13_12:2;
- u32 sid_sofn:16;
- u32 reserved31_30:2;
- };
- u32 control;
- };
-} __packed;
+/* TRB Length, PCM and Status */
+#define DWC3_TRB_SIZE_MASK (0x00ffffff)
+#define DWC3_TRB_SIZE_LENGTH(n) ((n) & DWC3_TRB_SIZE_MASK)
+#define DWC3_TRB_SIZE_PCM1(n) (((n) & 0x03) << 24)
+#define DWC3_TRB_SIZE_TRBSTS(n) (((n) & (0x0f << 28) >> 28))
+
+#define DWC3_TRBSTS_OK 0
+#define DWC3_TRBSTS_MISSED_ISOC 1
+#define DWC3_TRBSTS_SETUP_PENDING 2
+
+/* TRB Control */
+#define DWC3_TRB_CTRL_HWO (1 << 0)
+#define DWC3_TRB_CTRL_LST (1 << 1)
+#define DWC3_TRB_CTRL_CHN (1 << 2)
+#define DWC3_TRB_CTRL_CSP (1 << 3)
+#define DWC3_TRB_CTRL_TRBCTL(n) (((n) & 0x3f) << 4)
+#define DWC3_TRB_CTRL_ISP_IMI (1 << 10)
+#define DWC3_TRB_CTRL_IOC (1 << 11)
+#define DWC3_TRB_CTRL_SID_SOFN(n) (((n) & 0xffff) << 14)
+
+#define DWC3_TRBCTL_NORMAL DWC3_TRB_CTRL_TRBCTL(1)
+#define DWC3_TRBCTL_CONTROL_SETUP DWC3_TRB_CTRL_TRBCTL(2)
+#define DWC3_TRBCTL_CONTROL_STATUS2 DWC3_TRB_CTRL_TRBCTL(3)
+#define DWC3_TRBCTL_CONTROL_STATUS3 DWC3_TRB_CTRL_TRBCTL(4)
+#define DWC3_TRBCTL_CONTROL_DATA DWC3_TRB_CTRL_TRBCTL(5)
+#define DWC3_TRBCTL_ISOCHRONOUS_FIRST DWC3_TRB_CTRL_TRBCTL(6)
+#define DWC3_TRBCTL_ISOCHRONOUS DWC3_TRB_CTRL_TRBCTL(7)
+#define DWC3_TRBCTL_LINK_TRB DWC3_TRB_CTRL_TRBCTL(8)
/**
- * struct dwc3_trb_hw - transfer request block (hw format)
+ * struct dwc3_trb - transfer request block (hw format)
* @bpl: DW0-3
* @bph: DW4-7
* @size: DW8-B
* @trl: DWC-F
*/
-struct dwc3_trb_hw {
- __le32 bpl;
- __le32 bph;
- __le32 size;
- __le32 ctrl;
+struct dwc3_trb {
+ u32 bpl;
+ u32 bph;
+ u32 size;
+ u32 ctrl;
} __packed;
-static inline void dwc3_trb_to_hw(struct dwc3_trb *nat, struct dwc3_trb_hw *hw)
-{
- hw->bpl = cpu_to_le32(lower_32_bits(nat->bplh));
- hw->bph = cpu_to_le32(upper_32_bits(nat->bplh));
- hw->size = cpu_to_le32p(&nat->len_pcm);
- /* HWO is written last */
- hw->ctrl = cpu_to_le32p(&nat->control);
-}
-
-static inline void dwc3_trb_to_nat(struct dwc3_trb_hw *hw, struct dwc3_trb *nat)
-{
- u64 bplh;
-
- bplh = le32_to_cpup(&hw->bpl);
- bplh |= (u64) le32_to_cpup(&hw->bph) << 32;
- nat->bplh = bplh;
-
- nat->len_pcm = le32_to_cpup(&hw->size);
- nat->control = le32_to_cpup(&hw->ctrl);
-}
-
/**
* dwc3_hwparams - copy of HWPARAMS registers
* @hwparams0 - GHWPARAMS0
@@ -546,8 +507,13 @@ struct dwc3_hwparams {
#define DWC3_MODE_DRD 2
#define DWC3_MODE_HUB 3
+#define DWC3_MDWIDTH(n) (((n) & 0xff00) >> 8)
+
/* HWPARAMS1 */
-#define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15)
+#define DWC3_NUM_INT(n) (((n) & (0x3f << 15)) >> 15)
+
+/* HWPARAMS7 */
+#define DWC3_RAM1_DEPTH(n) ((n) & 0xffff)
struct dwc3_request {
struct usb_request request;
@@ -555,7 +521,7 @@ struct dwc3_request {
struct dwc3_ep *dep;
u8 epnum;
- struct dwc3_trb_hw *trb;
+ struct dwc3_trb *trb;
dma_addr_t trb_dma;
unsigned direction:1;
@@ -572,7 +538,6 @@ struct dwc3_request {
* @ctrl_req_addr: dma address of ctrl_req
* @ep0_trb: dma address of ep0_trb
* @ep0_usb_req: dummy req used while handling STD USB requests
- * @setup_buf_addr: dma address of setup_buf
* @ep0_bounce_addr: dma address of ep0_bounce
* @lock: for synchronizing
* @dev: pointer to our struct device
@@ -594,6 +559,8 @@ struct dwc3_request {
* @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
+ * @needs_fifo_resize: not all users might want fifo resizing, flag it
+ * @resize_fifos: tells us it's ok to reconfigure our TxFIFO sizes.
* @ep0_next_event: hold the next expected event
* @ep0state: state of endpoint zero
* @link_state: link state
@@ -604,12 +571,11 @@ struct dwc3_request {
*/
struct dwc3 {
struct usb_ctrlrequest *ctrl_req;
- struct dwc3_trb_hw *ep0_trb;
+ struct dwc3_trb *ep0_trb;
void *ep0_bounce;
u8 *setup_buf;
dma_addr_t ctrl_req_addr;
dma_addr_t ep0_trb_addr;
- dma_addr_t setup_buf_addr;
dma_addr_t ep0_bounce_addr;
struct dwc3_request ep0_usb_req;
/* device lock */
@@ -651,6 +617,8 @@ struct dwc3 {
unsigned start_config_issued:1;
unsigned setup_packet_pending:1;
unsigned delayed_status:1;
+ unsigned needs_fifo_resize:1;
+ unsigned resize_fifos:1;
enum dwc3_ep0_next ep0_next_event;
enum dwc3_ep0_state ep0state;
@@ -662,23 +630,13 @@ struct dwc3 {
struct dwc3_hwparams hwparams;
struct dentry *root;
+
+ u8 test_mode;
+ u8 test_mode_nr;
};
/* -------------------------------------------------------------------------- */
-#define DWC3_TRBSTS_OK 0
-#define DWC3_TRBSTS_MISSED_ISOC 1
-#define DWC3_TRBSTS_SETUP_PENDING 2
-
-#define DWC3_TRBCTL_NORMAL 1
-#define DWC3_TRBCTL_CONTROL_SETUP 2
-#define DWC3_TRBCTL_CONTROL_STATUS2 3
-#define DWC3_TRBCTL_CONTROL_STATUS3 4
-#define DWC3_TRBCTL_CONTROL_DATA 5
-#define DWC3_TRBCTL_ISOCHRONOUS_FIRST 6
-#define DWC3_TRBCTL_ISOCHRONOUS 7
-#define DWC3_TRBCTL_LINK_TRB 8
-
/* -------------------------------------------------------------------------- */
struct dwc3_event_type {
@@ -719,9 +677,14 @@ struct dwc3_event_depevt {
u32 endpoint_event:4;
u32 reserved11_10:2;
u32 status:4;
-#define DEPEVT_STATUS_BUSERR (1 << 0)
-#define DEPEVT_STATUS_SHORT (1 << 1)
-#define DEPEVT_STATUS_IOC (1 << 2)
+
+/* Within XferNotReady */
+#define DEPEVT_STATUS_TRANSFER_ACTIVE (1 << 3)
+
+/* Within XferComplete */
+#define DEPEVT_STATUS_BUSERR (1 << 0)
+#define DEPEVT_STATUS_SHORT (1 << 1)
+#define DEPEVT_STATUS_IOC (1 << 2)
#define DEPEVT_STATUS_LST (1 << 3)
/* Stream event only */
@@ -807,6 +770,7 @@ union dwc3_event {
/* prototypes */
void dwc3_set_mode(struct dwc3 *dwc, u32 mode);
+int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc);
int dwc3_host_init(struct dwc3 *dwc);
void dwc3_host_exit(struct dwc3 *dwc);
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index 433c97c15fc5..d4a30f118724 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -46,6 +46,8 @@
#include <linux/delay.h>
#include <linux/uaccess.h>
+#include <linux/usb/ch9.h>
+
#include "core.h"
#include "gadget.h"
#include "io.h"
@@ -464,6 +466,192 @@ static const struct file_operations dwc3_mode_fops = {
.release = single_release,
};
+static int dwc3_testmode_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_DCTL);
+ reg &= DWC3_DCTL_TSTCTRL_MASK;
+ reg >>= 1;
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ switch (reg) {
+ case 0:
+ seq_printf(s, "no test\n");
+ break;
+ case TEST_J:
+ seq_printf(s, "test_j\n");
+ break;
+ case TEST_K:
+ seq_printf(s, "test_k\n");
+ break;
+ case TEST_SE0_NAK:
+ seq_printf(s, "test_se0_nak\n");
+ break;
+ case TEST_PACKET:
+ seq_printf(s, "test_packet\n");
+ break;
+ case TEST_FORCE_EN:
+ seq_printf(s, "test_force_enable\n");
+ break;
+ default:
+ seq_printf(s, "UNKNOWN %d\n", reg);
+ }
+
+ return 0;
+}
+
+static int dwc3_testmode_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dwc3_testmode_show, inode->i_private);
+}
+
+static ssize_t dwc3_testmode_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 testmode = 0;
+ char buf[32];
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ if (!strncmp(buf, "test_j", 6))
+ testmode = TEST_J;
+ else if (!strncmp(buf, "test_k", 6))
+ testmode = TEST_K;
+ else if (!strncmp(buf, "test_se0_nak", 12))
+ testmode = TEST_SE0_NAK;
+ else if (!strncmp(buf, "test_packet", 11))
+ testmode = TEST_PACKET;
+ else if (!strncmp(buf, "test_force_enable", 17))
+ testmode = TEST_FORCE_EN;
+ else
+ testmode = 0;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ dwc3_gadget_set_test_mode(dwc, testmode);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return count;
+}
+
+static const struct file_operations dwc3_testmode_fops = {
+ .open = dwc3_testmode_open,
+ .write = dwc3_testmode_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int dwc3_link_state_show(struct seq_file *s, void *unused)
+{
+ struct dwc3 *dwc = s->private;
+ unsigned long flags;
+ enum dwc3_link_state state;
+ u32 reg;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+ state = DWC3_DSTS_USBLNKST(reg);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ switch (state) {
+ case DWC3_LINK_STATE_U0:
+ seq_printf(s, "U0\n");
+ break;
+ case DWC3_LINK_STATE_U1:
+ seq_printf(s, "U1\n");
+ break;
+ case DWC3_LINK_STATE_U2:
+ seq_printf(s, "U2\n");
+ break;
+ case DWC3_LINK_STATE_U3:
+ seq_printf(s, "U3\n");
+ break;
+ case DWC3_LINK_STATE_SS_DIS:
+ seq_printf(s, "SS.Disabled\n");
+ break;
+ case DWC3_LINK_STATE_RX_DET:
+ seq_printf(s, "Rx.Detect\n");
+ break;
+ case DWC3_LINK_STATE_SS_INACT:
+ seq_printf(s, "SS.Inactive\n");
+ break;
+ case DWC3_LINK_STATE_POLL:
+ seq_printf(s, "Poll\n");
+ break;
+ case DWC3_LINK_STATE_RECOV:
+ seq_printf(s, "Recovery\n");
+ break;
+ case DWC3_LINK_STATE_HRESET:
+ seq_printf(s, "HRESET\n");
+ break;
+ case DWC3_LINK_STATE_CMPLY:
+ seq_printf(s, "Compliance\n");
+ break;
+ case DWC3_LINK_STATE_LPBK:
+ seq_printf(s, "Loopback\n");
+ break;
+ default:
+ seq_printf(s, "UNKNOWN %d\n", reg);
+ }
+
+ return 0;
+}
+
+static int dwc3_link_state_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, dwc3_link_state_show, inode->i_private);
+}
+
+static ssize_t dwc3_link_state_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;
+ enum dwc3_link_state state = 0;
+ char buf[32];
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ if (!strncmp(buf, "SS.Disabled", 11))
+ state = DWC3_LINK_STATE_SS_DIS;
+ else if (!strncmp(buf, "Rx.Detect", 9))
+ state = DWC3_LINK_STATE_RX_DET;
+ else if (!strncmp(buf, "SS.Inactive", 11))
+ state = DWC3_LINK_STATE_SS_INACT;
+ else if (!strncmp(buf, "Recovery", 8))
+ state = DWC3_LINK_STATE_RECOV;
+ else if (!strncmp(buf, "Compliance", 10))
+ state = DWC3_LINK_STATE_CMPLY;
+ else if (!strncmp(buf, "Loopback", 8))
+ state = DWC3_LINK_STATE_LPBK;
+ else
+ return -EINVAL;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ dwc3_gadget_set_link_state(dwc, state);
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return count;
+}
+
+static const struct file_operations dwc3_link_state_fops = {
+ .open = dwc3_link_state_open,
+ .write = dwc3_link_state_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
{
struct dentry *root;
@@ -471,8 +659,8 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
int ret;
root = debugfs_create_dir(dev_name(dwc->dev), NULL);
- if (IS_ERR(root)) {
- ret = PTR_ERR(root);
+ if (!root) {
+ ret = -ENOMEM;
goto err0;
}
@@ -480,15 +668,29 @@ int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
file = debugfs_create_file("regdump", S_IRUGO, root, dwc,
&dwc3_regdump_fops);
- if (IS_ERR(file)) {
- ret = PTR_ERR(file);
+ if (!file) {
+ ret = -ENOMEM;
goto err1;
}
file = debugfs_create_file("mode", S_IRUGO | S_IWUSR, root,
dwc, &dwc3_mode_fops);
- if (IS_ERR(file)) {
- ret = PTR_ERR(file);
+ if (!file) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR, root,
+ dwc, &dwc3_testmode_fops);
+ if (!file) {
+ ret = -ENOMEM;
+ goto err1;
+ }
+
+ file = debugfs_create_file("link_state", S_IRUGO | S_IWUSR, root,
+ dwc, &dwc3_link_state_fops);
+ if (!file) {
+ ret = -ENOMEM;
goto err1;
}
diff --git a/drivers/usb/dwc3/dwc3-exynos.c b/drivers/usb/dwc3/dwc3-exynos.c
new file mode 100644
index 000000000000..d19030198086
--- /dev/null
+++ b/drivers/usb/dwc3/dwc3-exynos.c
@@ -0,0 +1,151 @@
+/**
+ * dwc3-exynos.c - Samsung EXYNOS DWC3 Specific Glue layer
+ *
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Anton Tikhomirov <av.tikhomirov@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/dwc3-exynos.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+
+#include "core.h"
+
+struct dwc3_exynos {
+ struct platform_device *dwc3;
+ struct device *dev;
+
+ struct clk *clk;
+};
+
+static int __devinit dwc3_exynos_probe(struct platform_device *pdev)
+{
+ struct dwc3_exynos_data *pdata = pdev->dev.platform_data;
+ struct platform_device *dwc3;
+ struct dwc3_exynos *exynos;
+ struct clk *clk;
+
+ int devid;
+ int ret = -ENOMEM;
+
+ exynos = kzalloc(sizeof(*exynos), GFP_KERNEL);
+ if (!exynos) {
+ dev_err(&pdev->dev, "not enough memory\n");
+ goto err0;
+ }
+
+ platform_set_drvdata(pdev, exynos);
+
+ devid = dwc3_get_device_id();
+ if (devid < 0)
+ goto err1;
+
+ dwc3 = platform_device_alloc("dwc3", devid);
+ if (!dwc3) {
+ dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
+ goto err2;
+ }
+
+ clk = clk_get(&pdev->dev, "usbdrd30");
+ if (IS_ERR(clk)) {
+ dev_err(&pdev->dev, "couldn't get clock\n");
+ ret = -EINVAL;
+ goto err3;
+ }
+
+ dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
+
+ dwc3->dev.parent = &pdev->dev;
+ dwc3->dev.dma_mask = pdev->dev.dma_mask;
+ dwc3->dev.dma_parms = pdev->dev.dma_parms;
+ exynos->dwc3 = dwc3;
+ exynos->dev = &pdev->dev;
+ exynos->clk = clk;
+
+ clk_enable(exynos->clk);
+
+ /* PHY initialization */
+ if (!pdata) {
+ dev_dbg(&pdev->dev, "missing platform data\n");
+ } else {
+ if (pdata->phy_init)
+ pdata->phy_init(pdev, pdata->phy_type);
+ }
+
+ ret = platform_device_add_resources(dwc3, pdev->resource,
+ pdev->num_resources);
+ if (ret) {
+ dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
+ goto err4;
+ }
+
+ ret = platform_device_add(dwc3);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to register dwc3 device\n");
+ goto err4;
+ }
+
+ return 0;
+
+err4:
+ if (pdata && pdata->phy_exit)
+ pdata->phy_exit(pdev, pdata->phy_type);
+
+ clk_disable(clk);
+ clk_put(clk);
+err3:
+ platform_device_put(dwc3);
+err2:
+ dwc3_put_device_id(devid);
+err1:
+ kfree(exynos);
+err0:
+ return ret;
+}
+
+static int __devexit dwc3_exynos_remove(struct platform_device *pdev)
+{
+ struct dwc3_exynos *exynos = platform_get_drvdata(pdev);
+ struct dwc3_exynos_data *pdata = pdev->dev.platform_data;
+
+ platform_device_unregister(exynos->dwc3);
+
+ dwc3_put_device_id(exynos->dwc3->id);
+
+ if (pdata && pdata->phy_exit)
+ pdata->phy_exit(pdev, pdata->phy_type);
+
+ clk_disable(exynos->clk);
+ clk_put(exynos->clk);
+
+ kfree(exynos);
+
+ return 0;
+}
+
+static struct platform_driver dwc3_exynos_driver = {
+ .probe = dwc3_exynos_probe,
+ .remove = __devexit_p(dwc3_exynos_remove),
+ .driver = {
+ .name = "exynos-dwc3",
+ },
+};
+
+module_platform_driver(dwc3_exynos_driver);
+
+MODULE_ALIAS("platform:exynos-dwc3");
+MODULE_AUTHOR("Anton Tikhomirov <av.tikhomirov@samsung.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("DesignWare USB3 EXYNOS Glue Layer");
diff --git a/drivers/usb/dwc3/dwc3-omap.c b/drivers/usb/dwc3/dwc3-omap.c
index 3274ac8f1200..d7d9c0ec9515 100644
--- a/drivers/usb/dwc3/dwc3-omap.c
+++ b/drivers/usb/dwc3/dwc3-omap.c
@@ -46,7 +46,7 @@
#include <linux/dma-mapping.h>
#include <linux/ioport.h>
#include <linux/io.h>
-#include <linux/module.h>
+#include <linux/of.h>
#include "core.h"
#include "io.h"
@@ -197,91 +197,99 @@ static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
static int __devinit dwc3_omap_probe(struct platform_device *pdev)
{
struct dwc3_omap_data *pdata = pdev->dev.platform_data;
+ struct device_node *node = pdev->dev.of_node;
+
struct platform_device *dwc3;
struct dwc3_omap *omap;
struct resource *res;
+ struct device *dev = &pdev->dev;
int devid;
+ int size;
int ret = -ENOMEM;
int irq;
+ const u32 *utmi_mode;
u32 reg;
void __iomem *base;
void *context;
- omap = kzalloc(sizeof(*omap), GFP_KERNEL);
+ omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL);
if (!omap) {
- dev_err(&pdev->dev, "not enough memory\n");
- goto err0;
+ dev_err(dev, "not enough memory\n");
+ return -ENOMEM;
}
platform_set_drvdata(pdev, omap);
irq = platform_get_irq(pdev, 1);
if (irq < 0) {
- dev_err(&pdev->dev, "missing IRQ resource\n");
- ret = -EINVAL;
- goto err1;
+ dev_err(dev, "missing IRQ resource\n");
+ return -EINVAL;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
if (!res) {
- dev_err(&pdev->dev, "missing memory base resource\n");
- ret = -EINVAL;
- goto err1;
+ dev_err(dev, "missing memory base resource\n");
+ return -EINVAL;
}
- base = ioremap_nocache(res->start, resource_size(res));
+ base = devm_ioremap_nocache(dev, res->start, resource_size(res));
if (!base) {
- dev_err(&pdev->dev, "ioremap failed\n");
- goto err1;
+ dev_err(dev, "ioremap failed\n");
+ return -ENOMEM;
}
devid = dwc3_get_device_id();
if (devid < 0)
- goto err2;
+ return -ENODEV;
dwc3 = platform_device_alloc("dwc3", devid);
if (!dwc3) {
- dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
- goto err3;
+ dev_err(dev, "couldn't allocate dwc3 device\n");
+ goto err1;
}
- context = kzalloc(resource_size(res), GFP_KERNEL);
+ context = devm_kzalloc(dev, resource_size(res), GFP_KERNEL);
if (!context) {
- dev_err(&pdev->dev, "couldn't allocate dwc3 context memory\n");
- goto err4;
+ dev_err(dev, "couldn't allocate dwc3 context memory\n");
+ goto err2;
}
spin_lock_init(&omap->lock);
- dma_set_coherent_mask(&dwc3->dev, pdev->dev.coherent_dma_mask);
+ dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
- dwc3->dev.parent = &pdev->dev;
- dwc3->dev.dma_mask = pdev->dev.dma_mask;
- dwc3->dev.dma_parms = pdev->dev.dma_parms;
+ dwc3->dev.parent = dev;
+ dwc3->dev.dma_mask = dev->dma_mask;
+ dwc3->dev.dma_parms = dev->dma_parms;
omap->resource_size = resource_size(res);
omap->context = context;
- omap->dev = &pdev->dev;
+ omap->dev = dev;
omap->irq = irq;
omap->base = base;
omap->dwc3 = dwc3;
reg = dwc3_readl(omap->base, USBOTGSS_UTMI_OTG_STATUS);
- if (!pdata) {
- dev_dbg(&pdev->dev, "missing platform data\n");
+ utmi_mode = of_get_property(node, "utmi-mode", &size);
+ if (utmi_mode && size == sizeof(*utmi_mode)) {
+ reg |= *utmi_mode;
} else {
- switch (pdata->utmi_mode) {
- case DWC3_OMAP_UTMI_MODE_SW:
- reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
- break;
- case DWC3_OMAP_UTMI_MODE_HW:
- reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
- break;
- default:
- dev_dbg(&pdev->dev, "UNKNOWN utmi mode %d\n",
- pdata->utmi_mode);
+ if (!pdata) {
+ dev_dbg(dev, "missing platform data\n");
+ } else {
+ switch (pdata->utmi_mode) {
+ case DWC3_OMAP_UTMI_MODE_SW:
+ reg |= USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+ break;
+ case DWC3_OMAP_UTMI_MODE_HW:
+ reg &= ~USBOTGSS_UTMI_OTG_STATUS_SW_MODE;
+ break;
+ default:
+ dev_dbg(dev, "UNKNOWN utmi mode %d\n",
+ pdata->utmi_mode);
+ }
}
}
@@ -300,12 +308,12 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
- ret = request_irq(omap->irq, dwc3_omap_interrupt, 0,
+ ret = devm_request_irq(dev, omap->irq, dwc3_omap_interrupt, 0,
"dwc3-omap", omap);
if (ret) {
- dev_err(&pdev->dev, "failed to request IRQ #%d --> %d\n",
+ dev_err(dev, "failed to request IRQ #%d --> %d\n",
omap->irq, ret);
- goto err5;
+ goto err2;
}
/* enable all IRQs */
@@ -327,37 +335,24 @@ static int __devinit dwc3_omap_probe(struct platform_device *pdev)
ret = platform_device_add_resources(dwc3, pdev->resource,
pdev->num_resources);
if (ret) {
- dev_err(&pdev->dev, "couldn't add resources to dwc3 device\n");
- goto err6;
+ dev_err(dev, "couldn't add resources to dwc3 device\n");
+ goto err2;
}
ret = platform_device_add(dwc3);
if (ret) {
- dev_err(&pdev->dev, "failed to register dwc3 device\n");
- goto err6;
+ dev_err(dev, "failed to register dwc3 device\n");
+ goto err2;
}
return 0;
-err6:
- free_irq(omap->irq, omap);
-
-err5:
- kfree(omap->context);
-
-err4:
- platform_device_put(dwc3);
-
-err3:
- dwc3_put_device_id(devid);
-
err2:
- iounmap(base);
+ platform_device_put(dwc3);
err1:
- kfree(omap);
+ dwc3_put_device_id(devid);
-err0:
return ret;
}
@@ -368,11 +363,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);
-
- kfree(omap->context);
- kfree(omap);
return 0;
}
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index 64e1f7c67b08..a9ca9adba391 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -61,32 +61,36 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,
struct dwc3_pci *glue;
int ret = -ENOMEM;
int devid;
+ struct device *dev = &pci->dev;
- glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+ glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
if (!glue) {
- dev_err(&pci->dev, "not enough memory\n");
- goto err0;
+ dev_err(dev, "not enough memory\n");
+ return -ENOMEM;
}
- glue->dev = &pci->dev;
+ glue->dev = dev;
ret = pci_enable_device(pci);
if (ret) {
- dev_err(&pci->dev, "failed to enable pci device\n");
- goto err1;
+ dev_err(dev, "failed to enable pci device\n");
+ return -ENODEV;
}
pci_set_power_state(pci, PCI_D0);
pci_set_master(pci);
devid = dwc3_get_device_id();
- if (devid < 0)
- goto err2;
+ if (devid < 0) {
+ ret = -ENOMEM;
+ goto err1;
+ }
dwc3 = platform_device_alloc("dwc3", devid);
if (!dwc3) {
- dev_err(&pci->dev, "couldn't allocate dwc3 device\n");
- goto err3;
+ dev_err(dev, "couldn't allocate dwc3 device\n");
+ ret = -ENOMEM;
+ goto err1;
}
memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
@@ -102,41 +106,37 @@ static int __devinit dwc3_pci_probe(struct pci_dev *pci,
ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
if (ret) {
- dev_err(&pci->dev, "couldn't add resources to dwc3 device\n");
- goto err4;
+ dev_err(dev, "couldn't add resources to dwc3 device\n");
+ goto err2;
}
pci_set_drvdata(pci, glue);
- dma_set_coherent_mask(&dwc3->dev, pci->dev.coherent_dma_mask);
+ dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
- dwc3->dev.dma_mask = pci->dev.dma_mask;
- dwc3->dev.dma_parms = pci->dev.dma_parms;
- dwc3->dev.parent = &pci->dev;
- glue->dwc3 = dwc3;
+ dwc3->dev.dma_mask = dev->dma_mask;
+ dwc3->dev.dma_parms = dev->dma_parms;
+ dwc3->dev.parent = dev;
+ glue->dwc3 = dwc3;
ret = platform_device_add(dwc3);
if (ret) {
- dev_err(&pci->dev, "failed to register dwc3 device\n");
- goto err4;
+ dev_err(dev, "failed to register dwc3 device\n");
+ goto err3;
}
return 0;
-err4:
+err3:
pci_set_drvdata(pci, NULL);
platform_device_put(dwc3);
-err3:
- dwc3_put_device_id(devid);
-
err2:
- pci_disable_device(pci);
+ dwc3_put_device_id(devid);
err1:
- kfree(glue);
+ pci_disable_device(pci);
-err0:
return ret;
}
@@ -148,7 +148,6 @@ static void __devexit dwc3_pci_remove(struct pci_dev *pci)
platform_device_unregister(glue->dwc3);
pci_set_drvdata(pci, NULL);
pci_disable_device(pci);
- kfree(glue);
}
static DEFINE_PCI_DEVICE_TABLE(dwc3_pci_id_table) = {
@@ -171,14 +170,4 @@ MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
MODULE_LICENSE("Dual BSD/GPL");
MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
-static int __devinit dwc3_pci_init(void)
-{
- return pci_register_driver(&dwc3_pci_driver);
-}
-module_init(dwc3_pci_init);
-
-static void __exit dwc3_pci_exit(void)
-{
- pci_unregister_driver(&dwc3_pci_driver);
-}
-module_exit(dwc3_pci_exit);
+module_pci_driver(dwc3_pci_driver);
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index c8df1dd967ef..3584a169886f 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -76,8 +76,7 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
u32 len, u32 type)
{
struct dwc3_gadget_ep_cmd_params params;
- struct dwc3_trb_hw *trb_hw;
- struct dwc3_trb trb;
+ struct dwc3_trb *trb;
struct dwc3_ep *dep;
int ret;
@@ -88,19 +87,17 @@ static int dwc3_ep0_start_trans(struct dwc3 *dwc, u8 epnum, dma_addr_t buf_dma,
return 0;
}
- trb_hw = dwc->ep0_trb;
- memset(&trb, 0, sizeof(trb));
+ trb = dwc->ep0_trb;
- trb.trbctl = type;
- trb.bplh = buf_dma;
- trb.length = len;
+ trb->bpl = lower_32_bits(buf_dma);
+ trb->bph = upper_32_bits(buf_dma);
+ trb->size = len;
+ trb->ctrl = type;
- trb.hwo = 1;
- trb.lst = 1;
- trb.ioc = 1;
- trb.isp_imi = 1;
-
- dwc3_trb_to_hw(&trb, trb_hw);
+ trb->ctrl |= (DWC3_TRB_CTRL_HWO
+ | DWC3_TRB_CTRL_LST
+ | DWC3_TRB_CTRL_IOC
+ | DWC3_TRB_CTRL_ISP_IMI);
memset(&params, 0, sizeof(params));
params.param0 = upper_32_bits(dwc->ep0_trb_addr);
@@ -302,7 +299,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
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.buf = dwc->setup_buf;
dwc->ep0_usb_req.request.complete = dwc3_ep0_status_cmpl;
return __dwc3_gadget_ep0_queue(dep, &dwc->ep0_usb_req);
@@ -315,9 +312,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
u32 recip;
u32 wValue;
u32 wIndex;
- u32 reg;
int ret;
- u32 mode;
wValue = le16_to_cpu(ctrl->wValue);
wIndex = le16_to_cpu(ctrl->wIndex);
@@ -356,22 +351,8 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
if (!set)
return -EINVAL;
- mode = wIndex >> 8;
- reg = dwc3_readl(dwc->regs, DWC3_DCTL);
- reg &= ~DWC3_DCTL_TSTCTRL_MASK;
-
- switch (mode) {
- case TEST_J:
- case TEST_K:
- case TEST_SE0_NAK:
- case TEST_PACKET:
- case TEST_FORCE_EN:
- reg |= mode << 1;
- break;
- default:
- return -EINVAL;
- }
- dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+ dwc->test_mode_nr = wIndex >> 8;
+ dwc->test_mode = true;
break;
default:
return -EINVAL;
@@ -396,7 +377,7 @@ static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
case USB_RECIP_ENDPOINT:
switch (wValue) {
case USB_ENDPOINT_HALT:
- dep = dwc3_wIndex_to_dep(dwc, wIndex);
+ dep = dwc3_wIndex_to_dep(dwc, wIndex);
if (!dep)
return -EINVAL;
ret = __dwc3_gadget_ep_set_halt(dep, set);
@@ -470,8 +451,11 @@ static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
case DWC3_ADDRESS_STATE:
ret = dwc3_ep0_delegate_req(dwc, ctrl);
/* if the cfg matches and the cfg is non zero */
- if (!ret && cfg)
+ if (cfg && (!ret || (ret == USB_GADGET_DELAYED_STATUS))) {
dwc->dev_state = DWC3_CONFIGURED_STATE;
+ dwc->resize_fifos = true;
+ dev_dbg(dwc->dev, "resize fifos flag SET\n");
+ }
break;
case DWC3_CONFIGURED_STATE:
@@ -560,9 +544,10 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
{
struct dwc3_request *r = NULL;
struct usb_request *ur;
- struct dwc3_trb trb;
+ struct dwc3_trb *trb;
struct dwc3_ep *ep0;
u32 transferred;
+ u32 length;
u8 epnum;
epnum = event->endpoint_number;
@@ -573,19 +558,24 @@ static void dwc3_ep0_complete_data(struct dwc3 *dwc,
r = next_request(&ep0->request_list);
ur = &r->request;
- dwc3_trb_to_nat(dwc->ep0_trb, &trb);
+ trb = dwc->ep0_trb;
+ length = trb->size & DWC3_TRB_SIZE_MASK;
if (dwc->ep0_bounced) {
+ unsigned transfer_size = ur->length;
+ unsigned maxp = ep0->endpoint.maxpacket;
+ transfer_size += (maxp - (transfer_size % maxp));
transferred = min_t(u32, ur->length,
- ep0->endpoint.maxpacket - trb.length);
+ transfer_size - length);
memcpy(ur->buf, dwc->ep0_bounce, transferred);
dwc->ep0_bounced = false;
} else {
- transferred = ur->length - trb.length;
- ur->actual += transferred;
+ transferred = ur->length - length;
}
+ ur->actual += transferred;
+
if ((epnum & 1) && ur->actual < ur->length) {
/* for some reason we did not get everything out */
@@ -614,6 +604,17 @@ static void dwc3_ep0_complete_req(struct dwc3 *dwc,
dwc3_gadget_giveback(dep, r, 0);
}
+ if (dwc->test_mode) {
+ int ret;
+
+ ret = dwc3_gadget_set_test_mode(dwc, dwc->test_mode_nr);
+ if (ret < 0) {
+ dev_dbg(dwc->dev, "Invalid Test #%d\n",
+ dwc->test_mode_nr);
+ dwc3_ep0_stall_and_restart(dwc);
+ }
+ }
+
dwc->ep0state = EP0_SETUP_PHASE;
dwc3_ep0_out_start(dwc);
}
@@ -624,6 +625,7 @@ static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
struct dwc3_ep *dep = dwc->eps[event->endpoint_number];
dep->flags &= ~DWC3_EP_BUSY;
+ dep->res_trans_idx = 0;
dwc->setup_packet_pending = false;
switch (dwc->ep0state) {
@@ -679,7 +681,12 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
DWC3_TRBCTL_CONTROL_DATA);
} else if ((req->request.length % dep->endpoint.maxpacket)
&& (event->endpoint_number == 0)) {
- dwc3_map_buffer_to_dma(req);
+ ret = usb_gadget_map_request(&dwc->gadget, &req->request,
+ event->endpoint_number);
+ if (ret) {
+ dev_dbg(dwc->dev, "failed to map request\n");
+ return;
+ }
WARN_ON(req->request.length > dep->endpoint.maxpacket);
@@ -694,7 +701,12 @@ static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
dwc->ep0_bounce_addr, dep->endpoint.maxpacket,
DWC3_TRBCTL_CONTROL_DATA);
} else {
- dwc3_map_buffer_to_dma(req);
+ ret = usb_gadget_map_request(&dwc->gadget, &req->request,
+ event->endpoint_number);
+ if (ret) {
+ dev_dbg(dwc->dev, "failed to map request\n");
+ return;
+ }
ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
req->request.dma, req->request.length,
@@ -720,6 +732,12 @@ static void dwc3_ep0_do_control_status(struct dwc3 *dwc, u32 epnum)
{
struct dwc3_ep *dep = dwc->eps[epnum];
+ if (dwc->resize_fifos) {
+ dev_dbg(dwc->dev, "starting to resize fifos\n");
+ dwc3_gadget_resize_tx_fifos(dwc);
+ dwc->resize_fifos = 0;
+ }
+
WARN_ON(dwc3_ep0_start_control_status(dep));
}
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 064b6e2cd411..5255fe975ea1 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -54,68 +54,162 @@
#include "gadget.h"
#include "io.h"
-#define DMA_ADDR_INVALID (~(dma_addr_t)0)
-
-void dwc3_map_buffer_to_dma(struct dwc3_request *req)
+/**
+ * dwc3_gadget_set_test_mode - Enables USB2 Test Modes
+ * @dwc: pointer to our context structure
+ * @mode: the mode to set (J, K SE0 NAK, Force Enable)
+ *
+ * Caller should take care of locking. This function will
+ * return 0 on success or -EINVAL if wrong Test Selector
+ * is passed
+ */
+int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
{
- struct dwc3 *dwc = req->dep->dwc;
+ u32 reg;
- if (req->request.length == 0) {
- /* req->request.dma = dwc->setup_buf_addr; */
- return;
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ reg &= ~DWC3_DCTL_TSTCTRL_MASK;
+
+ switch (mode) {
+ case TEST_J:
+ case TEST_K:
+ case TEST_SE0_NAK:
+ case TEST_PACKET:
+ case TEST_FORCE_EN:
+ reg |= mode << 1;
+ break;
+ default:
+ return -EINVAL;
}
- if (req->request.num_sgs) {
- int mapped;
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
- mapped = dma_map_sg(dwc->dev, req->request.sg,
- req->request.num_sgs,
- req->direction ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
- if (mapped < 0) {
- dev_err(dwc->dev, "failed to map SGs\n");
- return;
- }
+ return 0;
+}
- req->request.num_mapped_sgs = mapped;
- return;
- }
+/**
+ * dwc3_gadget_set_link_state - Sets USB Link to a particular State
+ * @dwc: pointer to our context structure
+ * @state: the state to put link into
+ *
+ * Caller should take care of locking. This function will
+ * return 0 on success or -ETIMEDOUT.
+ */
+int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
+{
+ int retries = 10000;
+ u32 reg;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
- if (req->request.dma == DMA_ADDR_INVALID) {
- req->request.dma = dma_map_single(dwc->dev, req->request.buf,
- req->request.length, req->direction
- ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- req->mapped = true;
+ /* set requested state */
+ reg |= DWC3_DCTL_ULSTCHNGREQ(state);
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+ /* wait for a change in DSTS */
+ while (--retries) {
+ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+
+ if (DWC3_DSTS_USBLNKST(reg) == state)
+ return 0;
+
+ udelay(5);
}
+
+ dev_vdbg(dwc->dev, "link state change request timed out\n");
+
+ return -ETIMEDOUT;
}
-void dwc3_unmap_buffer_from_dma(struct dwc3_request *req)
+/**
+ * dwc3_gadget_resize_tx_fifos - reallocate fifo spaces for current use-case
+ * @dwc: pointer to our context structure
+ *
+ * This function will a best effort FIFO allocation in order
+ * to improve FIFO usage and throughput, while still allowing
+ * us to enable as many endpoints as possible.
+ *
+ * Keep in mind that this operation will be highly dependent
+ * on the configured size for RAM1 - which contains TxFifo -,
+ * the amount of endpoints enabled on coreConsultant tool, and
+ * the width of the Master Bus.
+ *
+ * In the ideal world, we would always be able to satisfy the
+ * following equation:
+ *
+ * ((512 + 2 * MDWIDTH-Bytes) + (Number of IN Endpoints - 1) * \
+ * (3 * (1024 + MDWIDTH-Bytes) + MDWIDTH-Bytes)) / MDWIDTH-Bytes
+ *
+ * Unfortunately, due to many variables that's not always the case.
+ */
+int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
{
- struct dwc3 *dwc = req->dep->dwc;
+ int last_fifo_depth = 0;
+ int ram1_depth;
+ int fifo_size;
+ int mdwidth;
+ int num;
- if (req->request.length == 0) {
- req->request.dma = DMA_ADDR_INVALID;
- return;
- }
+ if (!dwc->needs_fifo_resize)
+ return 0;
- if (req->request.num_mapped_sgs) {
- req->request.dma = DMA_ADDR_INVALID;
- dma_unmap_sg(dwc->dev, req->request.sg,
- req->request.num_mapped_sgs,
- req->direction ? DMA_TO_DEVICE
- : DMA_FROM_DEVICE);
+ ram1_depth = DWC3_RAM1_DEPTH(dwc->hwparams.hwparams7);
+ mdwidth = DWC3_MDWIDTH(dwc->hwparams.hwparams0);
- req->request.num_mapped_sgs = 0;
- return;
- }
+ /* MDWIDTH is represented in bits, we need it in bytes */
+ mdwidth >>= 3;
+
+ /*
+ * FIXME For now we will only allocate 1 wMaxPacketSize space
+ * for each enabled endpoint, later patches will come to
+ * improve this algorithm so that we better use the internal
+ * FIFO space
+ */
+ for (num = 0; num < DWC3_ENDPOINTS_NUM; num++) {
+ struct dwc3_ep *dep = dwc->eps[num];
+ int fifo_number = dep->number >> 1;
+ int mult = 1;
+ int tmp;
+
+ if (!(dep->number & 1))
+ continue;
+
+ if (!(dep->flags & DWC3_EP_ENABLED))
+ continue;
+
+ if (usb_endpoint_xfer_bulk(dep->desc)
+ || usb_endpoint_xfer_isoc(dep->desc))
+ mult = 3;
+
+ /*
+ * REVISIT: the following assumes we will always have enough
+ * space available on the FIFO RAM for all possible use cases.
+ * Make sure that's true somehow and change FIFO allocation
+ * accordingly.
+ *
+ * If we have Bulk or Isochronous endpoints, we want
+ * them to be able to be very, very fast. So we're giving
+ * those endpoints a fifo_size which is enough for 3 full
+ * packets
+ */
+ tmp = mult * (dep->endpoint.maxpacket + mdwidth);
+ tmp += mdwidth;
+
+ fifo_size = DIV_ROUND_UP(tmp, mdwidth);
+
+ fifo_size |= (last_fifo_depth << 16);
+
+ dev_vdbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n",
+ dep->name, last_fifo_depth, fifo_size & 0xffff);
+
+ dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(fifo_number),
+ fifo_size);
- if (req->mapped) {
- dma_unmap_single(dwc->dev, req->request.dma,
- req->request.length, req->direction
- ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- req->mapped = 0;
- req->request.dma = DMA_ADDR_INVALID;
+ last_fifo_depth += (fifo_size & 0xffff);
}
+
+ return 0;
}
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
@@ -144,14 +238,15 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
if (req->request.status == -EINPROGRESS)
req->request.status = status;
- dwc3_unmap_buffer_from_dma(req);
+ usb_gadget_unmap_request(&dwc->gadget, &req->request,
+ req->direction);
dev_dbg(dwc->dev, "request %p from %s completed %d/%d ===> %d\n",
req, dep->name, req->request.actual,
req->request.length, status);
spin_unlock(&dwc->lock);
- req->request.complete(&req->dep->endpoint, &req->request);
+ req->request.complete(&dep->endpoint, &req->request);
spin_lock(&dwc->lock);
}
@@ -219,7 +314,7 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
}
static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
- struct dwc3_trb_hw *trb)
+ struct dwc3_trb *trb)
{
u32 offset = (char *) trb - (char *) dep->trb_pool;
@@ -368,9 +463,8 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
return ret;
if (!(dep->flags & DWC3_EP_ENABLED)) {
- struct dwc3_trb_hw *trb_st_hw;
- struct dwc3_trb_hw *trb_link_hw;
- struct dwc3_trb trb_link;
+ struct dwc3_trb *trb_st_hw;
+ struct dwc3_trb *trb_link;
ret = dwc3_gadget_set_xfer_resource(dwc, dep);
if (ret)
@@ -390,15 +484,15 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
memset(&trb_link, 0, sizeof(trb_link));
- /* Link TRB for ISOC. The HWO but is never reset */
+ /* Link TRB for ISOC. The HWO bit is never reset */
trb_st_hw = &dep->trb_pool[0];
- trb_link.bplh = dwc3_trb_dma_offset(dep, trb_st_hw);
- trb_link.trbctl = DWC3_TRBCTL_LINK_TRB;
- trb_link.hwo = true;
+ trb_link = &dep->trb_pool[DWC3_TRB_NUM - 1];
- trb_link_hw = &dep->trb_pool[DWC3_TRB_NUM - 1];
- dwc3_trb_to_hw(&trb_link, trb_link_hw);
+ trb_link->bpl = lower_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
+ trb_link->bph = upper_32_bits(dwc3_trb_dma_offset(dep, trb_st_hw));
+ trb_link->ctrl |= DWC3_TRBCTL_LINK_TRB;
+ trb_link->ctrl |= DWC3_TRB_CTRL_HWO;
}
return 0;
@@ -440,6 +534,7 @@ static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
dep->stream_capable = false;
dep->desc = NULL;
+ dep->endpoint.desc = NULL;
dep->comp_desc = NULL;
dep->type = 0;
dep->flags = 0;
@@ -485,16 +580,16 @@ static int dwc3_gadget_ep_enable(struct usb_ep *ep,
switch (usb_endpoint_type(desc)) {
case USB_ENDPOINT_XFER_CONTROL:
- strncat(dep->name, "-control", sizeof(dep->name));
+ strlcat(dep->name, "-control", sizeof(dep->name));
break;
case USB_ENDPOINT_XFER_ISOC:
- strncat(dep->name, "-isoc", sizeof(dep->name));
+ strlcat(dep->name, "-isoc", sizeof(dep->name));
break;
case USB_ENDPOINT_XFER_BULK:
- strncat(dep->name, "-bulk", sizeof(dep->name));
+ strlcat(dep->name, "-bulk", sizeof(dep->name));
break;
case USB_ENDPOINT_XFER_INT:
- strncat(dep->name, "-int", sizeof(dep->name));
+ strlcat(dep->name, "-int", sizeof(dep->name));
break;
default:
dev_err(dwc->dev, "invalid endpoint transfer type\n");
@@ -562,7 +657,6 @@ static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep,
req->epnum = dep->number;
req->dep = dep;
- req->request.dma = DMA_ADDR_INVALID;
return &req->request;
}
@@ -585,8 +679,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
unsigned length, unsigned last, unsigned chain)
{
struct dwc3 *dwc = dep->dwc;
- struct dwc3_trb_hw *trb_hw;
- struct dwc3_trb trb;
+ struct dwc3_trb *trb;
unsigned int cur_slot;
@@ -595,7 +688,7 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
length, last ? " last" : "",
chain ? " chain" : "");
- trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+ trb = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
cur_slot = dep->free_slot;
dep->free_slot++;
@@ -604,40 +697,32 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
usb_endpoint_xfer_isoc(dep->desc))
return;
- memset(&trb, 0, sizeof(trb));
if (!req->trb) {
dwc3_gadget_move_request_queued(req);
- req->trb = trb_hw;
- req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
+ req->trb = trb;
+ req->trb_dma = dwc3_trb_dma_offset(dep, trb);
}
- if (usb_endpoint_xfer_isoc(dep->desc)) {
- trb.isp_imi = true;
- trb.csp = true;
- } else {
- trb.chn = chain;
- trb.lst = last;
- }
-
- if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
- trb.sid_sofn = req->request.stream_id;
+ trb->size = DWC3_TRB_SIZE_LENGTH(length);
+ trb->bpl = lower_32_bits(dma);
+ trb->bph = upper_32_bits(dma);
switch (usb_endpoint_type(dep->desc)) {
case USB_ENDPOINT_XFER_CONTROL:
- trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
+ trb->ctrl = DWC3_TRBCTL_CONTROL_SETUP;
break;
case USB_ENDPOINT_XFER_ISOC:
- trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
+ trb->ctrl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
/* IOC every DWC3_TRB_NUM / 4 so we can refill */
if (!(cur_slot % (DWC3_TRB_NUM / 4)))
- trb.ioc = last;
+ trb->ctrl |= DWC3_TRB_CTRL_IOC;
break;
case USB_ENDPOINT_XFER_BULK:
case USB_ENDPOINT_XFER_INT:
- trb.trbctl = DWC3_TRBCTL_NORMAL;
+ trb->ctrl = DWC3_TRBCTL_NORMAL;
break;
default:
/*
@@ -647,11 +732,21 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
BUG();
}
- trb.length = length;
- trb.bplh = dma;
- trb.hwo = true;
+ if (usb_endpoint_xfer_isoc(dep->desc)) {
+ trb->ctrl |= DWC3_TRB_CTRL_ISP_IMI;
+ trb->ctrl |= DWC3_TRB_CTRL_CSP;
+ } else {
+ if (chain)
+ trb->ctrl |= DWC3_TRB_CTRL_CHN;
+
+ if (last)
+ trb->ctrl |= DWC3_TRB_CTRL_LST;
+ }
- dwc3_trb_to_hw(&trb, trb_hw);
+ if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
+ trb->ctrl |= DWC3_TRB_CTRL_SID_SOFN(req->request.stream_id);
+
+ trb->ctrl |= DWC3_TRB_CTRL_HWO;
}
/*
@@ -659,14 +754,15 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
* @dep: endpoint for which requests are being prepared
* @starting: true if the endpoint is idle and no requests are queued.
*
- * The functions goes through the requests list and setups TRBs for the
- * transfers. The functions returns once there are not more TRBs available or
- * it run out of requests.
+ * The function goes through the requests list and sets up TRBs for the
+ * transfers. The function returns once there are no more TRBs available or
+ * it runs out of requests.
*/
static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
{
struct dwc3_request *req, *n;
u32 trbs_left;
+ u32 max;
unsigned int last_one = 0;
BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
@@ -674,9 +770,16 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
/* the first request must not be queued */
trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
+ /* Can't wrap around on a non-isoc EP since there's no link TRB */
+ if (!usb_endpoint_xfer_isoc(dep->desc)) {
+ max = DWC3_TRB_NUM - (dep->free_slot & DWC3_TRB_MASK);
+ if (trbs_left > max)
+ trbs_left = max;
+ }
+
/*
- * if busy & slot are equal than it is either full or empty. If we are
- * starting to proceed requests then we are empty. Otherwise we ar
+ * If busy & slot are equal than it is either full or empty. If we are
+ * starting to process requests then we are empty. Otherwise we are
* full and don't do anything
*/
if (!trbs_left) {
@@ -687,7 +790,7 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
* In case we start from scratch, we queue the ISOC requests
* starting from slot 1. This is done because we use ring
* buffer and have no LST bit to stop us. Instead, we place
- * IOC bit TRB_NUM/4. We try to avoid to having an interrupt
+ * IOC bit every TRB_NUM/4. We try to avoid having an interrupt
* after the first request so we start at slot 1 and have
* 7 requests proceed before we hit the first IOC.
* Other transfer types don't use the ring buffer and are
@@ -723,8 +826,8 @@ static void dwc3_prepare_trbs(struct dwc3_ep *dep, bool starting)
length = sg_dma_len(s);
dma = sg_dma_address(s);
- if (i == (request->num_mapped_sgs - 1)
- || sg_is_last(s)) {
+ if (i == (request->num_mapped_sgs - 1) ||
+ sg_is_last(s)) {
last_one = true;
chain = false;
}
@@ -792,8 +895,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
dwc3_prepare_trbs(dep, start_new);
/*
- * req points to the first request where HWO changed
- * from 0 to 1
+ * req points to the first request where HWO changed from 0 to 1
*/
req = next_request(&dep->req_queued);
}
@@ -819,9 +921,10 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
/*
* FIXME we need to iterate over the list of requests
* here and stop, unmap, free and del each of the linked
- * requests instead of we do now.
+ * requests instead of what we do now.
*/
- dwc3_unmap_buffer_from_dma(req);
+ usb_gadget_unmap_request(&dwc->gadget, &req->request,
+ req->direction);
list_del(&req->list);
return ret;
}
@@ -837,6 +940,9 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
{
+ struct dwc3 *dwc = dep->dwc;
+ int ret;
+
req->request.actual = 0;
req->request.status = -EINPROGRESS;
req->direction = dep->direction;
@@ -852,9 +958,13 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
* particular token from the Host side.
*
* This will also avoid Host cancelling URBs due to too
- * many NACKs.
+ * many NAKs.
*/
- dwc3_map_buffer_to_dma(req);
+ ret = usb_gadget_map_request(&dwc->gadget, &req->request,
+ dep->direction);
+ if (ret)
+ return ret;
+
list_add_tail(&req->list, &dep->request_list);
/*
@@ -874,11 +984,11 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
int start_trans;
start_trans = 1;
- if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
- dep->flags & DWC3_EP_BUSY)
+ if (usb_endpoint_xfer_isoc(dep->desc) &&
+ (dep->flags & DWC3_EP_BUSY))
start_trans = 0;
- ret = __dwc3_gadget_kick_transfer(dep, 0, start_trans);
+ ret = __dwc3_gadget_kick_transfer(dep, 0, start_trans);
if (ret && ret != -EBUSY) {
struct dwc3 *dwc = dep->dwc;
@@ -1031,8 +1141,12 @@ out:
static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
{
struct dwc3_ep *dep = to_dwc3_ep(ep);
+ struct dwc3 *dwc = dep->dwc;
+ unsigned long flags;
+ spin_lock_irqsave(&dwc->lock, flags);
dep->flags |= DWC3_EP_WEDGE;
+ spin_unlock_irqrestore(&dwc->lock, flags);
return dwc3_gadget_ep_set_halt(ep, 1);
}
@@ -1122,26 +1236,20 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
goto out;
}
- reg = dwc3_readl(dwc->regs, DWC3_DCTL);
-
- /*
- * Switch link state to Recovery. In HS/FS/LS this means
- * RemoteWakeup Request
- */
- reg |= DWC3_DCTL_ULSTCHNG_RECOVERY;
- dwc3_writel(dwc->regs, DWC3_DCTL, reg);
-
- /* wait for at least 2000us */
- usleep_range(2000, 2500);
+ ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV);
+ if (ret < 0) {
+ dev_err(dwc->dev, "failed to put link in Recovery\n");
+ goto out;
+ }
/* write zeroes to Link Change Request */
reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
- /* pool until Link State change to ON */
+ /* poll until Link State changes to ON */
timeout = jiffies + msecs_to_jiffies(100);
- while (!(time_after(jiffies, timeout))) {
+ while (!time_after(jiffies, timeout)) {
reg = dwc3_readl(dwc->regs, DWC3_DSTS);
/* in HS, means ON */
@@ -1164,8 +1272,11 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
int is_selfpowered)
{
struct dwc3 *dwc = gadget_to_dwc(g);
+ unsigned long flags;
+ spin_lock_irqsave(&dwc->lock, flags);
dwc->is_selfpowered = !!is_selfpowered;
+ spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
}
@@ -1176,10 +1287,13 @@ static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
u32 timeout = 500;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
- if (is_on)
- reg |= DWC3_DCTL_RUN_STOP;
- else
+ if (is_on) {
+ reg &= ~DWC3_DCTL_TRGTULST_MASK;
+ reg |= (DWC3_DCTL_RUN_STOP
+ | DWC3_DCTL_TRGTULST_RX_DET);
+ } else {
reg &= ~DWC3_DCTL_RUN_STOP;
+ }
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
@@ -1386,7 +1500,7 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
const struct dwc3_event_depevt *event, int status)
{
struct dwc3_request *req;
- struct dwc3_trb trb;
+ struct dwc3_trb *trb;
unsigned int count;
unsigned int s_pkt = 0;
@@ -1397,20 +1511,20 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
return 1;
}
- dwc3_trb_to_nat(req->trb, &trb);
+ trb = req->trb;
- if (trb.hwo && status != -ESHUTDOWN)
+ if ((trb->ctrl & DWC3_TRB_CTRL_HWO) && status != -ESHUTDOWN)
/*
* We continue despite the error. There is not much we
- * can do. If we don't clean in up we loop for ever. If
- * we skip the TRB than it gets overwritten reused after
- * a while since we use them in a ring buffer. a BUG()
- * would help. Lets hope that if this occures, someone
+ * can do. If we don't clean it up we loop forever. If
+ * we skip the TRB then it gets overwritten after a
+ * while since we use them in a ring buffer. A BUG()
+ * would help. Lets hope that if this occurs, someone
* fixes the root cause instead of looking away :)
*/
dev_err(dwc->dev, "%s's TRB (%p) still owned by HW\n",
dep->name, req->trb);
- count = trb.length;
+ count = trb->size & DWC3_TRB_SIZE_MASK;
if (dep->direction) {
if (count) {
@@ -1434,13 +1548,16 @@ static int dwc3_cleanup_done_reqs(struct dwc3 *dwc, struct dwc3_ep *dep,
dwc3_gadget_giveback(dep, req, status);
if (s_pkt)
break;
- if ((event->status & DEPEVT_STATUS_LST) && trb.lst)
+ if ((event->status & DEPEVT_STATUS_LST) &&
+ (trb->ctrl & DWC3_TRB_CTRL_LST))
break;
- if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
+ if ((event->status & DEPEVT_STATUS_IOC) &&
+ (trb->ctrl & DWC3_TRB_CTRL_IOC))
break;
} while (1);
- if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
+ if ((event->status & DEPEVT_STATUS_IOC) &&
+ (trb->ctrl & DWC3_TRB_CTRL_IOC))
return 0;
return 1;
}
@@ -1455,11 +1572,9 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
if (event->status & DEPEVT_STATUS_BUSERR)
status = -ECONNRESET;
- clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status);
- if (clean_busy) {
+ clean_busy = dwc3_cleanup_done_reqs(dwc, dep, event, status);
+ if (clean_busy)
dep->flags &= ~DWC3_EP_BUSY;
- dep->res_trans_idx = 0;
- }
/*
* WORKAROUND: This is the 2nd half of U1/U2 -> U0 workaround.
@@ -1490,7 +1605,7 @@ static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
{
- u32 uf;
+ u32 uf, mask;
if (list_empty(&dep->request_list)) {
dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
@@ -1498,16 +1613,10 @@ static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
return;
}
- if (event->parameters) {
- u32 mask;
-
- mask = ~(dep->interval - 1);
- uf = event->parameters & mask;
- /* 4 micro frames in the future */
- uf += dep->interval * 4;
- } else {
- uf = 0;
- }
+ mask = ~(dep->interval - 1);
+ uf = event->parameters & mask;
+ /* 4 micro frames in the future */
+ uf += dep->interval * 4;
__dwc3_gadget_kick_transfer(dep, uf, 1);
}
@@ -1519,8 +1628,8 @@ static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep,
struct dwc3_event_depevt mod_ev = *event;
/*
- * We were asked to remove one requests. It is possible that this
- * request and a few other were started together and have the same
+ * We were asked to remove one request. It is possible that this
+ * request and a few others were started together and have the same
* transfer index. Since we stopped the complete endpoint we don't
* know how many requests were already completed (and not yet)
* reported and how could be done (later). We purge them all until
@@ -1529,7 +1638,7 @@ static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep,
mod_ev.status = DEPEVT_STATUS_LST;
dwc3_cleanup_done_reqs(dwc, dep, &mod_ev, -ESHUTDOWN);
dep->flags &= ~DWC3_EP_BUSY;
- /* pending requets are ignored and are queued on XferNotReady */
+ /* pending requests are ignored and are queued on XferNotReady */
}
static void dwc3_ep_cmd_compl(struct dwc3_ep *dep,
@@ -1570,6 +1679,8 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
switch (event->endpoint_event) {
case DWC3_DEPEVT_XFERCOMPLETE:
+ dep->res_trans_idx = 0;
+
if (usb_endpoint_xfer_isoc(dep->desc)) {
dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n",
dep->name);
@@ -1594,7 +1705,8 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
int ret;
dev_vdbg(dwc->dev, "%s: reason %s\n",
- dep->name, event->status
+ dep->name, event->status &
+ DEPEVT_STATUS_TRANSFER_ACTIVE
? "Transfer Active"
: "Transfer Not Active");
@@ -1805,6 +1917,7 @@ static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
reg &= ~DWC3_DCTL_TSTCTRL_MASK;
dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+ dwc->test_mode = false;
dwc3_stop_active_transfers(dwc);
dwc3_clear_stall_all_ep(dwc);
@@ -2082,7 +2195,8 @@ static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
while (left > 0) {
union dwc3_event event;
- memcpy(&event.raw, (evt->buf + evt->lpos), sizeof(event.raw));
+ event.raw = *(u32 *) (evt->buf + evt->lpos);
+
dwc3_process_event_entry(dwc, &event);
/*
* XXX we wrap around correctly to the next entry as almost all
@@ -2123,7 +2237,7 @@ static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
/**
* dwc3_gadget_init - Initializes gadget related registers
- * @dwc: Pointer to out controller context structure
+ * @dwc: pointer to our controller context structure
*
* Returns 0 on success otherwise negative errno.
*/
@@ -2149,9 +2263,8 @@ int __devinit dwc3_gadget_init(struct dwc3 *dwc)
goto err1;
}
- dwc->setup_buf = dma_alloc_coherent(dwc->dev,
- sizeof(*dwc->setup_buf) * 2,
- &dwc->setup_buf_addr, GFP_KERNEL);
+ dwc->setup_buf = kzalloc(sizeof(*dwc->setup_buf) * 2,
+ GFP_KERNEL);
if (!dwc->setup_buf) {
dev_err(dwc->dev, "failed to allocate setup buffer\n");
ret = -ENOMEM;
@@ -2242,8 +2355,7 @@ err4:
dwc->ep0_bounce_addr);
err3:
- dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
- dwc->setup_buf, dwc->setup_buf_addr);
+ kfree(dwc->setup_buf);
err2:
dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
@@ -2272,8 +2384,7 @@ void dwc3_gadget_exit(struct dwc3 *dwc)
dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
dwc->ep0_bounce_addr);
- dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
- dwc->setup_buf, dwc->setup_buf_addr);
+ kfree(dwc->setup_buf);
dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
dwc->ep0_trb, dwc->ep0_trb_addr);
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index d97f467d41cc..a8600084348c 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -100,6 +100,9 @@ static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
int status);
+int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode);
+int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state);
+
void dwc3_ep0_interrupt(struct dwc3 *dwc,
const struct dwc3_event_depevt *event);
void dwc3_ep0_out_start(struct dwc3 *dwc);
@@ -108,8 +111,6 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value);
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params);
-void dwc3_map_buffer_to_dma(struct dwc3_request *req);
-void dwc3_unmap_buffer_from_dma(struct dwc3_request *req);
/**
* dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW
diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
index 7cfe211b6c37..b108d18fd40d 100644
--- a/drivers/usb/dwc3/host.c
+++ b/drivers/usb/dwc3/host.c
@@ -53,7 +53,7 @@ int dwc3_host_init(struct dwc3 *dwc)
struct platform_device *xhci;
int ret;
- xhci = platform_device_alloc("xhci", -1);
+ xhci = platform_device_alloc("xhci-hcd", -1);
if (!xhci) {
dev_err(dwc->dev, "couldn't allocate xHCI device\n");
ret = -ENOMEM;
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 7ecb68a67411..2633f7595116 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -137,7 +137,7 @@ choice
config USB_AT91
tristate "Atmel AT91 USB Device Port"
- depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9 && !ARCH_AT91SAM9G45
+ depends on ARCH_AT91
help
Many Atmel AT91 processors (such as the AT91RM2000) have a
full speed USB Device Port with support for five configurable
@@ -150,7 +150,7 @@ config USB_AT91
config USB_ATMEL_USBA
tristate "Atmel USBA"
select USB_GADGET_DUALSPEED
- depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
+ depends on AVR32 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
help
USBA is the integrated high-speed USB Device controller on
the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
@@ -284,7 +284,7 @@ config USB_IMX
config USB_S3C2410
tristate "S3C2410 USB Device Controller"
- depends on ARCH_S3C2410
+ depends on ARCH_S3C24XX
help
Samsung's S3C2410 is an ARM-4 processor with an integrated
full speed USB 1.1 device controller. It has 4 configurable
@@ -299,7 +299,7 @@ config USB_S3C2410_DEBUG
config USB_S3C_HSUDC
tristate "S3C2416, S3C2443 and S3C2450 USB Device Controller"
- depends on ARCH_S3C2410
+ depends on ARCH_S3C24XX
select USB_GADGET_DUALSPEED
help
Samsung's S3C2416, S3C2443 and S3C2450 is an ARM9 based SoC
@@ -599,16 +599,29 @@ config USB_AUDIO
depends on SND
select SND_PCM
help
- Gadget Audio is compatible with USB Audio Class specification 1.0.
- It will include at least one AudioControl interface, zero or more
- AudioStream interface and zero or more MIDIStream interface.
-
- Gadget Audio will use on-board ALSA (CONFIG_SND) audio card to
- playback or capture audio stream.
+ This Gadget Audio driver is compatible with USB Audio Class
+ specification 2.0. It implements 1 AudioControl interface,
+ 1 AudioStreaming Interface each for USB-OUT and USB-IN.
+ Number of channels, sample rate and sample size can be
+ specified as module parameters.
+ This driver doesn't expect any real Audio codec to be present
+ on the device - the audio streams are simply sinked to and
+ sourced from a virtual ALSA sound card created. The user-space
+ application may choose to do whatever it wants with the data
+ received from the USB Host and choose to provide whatever it
+ wants as audio data to the USB Host.
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "g_audio".
+config GADGET_UAC1
+ bool "UAC 1.0 (Legacy)"
+ depends on USB_AUDIO
+ help
+ If you instead want older UAC Spec-1.0 driver that also has audio
+ paths hardwired to the Audio codec chip on-board and doesn't work
+ without one.
+
config USB_ETH
tristate "Ethernet Gadget (with CDC Ethernet support)"
depends on NET
@@ -685,7 +698,7 @@ config USB_G_NCM
help
This driver implements USB CDC NCM subclass standard. NCM is
an advanced protocol for Ethernet encapsulation, allows grouping
- of several ethernet frames into one USB transfer and diffferent
+ of several ethernet frames into one USB transfer and different
alignment possibilities.
Say "y" to link the driver statically, or "m" to build a
diff --git a/drivers/usb/gadget/amd5536udc.c b/drivers/usb/gadget/amd5536udc.c
index c16ff55a74e8..77779271f487 100644
--- a/drivers/usb/gadget/amd5536udc.c
+++ b/drivers/usb/gadget/amd5536udc.c
@@ -29,7 +29,7 @@
/* Driver strings */
#define UDC_MOD_DESCRIPTION "AMD 5536 UDC - USB Device Controller"
-#define UDC_DRIVER_VERSION_STRING "01.00.0206 - $Revision: #3 $"
+#define UDC_DRIVER_VERSION_STRING "01.00.0206"
/* system */
#include <linux/module.h>
@@ -54,7 +54,6 @@
#include <linux/prefetch.h>
#include <asm/byteorder.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
/* gadget stack */
@@ -140,7 +139,7 @@ static DECLARE_TASKLET(disconnect_tasklet, udc_tasklet_disconnect,
/* endpoint names used for print */
static const char ep0_string[] = "ep0in";
-static const char *ep_string[] = {
+static const char *const ep_string[] = {
ep0_string,
"ep1in-int", "ep2in-bulk", "ep3in-bulk", "ep4in-bulk", "ep5in-bulk",
"ep6in-bulk", "ep7in-bulk", "ep8in-bulk", "ep9in-bulk", "ep10in-bulk",
@@ -204,9 +203,8 @@ static void print_regs(struct udc *dev)
DBG(dev, "DMA mode = BF (buffer fill mode)\n");
dev_info(&dev->pdev->dev, "DMA mode (%s)\n", "BF");
}
- if (!use_dma) {
+ if (!use_dma)
dev_info(&dev->pdev->dev, "FIFO mode\n");
- }
DBG(dev, "-------------------------------------------------------\n");
}
@@ -445,6 +443,7 @@ static void ep_init(struct udc_regs __iomem *regs, struct udc_ep *ep)
VDBG(ep->dev, "ep-%d reset\n", ep->num);
ep->desc = NULL;
+ ep->ep.desc = NULL;
ep->ep.ops = &udc_ep_ops;
INIT_LIST_HEAD(&ep->queue);
@@ -569,9 +568,8 @@ udc_free_request(struct usb_ep *usbep, struct usb_request *usbreq)
VDBG(ep->dev, "req->td_data=%p\n", req->td_data);
/* free dma chain if created */
- if (req->chain_len > 1) {
+ if (req->chain_len > 1)
udc_free_dma_chain(ep->dev, req);
- }
pci_pool_free(ep->dev->data_requests, req->td_data,
req->td_phys);
@@ -639,9 +637,8 @@ udc_txfifo_write(struct udc_ep *ep, struct usb_request *req)
bytes = remaining;
/* dwords first */
- for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+ for (i = 0; i < bytes / UDC_DWORD_BYTES; i++)
writel(*(buf + i), ep->txfifo);
- }
/* remaining bytes must be written by byte access */
for (j = 0; j < bytes % UDC_DWORD_BYTES; j++) {
@@ -660,9 +657,8 @@ static int udc_rxfifo_read_dwords(struct udc *dev, u32 *buf, int dwords)
VDBG(dev, "udc_read_dwords(): %d dwords\n", dwords);
- for (i = 0; i < dwords; i++) {
+ for (i = 0; i < dwords; i++)
*(buf + i) = readl(dev->rxfifo);
- }
return 0;
}
@@ -675,9 +671,8 @@ static int udc_rxfifo_read_bytes(struct udc *dev, u8 *buf, int bytes)
VDBG(dev, "udc_read_bytes(): %d bytes\n", bytes);
/* dwords first */
- for (i = 0; i < bytes / UDC_DWORD_BYTES; i++) {
+ for (i = 0; i < bytes / UDC_DWORD_BYTES; i++)
*((u32 *)(buf + (i<<2))) = readl(dev->rxfifo);
- }
/* remaining bytes must be read by byte access */
if (bytes % UDC_DWORD_BYTES) {
@@ -831,20 +826,8 @@ __acquires(ep->dev->lock)
dev = ep->dev;
/* unmap DMA */
- if (req->dma_mapping) {
- if (ep->in)
- pci_unmap_single(dev->pdev,
- req->req.dma,
- req->req.length,
- PCI_DMA_TODEVICE);
- else
- pci_unmap_single(dev->pdev,
- req->req.dma,
- req->req.length,
- PCI_DMA_FROMDEVICE);
- req->dma_mapping = 0;
- req->req.dma = DMA_DONT_USE;
- }
+ if (ep->dma)
+ usb_gadget_unmap_request(&dev->gadget, &req->req, ep->in);
halted = ep->halted;
ep->halted = 1;
@@ -897,9 +880,8 @@ static struct udc_data_dma *udc_get_last_dma_desc(struct udc_request *req)
struct udc_data_dma *td;
td = req->td_data;
- while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L))) {
+ while (td && !(td->status & AMD_BIT(UDC_DMA_IN_STS_L)))
td = phys_to_virt(td->next);
- }
return td;
@@ -949,21 +931,18 @@ static int udc_create_dma_chain(
dma_addr = DMA_DONT_USE;
/* unset L bit in first desc for OUT */
- if (!ep->in) {
+ if (!ep->in)
req->td_data->status &= AMD_CLEAR_BIT(UDC_DMA_IN_STS_L);
- }
/* alloc only new desc's if not already available */
len = req->req.length / ep->ep.maxpacket;
- if (req->req.length % ep->ep.maxpacket) {
+ if (req->req.length % ep->ep.maxpacket)
len++;
- }
if (len > req->chain_len) {
/* shorter chain already allocated before */
- if (req->chain_len > 1) {
+ if (req->chain_len > 1)
udc_free_dma_chain(ep->dev, req);
- }
req->chain_len = len;
create_new_chain = 1;
}
@@ -1006,11 +985,12 @@ static int udc_create_dma_chain(
/* link td and assign tx bytes */
if (i == buf_len) {
- if (create_new_chain) {
+ if (create_new_chain)
req->td_data->next = dma_addr;
- } else {
- /* req->td_data->next = virt_to_phys(td); */
- }
+ /*
+ else
+ req->td_data->next = virt_to_phys(td);
+ */
/* write tx bytes */
if (ep->in) {
/* first desc */
@@ -1024,11 +1004,12 @@ static int udc_create_dma_chain(
UDC_DMA_IN_STS_TXBYTES);
}
} else {
- if (create_new_chain) {
+ if (create_new_chain)
last->next = dma_addr;
- } else {
- /* last->next = virt_to_phys(td); */
- }
+ /*
+ else
+ last->next = virt_to_phys(td);
+ */
if (ep->in) {
/* write tx bytes */
td->status = AMD_ADDBITS(td->status,
@@ -1095,20 +1076,11 @@ udc_queue(struct usb_ep *usbep, struct usb_request *usbreq, gfp_t gfp)
return -ESHUTDOWN;
/* map dma (usually done before) */
- if (ep->dma && usbreq->length != 0
- && (usbreq->dma == DMA_DONT_USE || usbreq->dma == 0)) {
+ if (ep->dma) {
VDBG(dev, "DMA map req %p\n", req);
- if (ep->in)
- usbreq->dma = pci_map_single(dev->pdev,
- usbreq->buf,
- usbreq->length,
- PCI_DMA_TODEVICE);
- else
- usbreq->dma = pci_map_single(dev->pdev,
- usbreq->buf,
- usbreq->length,
- PCI_DMA_FROMDEVICE);
- req->dma_mapping = 1;
+ retval = usb_gadget_map_request(&udc->gadget, usbreq, ep->in);
+ if (retval)
+ return retval;
}
VDBG(dev, "%s queue req %p, len %d req->td_data=%p buf %p\n",
@@ -1479,11 +1451,10 @@ static int startup_registers(struct udc *dev)
/* program speed */
tmp = readl(&dev->regs->cfg);
- if (use_fullspeed) {
+ if (use_fullspeed)
tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_FS, UDC_DEVCFG_SPD);
- } else {
+ else
tmp = AMD_ADDBITS(tmp, UDC_DEVCFG_SPD_HS, UDC_DEVCFG_SPD);
- }
writel(tmp, &dev->regs->cfg);
return 0;
@@ -1504,9 +1475,8 @@ static void udc_basic_init(struct udc *dev)
mod_timer(&udc_timer, jiffies - 1);
}
/* stop poll stall timer */
- if (timer_pending(&udc_pollstall_timer)) {
+ if (timer_pending(&udc_pollstall_timer))
mod_timer(&udc_pollstall_timer, jiffies - 1);
- }
/* disable DMA */
tmp = readl(&dev->regs->ctl);
tmp &= AMD_UNMASK_BIT(UDC_DEVCTL_RDE);
@@ -1540,11 +1510,10 @@ static void udc_setup_endpoints(struct udc *dev)
/* read enum speed */
tmp = readl(&dev->regs->sts);
tmp = AMD_GETBITS(tmp, UDC_DEVSTS_ENUM_SPEED);
- if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH) {
+ if (tmp == UDC_DEVSTS_ENUM_SPEED_HIGH)
dev->gadget.speed = USB_SPEED_HIGH;
- } else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL) {
+ else if (tmp == UDC_DEVSTS_ENUM_SPEED_FULL)
dev->gadget.speed = USB_SPEED_FULL;
- }
/* set basic ep parameters */
for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
@@ -1570,9 +1539,8 @@ static void udc_setup_endpoints(struct udc *dev)
* disabling ep interrupts when ENUM interrupt occurs but ep is
* not enabled by gadget driver
*/
- if (!ep->desc) {
+ if (!ep->desc)
ep_init(dev->regs, ep);
- }
if (use_dma) {
/*
@@ -1670,9 +1638,8 @@ static void udc_tasklet_disconnect(unsigned long par)
spin_lock(&dev->lock);
/* empty queues */
- for (tmp = 0; tmp < UDC_EP_NUM; tmp++) {
+ for (tmp = 0; tmp < UDC_EP_NUM; tmp++)
empty_req_queue(&dev->ep[tmp]);
- }
}
@@ -1746,9 +1713,8 @@ static void udc_timer_function(unsigned long v)
* open the fifo
*/
udc_timer.expires = jiffies + HZ/UDC_RDE_TIMER_DIV;
- if (!stop_timer) {
+ if (!stop_timer)
add_timer(&udc_timer);
- }
} else {
/*
* fifo contains data now, setup timer for opening
@@ -1760,9 +1726,8 @@ static void udc_timer_function(unsigned long v)
set_rde++;
/* debug: lhadmot_timer_start = 221070 */
udc_timer.expires = jiffies + HZ*UDC_RDE_TIMER_SECONDS;
- if (!stop_timer) {
+ if (!stop_timer)
add_timer(&udc_timer);
- }
}
} else
@@ -1907,19 +1872,17 @@ static void activate_control_endpoints(struct udc *dev)
mod_timer(&udc_timer, jiffies - 1);
}
/* stop pollstall timer */
- if (timer_pending(&udc_pollstall_timer)) {
+ if (timer_pending(&udc_pollstall_timer))
mod_timer(&udc_pollstall_timer, jiffies - 1);
- }
/* enable DMA */
tmp = readl(&dev->regs->ctl);
tmp |= AMD_BIT(UDC_DEVCTL_MODE)
| AMD_BIT(UDC_DEVCTL_RDE)
| AMD_BIT(UDC_DEVCTL_TDE);
- if (use_dma_bufferfill_mode) {
+ if (use_dma_bufferfill_mode)
tmp |= AMD_BIT(UDC_DEVCTL_BF);
- } else if (use_dma_ppb_du) {
+ else if (use_dma_ppb_du)
tmp |= AMD_BIT(UDC_DEVCTL_DU);
- }
writel(tmp, &dev->regs->ctl);
}
@@ -2104,9 +2067,8 @@ static void udc_ep0_set_rde(struct udc *dev)
udc_timer.expires =
jiffies + HZ/UDC_RDE_TIMER_DIV;
set_rde = 1;
- if (!stop_timer) {
+ if (!stop_timer)
add_timer(&udc_timer);
- }
}
}
}
@@ -2131,7 +2093,7 @@ static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix)
if (use_dma) {
/* BNA event ? */
if (tmp & AMD_BIT(UDC_EPSTS_BNA)) {
- DBG(dev, "BNA ep%dout occurred - DESPTR = %x \n",
+ DBG(dev, "BNA ep%dout occurred - DESPTR = %x\n",
ep->num, readl(&ep->regs->desptr));
/* clear BNA */
writel(tmp | AMD_BIT(UDC_EPSTS_BNA), &ep->regs->sts);
@@ -2294,9 +2256,8 @@ static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix)
jiffies
+ HZ*UDC_RDE_TIMER_SECONDS;
set_rde = 1;
- if (!stop_timer) {
+ if (!stop_timer)
add_timer(&udc_timer);
- }
}
if (ep->num != UDC_EP0OUT_IX)
dev->data_ep_queued = 0;
@@ -2318,9 +2279,8 @@ static irqreturn_t udc_data_out_isr(struct udc *dev, int ep_ix)
/* check pending CNAKS */
if (cnak_pending) {
/* CNAk processing when rxfifo empty only */
- if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+ if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))
udc_process_cnak_queue(dev);
- }
}
/* clear OUT bits in ep status */
@@ -2348,7 +2308,7 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
/* BNA ? */
if (epsts & AMD_BIT(UDC_EPSTS_BNA)) {
dev_err(&dev->pdev->dev,
- "BNA ep%din occurred - DESPTR = %08lx \n",
+ "BNA ep%din occurred - DESPTR = %08lx\n",
ep->num,
(unsigned long) readl(&ep->regs->desptr));
@@ -2361,7 +2321,7 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
/* HE event ? */
if (epsts & AMD_BIT(UDC_EPSTS_HE)) {
dev_err(&dev->pdev->dev,
- "HE ep%dn occurred - DESPTR = %08lx \n",
+ "HE ep%dn occurred - DESPTR = %08lx\n",
ep->num, (unsigned long) readl(&ep->regs->desptr));
/* clear HE */
@@ -2427,9 +2387,9 @@ static irqreturn_t udc_data_in_isr(struct udc *dev, int ep_ix)
/* write fifo */
udc_txfifo_write(ep, &req->req);
len = req->req.length - req->req.actual;
- if (len > ep->ep.maxpacket)
- len = ep->ep.maxpacket;
- req->req.actual += len;
+ if (len > ep->ep.maxpacket)
+ len = ep->ep.maxpacket;
+ req->req.actual += len;
if (req->req.actual == req->req.length
|| (len != ep->ep.maxpacket)) {
/* complete req */
@@ -2581,9 +2541,8 @@ __acquires(dev->lock)
if (!timer_pending(&udc_timer)) {
udc_timer.expires = jiffies +
HZ/UDC_RDE_TIMER_DIV;
- if (!stop_timer) {
+ if (!stop_timer)
add_timer(&udc_timer);
- }
}
}
@@ -2697,9 +2656,8 @@ __acquires(dev->lock)
/* check pending CNAKS */
if (cnak_pending) {
/* CNAk processing when rxfifo empty only */
- if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY)) {
+ if (readl(&dev->regs->sts) & AMD_BIT(UDC_DEVSTS_RXFIFO_EMPTY))
udc_process_cnak_queue(dev);
- }
}
finished:
@@ -2723,7 +2681,7 @@ static irqreturn_t udc_control_in_isr(struct udc *dev)
tmp = readl(&dev->ep[UDC_EP0IN_IX].regs->sts);
/* DMA completion */
if (tmp & AMD_BIT(UDC_EPSTS_TDC)) {
- VDBG(dev, "isr: TDC clear \n");
+ VDBG(dev, "isr: TDC clear\n");
ret_val = IRQ_HANDLED;
/* clear TDC bit */
@@ -3426,7 +3384,7 @@ static int udc_remote_wakeup(struct udc *dev)
}
/* PCI device parameters */
-static const struct pci_device_id pci_id[] = {
+static DEFINE_PCI_DEVICE_TABLE(pci_id) = {
{
PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x2096),
.class = (PCI_CLASS_SERIAL_USB << 8) | 0xfe,
diff --git a/drivers/usb/gadget/at91_udc.c b/drivers/usb/gadget/at91_udc.c
index 143a7256b598..9d7bcd910074 100644
--- a/drivers/usb/gadget/at91_udc.c
+++ b/drivers/usb/gadget/at91_udc.c
@@ -29,18 +29,19 @@
#include <linux/clk.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
-#include <linux/prefetch.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
#include <asm/byteorder.h>
#include <mach/hardware.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/gpio.h>
#include <mach/board.h>
#include <mach/cpu.h>
#include <mach/at91sam9261_matrix.h>
+#include <mach/at91_matrix.h>
#include "at91_udc.h"
@@ -558,6 +559,7 @@ static int at91_ep_disable (struct usb_ep * _ep)
/* restore the endpoint's pristine config */
ep->desc = NULL;
+ ep->ep.desc = NULL;
ep->ep.maxpacket = ep->maxpacket;
/* reset fifos and endpoint */
@@ -910,9 +912,9 @@ static void pullup(struct at91_udc *udc, int is_on)
} else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
u32 usbpucr;
- usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
+ usbpucr = at91_matrix_read(AT91_MATRIX_USBPUCR);
usbpucr |= AT91_MATRIX_USBPUCR_PUON;
- at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr);
+ at91_matrix_write(AT91_MATRIX_USBPUCR, usbpucr);
}
} else {
stop_activity(udc);
@@ -928,9 +930,9 @@ static void pullup(struct at91_udc *udc, int is_on)
} else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
u32 usbpucr;
- usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
+ usbpucr = at91_matrix_read(AT91_MATRIX_USBPUCR);
usbpucr &= ~AT91_MATRIX_USBPUCR_PUON;
- at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr);
+ at91_matrix_write(AT91_MATRIX_USBPUCR, usbpucr);
}
clk_off(udc);
}
@@ -1706,7 +1708,27 @@ static void at91udc_shutdown(struct platform_device *dev)
spin_unlock_irqrestore(&udc->lock, flags);
}
-static int __init at91udc_probe(struct platform_device *pdev)
+static void __devinit at91udc_of_init(struct at91_udc *udc,
+ struct device_node *np)
+{
+ struct at91_udc_data *board = &udc->board;
+ u32 val;
+ enum of_gpio_flags flags;
+
+ if (of_property_read_u32(np, "atmel,vbus-polled", &val) == 0)
+ board->vbus_polled = 1;
+
+ board->vbus_pin = of_get_named_gpio_flags(np, "atmel,vbus-gpio", 0,
+ &flags);
+ board->vbus_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
+
+ board->pullup_pin = of_get_named_gpio_flags(np, "atmel,pullup-gpio", 0,
+ &flags);
+
+ board->pullup_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
+}
+
+static int __devinit at91udc_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct at91_udc *udc;
@@ -1741,7 +1763,11 @@ static int __init at91udc_probe(struct platform_device *pdev)
/* init software state */
udc = &controller;
udc->gadget.dev.parent = dev;
- udc->board = *(struct at91_udc_data *) dev->platform_data;
+ if (pdev->dev.of_node)
+ at91udc_of_init(udc, pdev->dev.of_node);
+ else
+ memcpy(&udc->board, dev->platform_data,
+ sizeof(struct at91_udc_data));
udc->pdev = pdev;
udc->enabled = 0;
spin_lock_init(&udc->lock);
@@ -1837,8 +1863,8 @@ static int __init at91udc_probe(struct platform_device *pdev)
mod_timer(&udc->vbus_timer,
jiffies + VBUS_POLL_TIMEOUT);
} else {
- if (request_irq(udc->board.vbus_pin, at91_vbus_irq,
- 0, driver_name, udc)) {
+ if (request_irq(gpio_to_irq(udc->board.vbus_pin),
+ at91_vbus_irq, 0, driver_name, udc)) {
DBG("request vbus irq %d failed\n",
udc->board.vbus_pin);
retval = -EBUSY;
@@ -1860,7 +1886,7 @@ static int __init at91udc_probe(struct platform_device *pdev)
return 0;
fail4:
if (gpio_is_valid(udc->board.vbus_pin) && !udc->board.vbus_polled)
- free_irq(udc->board.vbus_pin, udc);
+ free_irq(gpio_to_irq(udc->board.vbus_pin), udc);
fail3:
if (gpio_is_valid(udc->board.vbus_pin))
gpio_free(udc->board.vbus_pin);
@@ -1898,7 +1924,7 @@ static int __exit at91udc_remove(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 0);
remove_debug_file(udc);
if (gpio_is_valid(udc->board.vbus_pin)) {
- free_irq(udc->board.vbus_pin, udc);
+ free_irq(gpio_to_irq(udc->board.vbus_pin), udc);
gpio_free(udc->board.vbus_pin);
}
free_irq(udc->udp_irq, udc);
@@ -1970,6 +1996,15 @@ static int at91udc_resume(struct platform_device *pdev)
#define at91udc_resume NULL
#endif
+#if defined(CONFIG_OF)
+static const struct of_device_id at91_udc_dt_ids[] = {
+ { .compatible = "atmel,at91rm9200-udc" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, at91_udc_dt_ids);
+#endif
+
static struct platform_driver at91_udc_driver = {
.remove = __exit_p(at91udc_remove),
.shutdown = at91udc_shutdown,
@@ -1978,6 +2013,7 @@ static struct platform_driver at91_udc_driver = {
.driver = {
.name = (char *) driver_name,
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(at91_udc_dt_ids),
},
};
diff --git a/drivers/usb/gadget/atmel_usba_udc.c b/drivers/usb/gadget/atmel_usba_udc.c
index e2fb6d583bd9..9f98508966d1 100644
--- a/drivers/usb/gadget/atmel_usba_udc.c
+++ b/drivers/usb/gadget/atmel_usba_udc.c
@@ -332,12 +332,12 @@ static int vbus_is_present(struct usba_udc *udc)
static void toggle_bias(int is_on)
{
- unsigned int uckr = at91_sys_read(AT91_CKGR_UCKR);
+ unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
if (is_on)
- at91_sys_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
+ at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
else
- at91_sys_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
+ at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
}
#else
@@ -659,6 +659,7 @@ static int usba_ep_disable(struct usb_ep *_ep)
return -EINVAL;
}
ep->desc = NULL;
+ ep->ep.desc = NULL;
list_splice_init(&ep->queue, &req_list);
if (ep->can_dma) {
diff --git a/drivers/usb/gadget/audio.c b/drivers/usb/gadget/audio.c
index 9d89ae4765a9..98899244860e 100644
--- a/drivers/usb/gadget/audio.c
+++ b/drivers/usb/gadget/audio.c
@@ -14,10 +14,8 @@
#include <linux/kernel.h>
#include <linux/utsname.h>
-#include "u_audio.h"
-
#define DRIVER_DESC "Linux USB Audio Gadget"
-#define DRIVER_VERSION "Dec 18, 2008"
+#define DRIVER_VERSION "Feb 2, 2012"
/*-------------------------------------------------------------------------*/
@@ -33,8 +31,36 @@
#include "config.c"
#include "epautoconf.c"
-#include "u_audio.c"
-#include "f_audio.c"
+/* string IDs are assigned dynamically */
+
+#define STRING_MANUFACTURER_IDX 0
+#define STRING_PRODUCT_IDX 1
+
+static char manufacturer[50];
+
+static struct usb_string strings_dev[] = {
+ [STRING_MANUFACTURER_IDX].s = manufacturer,
+ [STRING_PRODUCT_IDX].s = DRIVER_DESC,
+ { } /* end of list */
+};
+
+static struct usb_gadget_strings stringtab_dev = {
+ .language = 0x0409, /* en-us */
+ .strings = strings_dev,
+};
+
+static struct usb_gadget_strings *audio_strings[] = {
+ &stringtab_dev,
+ NULL,
+};
+
+#ifdef CONFIG_GADGET_UAC1
+#include "u_uac1.h"
+#include "u_uac1.c"
+#include "f_uac1.c"
+#else
+#include "f_uac2.c"
+#endif
/*-------------------------------------------------------------------------*/
@@ -54,9 +80,15 @@ static struct usb_device_descriptor device_desc = {
.bcdUSB = __constant_cpu_to_le16(0x200),
+#ifdef CONFIG_GADGET_UAC1
.bDeviceClass = USB_CLASS_PER_INTERFACE,
.bDeviceSubClass = 0,
.bDeviceProtocol = 0,
+#else
+ .bDeviceClass = USB_CLASS_MISC,
+ .bDeviceSubClass = 0x02,
+ .bDeviceProtocol = 0x01,
+#endif
/* .bMaxPacketSize0 = f(hardware) */
/* Vendor and product id defaults change according to what configs
@@ -108,6 +140,9 @@ static struct usb_configuration audio_config_driver = {
.bConfigurationValue = 1,
/* .iConfiguration = DYNAMIC */
.bmAttributes = USB_CONFIG_ATT_SELFPOWER,
+#ifndef CONFIG_GADGET_UAC1
+ .unbind = uac2_unbind_config,
+#endif
};
/*-------------------------------------------------------------------------*/
@@ -157,7 +192,9 @@ fail:
static int __exit audio_unbind(struct usb_composite_dev *cdev)
{
+#ifdef CONFIG_GADGET_UAC1
gaudio_cleanup();
+#endif
return 0;
}
diff --git a/drivers/usb/gadget/ci13xxx_msm.c b/drivers/usb/gadget/ci13xxx_msm.c
index 1fc612914c52..d07e44c05e9b 100644
--- a/drivers/usb/gadget/ci13xxx_msm.c
+++ b/drivers/usb/gadget/ci13xxx_msm.c
@@ -37,10 +37,10 @@ static void ci13xxx_msm_notify_event(struct ci13xxx *udc, unsigned event)
* Put the transceiver in non-driving mode. Otherwise host
* may not detect soft-disconnection.
*/
- val = otg_io_read(udc->transceiver, ULPI_FUNC_CTRL);
+ val = usb_phy_io_read(udc->transceiver, ULPI_FUNC_CTRL);
val &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
val |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
- otg_io_write(udc->transceiver, val, ULPI_FUNC_CTRL);
+ usb_phy_io_write(udc->transceiver, val, ULPI_FUNC_CTRL);
break;
default:
dev_dbg(dev, "unknown ci13xxx_udc event\n");
diff --git a/drivers/usb/gadget/ci13xxx_udc.c b/drivers/usb/gadget/ci13xxx_udc.c
index 27e313718422..243ef1adf969 100644
--- a/drivers/usb/gadget/ci13xxx_udc.c
+++ b/drivers/usb/gadget/ci13xxx_udc.c
@@ -2181,6 +2181,7 @@ static int ep_disable(struct usb_ep *ep)
} while (mEp->dir != direction);
mEp->desc = NULL;
+ mEp->ep.desc = NULL;
spin_unlock_irqrestore(mEp->lock, flags);
return retval;
@@ -2537,7 +2538,7 @@ static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
struct ci13xxx *udc = container_of(_gadget, struct ci13xxx, gadget);
if (udc->transceiver)
- return otg_set_power(udc->transceiver, mA);
+ return usb_phy_set_power(udc->transceiver, mA);
return -ENOTSUPP;
}
@@ -2900,7 +2901,7 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
if (retval < 0)
goto free_udc;
- udc->transceiver = otg_get_transceiver();
+ udc->transceiver = usb_get_transceiver();
if (udc->udc_driver->flags & CI13XXX_REQUIRE_TRANSCEIVER) {
if (udc->transceiver == NULL) {
@@ -2928,7 +2929,8 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
goto unreg_device;
if (udc->transceiver) {
- retval = otg_set_peripheral(udc->transceiver, &udc->gadget);
+ retval = otg_set_peripheral(udc->transceiver->otg,
+ &udc->gadget);
if (retval)
goto remove_dbg;
}
@@ -2945,8 +2947,8 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
remove_trans:
if (udc->transceiver) {
- otg_set_peripheral(udc->transceiver, &udc->gadget);
- otg_put_transceiver(udc->transceiver);
+ otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
+ usb_put_transceiver(udc->transceiver);
}
err("error = %i", retval);
@@ -2958,7 +2960,7 @@ unreg_device:
device_unregister(&udc->gadget.dev);
put_transceiver:
if (udc->transceiver)
- otg_put_transceiver(udc->transceiver);
+ usb_put_transceiver(udc->transceiver);
free_udc:
kfree(udc);
_udc = NULL;
@@ -2981,8 +2983,8 @@ static void udc_remove(void)
usb_del_gadget_udc(&udc->gadget);
if (udc->transceiver) {
- otg_set_peripheral(udc->transceiver, &udc->gadget);
- otg_put_transceiver(udc->transceiver);
+ otg_set_peripheral(udc->transceiver->otg, &udc->gadget);
+ usb_put_transceiver(udc->transceiver);
}
#ifdef CONFIG_USB_GADGET_DEBUG_FILES
dbg_remove_files(&udc->gadget.dev);
diff --git a/drivers/usb/gadget/ci13xxx_udc.h b/drivers/usb/gadget/ci13xxx_udc.h
index f4871e1fac59..0d31af56c989 100644
--- a/drivers/usb/gadget/ci13xxx_udc.h
+++ b/drivers/usb/gadget/ci13xxx_udc.h
@@ -136,7 +136,7 @@ struct ci13xxx {
struct usb_gadget_driver *driver; /* 3rd party gadget driver */
struct ci13xxx_udc_driver *udc_driver; /* device controller driver */
int vbus_active; /* is VBUS active */
- struct otg_transceiver *transceiver; /* Transceiver struct */
+ struct usb_phy *transceiver; /* Transceiver struct */
};
/******************************************************************************
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index db815c2da7ed..a6dfd2164166 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -39,27 +39,26 @@
#include <linux/usb.h>
#include <linux/usb/gadget.h>
#include <linux/usb/hcd.h>
+#include <linux/scatterlist.h>
#include <asm/byteorder.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
-
#define DRIVER_DESC "USB Host+Gadget Emulator"
#define DRIVER_VERSION "02 May 2005"
#define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */
-static const char driver_name [] = "dummy_hcd";
-static const char driver_desc [] = "USB Host+Gadget Emulator";
+static const char driver_name[] = "dummy_hcd";
+static const char driver_desc[] = "USB Host+Gadget Emulator";
-static const char gadget_name [] = "dummy_udc";
+static const char gadget_name[] = "dummy_udc";
-MODULE_DESCRIPTION (DRIVER_DESC);
-MODULE_AUTHOR ("David Brownell");
-MODULE_LICENSE ("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("David Brownell");
+MODULE_LICENSE("GPL");
struct dummy_hcd_module_parameters {
bool is_super_speed;
@@ -83,10 +82,11 @@ struct dummy_ep {
struct usb_gadget *gadget;
const struct usb_endpoint_descriptor *desc;
struct usb_ep ep;
- unsigned halted : 1;
- unsigned wedged : 1;
- unsigned already_seen : 1;
- unsigned setup_stage : 1;
+ unsigned halted:1;
+ unsigned wedged:1;
+ unsigned already_seen:1;
+ unsigned setup_stage:1;
+ unsigned stream_en:1;
};
struct dummy_request {
@@ -94,15 +94,15 @@ struct dummy_request {
struct usb_request req;
};
-static inline struct dummy_ep *usb_ep_to_dummy_ep (struct usb_ep *_ep)
+static inline struct dummy_ep *usb_ep_to_dummy_ep(struct usb_ep *_ep)
{
- return container_of (_ep, struct dummy_ep, ep);
+ return container_of(_ep, struct dummy_ep, ep);
}
static inline struct dummy_request *usb_request_to_dummy_request
(struct usb_request *_req)
{
- return container_of (_req, struct dummy_request, req);
+ return container_of(_req, struct dummy_request, req);
}
/*-------------------------------------------------------------------------*/
@@ -121,9 +121,9 @@ static inline struct dummy_request *usb_request_to_dummy_request
* configurations, illegal or unsupported packet lengths, and so on.
*/
-static const char ep0name [] = "ep0";
+static const char ep0name[] = "ep0";
-static const char *const ep_name [] = {
+static const char *const ep_name[] = {
ep0name, /* everyone has ep0 */
/* act like a net2280: high speed, six configurable endpoints */
@@ -147,6 +147,8 @@ static const char *const ep_name [] = {
struct urbp {
struct urb *urb;
struct list_head urbp_list;
+ struct sg_mapping_iter miter;
+ u32 miter_started;
};
@@ -166,6 +168,8 @@ struct dummy_hcd {
struct usb_device *udev;
struct list_head urbp_list;
+ u32 stream_en_ep;
+ u8 num_stream[30 / 2];
unsigned active:1;
unsigned old_active:1;
@@ -178,12 +182,12 @@ struct dummy {
/*
* SLAVE/GADGET side support
*/
- struct dummy_ep ep [DUMMY_ENDPOINTS];
+ struct dummy_ep ep[DUMMY_ENDPOINTS];
int address;
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct dummy_request fifo_req;
- u8 fifo_buf [FIFO_SIZE];
+ u8 fifo_buf[FIFO_SIZE];
u16 devstatus;
unsigned udc_suspended:1;
unsigned pullup:1;
@@ -210,14 +214,14 @@ static inline struct device *dummy_dev(struct dummy_hcd *dum)
return dummy_hcd_to_hcd(dum)->self.controller;
}
-static inline struct device *udc_dev (struct dummy *dum)
+static inline struct device *udc_dev(struct dummy *dum)
{
return dum->gadget.dev.parent;
}
-static inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
+static inline struct dummy *ep_to_dummy(struct dummy_ep *ep)
{
- return container_of (ep->gadget, struct dummy, gadget);
+ return container_of(ep->gadget, struct dummy, gadget);
}
static inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)
@@ -229,9 +233,9 @@ static inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)
return dum->hs_hcd;
}
-static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
+static inline struct dummy *gadget_dev_to_dummy(struct device *dev)
{
- return container_of (dev, struct dummy, gadget.dev);
+ return container_of(dev, struct dummy, gadget.dev);
}
static struct dummy the_controller;
@@ -241,24 +245,23 @@ static struct dummy the_controller;
/* SLAVE/GADGET SIDE UTILITY ROUTINES */
/* called with spinlock held */
-static void nuke (struct dummy *dum, struct dummy_ep *ep)
+static void nuke(struct dummy *dum, struct dummy_ep *ep)
{
- while (!list_empty (&ep->queue)) {
+ while (!list_empty(&ep->queue)) {
struct dummy_request *req;
- req = list_entry (ep->queue.next, struct dummy_request, queue);
- list_del_init (&req->queue);
+ req = list_entry(ep->queue.next, struct dummy_request, queue);
+ list_del_init(&req->queue);
req->req.status = -ESHUTDOWN;
- spin_unlock (&dum->lock);
- req->req.complete (&ep->ep, &req->req);
- spin_lock (&dum->lock);
+ spin_unlock(&dum->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&dum->lock);
}
}
/* caller must hold lock */
-static void
-stop_activity (struct dummy *dum)
+static void stop_activity(struct dummy *dum)
{
struct dummy_ep *ep;
@@ -268,8 +271,8 @@ stop_activity (struct dummy *dum)
/* The timer is left running so that outstanding URBs can fail */
/* nuke any pending requests first, so driver i/o is quiesced */
- list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list)
- nuke (dum, ep);
+ list_for_each_entry(ep, &dum->gadget.ep_list, ep.ep_list)
+ nuke(dum, ep);
/* driver now does any non-usb quiescing necessary */
}
@@ -404,8 +407,8 @@ static void set_link_state(struct dummy_hcd *dum_hcd)
#define is_enabled(dum) \
(dum->port_status & USB_PORT_STAT_ENABLE)
-static int
-dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+static int dummy_enable(struct usb_ep *_ep,
+ const struct usb_endpoint_descriptor *desc)
{
struct dummy *dum;
struct dummy_hcd *dum_hcd;
@@ -413,11 +416,11 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
unsigned max;
int retval;
- ep = usb_ep_to_dummy_ep (_ep);
+ ep = usb_ep_to_dummy_ep(_ep);
if (!_ep || !desc || ep->desc || _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT)
return -EINVAL;
- dum = ep_to_dummy (ep);
+ dum = ep_to_dummy(ep);
if (!dum->driver)
return -ESHUTDOWN;
@@ -441,10 +444,10 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
* especially for "ep9out" style fixed function ones.)
*/
retval = -EINVAL;
- switch (desc->bmAttributes & 0x03) {
+ switch (usb_endpoint_type(desc)) {
case USB_ENDPOINT_XFER_BULK:
- if (strstr (ep->ep.name, "-iso")
- || strstr (ep->ep.name, "-int")) {
+ if (strstr(ep->ep.name, "-iso")
+ || strstr(ep->ep.name, "-int")) {
goto done;
}
switch (dum->gadget.speed) {
@@ -466,7 +469,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
}
break;
case USB_ENDPOINT_XFER_INT:
- if (strstr (ep->ep.name, "-iso")) /* bulk is ok */
+ if (strstr(ep->ep.name, "-iso")) /* bulk is ok */
goto done;
/* real hardware might not handle all packet sizes */
switch (dum->gadget.speed) {
@@ -486,8 +489,8 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
}
break;
case USB_ENDPOINT_XFER_ISOC:
- if (strstr (ep->ep.name, "-bulk")
- || strstr (ep->ep.name, "-int"))
+ if (strstr(ep->ep.name, "-bulk")
+ || strstr(ep->ep.name, "-int"))
goto done;
/* real hardware might not handle all packet sizes */
switch (dum->gadget.speed) {
@@ -510,14 +513,22 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
}
_ep->maxpacket = max;
+ if (usb_ss_max_streams(_ep->comp_desc)) {
+ if (!usb_endpoint_xfer_bulk(desc)) {
+ dev_err(udc_dev(dum), "Can't enable stream support on "
+ "non-bulk ep %s\n", _ep->name);
+ return -EINVAL;
+ }
+ ep->stream_en = 1;
+ }
ep->desc = desc;
- dev_dbg (udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n",
+ dev_dbg(udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d stream %s\n",
_ep->name,
desc->bEndpointAddress & 0x0f,
(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
({ char *val;
- switch (desc->bmAttributes & 0x03) {
+ switch (usb_endpoint_type(desc)) {
case USB_ENDPOINT_XFER_BULK:
val = "bulk";
break;
@@ -531,7 +542,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
val = "ctrl";
break;
}; val; }),
- max);
+ max, ep->stream_en ? "enabled" : "disabled");
/* at this point real hardware should be NAKing transfers
* to that endpoint, until a buffer is queued to it.
@@ -542,67 +553,67 @@ done:
return retval;
}
-static int dummy_disable (struct usb_ep *_ep)
+static int dummy_disable(struct usb_ep *_ep)
{
struct dummy_ep *ep;
struct dummy *dum;
unsigned long flags;
int retval;
- ep = usb_ep_to_dummy_ep (_ep);
+ ep = usb_ep_to_dummy_ep(_ep);
if (!_ep || !ep->desc || _ep->name == ep0name)
return -EINVAL;
- dum = ep_to_dummy (ep);
+ dum = ep_to_dummy(ep);
- spin_lock_irqsave (&dum->lock, flags);
+ spin_lock_irqsave(&dum->lock, flags);
ep->desc = NULL;
+ ep->stream_en = 0;
retval = 0;
- nuke (dum, ep);
- spin_unlock_irqrestore (&dum->lock, flags);
+ nuke(dum, ep);
+ spin_unlock_irqrestore(&dum->lock, flags);
- dev_dbg (udc_dev(dum), "disabled %s\n", _ep->name);
+ dev_dbg(udc_dev(dum), "disabled %s\n", _ep->name);
return retval;
}
-static struct usb_request *
-dummy_alloc_request (struct usb_ep *_ep, gfp_t mem_flags)
+static struct usb_request *dummy_alloc_request(struct usb_ep *_ep,
+ gfp_t mem_flags)
{
struct dummy_ep *ep;
struct dummy_request *req;
if (!_ep)
return NULL;
- ep = usb_ep_to_dummy_ep (_ep);
+ ep = usb_ep_to_dummy_ep(_ep);
req = kzalloc(sizeof(*req), mem_flags);
if (!req)
return NULL;
- INIT_LIST_HEAD (&req->queue);
+ INIT_LIST_HEAD(&req->queue);
return &req->req;
}
-static void
-dummy_free_request (struct usb_ep *_ep, struct usb_request *_req)
+static void dummy_free_request(struct usb_ep *_ep, struct usb_request *_req)
{
struct dummy_ep *ep;
struct dummy_request *req;
- ep = usb_ep_to_dummy_ep (_ep);
- if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
+ if (!_ep || !_req)
+ return;
+ ep = usb_ep_to_dummy_ep(_ep);
+ if (!ep->desc && _ep->name != ep0name)
return;
- req = usb_request_to_dummy_request (_req);
- WARN_ON (!list_empty (&req->queue));
- kfree (req);
+ req = usb_request_to_dummy_request(_req);
+ WARN_ON(!list_empty(&req->queue));
+ kfree(req);
}
-static void
-fifo_complete (struct usb_ep *ep, struct usb_request *req)
+static void fifo_complete(struct usb_ep *ep, struct usb_request *req)
{
}
-static int
-dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
+static int dummy_queue(struct usb_ep *_ep, struct usb_request *_req,
gfp_t mem_flags)
{
struct dummy_ep *ep;
@@ -611,49 +622,48 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
struct dummy_hcd *dum_hcd;
unsigned long flags;
- req = usb_request_to_dummy_request (_req);
- if (!_req || !list_empty (&req->queue) || !_req->complete)
+ req = usb_request_to_dummy_request(_req);
+ if (!_req || !list_empty(&req->queue) || !_req->complete)
return -EINVAL;
- ep = usb_ep_to_dummy_ep (_ep);
+ ep = usb_ep_to_dummy_ep(_ep);
if (!_ep || (!ep->desc && _ep->name != ep0name))
return -EINVAL;
- dum = ep_to_dummy (ep);
+ dum = ep_to_dummy(ep);
dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
if (!dum->driver || !is_enabled(dum_hcd))
return -ESHUTDOWN;
#if 0
- dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
+ dev_dbg(udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
ep, _req, _ep->name, _req->length, _req->buf);
#endif
-
_req->status = -EINPROGRESS;
_req->actual = 0;
- spin_lock_irqsave (&dum->lock, flags);
+ spin_lock_irqsave(&dum->lock, flags);
/* implement an emulated single-request FIFO */
if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
- list_empty (&dum->fifo_req.queue) &&
- list_empty (&ep->queue) &&
+ list_empty(&dum->fifo_req.queue) &&
+ list_empty(&ep->queue) &&
_req->length <= FIFO_SIZE) {
req = &dum->fifo_req;
req->req = *_req;
req->req.buf = dum->fifo_buf;
- memcpy (dum->fifo_buf, _req->buf, _req->length);
+ memcpy(dum->fifo_buf, _req->buf, _req->length);
req->req.context = dum;
req->req.complete = fifo_complete;
list_add_tail(&req->queue, &ep->queue);
- spin_unlock (&dum->lock);
+ spin_unlock(&dum->lock);
_req->actual = _req->length;
_req->status = 0;
- _req->complete (_ep, _req);
- spin_lock (&dum->lock);
+ _req->complete(_ep, _req);
+ spin_lock(&dum->lock);
} else
list_add_tail(&req->queue, &ep->queue);
- spin_unlock_irqrestore (&dum->lock, flags);
+ spin_unlock_irqrestore(&dum->lock, flags);
/* real hardware would likely enable transfers here, in case
* it'd been left NAKing.
@@ -661,7 +671,7 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
return 0;
}
-static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
+static int dummy_dequeue(struct usb_ep *_ep, struct usb_request *_req)
{
struct dummy_ep *ep;
struct dummy *dum;
@@ -671,31 +681,31 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
if (!_ep || !_req)
return retval;
- ep = usb_ep_to_dummy_ep (_ep);
- dum = ep_to_dummy (ep);
+ ep = usb_ep_to_dummy_ep(_ep);
+ dum = ep_to_dummy(ep);
if (!dum->driver)
return -ESHUTDOWN;
- local_irq_save (flags);
- spin_lock (&dum->lock);
- list_for_each_entry (req, &ep->queue, queue) {
+ local_irq_save(flags);
+ spin_lock(&dum->lock);
+ list_for_each_entry(req, &ep->queue, queue) {
if (&req->req == _req) {
- list_del_init (&req->queue);
+ list_del_init(&req->queue);
_req->status = -ECONNRESET;
retval = 0;
break;
}
}
- spin_unlock (&dum->lock);
+ spin_unlock(&dum->lock);
if (retval == 0) {
- dev_dbg (udc_dev(dum),
+ dev_dbg(udc_dev(dum),
"dequeued req %p from %s, len %d buf %p\n",
req, _ep->name, _req->length, _req->buf);
- _req->complete (_ep, _req);
+ _req->complete(_ep, _req);
}
- local_irq_restore (flags);
+ local_irq_restore(flags);
return retval;
}
@@ -707,14 +717,14 @@ dummy_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
if (!_ep)
return -EINVAL;
- ep = usb_ep_to_dummy_ep (_ep);
- dum = ep_to_dummy (ep);
+ ep = usb_ep_to_dummy_ep(_ep);
+ dum = ep_to_dummy(ep);
if (!dum->driver)
return -ESHUTDOWN;
if (!value)
ep->halted = ep->wedged = 0;
else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
- !list_empty (&ep->queue))
+ !list_empty(&ep->queue))
return -EAGAIN;
else {
ep->halted = 1;
@@ -755,15 +765,15 @@ static const struct usb_ep_ops dummy_ep_ops = {
/*-------------------------------------------------------------------------*/
/* there are both host and device side versions of this call ... */
-static int dummy_g_get_frame (struct usb_gadget *_gadget)
+static int dummy_g_get_frame(struct usb_gadget *_gadget)
{
struct timeval tv;
- do_gettimeofday (&tv);
+ do_gettimeofday(&tv);
return tv.tv_usec / 1000;
}
-static int dummy_wakeup (struct usb_gadget *_gadget)
+static int dummy_wakeup(struct usb_gadget *_gadget)
{
struct dummy_hcd *dum_hcd;
@@ -786,11 +796,11 @@ static int dummy_wakeup (struct usb_gadget *_gadget)
return 0;
}
-static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
+static int dummy_set_selfpowered(struct usb_gadget *_gadget, int value)
{
struct dummy *dum;
- dum = (gadget_to_dummy_hcd(_gadget))->dum;
+ dum = gadget_to_dummy_hcd(_gadget)->dum;
if (value)
dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
else
@@ -798,22 +808,15 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
return 0;
}
-static void dummy_udc_udpate_ep0(struct dummy *dum)
+static void dummy_udc_update_ep0(struct dummy *dum)
{
- u32 i;
-
- if (dum->gadget.speed == USB_SPEED_SUPER) {
- for (i = 0; i < DUMMY_ENDPOINTS; i++)
- dum->ep[i].ep.max_streams = 0x10;
+ if (dum->gadget.speed == USB_SPEED_SUPER)
dum->ep[0].ep.maxpacket = 9;
- } else {
- for (i = 0; i < DUMMY_ENDPOINTS; i++)
- dum->ep[i].ep.max_streams = 0;
+ else
dum->ep[0].ep.maxpacket = 64;
- }
}
-static int dummy_pullup (struct usb_gadget *_gadget, int value)
+static int dummy_pullup(struct usb_gadget *_gadget, int value)
{
struct dummy_hcd *dum_hcd;
struct dummy *dum;
@@ -829,7 +832,7 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value)
dum->driver->max_speed);
else
dum->gadget.speed = USB_SPEED_FULL;
- dummy_udc_udpate_ep0(dum);
+ dummy_udc_update_ep0(dum);
if (dum->gadget.speed < dum->driver->max_speed)
dev_dbg(udc_dev(dum), "This device can perform faster"
@@ -838,10 +841,10 @@ static int dummy_pullup (struct usb_gadget *_gadget, int value)
}
dum_hcd = gadget_to_dummy_hcd(_gadget);
- spin_lock_irqsave (&dum->lock, flags);
+ spin_lock_irqsave(&dum->lock, flags);
dum->pullup = (value != 0);
set_link_state(dum_hcd);
- spin_unlock_irqrestore (&dum->lock, flags);
+ spin_unlock_irqrestore(&dum->lock, flags);
usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
return 0;
@@ -864,16 +867,16 @@ static const struct usb_gadget_ops dummy_ops = {
/*-------------------------------------------------------------------------*/
/* "function" sysfs attribute */
-static ssize_t
-show_function (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_function(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- struct dummy *dum = gadget_dev_to_dummy (dev);
+ struct dummy *dum = gadget_dev_to_dummy(dev);
if (!dum->driver || !dum->driver->function)
return 0;
- return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function);
+ return scnprintf(buf, PAGE_SIZE, "%s\n", dum->driver->function);
}
-static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
+static DEVICE_ATTR(function, S_IRUGO, show_function, NULL);
/*-------------------------------------------------------------------------*/
@@ -908,7 +911,7 @@ static int dummy_udc_start(struct usb_gadget *g,
dum->devstatus = 0;
dum->driver = driver;
- dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
+ dev_dbg(udc_dev(dum), "binding gadget driver '%s'\n",
driver->driver.name);
return 0;
}
@@ -919,7 +922,7 @@ static int dummy_udc_stop(struct usb_gadget *g,
struct dummy_hcd *dum_hcd = gadget_to_dummy_hcd(g);
struct dummy *dum = dum_hcd->dum;
- dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
+ dev_dbg(udc_dev(dum), "unregister gadget driver '%s'\n",
driver->driver.name);
dum->driver = NULL;
@@ -932,8 +935,7 @@ static int dummy_udc_stop(struct usb_gadget *g,
/* The gadget structure is stored inside the hcd structure and will be
* released along with it. */
-static void
-dummy_gadget_release (struct device *dev)
+static void dummy_gadget_release(struct device *dev)
{
return;
}
@@ -954,6 +956,7 @@ static void init_dummy_udc_hw(struct dummy *dum)
ep->halted = ep->wedged = ep->already_seen =
ep->setup_stage = 0;
ep->ep.maxpacket = ~0;
+ ep->ep.max_streams = 16;
ep->last_io = jiffies;
ep->gadget = &dum->gadget;
ep->desc = NULL;
@@ -969,7 +972,7 @@ static void init_dummy_udc_hw(struct dummy *dum)
#endif
}
-static int dummy_udc_probe (struct platform_device *pdev)
+static int dummy_udc_probe(struct platform_device *pdev)
{
struct dummy *dum = &the_controller;
int rc;
@@ -981,7 +984,7 @@ static int dummy_udc_probe (struct platform_device *pdev)
dev_set_name(&dum->gadget.dev, "gadget");
dum->gadget.dev.parent = &pdev->dev;
dum->gadget.dev.release = dummy_gadget_release;
- rc = device_register (&dum->gadget.dev);
+ rc = device_register(&dum->gadget.dev);
if (rc < 0) {
put_device(&dum->gadget.dev);
return rc;
@@ -993,7 +996,7 @@ static int dummy_udc_probe (struct platform_device *pdev)
if (rc < 0)
goto err_udc;
- rc = device_create_file (&dum->gadget.dev, &dev_attr_function);
+ rc = device_create_file(&dum->gadget.dev, &dev_attr_function);
if (rc < 0)
goto err_dev;
platform_set_drvdata(pdev, dum);
@@ -1006,14 +1009,14 @@ err_udc:
return rc;
}
-static int dummy_udc_remove (struct platform_device *pdev)
+static int dummy_udc_remove(struct platform_device *pdev)
{
- struct dummy *dum = platform_get_drvdata (pdev);
+ struct dummy *dum = platform_get_drvdata(pdev);
usb_del_gadget_udc(&dum->gadget);
- platform_set_drvdata (pdev, NULL);
- device_remove_file (&dum->gadget.dev, &dev_attr_function);
- device_unregister (&dum->gadget.dev);
+ platform_set_drvdata(pdev, NULL);
+ device_remove_file(&dum->gadget.dev, &dev_attr_function);
+ device_unregister(&dum->gadget.dev);
return 0;
}
@@ -1061,6 +1064,16 @@ static struct platform_driver dummy_udc_driver = {
/*-------------------------------------------------------------------------*/
+static unsigned int dummy_get_ep_idx(const struct usb_endpoint_descriptor *desc)
+{
+ unsigned int index;
+
+ index = usb_endpoint_num(desc) << 1;
+ if (usb_endpoint_dir_in(desc))
+ index |= 1;
+ return index;
+}
+
/* MASTER/HOST SIDE DRIVER
*
* this uses the hcd framework to hook up to host side drivers.
@@ -1073,7 +1086,82 @@ static struct platform_driver dummy_udc_driver = {
* usb 2.0 rules.
*/
-static int dummy_urb_enqueue (
+static int dummy_ep_stream_en(struct dummy_hcd *dum_hcd, struct urb *urb)
+{
+ const struct usb_endpoint_descriptor *desc = &urb->ep->desc;
+ u32 index;
+
+ if (!usb_endpoint_xfer_bulk(desc))
+ return 0;
+
+ index = dummy_get_ep_idx(desc);
+ return (1 << index) & dum_hcd->stream_en_ep;
+}
+
+/*
+ * The max stream number is saved as a nibble so for the 30 possible endpoints
+ * we only 15 bytes of memory. Therefore we are limited to max 16 streams (0
+ * means we use only 1 stream). The maximum according to the spec is 16bit so
+ * if the 16 stream limit is about to go, the array size should be incremented
+ * to 30 elements of type u16.
+ */
+static int get_max_streams_for_pipe(struct dummy_hcd *dum_hcd,
+ unsigned int pipe)
+{
+ int max_streams;
+
+ max_streams = dum_hcd->num_stream[usb_pipeendpoint(pipe)];
+ if (usb_pipeout(pipe))
+ max_streams >>= 4;
+ else
+ max_streams &= 0xf;
+ max_streams++;
+ return max_streams;
+}
+
+static void set_max_streams_for_pipe(struct dummy_hcd *dum_hcd,
+ unsigned int pipe, unsigned int streams)
+{
+ int max_streams;
+
+ streams--;
+ max_streams = dum_hcd->num_stream[usb_pipeendpoint(pipe)];
+ if (usb_pipeout(pipe)) {
+ streams <<= 4;
+ max_streams &= 0xf;
+ } else {
+ max_streams &= 0xf0;
+ }
+ max_streams |= streams;
+ dum_hcd->num_stream[usb_pipeendpoint(pipe)] = max_streams;
+}
+
+static int dummy_validate_stream(struct dummy_hcd *dum_hcd, struct urb *urb)
+{
+ unsigned int max_streams;
+ int enabled;
+
+ enabled = dummy_ep_stream_en(dum_hcd, urb);
+ if (!urb->stream_id) {
+ if (enabled)
+ return -EINVAL;
+ return 0;
+ }
+ if (!enabled)
+ return -EINVAL;
+
+ max_streams = get_max_streams_for_pipe(dum_hcd,
+ usb_pipeendpoint(urb->pipe));
+ if (urb->stream_id > max_streams) {
+ dev_err(dummy_dev(dum_hcd), "Stream id %d is out of range.\n",
+ urb->stream_id);
+ BUG();
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int dummy_urb_enqueue(
struct usb_hcd *hcd,
struct urb *urb,
gfp_t mem_flags
@@ -1083,16 +1171,21 @@ static int dummy_urb_enqueue (
unsigned long flags;
int rc;
- if (!urb->transfer_buffer && urb->transfer_buffer_length)
- return -EINVAL;
-
- urbp = kmalloc (sizeof *urbp, mem_flags);
+ urbp = kmalloc(sizeof *urbp, mem_flags);
if (!urbp)
return -ENOMEM;
urbp->urb = urb;
+ urbp->miter_started = 0;
dum_hcd = hcd_to_dummy_hcd(hcd);
spin_lock_irqsave(&dum_hcd->dum->lock, flags);
+
+ rc = dummy_validate_stream(dum_hcd, urb);
+ if (rc) {
+ kfree(urbp);
+ goto done;
+ }
+
rc = usb_hcd_link_urb_to_ep(hcd, urb);
if (rc) {
kfree(urbp);
@@ -1107,7 +1200,7 @@ static int dummy_urb_enqueue (
list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
urb->hcpriv = urbp;
- if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
+ if (usb_pipetype(urb->pipe) == PIPE_CONTROL)
urb->error_count = 1; /* mark as a new urb */
/* kick the scheduler, it'll do the rest */
@@ -1139,20 +1232,91 @@ static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
return rc;
}
+static int dummy_perform_transfer(struct urb *urb, struct dummy_request *req,
+ u32 len)
+{
+ void *ubuf, *rbuf;
+ struct urbp *urbp = urb->hcpriv;
+ int to_host;
+ struct sg_mapping_iter *miter = &urbp->miter;
+ u32 trans = 0;
+ u32 this_sg;
+ bool next_sg;
+
+ to_host = usb_pipein(urb->pipe);
+ rbuf = req->req.buf + req->req.actual;
+
+ if (!urb->num_sgs) {
+ ubuf = urb->transfer_buffer + urb->actual_length;
+ if (to_host)
+ memcpy(ubuf, rbuf, len);
+ else
+ memcpy(rbuf, ubuf, len);
+ return len;
+ }
+
+ if (!urbp->miter_started) {
+ u32 flags = SG_MITER_ATOMIC;
+
+ if (to_host)
+ flags |= SG_MITER_TO_SG;
+ else
+ flags |= SG_MITER_FROM_SG;
+
+ sg_miter_start(miter, urb->sg, urb->num_sgs, flags);
+ urbp->miter_started = 1;
+ }
+ next_sg = sg_miter_next(miter);
+ if (next_sg == false) {
+ WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
+ do {
+ ubuf = miter->addr;
+ this_sg = min_t(u32, len, miter->length);
+ miter->consumed = this_sg;
+ trans += this_sg;
+
+ if (to_host)
+ memcpy(ubuf, rbuf, this_sg);
+ else
+ memcpy(rbuf, ubuf, this_sg);
+ len -= this_sg;
+
+ if (!len)
+ break;
+ next_sg = sg_miter_next(miter);
+ if (next_sg == false) {
+ WARN_ON_ONCE(1);
+ return -EINVAL;
+ }
+
+ rbuf += this_sg;
+ } while (1);
+
+ sg_miter_stop(miter);
+ return trans;
+}
+
/* transfer up to a frame's worth; caller must own lock */
-static int
-transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit,
- int *status)
+static int transfer(struct dummy_hcd *dum_hcd, struct urb *urb,
+ struct dummy_ep *ep, int limit, int *status)
{
+ struct dummy *dum = dum_hcd->dum;
struct dummy_request *req;
top:
/* if there's no request queued, the device is NAKing; return */
- list_for_each_entry (req, &ep->queue, queue) {
+ list_for_each_entry(req, &ep->queue, queue) {
unsigned host_len, dev_len, len;
int is_short, to_host;
int rescan = 0;
+ if (dummy_ep_stream_en(dum_hcd, urb)) {
+ if ((urb->stream_id != req->req.stream_id))
+ continue;
+ }
+
/* 1..N packets of ep->ep.maxpacket each ... the last one
* may be short (including zero length).
*
@@ -1162,20 +1326,18 @@ top:
*/
host_len = urb->transfer_buffer_length - urb->actual_length;
dev_len = req->req.length - req->req.actual;
- len = min (host_len, dev_len);
+ len = min(host_len, dev_len);
/* FIXME update emulated data toggle too */
- to_host = usb_pipein (urb->pipe);
- if (unlikely (len == 0))
+ to_host = usb_pipein(urb->pipe);
+ if (unlikely(len == 0))
is_short = 1;
else {
- char *ubuf, *rbuf;
-
/* not enough bandwidth left? */
if (limit < ep->ep.maxpacket && limit < len)
break;
- len = min (len, (unsigned) limit);
+ len = min_t(unsigned, len, limit);
if (len == 0)
break;
@@ -1186,18 +1348,16 @@ top:
}
is_short = (len % ep->ep.maxpacket) != 0;
- /* else transfer packet(s) */
- ubuf = urb->transfer_buffer + urb->actual_length;
- rbuf = req->req.buf + req->req.actual;
- if (to_host)
- memcpy (ubuf, rbuf, len);
- else
- memcpy (rbuf, ubuf, len);
- ep->last_io = jiffies;
+ len = dummy_perform_transfer(urb, req, len);
- limit -= len;
- urb->actual_length += len;
- req->req.actual += len;
+ ep->last_io = jiffies;
+ if ((int)len < 0) {
+ req->req.status = len;
+ } else {
+ limit -= len;
+ urb->actual_length += len;
+ req->req.actual += len;
+ }
}
/* short packets terminate, maybe with overflow/underflow.
@@ -1238,11 +1398,11 @@ top:
/* device side completion --> continuable */
if (req->req.status != -EINPROGRESS) {
- list_del_init (&req->queue);
+ list_del_init(&req->queue);
- spin_unlock (&dum->lock);
- req->req.complete (&ep->ep, &req->req);
- spin_lock (&dum->lock);
+ spin_unlock(&dum->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&dum->lock);
/* requests might have been unlinked... */
rescan = 1;
@@ -1259,7 +1419,7 @@ top:
return limit;
}
-static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
+static int periodic_bytes(struct dummy *dum, struct dummy_ep *ep)
{
int limit = ep->ep.maxpacket;
@@ -1273,7 +1433,7 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
limit += limit * tmp;
}
if (dum->gadget.speed == USB_SPEED_SUPER) {
- switch (ep->desc->bmAttributes & 0x03) {
+ switch (usb_endpoint_type(ep->desc)) {
case USB_ENDPOINT_XFER_ISOC:
/* Sec. 4.4.8.2 USB3.0 Spec */
limit = 3 * 16 * 1024 * 8;
@@ -1295,7 +1455,7 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
USB_PORT_STAT_SUSPEND)) \
== (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
-static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
+static struct dummy_ep *find_endpoint(struct dummy *dum, u8 address)
{
int i;
@@ -1303,9 +1463,9 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
dum->ss_hcd : dum->hs_hcd)))
return NULL;
if ((address & ~USB_DIR_IN) == 0)
- return &dum->ep [0];
+ return &dum->ep[0];
for (i = 1; i < DUMMY_ENDPOINTS; i++) {
- struct dummy_ep *ep = &dum->ep [i];
+ struct dummy_ep *ep = &dum->ep[i];
if (!ep->desc)
continue;
@@ -1535,19 +1695,19 @@ static void dummy_timer(unsigned long _dum_hcd)
/* FIXME if HZ != 1000 this will probably misbehave ... */
/* look at each urb queued by the host side driver */
- spin_lock_irqsave (&dum->lock, flags);
+ spin_lock_irqsave(&dum->lock, flags);
if (!dum_hcd->udev) {
dev_err(dummy_dev(dum_hcd),
"timer fired with no URBs pending?\n");
- spin_unlock_irqrestore (&dum->lock, flags);
+ spin_unlock_irqrestore(&dum->lock, flags);
return;
}
for (i = 0; i < DUMMY_ENDPOINTS; i++) {
- if (!ep_name [i])
+ if (!ep_name[i])
break;
- dum->ep [i].already_seen = 0;
+ dum->ep[i].already_seen = 0;
}
restart:
@@ -1564,7 +1724,7 @@ restart:
goto return_urb;
else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)
continue;
- type = usb_pipetype (urb->pipe);
+ type = usb_pipetype(urb->pipe);
/* used up this frame's non-periodic bandwidth?
* FIXME there's infinite bandwidth for control and
@@ -1575,7 +1735,7 @@ restart:
/* find the gadget's ep for this request (if configured) */
address = usb_pipeendpoint (urb->pipe);
- if (usb_pipein (urb->pipe))
+ if (usb_pipein(urb->pipe))
address |= USB_DIR_IN;
ep = find_endpoint(dum, address);
if (!ep) {
@@ -1590,7 +1750,7 @@ restart:
if (ep->already_seen)
continue;
ep->already_seen = 1;
- if (ep == &dum->ep [0] && urb->error_count) {
+ if (ep == &dum->ep[0] && urb->error_count) {
ep->setup_stage = 1; /* a new urb */
urb->error_count = 0;
}
@@ -1604,21 +1764,21 @@ restart:
/* FIXME make sure both ends agree on maxpacket */
/* handle control requests */
- if (ep == &dum->ep [0] && ep->setup_stage) {
+ if (ep == &dum->ep[0] && ep->setup_stage) {
struct usb_ctrlrequest setup;
int value = 1;
- setup = *(struct usb_ctrlrequest*) urb->setup_packet;
+ setup = *(struct usb_ctrlrequest *) urb->setup_packet;
/* paranoia, in case of stale queued data */
- list_for_each_entry (req, &ep->queue, queue) {
- list_del_init (&req->queue);
+ list_for_each_entry(req, &ep->queue, queue) {
+ list_del_init(&req->queue);
req->req.status = -EOVERFLOW;
- dev_dbg (udc_dev(dum), "stale req = %p\n",
+ dev_dbg(udc_dev(dum), "stale req = %p\n",
req);
- spin_unlock (&dum->lock);
- req->req.complete (&ep->ep, &req->req);
- spin_lock (&dum->lock);
+ spin_unlock(&dum->lock);
+ req->req.complete(&ep->ep, &req->req);
+ spin_lock(&dum->lock);
ep->already_seen = 0;
goto restart;
}
@@ -1638,10 +1798,10 @@ restart:
* until setup() returns; no reentrancy issues etc.
*/
if (value > 0) {
- spin_unlock (&dum->lock);
- value = dum->driver->setup (&dum->gadget,
+ spin_unlock(&dum->lock);
+ value = dum->driver->setup(&dum->gadget,
&setup);
- spin_lock (&dum->lock);
+ spin_lock(&dum->lock);
if (value >= 0) {
/* no delays (max 64KB data stage) */
@@ -1653,7 +1813,7 @@ restart:
if (value < 0) {
if (value != -EOPNOTSUPP)
- dev_dbg (udc_dev(dum),
+ dev_dbg(udc_dev(dum),
"setup --> %d\n",
value);
status = -EPIPE;
@@ -1665,14 +1825,14 @@ restart:
/* non-control requests */
limit = total;
- switch (usb_pipetype (urb->pipe)) {
+ switch (usb_pipetype(urb->pipe)) {
case PIPE_ISOCHRONOUS:
/* FIXME is it urb->interval since the last xfer?
* use urb->iso_frame_desc[i].
* complete whether or not ep has requests queued.
* report random errors, to debug drivers.
*/
- limit = max (limit, periodic_bytes (dum, ep));
+ limit = max(limit, periodic_bytes(dum, ep));
status = -ENOSYS;
break;
@@ -1680,14 +1840,13 @@ restart:
/* FIXME is it urb->interval since the last xfer?
* this almost certainly polls too fast.
*/
- limit = max (limit, periodic_bytes (dum, ep));
+ limit = max(limit, periodic_bytes(dum, ep));
/* FALLTHROUGH */
- // case PIPE_BULK: case PIPE_CONTROL:
default:
- treat_control_like_bulk:
+treat_control_like_bulk:
ep->last_io = jiffies;
- total = transfer(dum, urb, ep, limit, &status);
+ total = transfer(dum_hcd, urb, ep, limit, &status);
break;
}
@@ -1696,15 +1855,15 @@ restart:
continue;
return_urb:
- list_del (&urbp->urbp_list);
- kfree (urbp);
+ list_del(&urbp->urbp_list);
+ kfree(urbp);
if (ep)
ep->already_seen = ep->setup_stage = 0;
usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb);
- spin_unlock (&dum->lock);
+ spin_unlock(&dum->lock);
usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status);
- spin_lock (&dum->lock);
+ spin_lock(&dum->lock);
goto restart;
}
@@ -1717,7 +1876,7 @@ return_urb:
mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1));
}
- spin_unlock_irqrestore (&dum->lock, flags);
+ spin_unlock_irqrestore(&dum->lock, flags);
}
/*-------------------------------------------------------------------------*/
@@ -1729,7 +1888,7 @@ return_urb:
| USB_PORT_STAT_C_OVERCURRENT \
| USB_PORT_STAT_C_RESET) << 16)
-static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
+static int dummy_hub_status(struct usb_hcd *hcd, char *buf)
{
struct dummy_hcd *dum_hcd;
unsigned long flags;
@@ -1753,7 +1912,7 @@ static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
dum_hcd->port_status);
retval = 1;
if (dum_hcd->rh_state == DUMMY_RH_SUSPENDED)
- usb_hcd_resume_root_hub (hcd);
+ usb_hcd_resume_root_hub(hcd);
}
done:
spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
@@ -1772,10 +1931,9 @@ ss_hub_descriptor(struct usb_hub_descriptor *desc)
desc->u.ss.DeviceRemovable = 0xffff;
}
-static inline void
-hub_descriptor (struct usb_hub_descriptor *desc)
+static inline void hub_descriptor(struct usb_hub_descriptor *desc)
{
- memset (desc, 0, sizeof *desc);
+ memset(desc, 0, sizeof *desc);
desc->bDescriptorType = 0x29;
desc->bDescLength = 9;
desc->wHubCharacteristics = cpu_to_le16(0x0001);
@@ -1784,7 +1942,7 @@ hub_descriptor (struct usb_hub_descriptor *desc)
desc->u.hs.DeviceRemovable[1] = 0xff;
}
-static int dummy_hub_control (
+static int dummy_hub_control(
struct usb_hcd *hcd,
u16 typeReq,
u16 wValue,
@@ -1852,7 +2010,7 @@ static int dummy_hub_control (
hub_descriptor((struct usb_hub_descriptor *) buf);
break;
case GetHubStatus:
- *(__le32 *) buf = cpu_to_le32 (0);
+ *(__le32 *) buf = cpu_to_le32(0);
break;
case GetPortStatus:
if (wIndex != 1)
@@ -1894,8 +2052,8 @@ static int dummy_hub_control (
}
}
set_link_state(dum_hcd);
- ((__le16 *) buf)[0] = cpu_to_le16 (dum_hcd->port_status);
- ((__le16 *) buf)[1] = cpu_to_le16 (dum_hcd->port_status >> 16);
+ ((__le16 *) buf)[0] = cpu_to_le16(dum_hcd->port_status);
+ ((__le16 *) buf)[1] = cpu_to_le16(dum_hcd->port_status >> 16);
break;
case SetHubFeature:
retval = -EPIPE;
@@ -2029,15 +2187,15 @@ error:
spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
if ((dum_hcd->port_status & PORT_C_MASK) != 0)
- usb_hcd_poll_rh_status (hcd);
+ usb_hcd_poll_rh_status(hcd);
return retval;
}
-static int dummy_bus_suspend (struct usb_hcd *hcd)
+static int dummy_bus_suspend(struct usb_hcd *hcd)
{
struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
- dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
+ dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
spin_lock_irq(&dum_hcd->dum->lock);
dum_hcd->rh_state = DUMMY_RH_SUSPENDED;
@@ -2047,12 +2205,12 @@ static int dummy_bus_suspend (struct usb_hcd *hcd)
return 0;
}
-static int dummy_bus_resume (struct usb_hcd *hcd)
+static int dummy_bus_resume(struct usb_hcd *hcd)
{
struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
int rc = 0;
- dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
+ dev_dbg(&hcd->self.root_hub->dev, "%s\n", __func__);
spin_lock_irq(&dum_hcd->dum->lock);
if (!HCD_HW_ACCESSIBLE(hcd)) {
@@ -2070,55 +2228,54 @@ static int dummy_bus_resume (struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
-static inline ssize_t
-show_urb (char *buf, size_t size, struct urb *urb)
+static inline ssize_t show_urb(char *buf, size_t size, struct urb *urb)
{
- int ep = usb_pipeendpoint (urb->pipe);
+ int ep = usb_pipeendpoint(urb->pipe);
- return snprintf (buf, size,
+ return snprintf(buf, size,
"urb/%p %s ep%d%s%s len %d/%d\n",
urb,
({ char *s;
- switch (urb->dev->speed) {
- case USB_SPEED_LOW:
+ switch (urb->dev->speed) {
+ case USB_SPEED_LOW:
s = "ls";
break;
- case USB_SPEED_FULL:
+ case USB_SPEED_FULL:
s = "fs";
break;
- case USB_SPEED_HIGH:
+ case USB_SPEED_HIGH:
s = "hs";
break;
- case USB_SPEED_SUPER:
+ case USB_SPEED_SUPER:
s = "ss";
break;
- default:
+ default:
s = "?";
break;
}; s; }),
- ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
+ ep, ep ? (usb_pipein(urb->pipe) ? "in" : "out") : "",
({ char *s; \
- switch (usb_pipetype (urb->pipe)) { \
- case PIPE_CONTROL: \
+ switch (usb_pipetype(urb->pipe)) { \
+ case PIPE_CONTROL: \
s = ""; \
break; \
- case PIPE_BULK: \
+ case PIPE_BULK: \
s = "-bulk"; \
break; \
- case PIPE_INTERRUPT: \
+ case PIPE_INTERRUPT: \
s = "-int"; \
break; \
- default: \
+ default: \
s = "-iso"; \
break; \
- }; s;}),
+ }; s; }),
urb->actual_length, urb->transfer_buffer_length);
}
-static ssize_t
-show_urbs (struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t show_urbs(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
- struct usb_hcd *hcd = dev_get_drvdata (dev);
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
struct urbp *urbp;
size_t size = 0;
@@ -2128,7 +2285,7 @@ show_urbs (struct device *dev, struct device_attribute *attr, char *buf)
list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) {
size_t temp;
- temp = show_urb (buf, PAGE_SIZE - size, urbp->urb);
+ temp = show_urb(buf, PAGE_SIZE - size, urbp->urb);
buf += temp;
size += temp;
}
@@ -2136,7 +2293,7 @@ show_urbs (struct device *dev, struct device_attribute *attr, char *buf)
return size;
}
-static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
+static DEVICE_ATTR(urbs, S_IRUGO, show_urbs, NULL);
static int dummy_start_ss(struct dummy_hcd *dum_hcd)
{
@@ -2144,6 +2301,7 @@ static int dummy_start_ss(struct dummy_hcd *dum_hcd)
dum_hcd->timer.function = dummy_timer;
dum_hcd->timer.data = (unsigned long)dum_hcd;
dum_hcd->rh_state = DUMMY_RH_RUNNING;
+ dum_hcd->stream_en_ep = 0;
INIT_LIST_HEAD(&dum_hcd->urbp_list);
dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET;
dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING;
@@ -2189,11 +2347,11 @@ static int dummy_start(struct usb_hcd *hcd)
return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
}
-static void dummy_stop (struct usb_hcd *hcd)
+static void dummy_stop(struct usb_hcd *hcd)
{
struct dummy *dum;
- dum = (hcd_to_dummy_hcd(hcd))->dum;
+ dum = hcd_to_dummy_hcd(hcd)->dum;
device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs);
usb_gadget_unregister_driver(dum->driver);
dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");
@@ -2201,13 +2359,14 @@ static void dummy_stop (struct usb_hcd *hcd)
/*-------------------------------------------------------------------------*/
-static int dummy_h_get_frame (struct usb_hcd *hcd)
+static int dummy_h_get_frame(struct usb_hcd *hcd)
{
- return dummy_g_get_frame (NULL);
+ return dummy_g_get_frame(NULL);
}
static int dummy_setup(struct usb_hcd *hcd)
{
+ hcd->self.sg_tablesize = ~0;
if (usb_hcd_is_primary_hcd(hcd)) {
the_controller.hs_hcd = hcd_to_dummy_hcd(hcd);
the_controller.hs_hcd->dum = &the_controller;
@@ -2228,27 +2387,82 @@ static int dummy_setup(struct usb_hcd *hcd)
}
/* Change a group of bulk endpoints to support multiple stream IDs */
-int dummy_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
+static int dummy_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
struct usb_host_endpoint **eps, unsigned int num_eps,
unsigned int num_streams, gfp_t mem_flags)
{
- if (hcd->speed != HCD_USB3)
- dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)),
- "%s() - ERROR! Not supported for USB2.0 roothub\n",
- __func__);
- return 0;
+ struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
+ unsigned long flags;
+ int max_stream;
+ int ret_streams = num_streams;
+ unsigned int index;
+ unsigned int i;
+
+ if (!num_eps)
+ return -EINVAL;
+
+ spin_lock_irqsave(&dum_hcd->dum->lock, flags);
+ for (i = 0; i < num_eps; i++) {
+ index = dummy_get_ep_idx(&eps[i]->desc);
+ if ((1 << index) & dum_hcd->stream_en_ep) {
+ ret_streams = -EINVAL;
+ goto out;
+ }
+ max_stream = usb_ss_max_streams(&eps[i]->ss_ep_comp);
+ if (!max_stream) {
+ ret_streams = -EINVAL;
+ goto out;
+ }
+ if (max_stream < ret_streams) {
+ dev_dbg(dummy_dev(dum_hcd), "Ep 0x%x only supports %u "
+ "stream IDs.\n",
+ eps[i]->desc.bEndpointAddress,
+ max_stream);
+ ret_streams = max_stream;
+ }
+ }
+
+ for (i = 0; i < num_eps; i++) {
+ index = dummy_get_ep_idx(&eps[i]->desc);
+ dum_hcd->stream_en_ep |= 1 << index;
+ set_max_streams_for_pipe(dum_hcd,
+ usb_endpoint_num(&eps[i]->desc), ret_streams);
+ }
+out:
+ spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
+ return ret_streams;
}
/* Reverts a group of bulk endpoints back to not using stream IDs. */
-int dummy_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
+static int dummy_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
struct usb_host_endpoint **eps, unsigned int num_eps,
gfp_t mem_flags)
{
- if (hcd->speed != HCD_USB3)
- dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)),
- "%s() - ERROR! Not supported for USB2.0 roothub\n",
- __func__);
- return 0;
+ struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
+ unsigned long flags;
+ int ret;
+ unsigned int index;
+ unsigned int i;
+
+ spin_lock_irqsave(&dum_hcd->dum->lock, flags);
+ for (i = 0; i < num_eps; i++) {
+ index = dummy_get_ep_idx(&eps[i]->desc);
+ if (!((1 << index) & dum_hcd->stream_en_ep)) {
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+ for (i = 0; i < num_eps; i++) {
+ index = dummy_get_ep_idx(&eps[i]->desc);
+ dum_hcd->stream_en_ep &= ~(1 << index);
+ set_max_streams_for_pipe(dum_hcd,
+ usb_endpoint_num(&eps[i]->desc), 0);
+ }
+ ret = 0;
+out:
+ spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
+ return ret;
}
static struct hc_driver dummy_hcd = {
@@ -2262,13 +2476,13 @@ static struct hc_driver dummy_hcd = {
.start = dummy_start,
.stop = dummy_stop,
- .urb_enqueue = dummy_urb_enqueue,
- .urb_dequeue = dummy_urb_dequeue,
+ .urb_enqueue = dummy_urb_enqueue,
+ .urb_dequeue = dummy_urb_dequeue,
- .get_frame_number = dummy_h_get_frame,
+ .get_frame_number = dummy_h_get_frame,
- .hub_status_data = dummy_hub_status,
- .hub_control = dummy_hub_control,
+ .hub_status_data = dummy_hub_status,
+ .hub_control = dummy_hub_control,
.bus_suspend = dummy_bus_suspend,
.bus_resume = dummy_bus_resume,
@@ -2323,7 +2537,7 @@ static int dummy_hcd_remove(struct platform_device *pdev)
{
struct dummy *dum;
- dum = (hcd_to_dummy_hcd(platform_get_drvdata(pdev)))->dum;
+ dum = hcd_to_dummy_hcd(platform_get_drvdata(pdev))->dum;
if (dum->ss_hcd) {
usb_remove_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
@@ -2339,15 +2553,15 @@ static int dummy_hcd_remove(struct platform_device *pdev)
return 0;
}
-static int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
+static int dummy_hcd_suspend(struct platform_device *pdev, pm_message_t state)
{
struct usb_hcd *hcd;
struct dummy_hcd *dum_hcd;
int rc = 0;
- dev_dbg (&pdev->dev, "%s\n", __func__);
+ dev_dbg(&pdev->dev, "%s\n", __func__);
- hcd = platform_get_drvdata (pdev);
+ hcd = platform_get_drvdata(pdev);
dum_hcd = hcd_to_dummy_hcd(hcd);
if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
dev_warn(&pdev->dev, "Root hub isn't suspended!\n");
@@ -2357,15 +2571,15 @@ static int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
return rc;
}
-static int dummy_hcd_resume (struct platform_device *pdev)
+static int dummy_hcd_resume(struct platform_device *pdev)
{
struct usb_hcd *hcd;
- dev_dbg (&pdev->dev, "%s\n", __func__);
+ dev_dbg(&pdev->dev, "%s\n", __func__);
- hcd = platform_get_drvdata (pdev);
+ hcd = platform_get_drvdata(pdev);
set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
- usb_hcd_poll_rh_status (hcd);
+ usb_hcd_poll_rh_status(hcd);
return 0;
}
@@ -2385,11 +2599,11 @@ static struct platform_driver dummy_hcd_driver = {
static struct platform_device *the_udc_pdev;
static struct platform_device *the_hcd_pdev;
-static int __init init (void)
+static int __init init(void)
{
int retval = -ENOMEM;
- if (usb_disabled ())
+ if (usb_disabled())
return -ENODEV;
if (!mod_data.is_high_speed && mod_data.is_super_speed)
@@ -2448,13 +2662,13 @@ err_alloc_udc:
platform_device_put(the_hcd_pdev);
return retval;
}
-module_init (init);
+module_init(init);
-static void __exit cleanup (void)
+static void __exit cleanup(void)
{
platform_device_unregister(the_udc_pdev);
platform_device_unregister(the_hcd_pdev);
platform_driver_unregister(&dummy_udc_driver);
platform_driver_unregister(&dummy_hcd_driver);
}
-module_exit (cleanup);
+module_exit(cleanup);
diff --git a/drivers/usb/gadget/epautoconf.c b/drivers/usb/gadget/epautoconf.c
index e0e6375ef5dd..51f3d42f5a64 100644
--- a/drivers/usb/gadget/epautoconf.c
+++ b/drivers/usb/gadget/epautoconf.c
@@ -275,24 +275,24 @@ struct usb_ep *usb_ep_autoconfig_ss(
/* ep-e, ep-f are PIO with only 64 byte fifos */
ep = find_ep (gadget, "ep-e");
if (ep && ep_matches(gadget, ep, desc, ep_comp))
- return ep;
+ goto found_ep;
ep = find_ep (gadget, "ep-f");
if (ep && ep_matches(gadget, ep, desc, ep_comp))
- return ep;
+ goto found_ep;
} else if (gadget_is_goku (gadget)) {
if (USB_ENDPOINT_XFER_INT == type) {
/* single buffering is enough */
ep = find_ep(gadget, "ep3-bulk");
if (ep && ep_matches(gadget, ep, desc, ep_comp))
- return ep;
+ goto found_ep;
} else if (USB_ENDPOINT_XFER_BULK == type
&& (USB_DIR_IN & desc->bEndpointAddress)) {
/* DMA may be available */
ep = find_ep(gadget, "ep2-bulk");
if (ep && ep_matches(gadget, ep, desc,
ep_comp))
- return ep;
+ goto found_ep;
}
#ifdef CONFIG_BLACKFIN
@@ -311,18 +311,22 @@ struct usb_ep *usb_ep_autoconfig_ss(
} else
ep = NULL;
if (ep && ep_matches(gadget, ep, desc, ep_comp))
- return ep;
+ goto found_ep;
#endif
}
/* Second, look at endpoints until an unclaimed one looks usable */
list_for_each_entry (ep, &gadget->ep_list, ep_list) {
if (ep_matches(gadget, ep, desc, ep_comp))
- return ep;
+ goto found_ep;
}
/* Fail */
return NULL;
+found_ep:
+ ep->desc = NULL;
+ ep->comp_desc = NULL;
+ return ep;
}
/**
diff --git a/drivers/usb/gadget/f_acm.c b/drivers/usb/gadget/f_acm.c
index 3f8849339ade..d672250a61fa 100644
--- a/drivers/usb/gadget/f_acm.c
+++ b/drivers/usb/gadget/f_acm.c
@@ -5,7 +5,7 @@
* Copyright (C) 2008 by David Brownell
* Copyright (C) 2008 by Nokia Corporation
* Copyright (C) 2009 by Samsung Electronics
- * Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
+ * Author: Michal Nazarewicz (mina86@mina86.com)
*
* This software is distributed under the terms of the GNU General
* Public License ("GPL") as published by the Free Software Foundation,
@@ -237,6 +237,42 @@ static struct usb_descriptor_header *acm_hs_function[] = {
NULL,
};
+static struct usb_endpoint_descriptor acm_ss_in_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor acm_ss_out_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor acm_ss_bulk_comp_desc = {
+ .bLength = sizeof acm_ss_bulk_comp_desc,
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_descriptor_header *acm_ss_function[] = {
+ (struct usb_descriptor_header *) &acm_iad_descriptor,
+ (struct usb_descriptor_header *) &acm_control_interface_desc,
+ (struct usb_descriptor_header *) &acm_header_desc,
+ (struct usb_descriptor_header *) &acm_call_mgmt_descriptor,
+ (struct usb_descriptor_header *) &acm_descriptor,
+ (struct usb_descriptor_header *) &acm_union_desc,
+ (struct usb_descriptor_header *) &acm_hs_notify_desc,
+ (struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
+ (struct usb_descriptor_header *) &acm_data_interface_desc,
+ (struct usb_descriptor_header *) &acm_ss_in_desc,
+ (struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
+ (struct usb_descriptor_header *) &acm_ss_out_desc,
+ (struct usb_descriptor_header *) &acm_ss_bulk_comp_desc,
+ NULL,
+};
+
/* string descriptors: */
#define ACM_CTRL_IDX 0
@@ -643,9 +679,21 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
/* copy descriptors */
f->hs_descriptors = usb_copy_descriptors(acm_hs_function);
}
+ if (gadget_is_superspeed(c->cdev->gadget)) {
+ acm_ss_in_desc.bEndpointAddress =
+ acm_fs_in_desc.bEndpointAddress;
+ acm_ss_out_desc.bEndpointAddress =
+ acm_fs_out_desc.bEndpointAddress;
+
+ /* copy descriptors, and track endpoint copies */
+ f->ss_descriptors = usb_copy_descriptors(acm_ss_function);
+ if (!f->ss_descriptors)
+ goto fail;
+ }
DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
acm->port_num,
+ gadget_is_superspeed(c->cdev->gadget) ? "super" :
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
acm->port.in->name, acm->port.out->name,
acm->notify->name);
@@ -675,6 +723,8 @@ acm_unbind(struct usb_configuration *c, struct usb_function *f)
if (gadget_is_dualspeed(c->cdev->gadget))
usb_free_descriptors(f->hs_descriptors);
+ if (gadget_is_superspeed(c->cdev->gadget))
+ usb_free_descriptors(f->ss_descriptors);
usb_free_descriptors(f->descriptors);
gs_free_req(acm->notify, acm->notify_req);
kfree(acm);
diff --git a/drivers/usb/gadget/f_ecm.c b/drivers/usb/gadget/f_ecm.c
index 11c07cb7d337..30b908f2a53d 100644
--- a/drivers/usb/gadget/f_ecm.c
+++ b/drivers/usb/gadget/f_ecm.c
@@ -97,6 +97,20 @@ static inline unsigned ecm_bitrate(struct usb_gadget *g)
/* interface descriptor: */
+static struct usb_interface_assoc_descriptor
+ecm_iad_descriptor = {
+ .bLength = sizeof ecm_iad_descriptor,
+ .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
+
+ /* .bFirstInterface = DYNAMIC, */
+ .bInterfaceCount = 2, /* control + data */
+ .bFunctionClass = USB_CLASS_COMM,
+ .bFunctionSubClass = USB_CDC_SUBCLASS_ETHERNET,
+ .bFunctionProtocol = USB_CDC_PROTO_NONE,
+ /* .iFunction = DYNAMIC */
+};
+
+
static struct usb_interface_descriptor ecm_control_intf = {
.bLength = sizeof ecm_control_intf,
.bDescriptorType = USB_DT_INTERFACE,
@@ -199,6 +213,7 @@ static struct usb_endpoint_descriptor fs_ecm_out_desc = {
static struct usb_descriptor_header *ecm_fs_function[] = {
/* CDC ECM control descriptors */
+ (struct usb_descriptor_header *) &ecm_iad_descriptor,
(struct usb_descriptor_header *) &ecm_control_intf,
(struct usb_descriptor_header *) &ecm_header_desc,
(struct usb_descriptor_header *) &ecm_union_desc,
@@ -247,6 +262,7 @@ static struct usb_endpoint_descriptor hs_ecm_out_desc = {
static struct usb_descriptor_header *ecm_hs_function[] = {
/* CDC ECM control descriptors */
+ (struct usb_descriptor_header *) &ecm_iad_descriptor,
(struct usb_descriptor_header *) &ecm_control_intf,
(struct usb_descriptor_header *) &ecm_header_desc,
(struct usb_descriptor_header *) &ecm_union_desc,
@@ -339,6 +355,7 @@ static struct usb_string ecm_string_defs[] = {
[0].s = "CDC Ethernet Control Model (ECM)",
[1].s = NULL /* DYNAMIC */,
[2].s = "CDC Ethernet Data",
+ [3].s = "CDC ECM",
{ } /* end of list */
};
@@ -674,6 +691,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
if (status < 0)
goto fail;
ecm->ctrl_id = status;
+ ecm_iad_descriptor.bFirstInterface = status;
ecm_control_intf.bInterfaceNumber = status;
ecm_union_desc.bMasterInterface0 = status;
@@ -864,6 +882,13 @@ ecm_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
return status;
ecm_string_defs[1].id = status;
ecm_desc.iMACAddress = status;
+
+ /* IAD label */
+ status = usb_string_id(c->cdev);
+ if (status < 0)
+ return status;
+ ecm_string_defs[3].id = status;
+ ecm_iad_descriptor.iFunction = status;
}
/* allocate and initialize one new instance */
diff --git a/drivers/usb/gadget/f_fs.c b/drivers/usb/gadget/f_fs.c
index f63dc6c150d2..f52cb1ae45d9 100644
--- a/drivers/usb/gadget/f_fs.c
+++ b/drivers/usb/gadget/f_fs.c
@@ -2,7 +2,7 @@
* f_fs.c -- user mode file system API for USB composite function controllers
*
* Copyright (C) 2010 Samsung Electronics
- * Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
+ * Author: Michal Nazarewicz <mina86@mina86.com>
*
* Based on inode.c (GadgetFS) which was:
* Copyright (C) 2003-2004 David Brownell
@@ -712,7 +712,7 @@ static long ffs_ep0_ioctl(struct file *file, unsigned code, unsigned long value)
if (code == FUNCTIONFS_INTERFACE_REVMAP) {
struct ffs_function *func = ffs->func;
ret = func ? ffs_func_revmap_intf(func, value) : -ENODEV;
- } else if (gadget->ops->ioctl) {
+ } else if (gadget && gadget->ops->ioctl) {
ret = gadget->ops->ioctl(gadget, code, value);
} else {
ret = -ENOTTY;
@@ -1063,13 +1063,9 @@ static int ffs_sb_fill(struct super_block *sb, void *_data, int silent)
&simple_dir_operations,
&simple_dir_inode_operations,
&data->perms);
- if (unlikely(!inode))
+ sb->s_root = d_make_root(inode);
+ if (unlikely(!sb->s_root))
goto Enomem;
- sb->s_root = d_alloc_root(inode);
- if (unlikely(!sb->s_root)) {
- iput(inode);
- goto Enomem;
- }
/* EP0 file */
if (unlikely(!ffs_sb_create_file(sb, "ep0", ffs,
@@ -1258,9 +1254,7 @@ static void ffs_data_put(struct ffs_data *ffs)
if (unlikely(atomic_dec_and_test(&ffs->ref))) {
pr_info("%s(): freeing\n", __func__);
ffs_data_clear(ffs);
- BUG_ON(mutex_is_locked(&ffs->mutex) ||
- spin_is_locked(&ffs->ev.waitq.lock) ||
- waitqueue_active(&ffs->ev.waitq) ||
+ BUG_ON(waitqueue_active(&ffs->ev.waitq) ||
waitqueue_active(&ffs->ep0req_completion.wait));
kfree(ffs);
}
@@ -1388,6 +1382,7 @@ static void functionfs_unbind(struct ffs_data *ffs)
ffs->ep0req = NULL;
ffs->gadget = NULL;
ffs_data_put(ffs);
+ clear_bit(FFS_FL_BOUND, &ffs->flags);
}
}
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index ee8ceec01560..a371e966425f 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2003-2008 Alan Stern
* Copyright (C) 2009 Samsung Electronics
- * Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
+ * Author: Michal Nazarewicz <mina86@mina86.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -304,7 +304,6 @@
static const char fsg_string_interface[] = "Mass Storage";
-#define FSG_NO_INTR_EP 1
#define FSG_NO_DEVICE_STRINGS 1
#define FSG_NO_OTG 1
#define FSG_NO_INTR_EP 1
@@ -620,7 +619,7 @@ static int fsg_setup(struct usb_function *f,
switch (ctrl->bRequest) {
- case USB_BULK_RESET_REQUEST:
+ case US_BULK_RESET_REQUEST:
if (ctrl->bRequestType !=
(USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
break;
@@ -636,7 +635,7 @@ static int fsg_setup(struct usb_function *f,
raise_exception(fsg->common, FSG_STATE_RESET);
return DELAYED_STATUS;
- case USB_BULK_GET_MAX_LUN_REQUEST:
+ case US_BULK_GET_MAX_LUN:
if (ctrl->bRequestType !=
(USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE))
break;
@@ -1742,7 +1741,7 @@ static int send_status(struct fsg_common *common)
struct fsg_buffhd *bh;
struct bulk_cs_wrap *csw;
int rc;
- u8 status = USB_STATUS_PASS;
+ u8 status = US_BULK_STAT_OK;
u32 sd, sdinfo = 0;
/* Wait for the next buffer to become available */
@@ -1763,11 +1762,11 @@ static int send_status(struct fsg_common *common)
if (common->phase_error) {
DBG(common, "sending phase-error status\n");
- status = USB_STATUS_PHASE_ERROR;
+ status = US_BULK_STAT_PHASE;
sd = SS_INVALID_COMMAND;
} else if (sd != SS_NO_SENSE) {
DBG(common, "sending command-failure status\n");
- status = USB_STATUS_FAIL;
+ status = US_BULK_STAT_FAIL;
VDBG(common, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
" info x%x\n",
SK(sd), ASC(sd), ASCQ(sd), sdinfo);
@@ -1776,12 +1775,12 @@ static int send_status(struct fsg_common *common)
/* Store and send the Bulk-only CSW */
csw = (void *)bh->buf;
- csw->Signature = cpu_to_le32(USB_BULK_CS_SIG);
+ csw->Signature = cpu_to_le32(US_BULK_CS_SIGN);
csw->Tag = common->tag;
csw->Residue = cpu_to_le32(common->residue);
csw->Status = status;
- bh->inreq->length = USB_BULK_CS_WRAP_LEN;
+ bh->inreq->length = US_BULK_CS_WRAP_LEN;
bh->inreq->zero = 0;
if (!start_in_transfer(common, bh))
/* Don't know what to do if common->fsg is NULL */
@@ -2221,7 +2220,7 @@ unknown_cmnd:
static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
{
struct usb_request *req = bh->outreq;
- struct fsg_bulk_cb_wrap *cbw = req->buf;
+ struct bulk_cb_wrap *cbw = req->buf;
struct fsg_common *common = fsg->common;
/* Was this a real packet? Should it be ignored? */
@@ -2229,9 +2228,9 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
return -EINVAL;
/* Is the CBW valid? */
- if (req->actual != USB_BULK_CB_WRAP_LEN ||
+ if (req->actual != US_BULK_CB_WRAP_LEN ||
cbw->Signature != cpu_to_le32(
- USB_BULK_CB_SIG)) {
+ US_BULK_CB_SIGN)) {
DBG(fsg, "invalid CBW: len %u sig 0x%x\n",
req->actual,
le32_to_cpu(cbw->Signature));
@@ -2253,7 +2252,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
}
/* Is the CBW meaningful? */
- if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG ||
+ if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN ||
cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
"cmdlen %u\n",
@@ -2273,7 +2272,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
/* Save the command for later */
common->cmnd_size = cbw->Length;
memcpy(common->cmnd, cbw->CDB, common->cmnd_size);
- if (cbw->Flags & USB_BULK_IN_FLAG)
+ if (cbw->Flags & US_BULK_FLAG_IN)
common->data_dir = DATA_DIR_TO_HOST;
else
common->data_dir = DATA_DIR_FROM_HOST;
@@ -2303,7 +2302,7 @@ static int get_next_command(struct fsg_common *common)
}
/* Queue a request to read a Bulk-only CBW */
- set_bulk_out_req_length(common, bh, USB_BULK_CB_WRAP_LEN);
+ set_bulk_out_req_length(common, bh, US_BULK_CB_WRAP_LEN);
if (!start_out_transfer(common, bh))
/* Don't know what to do if common->fsg is NULL */
return -EIO;
diff --git a/drivers/usb/gadget/f_midi.c b/drivers/usb/gadget/f_midi.c
index 3797b3d6c622..2f7e8f2930cc 100644
--- a/drivers/usb/gadget/f_midi.c
+++ b/drivers/usb/gadget/f_midi.c
@@ -780,7 +780,7 @@ f_midi_bind(struct usb_configuration *c, struct usb_function *f)
midi->out_ep->driver_data = cdev; /* claim */
/* allocate temporary function list */
- midi_function = kcalloc((MAX_PORTS * 4) + 9, sizeof(midi_function),
+ midi_function = kcalloc((MAX_PORTS * 4) + 9, sizeof(*midi_function),
GFP_KERNEL);
if (!midi_function) {
status = -ENOMEM;
diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c
index 7cdcb63b21ff..965a6293206a 100644
--- a/drivers/usb/gadget/f_phonet.c
+++ b/drivers/usb/gadget/f_phonet.c
@@ -345,7 +345,7 @@ static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req)
}
skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
- skb->len <= 1, req->actual);
+ skb->len <= 1, req->actual, PAGE_SIZE);
page = NULL;
if (req->actual < req->length) { /* Last fragment */
diff --git a/drivers/usb/gadget/f_rndis.c b/drivers/usb/gadget/f_rndis.c
index 704d1d94f72a..52343654f5df 100644
--- a/drivers/usb/gadget/f_rndis.c
+++ b/drivers/usb/gadget/f_rndis.c
@@ -5,7 +5,7 @@
* Copyright (C) 2003-2004 Robert Schwebel, Benedikt Spranger
* Copyright (C) 2008 Nokia Corporation
* Copyright (C) 2009 Samsung Electronics
- * Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
+ * Author: Michal Nazarewicz (mina86@mina86.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -500,6 +500,7 @@ rndis_setup(struct usb_function *f, const struct usb_ctrlrequest *ctrl)
if (buf) {
memcpy(req->buf, buf, n);
req->complete = rndis_response_complete;
+ req->context = rndis;
rndis_free_response(rndis->config, buf);
value = n;
}
diff --git a/drivers/usb/gadget/f_serial.c b/drivers/usb/gadget/f_serial.c
index cf33a8d0fd5d..07197d63d9b1 100644
--- a/drivers/usb/gadget/f_serial.c
+++ b/drivers/usb/gadget/f_serial.c
@@ -99,6 +99,34 @@ static struct usb_descriptor_header *gser_hs_function[] __initdata = {
NULL,
};
+static struct usb_endpoint_descriptor gser_ss_in_desc __initdata = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor gser_ss_out_desc __initdata = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor gser_ss_bulk_comp_desc __initdata = {
+ .bLength = sizeof gser_ss_bulk_comp_desc,
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+};
+
+static struct usb_descriptor_header *gser_ss_function[] __initdata = {
+ (struct usb_descriptor_header *) &gser_interface_desc,
+ (struct usb_descriptor_header *) &gser_ss_in_desc,
+ (struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
+ (struct usb_descriptor_header *) &gser_ss_out_desc,
+ (struct usb_descriptor_header *) &gser_ss_bulk_comp_desc,
+ NULL,
+};
+
/* string descriptors: */
static struct usb_string gser_string_defs[] = {
@@ -201,9 +229,21 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
/* copy descriptors, and track endpoint copies */
f->hs_descriptors = usb_copy_descriptors(gser_hs_function);
}
+ if (gadget_is_superspeed(c->cdev->gadget)) {
+ gser_ss_in_desc.bEndpointAddress =
+ gser_fs_in_desc.bEndpointAddress;
+ gser_ss_out_desc.bEndpointAddress =
+ gser_fs_out_desc.bEndpointAddress;
+
+ /* copy descriptors, and track endpoint copies */
+ f->ss_descriptors = usb_copy_descriptors(gser_ss_function);
+ if (!f->ss_descriptors)
+ goto fail;
+ }
DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
gser->port_num,
+ gadget_is_superspeed(c->cdev->gadget) ? "super" :
gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
gser->port.in->name, gser->port.out->name);
return 0;
@@ -225,6 +265,8 @@ gser_unbind(struct usb_configuration *c, struct usb_function *f)
{
if (gadget_is_dualspeed(c->cdev->gadget))
usb_free_descriptors(f->hs_descriptors);
+ if (gadget_is_superspeed(c->cdev->gadget))
+ usb_free_descriptors(f->ss_descriptors);
usb_free_descriptors(f->descriptors);
kfree(func_to_gser(f));
}
diff --git a/drivers/usb/gadget/f_subset.c b/drivers/usb/gadget/f_subset.c
index c1540648125a..21ab474aca07 100644
--- a/drivers/usb/gadget/f_subset.c
+++ b/drivers/usb/gadget/f_subset.c
@@ -74,7 +74,7 @@ static inline struct f_gether *func_to_geth(struct usb_function *f)
/* interface descriptor: */
-static struct usb_interface_descriptor subset_data_intf __initdata = {
+static struct usb_interface_descriptor subset_data_intf = {
.bLength = sizeof subset_data_intf,
.bDescriptorType = USB_DT_INTERFACE,
@@ -87,7 +87,7 @@ static struct usb_interface_descriptor subset_data_intf __initdata = {
/* .iInterface = DYNAMIC */
};
-static struct usb_cdc_header_desc mdlm_header_desc __initdata = {
+static struct usb_cdc_header_desc mdlm_header_desc = {
.bLength = sizeof mdlm_header_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_HEADER_TYPE,
@@ -95,7 +95,7 @@ static struct usb_cdc_header_desc mdlm_header_desc __initdata = {
.bcdCDC = cpu_to_le16(0x0110),
};
-static struct usb_cdc_mdlm_desc mdlm_desc __initdata = {
+static struct usb_cdc_mdlm_desc mdlm_desc = {
.bLength = sizeof mdlm_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_MDLM_TYPE,
@@ -111,7 +111,7 @@ static struct usb_cdc_mdlm_desc mdlm_desc __initdata = {
* can't really use its struct. All we do here is say that we're using
* the submode of "SAFE" which directly matches the CDC Subset.
*/
-static u8 mdlm_detail_desc[] __initdata = {
+static u8 mdlm_detail_desc[] = {
6,
USB_DT_CS_INTERFACE,
USB_CDC_MDLM_DETAIL_TYPE,
@@ -121,7 +121,7 @@ static u8 mdlm_detail_desc[] __initdata = {
0, /* network data capabilities ("raw" encapsulation) */
};
-static struct usb_cdc_ether_desc ether_desc __initdata = {
+static struct usb_cdc_ether_desc ether_desc = {
.bLength = sizeof ether_desc,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubType = USB_CDC_ETHERNET_TYPE,
@@ -136,7 +136,7 @@ static struct usb_cdc_ether_desc ether_desc __initdata = {
/* full speed support: */
-static struct usb_endpoint_descriptor fs_subset_in_desc __initdata = {
+static struct usb_endpoint_descriptor fs_subset_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -144,7 +144,7 @@ static struct usb_endpoint_descriptor fs_subset_in_desc __initdata = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_endpoint_descriptor fs_subset_out_desc __initdata = {
+static struct usb_endpoint_descriptor fs_subset_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -152,7 +152,7 @@ static struct usb_endpoint_descriptor fs_subset_out_desc __initdata = {
.bmAttributes = USB_ENDPOINT_XFER_BULK,
};
-static struct usb_descriptor_header *fs_eth_function[] __initdata = {
+static struct usb_descriptor_header *fs_eth_function[] = {
(struct usb_descriptor_header *) &subset_data_intf,
(struct usb_descriptor_header *) &mdlm_header_desc,
(struct usb_descriptor_header *) &mdlm_desc,
@@ -165,7 +165,7 @@ static struct usb_descriptor_header *fs_eth_function[] __initdata = {
/* high speed support: */
-static struct usb_endpoint_descriptor hs_subset_in_desc __initdata = {
+static struct usb_endpoint_descriptor hs_subset_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -173,7 +173,7 @@ static struct usb_endpoint_descriptor hs_subset_in_desc __initdata = {
.wMaxPacketSize = cpu_to_le16(512),
};
-static struct usb_endpoint_descriptor hs_subset_out_desc __initdata = {
+static struct usb_endpoint_descriptor hs_subset_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -181,7 +181,7 @@ static struct usb_endpoint_descriptor hs_subset_out_desc __initdata = {
.wMaxPacketSize = cpu_to_le16(512),
};
-static struct usb_descriptor_header *hs_eth_function[] __initdata = {
+static struct usb_descriptor_header *hs_eth_function[] = {
(struct usb_descriptor_header *) &subset_data_intf,
(struct usb_descriptor_header *) &mdlm_header_desc,
(struct usb_descriptor_header *) &mdlm_desc,
@@ -194,7 +194,7 @@ static struct usb_descriptor_header *hs_eth_function[] __initdata = {
/* super speed support: */
-static struct usb_endpoint_descriptor ss_subset_in_desc __initdata = {
+static struct usb_endpoint_descriptor ss_subset_in_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -202,7 +202,7 @@ static struct usb_endpoint_descriptor ss_subset_in_desc __initdata = {
.wMaxPacketSize = cpu_to_le16(1024),
};
-static struct usb_endpoint_descriptor ss_subset_out_desc __initdata = {
+static struct usb_endpoint_descriptor ss_subset_out_desc = {
.bLength = USB_DT_ENDPOINT_SIZE,
.bDescriptorType = USB_DT_ENDPOINT,
@@ -210,7 +210,7 @@ static struct usb_endpoint_descriptor ss_subset_out_desc __initdata = {
.wMaxPacketSize = cpu_to_le16(1024),
};
-static struct usb_ss_ep_comp_descriptor ss_subset_bulk_comp_desc __initdata = {
+static struct usb_ss_ep_comp_descriptor ss_subset_bulk_comp_desc = {
.bLength = sizeof ss_subset_bulk_comp_desc,
.bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
@@ -219,7 +219,7 @@ static struct usb_ss_ep_comp_descriptor ss_subset_bulk_comp_desc __initdata = {
/* .bmAttributes = 0, */
};
-static struct usb_descriptor_header *ss_eth_function[] __initdata = {
+static struct usb_descriptor_header *ss_eth_function[] = {
(struct usb_descriptor_header *) &subset_data_intf,
(struct usb_descriptor_header *) &mdlm_header_desc,
(struct usb_descriptor_header *) &mdlm_desc,
@@ -290,7 +290,7 @@ static void geth_disable(struct usb_function *f)
/* serial function driver setup/binding */
-static int __init
+static int
geth_bind(struct usb_configuration *c, struct usb_function *f)
{
struct usb_composite_dev *cdev = c->cdev;
@@ -404,7 +404,7 @@ geth_unbind(struct usb_configuration *c, struct usb_function *f)
* Caller must have called @gether_setup(). Caller is also responsible
* for calling @gether_cleanup() before module unload.
*/
-int __init geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
+int geth_bind_config(struct usb_configuration *c, u8 ethaddr[ETH_ALEN])
{
struct f_gether *geth;
int status;
diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_uac1.c
index ec7ffcd0d0cd..1a5dcd5565e3 100644
--- a/drivers/usb/gadget/f_audio.c
+++ b/drivers/usb/gadget/f_uac1.c
@@ -14,7 +14,7 @@
#include <linux/device.h>
#include <linux/atomic.h>
-#include "u_audio.h"
+#include "u_uac1.h"
#define OUT_EP_MAX_PACKET_SIZE 200
static int req_buf_size = OUT_EP_MAX_PACKET_SIZE;
@@ -216,29 +216,6 @@ static struct usb_descriptor_header *f_audio_desc[] __initdata = {
NULL,
};
-/* string IDs are assigned dynamically */
-
-#define STRING_MANUFACTURER_IDX 0
-#define STRING_PRODUCT_IDX 1
-
-static char manufacturer[50];
-
-static struct usb_string strings_dev[] = {
- [STRING_MANUFACTURER_IDX].s = manufacturer,
- [STRING_PRODUCT_IDX].s = DRIVER_DESC,
- { } /* end of list */
-};
-
-static struct usb_gadget_strings stringtab_dev = {
- .language = 0x0409, /* en-us */
- .strings = strings_dev,
-};
-
-static struct usb_gadget_strings *audio_strings[] = {
- &stringtab_dev,
- NULL,
-};
-
/*
* This function is an ALSA sound card following USB Audio Class Spec 1.0.
*/
diff --git a/drivers/usb/gadget/f_uac2.c b/drivers/usb/gadget/f_uac2.c
new file mode 100644
index 000000000000..e7cc4de93e33
--- /dev/null
+++ b/drivers/usb/gadget/f_uac2.c
@@ -0,0 +1,1449 @@
+/*
+ * f_uac2.c -- USB Audio Class 2.0 Function
+ *
+ * Copyright (C) 2011
+ * Yadwinder Singh (yadi.brar01@gmail.com)
+ * Jaswinder Singh (jaswinder.singh@linaro.org)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/usb/audio.h>
+#include <linux/usb/audio-v2.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+/* Playback(USB-IN) Default Stereo - Fl/Fr */
+static int p_chmask = 0x3;
+module_param(p_chmask, uint, S_IRUGO);
+MODULE_PARM_DESC(p_chmask, "Playback Channel Mask");
+
+/* Playback Default 48 KHz */
+static int p_srate = 48000;
+module_param(p_srate, uint, S_IRUGO);
+MODULE_PARM_DESC(p_srate, "Playback Sampling Rate");
+
+/* Playback Default 16bits/sample */
+static int p_ssize = 2;
+module_param(p_ssize, uint, S_IRUGO);
+MODULE_PARM_DESC(p_ssize, "Playback Sample Size(bytes)");
+
+/* Capture(USB-OUT) Default Stereo - Fl/Fr */
+static int c_chmask = 0x3;
+module_param(c_chmask, uint, S_IRUGO);
+MODULE_PARM_DESC(c_chmask, "Capture Channel Mask");
+
+/* Capture Default 64 KHz */
+static int c_srate = 64000;
+module_param(c_srate, uint, S_IRUGO);
+MODULE_PARM_DESC(c_srate, "Capture Sampling Rate");
+
+/* Capture Default 16bits/sample */
+static int c_ssize = 2;
+module_param(c_ssize, uint, S_IRUGO);
+MODULE_PARM_DESC(c_ssize, "Capture Sample Size(bytes)");
+
+#define DMA_ADDR_INVALID (~(dma_addr_t)0)
+
+#define ALT_SET(x, a) do {(x) &= ~0xff; (x) |= (a); } while (0)
+#define ALT_GET(x) ((x) & 0xff)
+#define INTF_SET(x, i) do {(x) &= 0xff; (x) |= ((i) << 8); } while (0)
+#define INTF_GET(x) ((x >> 8) & 0xff)
+
+/* Keep everyone on toes */
+#define USB_XFERS 2
+
+/*
+ * The driver implements a simple UAC_2 topology.
+ * USB-OUT -> IT_1 -> OT_3 -> ALSA_Capture
+ * ALSA_Playback -> IT_2 -> OT_4 -> USB-IN
+ * Capture and Playback sampling rates are independently
+ * controlled by two clock sources :
+ * CLK_5 := c_srate, and CLK_6 := p_srate
+ */
+#define USB_OUT_IT_ID 1
+#define IO_IN_IT_ID 2
+#define IO_OUT_OT_ID 3
+#define USB_IN_OT_ID 4
+#define USB_OUT_CLK_ID 5
+#define USB_IN_CLK_ID 6
+
+#define CONTROL_ABSENT 0
+#define CONTROL_RDONLY 1
+#define CONTROL_RDWR 3
+
+#define CLK_FREQ_CTRL 0
+#define CLK_VLD_CTRL 2
+
+#define COPY_CTRL 0
+#define CONN_CTRL 2
+#define OVRLD_CTRL 4
+#define CLSTR_CTRL 6
+#define UNFLW_CTRL 8
+#define OVFLW_CTRL 10
+
+const char *uac2_name = "snd_uac2";
+
+struct uac2_req {
+ struct uac2_rtd_params *pp; /* parent param */
+ struct usb_request *req;
+};
+
+struct uac2_rtd_params {
+ bool ep_enabled; /* if the ep is enabled */
+ /* Size of the ring buffer */
+ size_t dma_bytes;
+ unsigned char *dma_area;
+
+ struct snd_pcm_substream *ss;
+
+ /* Ring buffer */
+ ssize_t hw_ptr;
+
+ void *rbuf;
+
+ size_t period_size;
+
+ unsigned max_psize;
+ struct uac2_req ureq[USB_XFERS];
+
+ spinlock_t lock;
+};
+
+struct snd_uac2_chip {
+ struct platform_device pdev;
+ struct platform_driver pdrv;
+
+ struct uac2_rtd_params p_prm;
+ struct uac2_rtd_params c_prm;
+
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+};
+
+#define BUFF_SIZE_MAX (PAGE_SIZE * 16)
+#define PRD_SIZE_MAX PAGE_SIZE
+#define MIN_PERIODS 4
+
+static struct snd_pcm_hardware uac2_pcm_hardware = {
+ .info = SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER
+ | SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID
+ | SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME,
+ .rates = SNDRV_PCM_RATE_CONTINUOUS,
+ .periods_max = BUFF_SIZE_MAX / PRD_SIZE_MAX,
+ .buffer_bytes_max = BUFF_SIZE_MAX,
+ .period_bytes_max = PRD_SIZE_MAX,
+ .periods_min = MIN_PERIODS,
+};
+
+struct audio_dev {
+ /* Currently active {Interface[15:8] | AltSettings[7:0]} */
+ __u16 ac_alt, as_out_alt, as_in_alt;
+
+ struct usb_ep *in_ep, *out_ep;
+ struct usb_function func;
+
+ /* The ALSA Sound Card it represents on the USB-Client side */
+ struct snd_uac2_chip uac2;
+};
+
+static struct audio_dev *agdev_g;
+
+static inline
+struct audio_dev *func_to_agdev(struct usb_function *f)
+{
+ return container_of(f, struct audio_dev, func);
+}
+
+static inline
+struct audio_dev *uac2_to_agdev(struct snd_uac2_chip *u)
+{
+ return container_of(u, struct audio_dev, uac2);
+}
+
+static inline
+struct snd_uac2_chip *pdev_to_uac2(struct platform_device *p)
+{
+ return container_of(p, struct snd_uac2_chip, pdev);
+}
+
+static inline
+struct snd_uac2_chip *prm_to_uac2(struct uac2_rtd_params *r)
+{
+ struct snd_uac2_chip *uac2 = container_of(r,
+ struct snd_uac2_chip, c_prm);
+
+ if (&uac2->c_prm != r)
+ uac2 = container_of(r, struct snd_uac2_chip, p_prm);
+
+ return uac2;
+}
+
+static inline
+uint num_channels(uint chanmask)
+{
+ uint num = 0;
+
+ while (chanmask) {
+ num += (chanmask & 1);
+ chanmask >>= 1;
+ }
+
+ return num;
+}
+
+static void
+agdev_iso_complete(struct usb_ep *ep, struct usb_request *req)
+{
+ unsigned pending;
+ unsigned long flags;
+ bool update_alsa = false;
+ unsigned char *src, *dst;
+ int status = req->status;
+ struct uac2_req *ur = req->context;
+ struct snd_pcm_substream *substream;
+ struct uac2_rtd_params *prm = ur->pp;
+ struct snd_uac2_chip *uac2 = prm_to_uac2(prm);
+
+ /* i/f shutting down */
+ if (!prm->ep_enabled)
+ return;
+
+ /*
+ * We can't really do much about bad xfers.
+ * Afterall, the ISOCH xfers could fail legitimately.
+ */
+ if (status)
+ pr_debug("%s: iso_complete status(%d) %d/%d\n",
+ __func__, status, req->actual, req->length);
+
+ substream = prm->ss;
+
+ /* Do nothing if ALSA isn't active */
+ if (!substream)
+ goto exit;
+
+ spin_lock_irqsave(&prm->lock, flags);
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ src = prm->dma_area + prm->hw_ptr;
+ req->actual = req->length;
+ dst = req->buf;
+ } else {
+ dst = prm->dma_area + prm->hw_ptr;
+ src = req->buf;
+ }
+
+ pending = prm->hw_ptr % prm->period_size;
+ pending += req->actual;
+ if (pending >= prm->period_size)
+ update_alsa = true;
+
+ prm->hw_ptr = (prm->hw_ptr + req->actual) % prm->dma_bytes;
+
+ spin_unlock_irqrestore(&prm->lock, flags);
+
+ /* Pack USB load in ALSA ring buffer */
+ memcpy(dst, src, req->actual);
+exit:
+ if (usb_ep_queue(ep, req, GFP_ATOMIC))
+ dev_err(&uac2->pdev.dev, "%d Error!\n", __LINE__);
+
+ if (update_alsa)
+ snd_pcm_period_elapsed(substream);
+
+ return;
+}
+
+static int
+uac2_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream);
+ struct audio_dev *agdev = uac2_to_agdev(uac2);
+ struct uac2_rtd_params *prm;
+ unsigned long flags;
+ struct usb_ep *ep;
+ int err = 0;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ ep = agdev->in_ep;
+ prm = &uac2->p_prm;
+ } else {
+ ep = agdev->out_ep;
+ prm = &uac2->c_prm;
+ }
+
+ spin_lock_irqsave(&prm->lock, flags);
+
+ /* Reset */
+ prm->hw_ptr = 0;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ prm->ss = substream;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ prm->ss = NULL;
+ break;
+ default:
+ err = -EINVAL;
+ }
+
+ spin_unlock_irqrestore(&prm->lock, flags);
+
+ /* Clear buffer after Play stops */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && !prm->ss)
+ memset(prm->rbuf, 0, prm->max_psize * USB_XFERS);
+
+ return err;
+}
+
+static snd_pcm_uframes_t uac2_pcm_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream);
+ struct uac2_rtd_params *prm;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ prm = &uac2->p_prm;
+ else
+ prm = &uac2->c_prm;
+
+ return bytes_to_frames(substream->runtime, prm->hw_ptr);
+}
+
+static int uac2_pcm_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream);
+ struct uac2_rtd_params *prm;
+ int err;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ prm = &uac2->p_prm;
+ else
+ prm = &uac2->c_prm;
+
+ err = snd_pcm_lib_malloc_pages(substream,
+ params_buffer_bytes(hw_params));
+ if (err >= 0) {
+ prm->dma_bytes = substream->runtime->dma_bytes;
+ prm->dma_area = substream->runtime->dma_area;
+ prm->period_size = params_period_bytes(hw_params);
+ }
+
+ return err;
+}
+
+static int uac2_pcm_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream);
+ struct uac2_rtd_params *prm;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ prm = &uac2->p_prm;
+ else
+ prm = &uac2->c_prm;
+
+ prm->dma_area = NULL;
+ prm->dma_bytes = 0;
+ prm->period_size = 0;
+
+ return snd_pcm_lib_free_pages(substream);
+}
+
+static int uac2_pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_uac2_chip *uac2 = snd_pcm_substream_chip(substream);
+ struct snd_pcm_runtime *runtime = substream->runtime;
+
+ runtime->hw = uac2_pcm_hardware;
+
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ spin_lock_init(&uac2->p_prm.lock);
+ runtime->hw.rate_min = p_srate;
+ runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; /* ! p_ssize ! */
+ runtime->hw.channels_min = num_channels(p_chmask);
+ runtime->hw.period_bytes_min = 2 * uac2->p_prm.max_psize
+ / runtime->hw.periods_min;
+ } else {
+ spin_lock_init(&uac2->c_prm.lock);
+ runtime->hw.rate_min = c_srate;
+ runtime->hw.formats = SNDRV_PCM_FMTBIT_S16_LE; /* ! c_ssize ! */
+ runtime->hw.channels_min = num_channels(c_chmask);
+ runtime->hw.period_bytes_min = 2 * uac2->c_prm.max_psize
+ / runtime->hw.periods_min;
+ }
+
+ runtime->hw.rate_max = runtime->hw.rate_min;
+ runtime->hw.channels_max = runtime->hw.channels_min;
+
+ snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+
+ return 0;
+}
+
+/* ALSA cries without these function pointers */
+static int uac2_pcm_null(struct snd_pcm_substream *substream)
+{
+ return 0;
+}
+
+static struct snd_pcm_ops uac2_pcm_ops = {
+ .open = uac2_pcm_open,
+ .close = uac2_pcm_null,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = uac2_pcm_hw_params,
+ .hw_free = uac2_pcm_hw_free,
+ .trigger = uac2_pcm_trigger,
+ .pointer = uac2_pcm_pointer,
+ .prepare = uac2_pcm_null,
+};
+
+static int __devinit snd_uac2_probe(struct platform_device *pdev)
+{
+ struct snd_uac2_chip *uac2 = pdev_to_uac2(pdev);
+ struct snd_card *card;
+ struct snd_pcm *pcm;
+ int err;
+
+ /* Choose any slot, with no id */
+ err = snd_card_create(-1, NULL, THIS_MODULE, 0, &card);
+ if (err < 0)
+ return err;
+
+ uac2->card = card;
+
+ /*
+ * Create first PCM device
+ * Create a substream only for non-zero channel streams
+ */
+ err = snd_pcm_new(uac2->card, "UAC2 PCM", 0,
+ p_chmask ? 1 : 0, c_chmask ? 1 : 0, &pcm);
+ if (err < 0)
+ goto snd_fail;
+
+ strcpy(pcm->name, "UAC2 PCM");
+ pcm->private_data = uac2;
+
+ uac2->pcm = pcm;
+
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &uac2_pcm_ops);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &uac2_pcm_ops);
+
+ strcpy(card->driver, "UAC2_Gadget");
+ strcpy(card->shortname, "UAC2_Gadget");
+ sprintf(card->longname, "UAC2_Gadget %i", pdev->id);
+
+ snd_card_set_dev(card, &pdev->dev);
+
+ snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+ snd_dma_continuous_data(GFP_KERNEL), 0, BUFF_SIZE_MAX);
+
+ err = snd_card_register(card);
+ if (!err) {
+ platform_set_drvdata(pdev, card);
+ return 0;
+ }
+
+snd_fail:
+ snd_card_free(card);
+
+ uac2->pcm = NULL;
+ uac2->card = NULL;
+
+ return err;
+}
+
+static int __devexit snd_uac2_remove(struct platform_device *pdev)
+{
+ struct snd_card *card = platform_get_drvdata(pdev);
+
+ platform_set_drvdata(pdev, NULL);
+
+ if (card)
+ return snd_card_free(card);
+
+ return 0;
+}
+
+static int alsa_uac2_init(struct audio_dev *agdev)
+{
+ struct snd_uac2_chip *uac2 = &agdev->uac2;
+ int err;
+
+ uac2->pdrv.probe = snd_uac2_probe;
+ uac2->pdrv.remove = snd_uac2_remove;
+ uac2->pdrv.driver.name = uac2_name;
+
+ uac2->pdev.id = 0;
+ uac2->pdev.name = uac2_name;
+
+ /* Register snd_uac2 driver */
+ err = platform_driver_register(&uac2->pdrv);
+ if (err)
+ return err;
+
+ /* Register snd_uac2 device */
+ err = platform_device_register(&uac2->pdev);
+ if (err)
+ platform_driver_unregister(&uac2->pdrv);
+
+ return err;
+}
+
+static void alsa_uac2_exit(struct audio_dev *agdev)
+{
+ struct snd_uac2_chip *uac2 = &agdev->uac2;
+
+ platform_driver_unregister(&uac2->pdrv);
+ platform_device_unregister(&uac2->pdev);
+}
+
+
+/* --------- USB Function Interface ------------- */
+
+enum {
+ STR_ASSOC,
+ STR_IF_CTRL,
+ STR_CLKSRC_IN,
+ STR_CLKSRC_OUT,
+ STR_USB_IT,
+ STR_IO_IT,
+ STR_USB_OT,
+ STR_IO_OT,
+ STR_AS_OUT_ALT0,
+ STR_AS_OUT_ALT1,
+ STR_AS_IN_ALT0,
+ STR_AS_IN_ALT1,
+};
+
+static const char ifassoc[] = "Source/Sink";
+static const char ifctrl[] = "Topology Control";
+static char clksrc_in[8];
+static char clksrc_out[8];
+static const char usb_it[] = "USBH Out";
+static const char io_it[] = "USBD Out";
+static const char usb_ot[] = "USBH In";
+static const char io_ot[] = "USBD In";
+static const char out_alt0[] = "Playback Inactive";
+static const char out_alt1[] = "Playback Active";
+static const char in_alt0[] = "Capture Inactive";
+static const char in_alt1[] = "Capture Active";
+
+static struct usb_string strings_fn[] = {
+ [STR_ASSOC].s = ifassoc,
+ [STR_IF_CTRL].s = ifctrl,
+ [STR_CLKSRC_IN].s = clksrc_in,
+ [STR_CLKSRC_OUT].s = clksrc_out,
+ [STR_USB_IT].s = usb_it,
+ [STR_IO_IT].s = io_it,
+ [STR_USB_OT].s = usb_ot,
+ [STR_IO_OT].s = io_ot,
+ [STR_AS_OUT_ALT0].s = out_alt0,
+ [STR_AS_OUT_ALT1].s = out_alt1,
+ [STR_AS_IN_ALT0].s = in_alt0,
+ [STR_AS_IN_ALT1].s = in_alt1,
+ { },
+};
+
+static struct usb_gadget_strings str_fn = {
+ .language = 0x0409, /* en-us */
+ .strings = strings_fn,
+};
+
+static struct usb_gadget_strings *fn_strings[] = {
+ &str_fn,
+ NULL,
+};
+
+static struct usb_qualifier_descriptor devqual_desc = {
+ .bLength = sizeof devqual_desc,
+ .bDescriptorType = USB_DT_DEVICE_QUALIFIER,
+
+ .bcdUSB = cpu_to_le16(0x200),
+ .bDeviceClass = USB_CLASS_MISC,
+ .bDeviceSubClass = 0x02,
+ .bDeviceProtocol = 0x01,
+ .bNumConfigurations = 1,
+ .bRESERVED = 0,
+};
+
+static struct usb_interface_assoc_descriptor iad_desc = {
+ .bLength = sizeof iad_desc,
+ .bDescriptorType = USB_DT_INTERFACE_ASSOCIATION,
+
+ .bFirstInterface = 0,
+ .bInterfaceCount = 3,
+ .bFunctionClass = USB_CLASS_AUDIO,
+ .bFunctionSubClass = UAC2_FUNCTION_SUBCLASS_UNDEFINED,
+ .bFunctionProtocol = UAC_VERSION_2,
+};
+
+/* Audio Control Interface */
+static struct usb_interface_descriptor std_ac_if_desc = {
+ .bLength = sizeof std_ac_if_desc,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
+ .bInterfaceProtocol = UAC_VERSION_2,
+};
+
+/* Clock source for IN traffic */
+struct uac_clock_source_descriptor in_clk_src_desc = {
+ .bLength = sizeof in_clk_src_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+
+ .bDescriptorSubtype = UAC2_CLOCK_SOURCE,
+ .bClockID = USB_IN_CLK_ID,
+ .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED,
+ .bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL),
+ .bAssocTerminal = 0,
+};
+
+/* Clock source for OUT traffic */
+struct uac_clock_source_descriptor out_clk_src_desc = {
+ .bLength = sizeof out_clk_src_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+
+ .bDescriptorSubtype = UAC2_CLOCK_SOURCE,
+ .bClockID = USB_OUT_CLK_ID,
+ .bmAttributes = UAC_CLOCK_SOURCE_TYPE_INT_FIXED,
+ .bmControls = (CONTROL_RDONLY << CLK_FREQ_CTRL),
+ .bAssocTerminal = 0,
+};
+
+/* Input Terminal for USB_OUT */
+struct uac2_input_terminal_descriptor usb_out_it_desc = {
+ .bLength = sizeof usb_out_it_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+
+ .bDescriptorSubtype = UAC_INPUT_TERMINAL,
+ .bTerminalID = USB_OUT_IT_ID,
+ .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING),
+ .bAssocTerminal = 0,
+ .bCSourceID = USB_OUT_CLK_ID,
+ .iChannelNames = 0,
+ .bmControls = (CONTROL_RDWR << COPY_CTRL),
+};
+
+/* Input Terminal for I/O-In */
+struct uac2_input_terminal_descriptor io_in_it_desc = {
+ .bLength = sizeof io_in_it_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+
+ .bDescriptorSubtype = UAC_INPUT_TERMINAL,
+ .bTerminalID = IO_IN_IT_ID,
+ .wTerminalType = cpu_to_le16(UAC_INPUT_TERMINAL_UNDEFINED),
+ .bAssocTerminal = 0,
+ .bCSourceID = USB_IN_CLK_ID,
+ .iChannelNames = 0,
+ .bmControls = (CONTROL_RDWR << COPY_CTRL),
+};
+
+/* Ouput Terminal for USB_IN */
+struct uac2_output_terminal_descriptor usb_in_ot_desc = {
+ .bLength = sizeof usb_in_ot_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+
+ .bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
+ .bTerminalID = USB_IN_OT_ID,
+ .wTerminalType = cpu_to_le16(UAC_TERMINAL_STREAMING),
+ .bAssocTerminal = 0,
+ .bSourceID = IO_IN_IT_ID,
+ .bCSourceID = USB_IN_CLK_ID,
+ .bmControls = (CONTROL_RDWR << COPY_CTRL),
+};
+
+/* Ouput Terminal for I/O-Out */
+struct uac2_output_terminal_descriptor io_out_ot_desc = {
+ .bLength = sizeof io_out_ot_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+
+ .bDescriptorSubtype = UAC_OUTPUT_TERMINAL,
+ .bTerminalID = IO_OUT_OT_ID,
+ .wTerminalType = cpu_to_le16(UAC_OUTPUT_TERMINAL_UNDEFINED),
+ .bAssocTerminal = 0,
+ .bSourceID = USB_OUT_IT_ID,
+ .bCSourceID = USB_OUT_CLK_ID,
+ .bmControls = (CONTROL_RDWR << COPY_CTRL),
+};
+
+struct uac2_ac_header_descriptor ac_hdr_desc = {
+ .bLength = sizeof ac_hdr_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+
+ .bDescriptorSubtype = UAC_MS_HEADER,
+ .bcdADC = cpu_to_le16(0x200),
+ .bCategory = UAC2_FUNCTION_IO_BOX,
+ .wTotalLength = sizeof in_clk_src_desc + sizeof out_clk_src_desc
+ + sizeof usb_out_it_desc + sizeof io_in_it_desc
+ + sizeof usb_in_ot_desc + sizeof io_out_ot_desc,
+ .bmControls = 0,
+};
+
+/* Audio Streaming OUT Interface - Alt0 */
+static struct usb_interface_descriptor std_as_out_if0_desc = {
+ .bLength = sizeof std_as_out_if0_desc,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
+ .bInterfaceProtocol = UAC_VERSION_2,
+};
+
+/* Audio Streaming OUT Interface - Alt1 */
+static struct usb_interface_descriptor std_as_out_if1_desc = {
+ .bLength = sizeof std_as_out_if1_desc,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bAlternateSetting = 1,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
+ .bInterfaceProtocol = UAC_VERSION_2,
+};
+
+/* Audio Stream OUT Intface Desc */
+struct uac2_as_header_descriptor as_out_hdr_desc = {
+ .bLength = sizeof as_out_hdr_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+
+ .bDescriptorSubtype = UAC_AS_GENERAL,
+ .bTerminalLink = USB_OUT_IT_ID,
+ .bmControls = 0,
+ .bFormatType = UAC_FORMAT_TYPE_I,
+ .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM),
+ .iChannelNames = 0,
+};
+
+/* Audio USB_OUT Format */
+struct uac2_format_type_i_descriptor as_out_fmt1_desc = {
+ .bLength = sizeof as_out_fmt1_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_FORMAT_TYPE,
+ .bFormatType = UAC_FORMAT_TYPE_I,
+};
+
+/* STD AS ISO OUT Endpoint */
+struct usb_endpoint_descriptor fs_epout_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ .bInterval = 1,
+};
+
+struct usb_endpoint_descriptor hs_epout_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ .bInterval = 4,
+};
+
+/* CS AS ISO OUT Endpoint */
+static struct uac2_iso_endpoint_descriptor as_iso_out_desc = {
+ .bLength = sizeof as_iso_out_desc,
+ .bDescriptorType = USB_DT_CS_ENDPOINT,
+
+ .bDescriptorSubtype = UAC_EP_GENERAL,
+ .bmAttributes = 0,
+ .bmControls = 0,
+ .bLockDelayUnits = 0,
+ .wLockDelay = 0,
+};
+
+/* Audio Streaming IN Interface - Alt0 */
+static struct usb_interface_descriptor std_as_in_if0_desc = {
+ .bLength = sizeof std_as_in_if0_desc,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bAlternateSetting = 0,
+ .bNumEndpoints = 0,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
+ .bInterfaceProtocol = UAC_VERSION_2,
+};
+
+/* Audio Streaming IN Interface - Alt1 */
+static struct usb_interface_descriptor std_as_in_if1_desc = {
+ .bLength = sizeof std_as_in_if1_desc,
+ .bDescriptorType = USB_DT_INTERFACE,
+
+ .bAlternateSetting = 1,
+ .bNumEndpoints = 1,
+ .bInterfaceClass = USB_CLASS_AUDIO,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
+ .bInterfaceProtocol = UAC_VERSION_2,
+};
+
+/* Audio Stream IN Intface Desc */
+struct uac2_as_header_descriptor as_in_hdr_desc = {
+ .bLength = sizeof as_in_hdr_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+
+ .bDescriptorSubtype = UAC_AS_GENERAL,
+ .bTerminalLink = USB_IN_OT_ID,
+ .bmControls = 0,
+ .bFormatType = UAC_FORMAT_TYPE_I,
+ .bmFormats = cpu_to_le32(UAC_FORMAT_TYPE_I_PCM),
+ .iChannelNames = 0,
+};
+
+/* Audio USB_IN Format */
+struct uac2_format_type_i_descriptor as_in_fmt1_desc = {
+ .bLength = sizeof as_in_fmt1_desc,
+ .bDescriptorType = USB_DT_CS_INTERFACE,
+ .bDescriptorSubtype = UAC_FORMAT_TYPE,
+ .bFormatType = UAC_FORMAT_TYPE_I,
+};
+
+/* STD AS ISO IN Endpoint */
+struct usb_endpoint_descriptor fs_epin_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bEndpointAddress = USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ .bInterval = 1,
+};
+
+struct usb_endpoint_descriptor hs_epin_desc = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+
+ .bmAttributes = USB_ENDPOINT_XFER_ISOC | USB_ENDPOINT_SYNC_ASYNC,
+ .bInterval = 4,
+};
+
+/* CS AS ISO IN Endpoint */
+static struct uac2_iso_endpoint_descriptor as_iso_in_desc = {
+ .bLength = sizeof as_iso_in_desc,
+ .bDescriptorType = USB_DT_CS_ENDPOINT,
+
+ .bDescriptorSubtype = UAC_EP_GENERAL,
+ .bmAttributes = 0,
+ .bmControls = 0,
+ .bLockDelayUnits = 0,
+ .wLockDelay = 0,
+};
+
+static struct usb_descriptor_header *fs_audio_desc[] = {
+ (struct usb_descriptor_header *)&iad_desc,
+ (struct usb_descriptor_header *)&std_ac_if_desc,
+
+ (struct usb_descriptor_header *)&ac_hdr_desc,
+ (struct usb_descriptor_header *)&in_clk_src_desc,
+ (struct usb_descriptor_header *)&out_clk_src_desc,
+ (struct usb_descriptor_header *)&usb_out_it_desc,
+ (struct usb_descriptor_header *)&io_in_it_desc,
+ (struct usb_descriptor_header *)&usb_in_ot_desc,
+ (struct usb_descriptor_header *)&io_out_ot_desc,
+
+ (struct usb_descriptor_header *)&std_as_out_if0_desc,
+ (struct usb_descriptor_header *)&std_as_out_if1_desc,
+
+ (struct usb_descriptor_header *)&as_out_hdr_desc,
+ (struct usb_descriptor_header *)&as_out_fmt1_desc,
+ (struct usb_descriptor_header *)&fs_epout_desc,
+ (struct usb_descriptor_header *)&as_iso_out_desc,
+
+ (struct usb_descriptor_header *)&std_as_in_if0_desc,
+ (struct usb_descriptor_header *)&std_as_in_if1_desc,
+
+ (struct usb_descriptor_header *)&as_in_hdr_desc,
+ (struct usb_descriptor_header *)&as_in_fmt1_desc,
+ (struct usb_descriptor_header *)&fs_epin_desc,
+ (struct usb_descriptor_header *)&as_iso_in_desc,
+ NULL,
+};
+
+static struct usb_descriptor_header *hs_audio_desc[] = {
+ (struct usb_descriptor_header *)&iad_desc,
+ (struct usb_descriptor_header *)&std_ac_if_desc,
+
+ (struct usb_descriptor_header *)&ac_hdr_desc,
+ (struct usb_descriptor_header *)&in_clk_src_desc,
+ (struct usb_descriptor_header *)&out_clk_src_desc,
+ (struct usb_descriptor_header *)&usb_out_it_desc,
+ (struct usb_descriptor_header *)&io_in_it_desc,
+ (struct usb_descriptor_header *)&usb_in_ot_desc,
+ (struct usb_descriptor_header *)&io_out_ot_desc,
+
+ (struct usb_descriptor_header *)&std_as_out_if0_desc,
+ (struct usb_descriptor_header *)&std_as_out_if1_desc,
+
+ (struct usb_descriptor_header *)&as_out_hdr_desc,
+ (struct usb_descriptor_header *)&as_out_fmt1_desc,
+ (struct usb_descriptor_header *)&hs_epout_desc,
+ (struct usb_descriptor_header *)&as_iso_out_desc,
+
+ (struct usb_descriptor_header *)&std_as_in_if0_desc,
+ (struct usb_descriptor_header *)&std_as_in_if1_desc,
+
+ (struct usb_descriptor_header *)&as_in_hdr_desc,
+ (struct usb_descriptor_header *)&as_in_fmt1_desc,
+ (struct usb_descriptor_header *)&hs_epin_desc,
+ (struct usb_descriptor_header *)&as_iso_in_desc,
+ NULL,
+};
+
+struct cntrl_cur_lay3 {
+ __u32 dCUR;
+};
+
+struct cntrl_range_lay3 {
+ __u16 wNumSubRanges;
+ __u32 dMIN;
+ __u32 dMAX;
+ __u32 dRES;
+} __packed;
+
+static inline void
+free_ep(struct uac2_rtd_params *prm, struct usb_ep *ep)
+{
+ struct snd_uac2_chip *uac2 = prm_to_uac2(prm);
+ int i;
+
+ prm->ep_enabled = false;
+
+ for (i = 0; i < USB_XFERS; i++) {
+ if (prm->ureq[i].req) {
+ usb_ep_dequeue(ep, prm->ureq[i].req);
+ usb_ep_free_request(ep, prm->ureq[i].req);
+ prm->ureq[i].req = NULL;
+ }
+ }
+
+ if (usb_ep_disable(ep))
+ dev_err(&uac2->pdev.dev,
+ "%s:%d Error!\n", __func__, __LINE__);
+}
+
+static int __init
+afunc_bind(struct usb_configuration *cfg, struct usb_function *fn)
+{
+ struct audio_dev *agdev = func_to_agdev(fn);
+ struct snd_uac2_chip *uac2 = &agdev->uac2;
+ struct usb_composite_dev *cdev = cfg->cdev;
+ struct usb_gadget *gadget = cdev->gadget;
+ struct uac2_rtd_params *prm;
+ int ret;
+
+ ret = usb_interface_id(cfg, fn);
+ if (ret < 0) {
+ dev_err(&uac2->pdev.dev,
+ "%s:%d Error!\n", __func__, __LINE__);
+ return ret;
+ }
+ std_ac_if_desc.bInterfaceNumber = ret;
+ ALT_SET(agdev->ac_alt, 0);
+ INTF_SET(agdev->ac_alt, ret);
+
+ ret = usb_interface_id(cfg, fn);
+ if (ret < 0) {
+ dev_err(&uac2->pdev.dev,
+ "%s:%d Error!\n", __func__, __LINE__);
+ return ret;
+ }
+ std_as_out_if0_desc.bInterfaceNumber = ret;
+ std_as_out_if1_desc.bInterfaceNumber = ret;
+ ALT_SET(agdev->as_out_alt, 0);
+ INTF_SET(agdev->as_out_alt, ret);
+
+ ret = usb_interface_id(cfg, fn);
+ if (ret < 0) {
+ dev_err(&uac2->pdev.dev,
+ "%s:%d Error!\n", __func__, __LINE__);
+ return ret;
+ }
+ std_as_in_if0_desc.bInterfaceNumber = ret;
+ std_as_in_if1_desc.bInterfaceNumber = ret;
+ ALT_SET(agdev->as_in_alt, 0);
+ INTF_SET(agdev->as_in_alt, ret);
+
+ agdev->out_ep = usb_ep_autoconfig(gadget, &fs_epout_desc);
+ if (!agdev->out_ep)
+ dev_err(&uac2->pdev.dev,
+ "%s:%d Error!\n", __func__, __LINE__);
+ agdev->out_ep->driver_data = agdev;
+
+ agdev->in_ep = usb_ep_autoconfig(gadget, &fs_epin_desc);
+ if (!agdev->in_ep)
+ dev_err(&uac2->pdev.dev,
+ "%s:%d Error!\n", __func__, __LINE__);
+ agdev->in_ep->driver_data = agdev;
+
+ hs_epout_desc.bEndpointAddress = fs_epout_desc.bEndpointAddress;
+ hs_epout_desc.wMaxPacketSize = fs_epout_desc.wMaxPacketSize;
+ hs_epin_desc.bEndpointAddress = fs_epin_desc.bEndpointAddress;
+ hs_epin_desc.wMaxPacketSize = fs_epin_desc.wMaxPacketSize;
+
+ fn->descriptors = usb_copy_descriptors(fs_audio_desc);
+ if (gadget_is_dualspeed(gadget))
+ fn->hs_descriptors = usb_copy_descriptors(hs_audio_desc);
+
+ prm = &agdev->uac2.c_prm;
+ prm->max_psize = hs_epout_desc.wMaxPacketSize;
+ prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
+ if (!prm->rbuf) {
+ prm->max_psize = 0;
+ dev_err(&uac2->pdev.dev,
+ "%s:%d Error!\n", __func__, __LINE__);
+ }
+
+ prm = &agdev->uac2.p_prm;
+ prm->max_psize = hs_epin_desc.wMaxPacketSize;
+ prm->rbuf = kzalloc(prm->max_psize * USB_XFERS, GFP_KERNEL);
+ if (!prm->rbuf) {
+ prm->max_psize = 0;
+ dev_err(&uac2->pdev.dev,
+ "%s:%d Error!\n", __func__, __LINE__);
+ }
+
+ return alsa_uac2_init(agdev);
+}
+
+static void
+afunc_unbind(struct usb_configuration *cfg, struct usb_function *fn)
+{
+ struct audio_dev *agdev = func_to_agdev(fn);
+ struct usb_composite_dev *cdev = cfg->cdev;
+ struct usb_gadget *gadget = cdev->gadget;
+ struct uac2_rtd_params *prm;
+
+ alsa_uac2_exit(agdev);
+
+ prm = &agdev->uac2.p_prm;
+ kfree(prm->rbuf);
+
+ prm = &agdev->uac2.c_prm;
+ kfree(prm->rbuf);
+
+ if (gadget_is_dualspeed(gadget))
+ usb_free_descriptors(fn->hs_descriptors);
+ usb_free_descriptors(fn->descriptors);
+
+ if (agdev->in_ep)
+ agdev->in_ep->driver_data = NULL;
+ if (agdev->out_ep)
+ agdev->out_ep->driver_data = NULL;
+}
+
+static int
+afunc_set_alt(struct usb_function *fn, unsigned intf, unsigned alt)
+{
+ struct usb_composite_dev *cdev = fn->config->cdev;
+ struct audio_dev *agdev = func_to_agdev(fn);
+ struct snd_uac2_chip *uac2 = &agdev->uac2;
+ struct usb_gadget *gadget = cdev->gadget;
+ struct usb_request *req;
+ struct usb_ep *ep;
+ struct uac2_rtd_params *prm;
+ int i;
+
+ /* No i/f has more than 2 alt settings */
+ if (alt > 1) {
+ dev_err(&uac2->pdev.dev,
+ "%s:%d Error!\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ if (intf == INTF_GET(agdev->ac_alt)) {
+ /* Control I/f has only 1 AltSetting - 0 */
+ if (alt) {
+ dev_err(&uac2->pdev.dev,
+ "%s:%d Error!\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ if (intf == INTF_GET(agdev->as_out_alt)) {
+ ep = agdev->out_ep;
+ prm = &uac2->c_prm;
+ config_ep_by_speed(gadget, fn, ep);
+ ALT_SET(agdev->as_out_alt, alt);
+ } else if (intf == INTF_GET(agdev->as_in_alt)) {
+ ep = agdev->in_ep;
+ prm = &uac2->p_prm;
+ config_ep_by_speed(gadget, fn, ep);
+ ALT_SET(agdev->as_in_alt, alt);
+ } else {
+ dev_err(&uac2->pdev.dev,
+ "%s:%d Error!\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ if (alt == 0) {
+ free_ep(prm, ep);
+ return 0;
+ }
+
+ prm->ep_enabled = true;
+ usb_ep_enable(ep);
+
+ for (i = 0; i < USB_XFERS; i++) {
+ if (prm->ureq[i].req) {
+ if (usb_ep_queue(ep, prm->ureq[i].req, GFP_ATOMIC))
+ dev_err(&uac2->pdev.dev, "%d Error!\n",
+ __LINE__);
+ continue;
+ }
+
+ req = usb_ep_alloc_request(ep, GFP_ATOMIC);
+ if (req == NULL) {
+ dev_err(&uac2->pdev.dev,
+ "%s:%d Error!\n", __func__, __LINE__);
+ return -EINVAL;
+ }
+
+ prm->ureq[i].req = req;
+ prm->ureq[i].pp = prm;
+
+ req->zero = 0;
+ req->dma = DMA_ADDR_INVALID;
+ req->context = &prm->ureq[i];
+ req->length = prm->max_psize;
+ req->complete = agdev_iso_complete;
+ req->buf = prm->rbuf + i * req->length;
+
+ if (usb_ep_queue(ep, req, GFP_ATOMIC))
+ dev_err(&uac2->pdev.dev, "%d Error!\n", __LINE__);
+ }
+
+ return 0;
+}
+
+static int
+afunc_get_alt(struct usb_function *fn, unsigned intf)
+{
+ struct audio_dev *agdev = func_to_agdev(fn);
+ struct snd_uac2_chip *uac2 = &agdev->uac2;
+
+ if (intf == INTF_GET(agdev->ac_alt))
+ return ALT_GET(agdev->ac_alt);
+ else if (intf == INTF_GET(agdev->as_out_alt))
+ return ALT_GET(agdev->as_out_alt);
+ else if (intf == INTF_GET(agdev->as_in_alt))
+ return ALT_GET(agdev->as_in_alt);
+ else
+ dev_err(&uac2->pdev.dev,
+ "%s:%d Invalid Interface %d!\n",
+ __func__, __LINE__, intf);
+
+ return -EINVAL;
+}
+
+static void
+afunc_disable(struct usb_function *fn)
+{
+ struct audio_dev *agdev = func_to_agdev(fn);
+ struct snd_uac2_chip *uac2 = &agdev->uac2;
+
+ free_ep(&uac2->p_prm, agdev->in_ep);
+ ALT_SET(agdev->as_in_alt, 0);
+
+ free_ep(&uac2->c_prm, agdev->out_ep);
+ ALT_SET(agdev->as_out_alt, 0);
+}
+
+static int
+in_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr)
+{
+ struct usb_request *req = fn->config->cdev->req;
+ struct audio_dev *agdev = func_to_agdev(fn);
+ struct snd_uac2_chip *uac2 = &agdev->uac2;
+ u16 w_length = le16_to_cpu(cr->wLength);
+ u16 w_index = le16_to_cpu(cr->wIndex);
+ u16 w_value = le16_to_cpu(cr->wValue);
+ u8 entity_id = (w_index >> 8) & 0xff;
+ u8 control_selector = w_value >> 8;
+ int value = -EOPNOTSUPP;
+
+ if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) {
+ struct cntrl_cur_lay3 c;
+
+ if (entity_id == USB_IN_CLK_ID)
+ c.dCUR = p_srate;
+ else if (entity_id == USB_OUT_CLK_ID)
+ c.dCUR = c_srate;
+
+ value = min_t(unsigned, w_length, sizeof c);
+ memcpy(req->buf, &c, value);
+ } else if (control_selector == UAC2_CS_CONTROL_CLOCK_VALID) {
+ *(u8 *)req->buf = 1;
+ value = min_t(unsigned, w_length, 1);
+ } else {
+ dev_err(&uac2->pdev.dev,
+ "%s:%d control_selector=%d TODO!\n",
+ __func__, __LINE__, control_selector);
+ }
+
+ return value;
+}
+
+static int
+in_rq_range(struct usb_function *fn, const struct usb_ctrlrequest *cr)
+{
+ struct usb_request *req = fn->config->cdev->req;
+ struct audio_dev *agdev = func_to_agdev(fn);
+ struct snd_uac2_chip *uac2 = &agdev->uac2;
+ u16 w_length = le16_to_cpu(cr->wLength);
+ u16 w_index = le16_to_cpu(cr->wIndex);
+ u16 w_value = le16_to_cpu(cr->wValue);
+ u8 entity_id = (w_index >> 8) & 0xff;
+ u8 control_selector = w_value >> 8;
+ struct cntrl_range_lay3 r;
+ int value = -EOPNOTSUPP;
+
+ if (control_selector == UAC2_CS_CONTROL_SAM_FREQ) {
+ if (entity_id == USB_IN_CLK_ID)
+ r.dMIN = p_srate;
+ else if (entity_id == USB_OUT_CLK_ID)
+ r.dMIN = c_srate;
+ else
+ return -EOPNOTSUPP;
+
+ r.dMAX = r.dMIN;
+ r.dRES = 0;
+ r.wNumSubRanges = 1;
+
+ value = min_t(unsigned, w_length, sizeof r);
+ memcpy(req->buf, &r, value);
+ } else {
+ dev_err(&uac2->pdev.dev,
+ "%s:%d control_selector=%d TODO!\n",
+ __func__, __LINE__, control_selector);
+ }
+
+ return value;
+}
+
+static int
+ac_rq_in(struct usb_function *fn, const struct usb_ctrlrequest *cr)
+{
+ if (cr->bRequest == UAC2_CS_CUR)
+ return in_rq_cur(fn, cr);
+ else if (cr->bRequest == UAC2_CS_RANGE)
+ return in_rq_range(fn, cr);
+ else
+ return -EOPNOTSUPP;
+}
+
+static int
+out_rq_cur(struct usb_function *fn, const struct usb_ctrlrequest *cr)
+{
+ u16 w_length = le16_to_cpu(cr->wLength);
+ u16 w_value = le16_to_cpu(cr->wValue);
+ u8 control_selector = w_value >> 8;
+
+ if (control_selector == UAC2_CS_CONTROL_SAM_FREQ)
+ return w_length;
+
+ return -EOPNOTSUPP;
+}
+
+static int
+setup_rq_inf(struct usb_function *fn, const struct usb_ctrlrequest *cr)
+{
+ struct audio_dev *agdev = func_to_agdev(fn);
+ struct snd_uac2_chip *uac2 = &agdev->uac2;
+ u16 w_index = le16_to_cpu(cr->wIndex);
+ u8 intf = w_index & 0xff;
+
+ if (intf != INTF_GET(agdev->ac_alt)) {
+ dev_err(&uac2->pdev.dev,
+ "%s:%d Error!\n", __func__, __LINE__);
+ return -EOPNOTSUPP;
+ }
+
+ if (cr->bRequestType & USB_DIR_IN)
+ return ac_rq_in(fn, cr);
+ else if (cr->bRequest == UAC2_CS_CUR)
+ return out_rq_cur(fn, cr);
+
+ return -EOPNOTSUPP;
+}
+
+static int
+afunc_setup(struct usb_function *fn, const struct usb_ctrlrequest *cr)
+{
+ struct usb_composite_dev *cdev = fn->config->cdev;
+ struct audio_dev *agdev = func_to_agdev(fn);
+ struct snd_uac2_chip *uac2 = &agdev->uac2;
+ struct usb_request *req = cdev->req;
+ u16 w_length = le16_to_cpu(cr->wLength);
+ int value = -EOPNOTSUPP;
+
+ /* Only Class specific requests are supposed to reach here */
+ if ((cr->bRequestType & USB_TYPE_MASK) != USB_TYPE_CLASS)
+ return -EOPNOTSUPP;
+
+ if ((cr->bRequestType & USB_RECIP_MASK) == USB_RECIP_INTERFACE)
+ value = setup_rq_inf(fn, cr);
+ else
+ dev_err(&uac2->pdev.dev, "%s:%d Error!\n", __func__, __LINE__);
+
+ if (value >= 0) {
+ req->length = value;
+ req->zero = value < w_length;
+ value = usb_ep_queue(cdev->gadget->ep0, req, GFP_ATOMIC);
+ if (value < 0) {
+ dev_err(&uac2->pdev.dev,
+ "%s:%d Error!\n", __func__, __LINE__);
+ req->status = 0;
+ }
+ }
+
+ return value;
+}
+
+static int audio_bind_config(struct usb_configuration *cfg)
+{
+ int id, res;
+
+ agdev_g = kzalloc(sizeof *agdev_g, GFP_KERNEL);
+ if (agdev_g == NULL) {
+ printk(KERN_ERR "Unable to allocate audio gadget\n");
+ return -ENOMEM;
+ }
+
+ id = usb_string_id(cfg->cdev);
+ if (id < 0)
+ return id;
+
+ strings_fn[STR_ASSOC].id = id;
+ iad_desc.iFunction = id,
+
+ id = usb_string_id(cfg->cdev);
+ if (id < 0)
+ return id;
+
+ strings_fn[STR_IF_CTRL].id = id;
+ std_ac_if_desc.iInterface = id,
+
+ id = usb_string_id(cfg->cdev);
+ if (id < 0)
+ return id;
+
+ strings_fn[STR_CLKSRC_IN].id = id;
+ in_clk_src_desc.iClockSource = id,
+
+ id = usb_string_id(cfg->cdev);
+ if (id < 0)
+ return id;
+
+ strings_fn[STR_CLKSRC_OUT].id = id;
+ out_clk_src_desc.iClockSource = id,
+
+ id = usb_string_id(cfg->cdev);
+ if (id < 0)
+ return id;
+
+ strings_fn[STR_USB_IT].id = id;
+ usb_out_it_desc.iTerminal = id,
+
+ id = usb_string_id(cfg->cdev);
+ if (id < 0)
+ return id;
+
+ strings_fn[STR_IO_IT].id = id;
+ io_in_it_desc.iTerminal = id;
+
+ id = usb_string_id(cfg->cdev);
+ if (id < 0)
+ return id;
+
+ strings_fn[STR_USB_OT].id = id;
+ usb_in_ot_desc.iTerminal = id;
+
+ id = usb_string_id(cfg->cdev);
+ if (id < 0)
+ return id;
+
+ strings_fn[STR_IO_OT].id = id;
+ io_out_ot_desc.iTerminal = id;
+
+ id = usb_string_id(cfg->cdev);
+ if (id < 0)
+ return id;
+
+ strings_fn[STR_AS_OUT_ALT0].id = id;
+ std_as_out_if0_desc.iInterface = id;
+
+ id = usb_string_id(cfg->cdev);
+ if (id < 0)
+ return id;
+
+ strings_fn[STR_AS_OUT_ALT1].id = id;
+ std_as_out_if1_desc.iInterface = id;
+
+ id = usb_string_id(cfg->cdev);
+ if (id < 0)
+ return id;
+
+ strings_fn[STR_AS_IN_ALT0].id = id;
+ std_as_in_if0_desc.iInterface = id;
+
+ id = usb_string_id(cfg->cdev);
+ if (id < 0)
+ return id;
+
+ strings_fn[STR_AS_IN_ALT1].id = id;
+ std_as_in_if1_desc.iInterface = id;
+
+ agdev_g->func.name = "uac2_func";
+ agdev_g->func.strings = fn_strings;
+ agdev_g->func.bind = afunc_bind;
+ agdev_g->func.unbind = afunc_unbind;
+ agdev_g->func.set_alt = afunc_set_alt;
+ agdev_g->func.get_alt = afunc_get_alt;
+ agdev_g->func.disable = afunc_disable;
+ agdev_g->func.setup = afunc_setup;
+
+ /* Initialize the configurable parameters */
+ usb_out_it_desc.bNrChannels = num_channels(c_chmask);
+ usb_out_it_desc.bmChannelConfig = cpu_to_le32(c_chmask);
+ io_in_it_desc.bNrChannels = num_channels(p_chmask);
+ io_in_it_desc.bmChannelConfig = cpu_to_le32(p_chmask);
+ as_out_hdr_desc.bNrChannels = num_channels(c_chmask);
+ as_out_hdr_desc.bmChannelConfig = cpu_to_le32(c_chmask);
+ as_in_hdr_desc.bNrChannels = num_channels(p_chmask);
+ as_in_hdr_desc.bmChannelConfig = cpu_to_le32(p_chmask);
+ as_out_fmt1_desc.bSubslotSize = c_ssize;
+ as_out_fmt1_desc.bBitResolution = c_ssize * 8;
+ as_in_fmt1_desc.bSubslotSize = p_ssize;
+ as_in_fmt1_desc.bBitResolution = p_ssize * 8;
+
+ snprintf(clksrc_in, sizeof(clksrc_in), "%uHz", p_srate);
+ snprintf(clksrc_out, sizeof(clksrc_out), "%uHz", c_srate);
+
+ res = usb_add_function(cfg, &agdev_g->func);
+ if (res < 0)
+ kfree(agdev_g);
+
+ return res;
+}
+
+static void
+uac2_unbind_config(struct usb_configuration *cfg)
+{
+ kfree(agdev_g);
+ agdev_g = NULL;
+}
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c
index 47766f0e7caa..4fac56927741 100644
--- a/drivers/usb/gadget/file_storage.c
+++ b/drivers/usb/gadget/file_storage.c
@@ -855,7 +855,7 @@ static int class_setup_req(struct fsg_dev *fsg,
if (transport_is_bbb()) {
switch (ctrl->bRequest) {
- case USB_BULK_RESET_REQUEST:
+ case US_BULK_RESET_REQUEST:
if (ctrl->bRequestType != (USB_DIR_OUT |
USB_TYPE_CLASS | USB_RECIP_INTERFACE))
break;
@@ -871,7 +871,7 @@ static int class_setup_req(struct fsg_dev *fsg,
value = DELAYED_STATUS;
break;
- case USB_BULK_GET_MAX_LUN_REQUEST:
+ case US_BULK_GET_MAX_LUN:
if (ctrl->bRequestType != (USB_DIR_IN |
USB_TYPE_CLASS | USB_RECIP_INTERFACE))
break;
@@ -2125,7 +2125,7 @@ static int send_status(struct fsg_dev *fsg)
struct fsg_lun *curlun = fsg->curlun;
struct fsg_buffhd *bh;
int rc;
- u8 status = USB_STATUS_PASS;
+ u8 status = US_BULK_STAT_OK;
u32 sd, sdinfo = 0;
/* Wait for the next buffer to become available */
@@ -2146,11 +2146,11 @@ static int send_status(struct fsg_dev *fsg)
if (fsg->phase_error) {
DBG(fsg, "sending phase-error status\n");
- status = USB_STATUS_PHASE_ERROR;
+ status = US_BULK_STAT_PHASE;
sd = SS_INVALID_COMMAND;
} else if (sd != SS_NO_SENSE) {
DBG(fsg, "sending command-failure status\n");
- status = USB_STATUS_FAIL;
+ status = US_BULK_STAT_FAIL;
VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;"
" info x%x\n",
SK(sd), ASC(sd), ASCQ(sd), sdinfo);
@@ -2160,12 +2160,12 @@ static int send_status(struct fsg_dev *fsg)
struct bulk_cs_wrap *csw = bh->buf;
/* Store and send the Bulk-only CSW */
- csw->Signature = cpu_to_le32(USB_BULK_CS_SIG);
+ csw->Signature = cpu_to_le32(US_BULK_CS_SIGN);
csw->Tag = fsg->tag;
csw->Residue = cpu_to_le32(fsg->residue);
csw->Status = status;
- bh->inreq->length = USB_BULK_CS_WRAP_LEN;
+ bh->inreq->length = US_BULK_CS_WRAP_LEN;
bh->inreq->zero = 0;
start_transfer(fsg, fsg->bulk_in, bh->inreq,
&bh->inreq_busy, &bh->state);
@@ -2609,16 +2609,16 @@ static int do_scsi_command(struct fsg_dev *fsg)
static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
{
struct usb_request *req = bh->outreq;
- struct fsg_bulk_cb_wrap *cbw = req->buf;
+ struct bulk_cb_wrap *cbw = req->buf;
/* Was this a real packet? Should it be ignored? */
if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags))
return -EINVAL;
/* Is the CBW valid? */
- if (req->actual != USB_BULK_CB_WRAP_LEN ||
+ if (req->actual != US_BULK_CB_WRAP_LEN ||
cbw->Signature != cpu_to_le32(
- USB_BULK_CB_SIG)) {
+ US_BULK_CB_SIGN)) {
DBG(fsg, "invalid CBW: len %u sig 0x%x\n",
req->actual,
le32_to_cpu(cbw->Signature));
@@ -2638,7 +2638,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
}
/* Is the CBW meaningful? */
- if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~USB_BULK_IN_FLAG ||
+ if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN ||
cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) {
DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, "
"cmdlen %u\n",
@@ -2656,7 +2656,7 @@ static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh)
/* Save the command for later */
fsg->cmnd_size = cbw->Length;
memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size);
- if (cbw->Flags & USB_BULK_IN_FLAG)
+ if (cbw->Flags & US_BULK_FLAG_IN)
fsg->data_dir = DATA_DIR_TO_HOST;
else
fsg->data_dir = DATA_DIR_FROM_HOST;
@@ -2685,7 +2685,7 @@ static int get_next_command(struct fsg_dev *fsg)
}
/* Queue a request to read a Bulk-only CBW */
- set_bulk_out_req_length(fsg, bh, USB_BULK_CB_WRAP_LEN);
+ set_bulk_out_req_length(fsg, bh, US_BULK_CB_WRAP_LEN);
start_transfer(fsg, fsg->bulk_out, bh->outreq,
&bh->outreq_busy, &bh->state);
diff --git a/drivers/usb/gadget/fsl_qe_udc.c b/drivers/usb/gadget/fsl_qe_udc.c
index b95697c03d07..877a2c46672b 100644
--- a/drivers/usb/gadget/fsl_qe_udc.c
+++ b/drivers/usb/gadget/fsl_qe_udc.c
@@ -1638,6 +1638,7 @@ static int qe_ep_disable(struct usb_ep *_ep)
/* Nuke all pending requests (does flush) */
nuke(ep, -ESHUTDOWN);
ep->desc = NULL;
+ ep->ep.desc = NULL;
ep->stopped = 1;
ep->tx_req = NULL;
qe_ep_reset(udc, ep->epnum);
diff --git a/drivers/usb/gadget/fsl_udc_core.c b/drivers/usb/gadget/fsl_udc_core.c
index b04712f19f1e..55abfb6bd612 100644
--- a/drivers/usb/gadget/fsl_udc_core.c
+++ b/drivers/usb/gadget/fsl_udc_core.c
@@ -43,7 +43,6 @@
#include <asm/byteorder.h>
#include <asm/io.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#include <asm/dma.h>
@@ -659,6 +658,7 @@ static int fsl_ep_disable(struct usb_ep *_ep)
nuke(ep, -ESHUTDOWN);
ep->desc = NULL;
+ ep->ep.desc = NULL;
ep->stopped = 1;
spin_unlock_irqrestore(&udc->lock, flags);
@@ -730,7 +730,7 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
: (1 << (ep_index(ep)));
/* check if the pipe is empty */
- if (!(list_empty(&ep->queue))) {
+ if (!(list_empty(&ep->queue)) && !(ep_index(ep) == 0)) {
/* Add td to the end */
struct fsl_req *lastreq;
lastreq = list_entry(ep->queue.prev, struct fsl_req, queue);
@@ -768,7 +768,7 @@ static void fsl_queue_td(struct fsl_ep *ep, struct fsl_req *req)
* @is_last: return flag if it is the last dTD of the request
* return: pointer to the built dTD */
static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
- dma_addr_t *dma, int *is_last)
+ dma_addr_t *dma, int *is_last, gfp_t gfp_flags)
{
u32 swap_temp;
struct ep_td_struct *dtd;
@@ -777,7 +777,7 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
*length = min(req->req.length - req->req.actual,
(unsigned)EP_MAX_LENGTH_TRANSFER);
- dtd = dma_pool_alloc(udc_controller->td_pool, GFP_KERNEL, dma);
+ dtd = dma_pool_alloc(udc_controller->td_pool, gfp_flags, dma);
if (dtd == NULL)
return dtd;
@@ -827,7 +827,7 @@ static struct ep_td_struct *fsl_build_dtd(struct fsl_req *req, unsigned *length,
}
/* Generate dtd chain for a request */
-static int fsl_req_to_dtd(struct fsl_req *req)
+static int fsl_req_to_dtd(struct fsl_req *req, gfp_t gfp_flags)
{
unsigned count;
int is_last;
@@ -836,7 +836,7 @@ static int fsl_req_to_dtd(struct fsl_req *req)
dma_addr_t dma;
do {
- dtd = fsl_build_dtd(req, &count, &dma, &is_last);
+ dtd = fsl_build_dtd(req, &count, &dma, &is_last, gfp_flags);
if (dtd == NULL)
return -ENOMEM;
@@ -910,20 +910,14 @@ fsl_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
req->req.actual = 0;
req->dtd_count = 0;
- spin_lock_irqsave(&udc->lock, flags);
-
/* build dtds and push them to device queue */
- if (!fsl_req_to_dtd(req)) {
+ if (!fsl_req_to_dtd(req, gfp_flags)) {
+ spin_lock_irqsave(&udc->lock, flags);
fsl_queue_td(ep, req);
} else {
- spin_unlock_irqrestore(&udc->lock, flags);
return -ENOMEM;
}
- /* Update ep0 state */
- if ((ep_index(ep) == 0))
- udc->ep0_state = DATA_STATE_XMIT;
-
/* irq handler advances the queue */
if (req != NULL)
list_add_tail(&req->queue, &ep->queue);
@@ -1217,7 +1211,7 @@ static int fsl_vbus_draw(struct usb_gadget *gadget, unsigned mA)
udc = container_of(gadget, struct fsl_udc, gadget);
if (udc->transceiver)
- return otg_set_power(udc->transceiver, mA);
+ return usb_phy_set_power(udc->transceiver, mA);
return -ENOTSUPP;
}
@@ -1281,7 +1275,8 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction)
udc->ep0_dir = USB_DIR_OUT;
ep = &udc->eps[0];
- udc->ep0_state = WAIT_FOR_OUT_STATUS;
+ if (udc->ep0_state != DATA_STATE_XMIT)
+ udc->ep0_state = WAIT_FOR_OUT_STATUS;
req->ep = ep;
req->req.length = 0;
@@ -1295,7 +1290,7 @@ static int ep0_prime_status(struct fsl_udc *udc, int direction)
ep_is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
req->mapped = 1;
- if (fsl_req_to_dtd(req) == 0)
+ if (fsl_req_to_dtd(req, GFP_ATOMIC) == 0)
fsl_queue_td(ep, req);
else
return -ENOMEM;
@@ -1379,13 +1374,16 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
req->mapped = 1;
/* prime the data phase */
- if ((fsl_req_to_dtd(req) == 0))
+ if ((fsl_req_to_dtd(req, GFP_ATOMIC) == 0))
fsl_queue_td(ep, req);
else /* no mem */
goto stall;
list_add_tail(&req->queue, &ep->queue);
udc->ep0_state = DATA_STATE_XMIT;
+ if (ep0_prime_status(udc, EP_DIR_OUT))
+ ep0stall(udc);
+
return;
stall:
ep0stall(udc);
@@ -1494,6 +1492,14 @@ static void setup_received_irq(struct fsl_udc *udc,
spin_lock(&udc->lock);
udc->ep0_state = (setup->bRequestType & USB_DIR_IN)
? DATA_STATE_XMIT : DATA_STATE_RECV;
+ /*
+ * If the data stage is IN, send status prime immediately.
+ * See 2.0 Spec chapter 8.5.3.3 for detail.
+ */
+ if (udc->ep0_state == DATA_STATE_XMIT)
+ if (ep0_prime_status(udc, EP_DIR_OUT))
+ ep0stall(udc);
+
} else {
/* No data phase, IN status from gadget */
udc->ep0_dir = USB_DIR_IN;
@@ -1522,9 +1528,8 @@ static void ep0_req_complete(struct fsl_udc *udc, struct fsl_ep *ep0,
switch (udc->ep0_state) {
case DATA_STATE_XMIT:
- /* receive status phase */
- if (ep0_prime_status(udc, EP_DIR_OUT))
- ep0stall(udc);
+ /* already primed at setup_received_irq */
+ udc->ep0_state = WAIT_FOR_OUT_STATUS;
break;
case DATA_STATE_RECV:
/* send status phase */
@@ -1966,7 +1971,8 @@ static int fsl_start(struct usb_gadget_driver *driver,
/* connect to bus through transceiver */
if (udc_controller->transceiver) {
- retval = otg_set_peripheral(udc_controller->transceiver,
+ retval = otg_set_peripheral(
+ udc_controller->transceiver->otg,
&udc_controller->gadget);
if (retval < 0) {
ERR("can't bind to transceiver\n");
@@ -2006,7 +2012,7 @@ static int fsl_stop(struct usb_gadget_driver *driver)
return -EINVAL;
if (udc_controller->transceiver)
- otg_set_peripheral(udc_controller->transceiver, NULL);
+ otg_set_peripheral(udc_controller->transceiver->otg, NULL);
/* stop DR, disable intr */
dr_controller_stop(udc_controller);
@@ -2430,7 +2436,7 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
#ifdef CONFIG_USB_OTG
if (pdata->operating_mode == FSL_USB2_DR_OTG) {
- udc_controller->transceiver = otg_get_transceiver();
+ udc_controller->transceiver = usb_get_transceiver();
if (!udc_controller->transceiver) {
ERR("Can't find OTG driver!\n");
ret = -ENODEV;
diff --git a/drivers/usb/gadget/fsl_usb2_udc.h b/drivers/usb/gadget/fsl_usb2_udc.h
index f781f5dec417..e651469fd39b 100644
--- a/drivers/usb/gadget/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/fsl_usb2_udc.h
@@ -471,7 +471,7 @@ struct fsl_udc {
struct usb_ctrlrequest local_setup_buff;
spinlock_t lock;
- struct otg_transceiver *transceiver;
+ struct usb_phy *transceiver;
unsigned softconnect:1;
unsigned vbus_active:1;
unsigned stopped:1;
diff --git a/drivers/usb/gadget/g_ffs.c b/drivers/usb/gadget/g_ffs.c
index 0519d77915ec..a85eaf40b948 100644
--- a/drivers/usb/gadget/g_ffs.c
+++ b/drivers/usb/gadget/g_ffs.c
@@ -2,7 +2,7 @@
* g_ffs.c -- user mode file system API for USB composite function controllers
*
* Copyright (C) 2010 Samsung Electronics
- * Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
+ * Author: Michal Nazarewicz <mina86@mina86.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -161,7 +161,7 @@ static struct usb_composite_driver gfs_driver = {
static struct ffs_data *gfs_ffs_data;
static unsigned long gfs_registered;
-static int gfs_init(void)
+static int __init gfs_init(void)
{
ENTER();
@@ -169,7 +169,7 @@ static int gfs_init(void)
}
module_init(gfs_init);
-static void gfs_exit(void)
+static void __exit gfs_exit(void)
{
ENTER();
diff --git a/drivers/usb/gadget/goku_udc.c b/drivers/usb/gadget/goku_udc.c
index 5af70fcce139..e151d6b87dee 100644
--- a/drivers/usb/gadget/goku_udc.c
+++ b/drivers/usb/gadget/goku_udc.c
@@ -43,7 +43,6 @@
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
@@ -235,6 +234,7 @@ static void ep_reset(struct goku_udc_regs __iomem *regs, struct goku_ep *ep)
ep->ep.maxpacket = MAX_FIFO_SIZE;
ep->desc = NULL;
+ ep->ep.desc = NULL;
ep->stopped = 1;
ep->irqs = 0;
ep->dma = 0;
@@ -310,12 +310,9 @@ done(struct goku_ep *ep, struct goku_request *req, int status)
status = req->req.status;
dev = ep->dev;
- if (req->mapped) {
- pci_unmap_single(dev->pdev, req->req.dma, req->req.length,
- ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
- req->req.dma = DMA_ADDR_INVALID;
- req->mapped = 0;
- }
+
+ if (ep->dma)
+ usb_gadget_unmap_request(&dev->gadget, &req->req, ep->is_in);
#ifndef USB_TRACE
if (status && status != -ESHUTDOWN)
@@ -736,10 +733,11 @@ goku_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
return -EBUSY;
/* set up dma mapping in case the caller didn't */
- if (ep->dma && _req->dma == DMA_ADDR_INVALID) {
- _req->dma = pci_map_single(dev->pdev, _req->buf, _req->length,
- ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
- req->mapped = 1;
+ if (ep->dma) {
+ status = usb_gadget_map_request(&dev->gadget, &req->req,
+ ep->is_in);
+ if (status)
+ return status;
}
#ifdef USB_TRACE
diff --git a/drivers/usb/gadget/hid.c b/drivers/usb/gadget/hid.c
index f888c3ede860..3493adf064f5 100644
--- a/drivers/usb/gadget/hid.c
+++ b/drivers/usb/gadget/hid.c
@@ -60,9 +60,9 @@ static struct usb_device_descriptor device_desc = {
/* .bDeviceClass = USB_CLASS_COMM, */
/* .bDeviceSubClass = 0, */
/* .bDeviceProtocol = 0, */
- .bDeviceClass = 0xEF,
- .bDeviceSubClass = 2,
- .bDeviceProtocol = 1,
+ .bDeviceClass = USB_CLASS_PER_INTERFACE,
+ .bDeviceSubClass = 0,
+ .bDeviceProtocol = 0,
/* .bMaxPacketSize0 = f(hardware) */
/* Vendor and product id can be overridden by module parameters. */
diff --git a/drivers/usb/gadget/inode.c b/drivers/usb/gadget/inode.c
index ae04266dba1b..e58b16442971 100644
--- a/drivers/usb/gadget/inode.c
+++ b/drivers/usb/gadget/inode.c
@@ -1043,6 +1043,8 @@ ep0_read (struct file *fd, char __user *buf, size_t len, loff_t *ptr)
// FIXME don't call this with the spinlock held ...
if (copy_to_user (buf, dev->req->buf, len))
retval = -EFAULT;
+ else
+ retval = len;
clean_req (dev->gadget->ep0, dev->req);
/* NOTE userspace can't yet choose to stall */
}
@@ -1569,20 +1571,17 @@ delegate:
static void destroy_ep_files (struct dev_data *dev)
{
- struct list_head *entry, *tmp;
-
DBG (dev, "%s %d\n", __func__, dev->state);
/* dev->state must prevent interference */
-restart:
spin_lock_irq (&dev->lock);
- list_for_each_safe (entry, tmp, &dev->epfiles) {
+ while (!list_empty(&dev->epfiles)) {
struct ep_data *ep;
struct inode *parent;
struct dentry *dentry;
/* break link to FS */
- ep = list_entry (entry, struct ep_data, epfiles);
+ ep = list_first_entry (&dev->epfiles, struct ep_data, epfiles);
list_del_init (&ep->epfiles);
dentry = ep->dentry;
ep->dentry = NULL;
@@ -1605,8 +1604,7 @@ restart:
dput (dentry);
mutex_unlock (&parent->i_mutex);
- /* fds may still be open */
- goto restart;
+ spin_lock_irq (&dev->lock);
}
spin_unlock_irq (&dev->lock);
}
@@ -2059,10 +2057,8 @@ gadgetfs_fill_super (struct super_block *sb, void *opts, int silent)
if (!inode)
goto Enomem;
inode->i_op = &simple_dir_inode_operations;
- if (!(sb->s_root = d_alloc_root (inode))) {
- iput(inode);
+ if (!(sb->s_root = d_make_root (inode)))
goto Enomem;
- }
/* the ep0 file is named after the controller we expect;
* user mode code can use it for sanity checks, like we do.
diff --git a/drivers/usb/gadget/langwell_udc.c b/drivers/usb/gadget/langwell_udc.c
index e2293c1588ee..f9cedd52cf20 100644
--- a/drivers/usb/gadget/langwell_udc.c
+++ b/drivers/usb/gadget/langwell_udc.c
@@ -32,7 +32,6 @@
#include <linux/pm.h>
#include <linux/io.h>
#include <linux/irq.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#include "langwell_udc.h"
@@ -401,16 +400,7 @@ static void done(struct langwell_ep *ep, struct langwell_request *req,
dma_pool_free(dev->dtd_pool, curr_dtd, curr_dtd->dtd_dma);
}
- if (req->mapped) {
- dma_unmap_single(&dev->pdev->dev,
- req->req.dma, req->req.length,
- is_in(ep) ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
- req->req.dma = DMA_ADDR_INVALID;
- req->mapped = 0;
- } else
- dma_sync_single_for_cpu(&dev->pdev->dev, req->req.dma,
- req->req.length,
- is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ usb_gadget_unmap_request(&dev->gadget, &req->req, is_in(ep));
if (status != -ESHUTDOWN)
dev_dbg(&dev->pdev->dev,
@@ -487,6 +477,7 @@ static int langwell_ep_disable(struct usb_ep *_ep)
nuke(ep, -ESHUTDOWN);
ep->desc = NULL;
+ ep->ep.desc = NULL;
ep->stopped = 1;
spin_unlock_irqrestore(&dev->lock, flags);
@@ -749,7 +740,8 @@ static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
struct langwell_ep *ep;
struct langwell_udc *dev;
unsigned long flags;
- int is_iso = 0, zlflag = 0;
+ int is_iso = 0;
+ int ret;
/* always require a cpu-view buffer */
req = container_of(_req, struct langwell_request, req);
@@ -776,33 +768,10 @@ static int langwell_ep_queue(struct usb_ep *_ep, struct usb_request *_req,
if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN))
return -ESHUTDOWN;
- /* set up dma mapping in case the caller didn't */
- if (_req->dma == DMA_ADDR_INVALID) {
- /* WORKAROUND: WARN_ON(size == 0) */
- if (_req->length == 0) {
- dev_vdbg(&dev->pdev->dev, "req->length: 0->1\n");
- zlflag = 1;
- _req->length++;
- }
-
- _req->dma = dma_map_single(&dev->pdev->dev,
- _req->buf, _req->length,
- is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- if (zlflag && (_req->length == 1)) {
- dev_vdbg(&dev->pdev->dev, "req->length: 1->0\n");
- zlflag = 0;
- _req->length = 0;
- }
-
- req->mapped = 1;
- dev_vdbg(&dev->pdev->dev, "req->mapped = 1\n");
- } else {
- dma_sync_single_for_device(&dev->pdev->dev,
- _req->dma, _req->length,
- is_in(ep) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- req->mapped = 0;
- dev_vdbg(&dev->pdev->dev, "req->mapped = 0\n");
- }
+ /* set up dma mapping */
+ ret = usb_gadget_map_request(&dev->gadget, &req->req, is_in(ep));
+ if (ret)
+ return ret;
dev_dbg(&dev->pdev->dev,
"%s queue req %p, len %u, buf %p, dma 0x%08x\n",
@@ -1261,9 +1230,9 @@ static int langwell_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
if (dev->transceiver) {
- dev_vdbg(&dev->pdev->dev, "otg_set_power\n");
+ dev_vdbg(&dev->pdev->dev, "usb_phy_set_power\n");
dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
- return otg_set_power(dev->transceiver, mA);
+ return usb_phy_set_power(dev->transceiver, mA);
}
dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
@@ -1906,7 +1875,7 @@ static int langwell_stop(struct usb_gadget *g,
/* unbind OTG transceiver */
if (dev->transceiver)
- (void)otg_set_peripheral(dev->transceiver, 0);
+ (void)otg_set_peripheral(dev->transceiver->otg, 0);
/* disable interrupt and set controller to stop state */
langwell_udc_stop(dev);
diff --git a/drivers/usb/gadget/langwell_udc.h b/drivers/usb/gadget/langwell_udc.h
index d6e78accaffe..8c8087abb481 100644
--- a/drivers/usb/gadget/langwell_udc.h
+++ b/drivers/usb/gadget/langwell_udc.h
@@ -162,7 +162,7 @@ struct langwell_udc {
spinlock_t lock; /* device lock */
struct langwell_ep *ep;
struct usb_gadget_driver *driver;
- struct otg_transceiver *transceiver;
+ struct usb_phy *transceiver;
u8 dev_addr;
u32 usb_state;
u32 resume_state;
diff --git a/drivers/usb/gadget/mass_storage.c b/drivers/usb/gadget/mass_storage.c
index e24f72f82a47..1f376eba31f6 100644
--- a/drivers/usb/gadget/mass_storage.c
+++ b/drivers/usb/gadget/mass_storage.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2003-2008 Alan Stern
* Copyright (C) 2009 Samsung Electronics
- * Author: Michal Nazarewicz <m.nazarewicz@samsung.com>
+ * Author: Michal Nazarewicz <mina86@mina86.com>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
diff --git a/drivers/usb/gadget/multi.c b/drivers/usb/gadget/multi.c
index 7e7f515b8b19..c37fb33a3d1b 100644
--- a/drivers/usb/gadget/multi.c
+++ b/drivers/usb/gadget/multi.c
@@ -4,7 +4,7 @@
* Copyright (C) 2008 David Brownell
* Copyright (C) 2008 Nokia Corporation
* Copyright (C) 2009 Samsung Electronics
- * Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
+ * Author: Michal Nazarewicz (mina86@mina86.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/drivers/usb/gadget/mv_udc.h b/drivers/usb/gadget/mv_udc.h
index 34aadfae723d..e2be9519abbe 100644
--- a/drivers/usb/gadget/mv_udc.h
+++ b/drivers/usb/gadget/mv_udc.h
@@ -217,7 +217,7 @@ struct mv_udc {
struct work_struct vbus_work;
struct workqueue_struct *qwork;
- struct otg_transceiver *transceiver;
+ struct usb_phy *transceiver;
struct mv_usb_platform_data *pdata;
diff --git a/drivers/usb/gadget/mv_udc_core.c b/drivers/usb/gadget/mv_udc_core.c
index f97e737d26f7..a73cf406e2a4 100644
--- a/drivers/usb/gadget/mv_udc_core.c
+++ b/drivers/usb/gadget/mv_udc_core.c
@@ -34,7 +34,6 @@
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/platform_data/mv_usb.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#include "mv_udc.h"
@@ -608,6 +607,7 @@ static int mv_ep_disable(struct usb_ep *_ep)
nuke(ep, -ESHUTDOWN);
ep->desc = NULL;
+ ep->ep.desc = NULL;
ep->stopped = 1;
spin_unlock_irqrestore(&udc->lock, flags);
@@ -771,8 +771,7 @@ mv_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
udc->ep0_state = DATA_STATE_XMIT;
/* irq handler advances the queue */
- if (req != NULL)
- list_add_tail(&req->queue, &ep->queue);
+ list_add_tail(&req->queue, &ep->queue);
spin_unlock_irqrestore(&udc->lock, flags);
return 0;
@@ -1384,7 +1383,8 @@ static int mv_udc_start(struct usb_gadget_driver *driver,
}
if (udc->transceiver) {
- retval = otg_set_peripheral(udc->transceiver, &udc->gadget);
+ retval = otg_set_peripheral(udc->transceiver->otg,
+ &udc->gadget);
if (retval) {
dev_err(&udc->dev->dev,
"unable to register peripheral to otg\n");
@@ -2181,7 +2181,7 @@ static int __devinit mv_udc_probe(struct platform_device *dev)
#ifdef CONFIG_USB_OTG_UTILS
if (pdata->mode == MV_USB_MODE_OTG)
- udc->transceiver = otg_get_transceiver();
+ udc->transceiver = usb_get_transceiver();
#endif
udc->clknum = pdata->clknum;
diff --git a/drivers/usb/gadget/net2272.c b/drivers/usb/gadget/net2272.c
index 7322d293213e..43ac7482fa91 100644
--- a/drivers/usb/gadget/net2272.c
+++ b/drivers/usb/gadget/net2272.c
@@ -42,7 +42,6 @@
#include <linux/usb/gadget.h>
#include <asm/byteorder.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#include "net2272.h"
@@ -385,12 +384,9 @@ net2272_done(struct net2272_ep *ep, struct net2272_request *req, int status)
status = req->req.status;
dev = ep->dev;
- if (use_dma && req->mapped) {
- dma_unmap_single(dev->dev, req->req.dma, req->req.length,
- ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- req->req.dma = DMA_ADDR_INVALID;
- req->mapped = 0;
- }
+ if (use_dma && ep->dma)
+ usb_gadget_unmap_request(&dev->gadget, &req->req,
+ ep->is_in);
if (status && status != -ESHUTDOWN)
dev_vdbg(dev->dev, "complete %s req %p stat %d len %u/%u buf %p\n",
@@ -850,10 +846,11 @@ net2272_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
return -ESHUTDOWN;
/* set up dma mapping in case the caller didn't */
- if (use_dma && ep->dma && _req->dma == DMA_ADDR_INVALID) {
- _req->dma = dma_map_single(dev->dev, _req->buf, _req->length,
- ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
- req->mapped = 1;
+ if (use_dma && ep->dma) {
+ status = usb_gadget_map_request(&dev->gadget, _req,
+ ep->is_in);
+ if (status)
+ return status;
}
dev_vdbg(dev->dev, "%s queue req %p, len %d buf %p dma %08llx %s\n",
diff --git a/drivers/usb/gadget/net2280.c b/drivers/usb/gadget/net2280.c
index cdedd1336745..ac335af154ba 100644
--- a/drivers/usb/gadget/net2280.c
+++ b/drivers/usb/gadget/net2280.c
@@ -59,7 +59,6 @@
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
@@ -806,12 +805,8 @@ done (struct net2280_ep *ep, struct net2280_request *req, int status)
status = req->req.status;
dev = ep->dev;
- if (req->mapped) {
- pci_unmap_single (dev->pdev, req->req.dma, req->req.length,
- ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
- req->req.dma = DMA_ADDR_INVALID;
- req->mapped = 0;
- }
+ if (ep->dma)
+ usb_gadget_unmap_request(&dev->gadget, &req->req, ep->is_in);
if (status && status != -ESHUTDOWN)
VDEBUG (dev, "complete %s req %p stat %d len %u/%u\n",
@@ -857,10 +852,13 @@ net2280_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
return -EOPNOTSUPP;
/* set up dma mapping in case the caller didn't */
- if (ep->dma && _req->dma == DMA_ADDR_INVALID) {
- _req->dma = pci_map_single (dev->pdev, _req->buf, _req->length,
- ep->is_in ? PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
- req->mapped = 1;
+ if (ep->dma) {
+ int ret;
+
+ ret = usb_gadget_map_request(&dev->gadget, _req,
+ ep->is_in);
+ if (ret)
+ return ret;
}
#if 0
diff --git a/drivers/usb/gadget/omap_udc.c b/drivers/usb/gadget/omap_udc.c
index 576cd8578b45..3b4b6dd0f95a 100644
--- a/drivers/usb/gadget/omap_udc.c
+++ b/drivers/usb/gadget/omap_udc.c
@@ -40,7 +40,6 @@
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#include <asm/mach-types.h>
@@ -251,6 +250,7 @@ static int omap_ep_disable(struct usb_ep *_ep)
spin_lock_irqsave(&ep->udc->lock, flags);
ep->desc = NULL;
+ ep->ep.desc = NULL;
nuke (ep, -ESHUTDOWN);
ep->ep.maxpacket = ep->maxpacket;
ep->has_dma = 0;
@@ -1213,7 +1213,7 @@ static int omap_wakeup(struct usb_gadget *gadget)
/* NOTE: non-OTG systems may use SRP TOO... */
} else if (!(udc->devstat & UDC_ATT)) {
if (udc->transceiver)
- retval = otg_start_srp(udc->transceiver);
+ retval = otg_start_srp(udc->transceiver->otg);
}
spin_unlock_irqrestore(&udc->lock, flags);
@@ -1345,7 +1345,7 @@ static int omap_vbus_draw(struct usb_gadget *gadget, unsigned mA)
udc = container_of(gadget, struct omap_udc, gadget);
if (udc->transceiver)
- return otg_set_power(udc->transceiver, mA);
+ return usb_phy_set_power(udc->transceiver, mA);
return -EOPNOTSUPP;
}
@@ -1839,11 +1839,13 @@ static void devstate_irq(struct omap_udc *udc, u16 irq_src)
spin_lock(&udc->lock);
}
if (udc->transceiver)
- otg_set_suspend(udc->transceiver, 1);
+ usb_phy_set_suspend(
+ udc->transceiver, 1);
} else {
VDBG("resume\n");
if (udc->transceiver)
- otg_set_suspend(udc->transceiver, 0);
+ usb_phy_set_suspend(
+ udc->transceiver, 0);
if (udc->gadget.speed == USB_SPEED_FULL
&& udc->driver->resume) {
spin_unlock(&udc->lock);
@@ -2154,7 +2156,8 @@ static int omap_udc_start(struct usb_gadget_driver *driver,
/* connect to bus through transceiver */
if (udc->transceiver) {
- status = otg_set_peripheral(udc->transceiver, &udc->gadget);
+ status = otg_set_peripheral(udc->transceiver->otg,
+ &udc->gadget);
if (status < 0) {
ERR("can't bind to transceiver\n");
if (driver->unbind) {
@@ -2200,7 +2203,7 @@ static int omap_udc_stop(struct usb_gadget_driver *driver)
omap_vbus_session(&udc->gadget, 0);
if (udc->transceiver)
- (void) otg_set_peripheral(udc->transceiver, NULL);
+ (void) otg_set_peripheral(udc->transceiver->otg, NULL);
else
pullup_disable(udc);
@@ -2650,7 +2653,7 @@ static void omap_udc_release(struct device *dev)
}
static int __init
-omap_udc_setup(struct platform_device *odev, struct otg_transceiver *xceiv)
+omap_udc_setup(struct platform_device *odev, struct usb_phy *xceiv)
{
unsigned tmp, buf;
@@ -2790,7 +2793,7 @@ static int __init omap_udc_probe(struct platform_device *pdev)
{
int status = -ENODEV;
int hmc;
- struct otg_transceiver *xceiv = NULL;
+ struct usb_phy *xceiv = NULL;
const char *type = NULL;
struct omap_usb_config *config = pdev->dev.platform_data;
struct clk *dc_clk;
@@ -2863,7 +2866,7 @@ static int __init omap_udc_probe(struct platform_device *pdev)
* use it. Except for OTG, we don't _need_ to talk to one;
* but not having one probably means no VBUS detection.
*/
- xceiv = otg_get_transceiver();
+ xceiv = usb_get_transceiver();
if (xceiv)
type = xceiv->label;
else if (config->otg) {
@@ -3009,7 +3012,7 @@ cleanup1:
cleanup0:
if (xceiv)
- otg_put_transceiver(xceiv);
+ usb_put_transceiver(xceiv);
if (cpu_is_omap16xx() || cpu_is_omap24xx() || cpu_is_omap7xx()) {
clk_disable(hhc_clk);
@@ -3039,7 +3042,7 @@ static int __exit omap_udc_remove(struct platform_device *pdev)
pullup_disable(udc);
if (udc->transceiver) {
- otg_put_transceiver(udc->transceiver);
+ usb_put_transceiver(udc->transceiver);
udc->transceiver = NULL;
}
omap_writew(0, UDC_SYSCON1);
diff --git a/drivers/usb/gadget/omap_udc.h b/drivers/usb/gadget/omap_udc.h
index 29edc51b6b22..59d3b2213cb1 100644
--- a/drivers/usb/gadget/omap_udc.h
+++ b/drivers/usb/gadget/omap_udc.h
@@ -164,7 +164,7 @@ struct omap_udc {
struct omap_ep ep[32];
u16 devstat;
u16 clr_halt;
- struct otg_transceiver *transceiver;
+ struct usb_phy *transceiver;
struct list_head iso;
unsigned softconnect:1;
unsigned vbus_active:1;
diff --git a/drivers/usb/gadget/pch_udc.c b/drivers/usb/gadget/pch_udc.c
index a3fcaae4bc2a..65307064a6fd 100644
--- a/drivers/usb/gadget/pch_udc.c
+++ b/drivers/usb/gadget/pch_udc.c
@@ -15,6 +15,14 @@
#include <linux/interrupt.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
+#include <linux/gpio.h>
+#include <linux/irq.h>
+
+/* GPIO port for VBUS detecting */
+static int vbus_gpio_port = -1; /* GPIO port number (-1:Not used) */
+
+#define PCH_VBUS_PERIOD 3000 /* VBUS polling period (msec) */
+#define PCH_VBUS_INTERVAL 10 /* VBUS polling interval (msec) */
/* Address offset of Registers */
#define UDC_EP_REG_SHIFT 0x20 /* Offset to next EP */
@@ -296,6 +304,21 @@ struct pch_udc_ep {
};
/**
+ * struct pch_vbus_gpio_data - Structure holding GPIO informaton
+ * for detecting VBUS
+ * @port: gpio port number
+ * @intr: gpio interrupt number
+ * @irq_work_fall Structure for WorkQueue
+ * @irq_work_rise Structure for WorkQueue
+ */
+struct pch_vbus_gpio_data {
+ int port;
+ int intr;
+ struct work_struct irq_work_fall;
+ struct work_struct irq_work_rise;
+};
+
+/**
* struct pch_udc_dev - Structure holding complete information
* of the PCH USB device
* @gadget: gadget driver data
@@ -311,6 +334,7 @@ struct pch_udc_ep {
* @registered: driver regsitered with system
* @suspended: driver in suspended state
* @connected: gadget driver associated
+ * @vbus_session: required vbus_session state
* @set_cfg_not_acked: pending acknowledgement 4 setup
* @waiting_zlp_ack: pending acknowledgement 4 ZLP
* @data_requests: DMA pool for data requests
@@ -322,6 +346,7 @@ struct pch_udc_ep {
* @base_addr: for mapped device memory
* @irq: IRQ line for the device
* @cfg_data: current cfg, intf, and alt in use
+ * @vbus_gpio: GPIO informaton for detecting VBUS
*/
struct pch_udc_dev {
struct usb_gadget gadget;
@@ -337,6 +362,7 @@ struct pch_udc_dev {
registered:1,
suspended:1,
connected:1,
+ vbus_session:1,
set_cfg_not_acked:1,
waiting_zlp_ack:1;
struct pci_pool *data_requests;
@@ -347,7 +373,8 @@ struct pch_udc_dev {
unsigned long phys_addr;
void __iomem *base_addr;
unsigned irq;
- struct pch_udc_cfg_data cfg_data;
+ struct pch_udc_cfg_data cfg_data;
+ struct pch_vbus_gpio_data vbus_gpio;
};
#define PCH_UDC_PCI_BAR 1
@@ -554,6 +581,29 @@ static void pch_udc_clear_disconnect(struct pch_udc_dev *dev)
}
/**
+ * pch_udc_reconnect() - This API initializes usb device controller,
+ * and clear the disconnect status.
+ * @dev: Reference to pch_udc_regs structure
+ */
+static void pch_udc_init(struct pch_udc_dev *dev);
+static void pch_udc_reconnect(struct pch_udc_dev *dev)
+{
+ pch_udc_init(dev);
+
+ /* enable device interrupts */
+ /* pch_udc_enable_interrupts() */
+ pch_udc_bit_clr(dev, UDC_DEVIRQMSK_ADDR,
+ UDC_DEVINT_UR | UDC_DEVINT_ENUM);
+
+ /* Clear the disconnect */
+ pch_udc_bit_set(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
+ pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_SD);
+ mdelay(1);
+ /* Resume USB signalling */
+ pch_udc_bit_clr(dev, UDC_DEVCTL_ADDR, UDC_DEVCTL_RES);
+}
+
+/**
* pch_udc_vbus_session() - set or clearr the disconnect status.
* @dev: Reference to pch_udc_regs structure
* @is_active: Parameter specifying the action
@@ -563,10 +613,18 @@ static void pch_udc_clear_disconnect(struct pch_udc_dev *dev)
static inline void pch_udc_vbus_session(struct pch_udc_dev *dev,
int is_active)
{
- if (is_active)
- pch_udc_clear_disconnect(dev);
- else
+ if (is_active) {
+ pch_udc_reconnect(dev);
+ dev->vbus_session = 1;
+ } else {
+ if (dev->driver && dev->driver->disconnect) {
+ spin_unlock(&dev->lock);
+ dev->driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
pch_udc_set_disconnect(dev);
+ dev->vbus_session = 0;
+ }
}
/**
@@ -1126,7 +1184,17 @@ static int pch_udc_pcd_pullup(struct usb_gadget *gadget, int is_on)
if (!gadget)
return -EINVAL;
dev = container_of(gadget, struct pch_udc_dev, gadget);
- pch_udc_vbus_session(dev, is_on);
+ if (is_on) {
+ pch_udc_reconnect(dev);
+ } else {
+ if (dev->driver && dev->driver->disconnect) {
+ spin_unlock(&dev->lock);
+ dev->driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
+ pch_udc_set_disconnect(dev);
+ }
+
return 0;
}
@@ -1183,6 +1251,188 @@ static const struct usb_gadget_ops pch_udc_ops = {
};
/**
+ * pch_vbus_gpio_get_value() - This API gets value of GPIO port as VBUS status.
+ * @dev: Reference to the driver structure
+ *
+ * Return value:
+ * 1: VBUS is high
+ * 0: VBUS is low
+ * -1: It is not enable to detect VBUS using GPIO
+ */
+static int pch_vbus_gpio_get_value(struct pch_udc_dev *dev)
+{
+ int vbus = 0;
+
+ if (dev->vbus_gpio.port)
+ vbus = gpio_get_value(dev->vbus_gpio.port) ? 1 : 0;
+ else
+ vbus = -1;
+
+ return vbus;
+}
+
+/**
+ * pch_vbus_gpio_work_fall() - This API keeps watch on VBUS becoming Low.
+ * If VBUS is Low, disconnect is processed
+ * @irq_work: Structure for WorkQueue
+ *
+ */
+static void pch_vbus_gpio_work_fall(struct work_struct *irq_work)
+{
+ struct pch_vbus_gpio_data *vbus_gpio = container_of(irq_work,
+ struct pch_vbus_gpio_data, irq_work_fall);
+ struct pch_udc_dev *dev =
+ container_of(vbus_gpio, struct pch_udc_dev, vbus_gpio);
+ int vbus_saved = -1;
+ int vbus;
+ int count;
+
+ if (!dev->vbus_gpio.port)
+ return;
+
+ for (count = 0; count < (PCH_VBUS_PERIOD / PCH_VBUS_INTERVAL);
+ count++) {
+ vbus = pch_vbus_gpio_get_value(dev);
+
+ if ((vbus_saved == vbus) && (vbus == 0)) {
+ dev_dbg(&dev->pdev->dev, "VBUS fell");
+ if (dev->driver
+ && dev->driver->disconnect) {
+ dev->driver->disconnect(
+ &dev->gadget);
+ }
+ if (dev->vbus_gpio.intr)
+ pch_udc_init(dev);
+ else
+ pch_udc_reconnect(dev);
+ return;
+ }
+ vbus_saved = vbus;
+ mdelay(PCH_VBUS_INTERVAL);
+ }
+}
+
+/**
+ * pch_vbus_gpio_work_rise() - This API checks VBUS is High.
+ * If VBUS is High, connect is processed
+ * @irq_work: Structure for WorkQueue
+ *
+ */
+static void pch_vbus_gpio_work_rise(struct work_struct *irq_work)
+{
+ struct pch_vbus_gpio_data *vbus_gpio = container_of(irq_work,
+ struct pch_vbus_gpio_data, irq_work_rise);
+ struct pch_udc_dev *dev =
+ container_of(vbus_gpio, struct pch_udc_dev, vbus_gpio);
+ int vbus;
+
+ if (!dev->vbus_gpio.port)
+ return;
+
+ mdelay(PCH_VBUS_INTERVAL);
+ vbus = pch_vbus_gpio_get_value(dev);
+
+ if (vbus == 1) {
+ dev_dbg(&dev->pdev->dev, "VBUS rose");
+ pch_udc_reconnect(dev);
+ return;
+ }
+}
+
+/**
+ * pch_vbus_gpio_irq() - IRQ handler for GPIO intrerrupt for changing VBUS
+ * @irq: Interrupt request number
+ * @dev: Reference to the device structure
+ *
+ * Return codes:
+ * 0: Success
+ * -EINVAL: GPIO port is invalid or can't be initialized.
+ */
+static irqreturn_t pch_vbus_gpio_irq(int irq, void *data)
+{
+ struct pch_udc_dev *dev = (struct pch_udc_dev *)data;
+
+ if (!dev->vbus_gpio.port || !dev->vbus_gpio.intr)
+ return IRQ_NONE;
+
+ if (pch_vbus_gpio_get_value(dev))
+ schedule_work(&dev->vbus_gpio.irq_work_rise);
+ else
+ schedule_work(&dev->vbus_gpio.irq_work_fall);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * pch_vbus_gpio_init() - This API initializes GPIO port detecting VBUS.
+ * @dev: Reference to the driver structure
+ * @vbus_gpio Number of GPIO port to detect gpio
+ *
+ * Return codes:
+ * 0: Success
+ * -EINVAL: GPIO port is invalid or can't be initialized.
+ */
+static int pch_vbus_gpio_init(struct pch_udc_dev *dev, int vbus_gpio_port)
+{
+ int err;
+ int irq_num = 0;
+
+ dev->vbus_gpio.port = 0;
+ dev->vbus_gpio.intr = 0;
+
+ if (vbus_gpio_port <= -1)
+ return -EINVAL;
+
+ err = gpio_is_valid(vbus_gpio_port);
+ if (!err) {
+ pr_err("%s: gpio port %d is invalid\n",
+ __func__, vbus_gpio_port);
+ return -EINVAL;
+ }
+
+ err = gpio_request(vbus_gpio_port, "pch_vbus");
+ if (err) {
+ pr_err("%s: can't request gpio port %d, err: %d\n",
+ __func__, vbus_gpio_port, err);
+ return -EINVAL;
+ }
+
+ dev->vbus_gpio.port = vbus_gpio_port;
+ gpio_direction_input(vbus_gpio_port);
+ INIT_WORK(&dev->vbus_gpio.irq_work_fall, pch_vbus_gpio_work_fall);
+
+ irq_num = gpio_to_irq(vbus_gpio_port);
+ if (irq_num > 0) {
+ irq_set_irq_type(irq_num, IRQ_TYPE_EDGE_BOTH);
+ err = request_irq(irq_num, pch_vbus_gpio_irq, 0,
+ "vbus_detect", dev);
+ if (!err) {
+ dev->vbus_gpio.intr = irq_num;
+ INIT_WORK(&dev->vbus_gpio.irq_work_rise,
+ pch_vbus_gpio_work_rise);
+ } else {
+ pr_err("%s: can't request irq %d, err: %d\n",
+ __func__, irq_num, err);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * pch_vbus_gpio_free() - This API frees resources of GPIO port
+ * @dev: Reference to the driver structure
+ */
+static void pch_vbus_gpio_free(struct pch_udc_dev *dev)
+{
+ if (dev->vbus_gpio.intr)
+ free_irq(dev->vbus_gpio.intr, dev);
+
+ if (dev->vbus_gpio.port)
+ gpio_free(dev->vbus_gpio.port);
+}
+
+/**
* complete_req() - This API is invoked from the driver when processing
* of a request is complete
* @ep: Reference to the endpoint structure
@@ -1493,6 +1743,7 @@ static int pch_udc_pcd_ep_disable(struct usb_ep *usbep)
pch_udc_ep_disable(ep);
pch_udc_disable_ep_interrupts(ep->dev, PCH_UDC_EPINT(ep->in, ep->num));
ep->desc = NULL;
+ ep->ep.desc = NULL;
INIT_LIST_HEAD(&ep->queue);
spin_unlock_irqrestore(&ep->dev->lock, iflags);
return 0;
@@ -2335,8 +2586,11 @@ static void pch_udc_svc_ur_interrupt(struct pch_udc_dev *dev)
/* Complete request queue */
empty_req_queue(ep);
}
- if (dev->driver && dev->driver->disconnect)
+ if (dev->driver && dev->driver->disconnect) {
+ spin_unlock(&dev->lock);
dev->driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
}
/**
@@ -2371,6 +2625,11 @@ static void pch_udc_svc_enum_interrupt(struct pch_udc_dev *dev)
pch_udc_set_dma(dev, DMA_DIR_TX);
pch_udc_set_dma(dev, DMA_DIR_RX);
pch_udc_ep_set_rrdy(&(dev->ep[UDC_EP0OUT_IDX]));
+
+ /* enable device interrupts */
+ pch_udc_enable_interrupts(dev, UDC_DEVINT_UR | UDC_DEVINT_US |
+ UDC_DEVINT_ES | UDC_DEVINT_ENUM |
+ UDC_DEVINT_SI | UDC_DEVINT_SC);
}
/**
@@ -2459,12 +2718,18 @@ static void pch_udc_svc_cfg_interrupt(struct pch_udc_dev *dev)
*/
static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr)
{
+ int vbus;
+
/* USB Reset Interrupt */
- if (dev_intr & UDC_DEVINT_UR)
+ if (dev_intr & UDC_DEVINT_UR) {
pch_udc_svc_ur_interrupt(dev);
+ dev_dbg(&dev->pdev->dev, "USB_RESET\n");
+ }
/* Enumeration Done Interrupt */
- if (dev_intr & UDC_DEVINT_ENUM)
+ if (dev_intr & UDC_DEVINT_ENUM) {
pch_udc_svc_enum_interrupt(dev);
+ dev_dbg(&dev->pdev->dev, "USB_ENUM\n");
+ }
/* Set Interface Interrupt */
if (dev_intr & UDC_DEVINT_SI)
pch_udc_svc_intf_interrupt(dev);
@@ -2472,8 +2737,30 @@ static void pch_udc_dev_isr(struct pch_udc_dev *dev, u32 dev_intr)
if (dev_intr & UDC_DEVINT_SC)
pch_udc_svc_cfg_interrupt(dev);
/* USB Suspend interrupt */
- if (dev_intr & UDC_DEVINT_US)
+ if (dev_intr & UDC_DEVINT_US) {
+ if (dev->driver
+ && dev->driver->suspend) {
+ spin_unlock(&dev->lock);
+ dev->driver->suspend(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
+
+ vbus = pch_vbus_gpio_get_value(dev);
+ if ((dev->vbus_session == 0)
+ && (vbus != 1)) {
+ if (dev->driver && dev->driver->disconnect) {
+ spin_unlock(&dev->lock);
+ dev->driver->disconnect(&dev->gadget);
+ spin_lock(&dev->lock);
+ }
+ pch_udc_reconnect(dev);
+ } else if ((dev->vbus_session == 0)
+ && (vbus == 1)
+ && !dev->vbus_gpio.intr)
+ schedule_work(&dev->vbus_gpio.irq_work_fall);
+
dev_dbg(&dev->pdev->dev, "USB_SUSPEND\n");
+ }
/* Clear the SOF interrupt, if enabled */
if (dev_intr & UDC_DEVINT_SOF)
dev_dbg(&dev->pdev->dev, "SOF\n");
@@ -2499,6 +2786,14 @@ static irqreturn_t pch_udc_isr(int irq, void *pdev)
dev_intr = pch_udc_read_device_interrupts(dev);
ep_intr = pch_udc_read_ep_interrupts(dev);
+ /* For a hot plug, this find that the controller is hung up. */
+ if (dev_intr == ep_intr)
+ if (dev_intr == pch_udc_readl(dev, UDC_DEVCFG_ADDR)) {
+ dev_dbg(&dev->pdev->dev, "UDC: Hung up\n");
+ /* The controller is reset */
+ pch_udc_writel(dev, UDC_SRST, UDC_SRST_ADDR);
+ return IRQ_HANDLED;
+ }
if (dev_intr)
/* Clear device interrupts */
pch_udc_write_device_interrupts(dev, dev_intr);
@@ -2625,6 +2920,7 @@ static int pch_udc_pcd_init(struct pch_udc_dev *dev)
{
pch_udc_init(dev);
pch_udc_pcd_reinit(dev);
+ pch_vbus_gpio_init(dev, vbus_gpio_port);
return 0;
}
@@ -2725,7 +3021,8 @@ static int pch_udc_start(struct usb_gadget_driver *driver,
pch_udc_setup_ep0(dev);
/* clear SD */
- pch_udc_clear_disconnect(dev);
+ if ((pch_vbus_gpio_get_value(dev) != 0) || !dev->vbus_gpio.intr)
+ pch_udc_clear_disconnect(dev);
dev->connected = 1;
return 0;
@@ -2803,6 +3100,8 @@ static void pch_udc_remove(struct pci_dev *pdev)
UDC_EP0OUT_BUFF_SIZE * 4, DMA_FROM_DEVICE);
kfree(dev->ep0out_buf);
+ pch_vbus_gpio_free(dev);
+
pch_udc_exit(dev);
if (dev->irq_registered)
@@ -2912,8 +3211,10 @@ static int pch_udc_probe(struct pci_dev *pdev,
}
pch_udc = dev;
/* initialize the hardware */
- if (pch_udc_pcd_init(dev))
+ if (pch_udc_pcd_init(dev)) {
+ retval = -ENODEV;
goto finished;
+ }
if (request_irq(pdev->irq, pch_udc_isr, IRQF_SHARED, KBUILD_MODNAME,
dev)) {
dev_err(&pdev->dev, "%s: request_irq(%d) fail\n", __func__,
diff --git a/drivers/usb/gadget/printer.c b/drivers/usb/gadget/printer.c
index d83134b0f78a..4e4dc1f5f388 100644
--- a/drivers/usb/gadget/printer.c
+++ b/drivers/usb/gadget/printer.c
@@ -34,7 +34,6 @@
#include <asm/byteorder.h>
#include <linux/io.h>
#include <linux/irq.h>
-#include <asm/system.h>
#include <linux/uaccess.h>
#include <asm/unaligned.h>
diff --git a/drivers/usb/gadget/pxa25x_udc.c b/drivers/usb/gadget/pxa25x_udc.c
index dd470635f4f7..41ed69c96d8c 100644
--- a/drivers/usb/gadget/pxa25x_udc.c
+++ b/drivers/usb/gadget/pxa25x_udc.c
@@ -41,7 +41,6 @@
#include <asm/byteorder.h>
#include <asm/dma.h>
#include <asm/gpio.h>
-#include <asm/system.h>
#include <asm/mach-types.h>
#include <asm/unaligned.h>
@@ -283,6 +282,7 @@ static int pxa25x_ep_disable (struct usb_ep *_ep)
pxa25x_ep_fifo_flush (_ep);
ep->desc = NULL;
+ ep->ep.desc = NULL;
ep->stopped = 1;
local_irq_restore(flags);
@@ -995,7 +995,7 @@ static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
udc = container_of(_gadget, struct pxa25x_udc, gadget);
if (udc->transceiver)
- return otg_set_power(udc->transceiver, mA);
+ return usb_phy_set_power(udc->transceiver, mA);
return -EOPNOTSUPP;
}
@@ -1192,6 +1192,7 @@ static void udc_reinit(struct pxa25x_udc *dev)
list_add_tail (&ep->ep.ep_list, &dev->gadget.ep_list);
ep->desc = NULL;
+ ep->ep.desc = NULL;
ep->stopped = 0;
INIT_LIST_HEAD (&ep->queue);
ep->pio_irqs = 0;
@@ -1301,7 +1302,8 @@ fail:
/* connect to bus through transceiver */
if (dev->transceiver) {
- retval = otg_set_peripheral(dev->transceiver, &dev->gadget);
+ retval = otg_set_peripheral(dev->transceiver->otg,
+ &dev->gadget);
if (retval) {
DMSG("can't bind to transceiver\n");
if (driver->unbind)
@@ -1360,7 +1362,7 @@ static int pxa25x_stop(struct usb_gadget_driver *driver)
local_irq_enable();
if (dev->transceiver)
- (void) otg_set_peripheral(dev->transceiver, NULL);
+ (void) otg_set_peripheral(dev->transceiver->otg, NULL);
driver->unbind(&dev->gadget);
dev->gadget.dev.driver = NULL;
@@ -2159,7 +2161,7 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
dev->dev = &pdev->dev;
dev->mach = pdev->dev.platform_data;
- dev->transceiver = otg_get_transceiver();
+ dev->transceiver = usb_get_transceiver();
if (gpio_is_valid(dev->mach->gpio_pullup)) {
if ((retval = gpio_request(dev->mach->gpio_pullup,
@@ -2238,7 +2240,7 @@ lubbock_fail0:
gpio_free(dev->mach->gpio_pullup);
err_gpio_pullup:
if (dev->transceiver) {
- otg_put_transceiver(dev->transceiver);
+ usb_put_transceiver(dev->transceiver);
dev->transceiver = NULL;
}
clk_put(dev->clk);
@@ -2280,7 +2282,7 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev)
clk_put(dev->clk);
if (dev->transceiver) {
- otg_put_transceiver(dev->transceiver);
+ usb_put_transceiver(dev->transceiver);
dev->transceiver = NULL;
}
diff --git a/drivers/usb/gadget/pxa25x_udc.h b/drivers/usb/gadget/pxa25x_udc.h
index 8eaf4e43726b..893e917f048e 100644
--- a/drivers/usb/gadget/pxa25x_udc.h
+++ b/drivers/usb/gadget/pxa25x_udc.h
@@ -119,7 +119,7 @@ struct pxa25x_udc {
struct device *dev;
struct clk *clk;
struct pxa2xx_udc_mach_info *mach;
- struct otg_transceiver *transceiver;
+ struct usb_phy *transceiver;
u64 dma_mask;
struct pxa25x_ep ep [PXA_UDC_NUM_ENDPOINTS];
diff --git a/drivers/usb/gadget/pxa27x_udc.c b/drivers/usb/gadget/pxa27x_udc.c
index f4c44eb806c3..98acb3ab9e17 100644
--- a/drivers/usb/gadget/pxa27x_udc.c
+++ b/drivers/usb/gadget/pxa27x_udc.c
@@ -1666,7 +1666,7 @@ static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
udc = to_gadget_udc(_gadget);
if (udc->transceiver)
- return otg_set_power(udc->transceiver, mA);
+ return usb_phy_set_power(udc->transceiver, mA);
return -EOPNOTSUPP;
}
@@ -1835,7 +1835,8 @@ static int pxa27x_udc_start(struct usb_gadget_driver *driver,
driver->driver.name);
if (udc->transceiver) {
- retval = otg_set_peripheral(udc->transceiver, &udc->gadget);
+ retval = otg_set_peripheral(udc->transceiver->otg,
+ &udc->gadget);
if (retval) {
dev_err(udc->dev, "can't bind to transceiver\n");
goto transceiver_fail;
@@ -1908,7 +1909,7 @@ static int pxa27x_udc_stop(struct usb_gadget_driver *driver)
driver->driver.name);
if (udc->transceiver)
- return otg_set_peripheral(udc->transceiver, NULL);
+ return otg_set_peripheral(udc->transceiver->otg, NULL);
return 0;
}
@@ -2463,7 +2464,7 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
udc->dev = &pdev->dev;
udc->mach = pdev->dev.platform_data;
- udc->transceiver = otg_get_transceiver();
+ udc->transceiver = usb_get_transceiver();
gpio = udc->mach->gpio_pullup;
if (gpio_is_valid(gpio)) {
@@ -2542,7 +2543,7 @@ static int __exit pxa_udc_remove(struct platform_device *_dev)
if (gpio_is_valid(gpio))
gpio_free(gpio);
- otg_put_transceiver(udc->transceiver);
+ usb_put_transceiver(udc->transceiver);
udc->transceiver = NULL;
platform_set_drvdata(_dev, NULL);
diff --git a/drivers/usb/gadget/pxa27x_udc.h b/drivers/usb/gadget/pxa27x_udc.h
index 7f4e8f424e80..a1d268c6f2cc 100644
--- a/drivers/usb/gadget/pxa27x_udc.h
+++ b/drivers/usb/gadget/pxa27x_udc.h
@@ -447,7 +447,7 @@ struct pxa_udc {
struct usb_gadget_driver *driver;
struct device *dev;
struct pxa2xx_udc_mach_info *mach;
- struct otg_transceiver *transceiver;
+ struct usb_phy *transceiver;
enum ep0_state ep0state;
struct udc_stats stats;
diff --git a/drivers/usb/gadget/r8a66597-udc.c b/drivers/usb/gadget/r8a66597-udc.c
index f5b8d215e1d5..c4401e7dd3a6 100644
--- a/drivers/usb/gadget/r8a66597-udc.c
+++ b/drivers/usb/gadget/r8a66597-udc.c
@@ -663,11 +663,7 @@ static int sudmac_alloc_channel(struct r8a66597 *r8a66597,
ep->fifoctr = D0FIFOCTR;
/* dma mapping */
- req->req.dma = dma_map_single(r8a66597_to_dev(ep->r8a66597),
- req->req.buf, req->req.length,
- dma->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
-
- return 0;
+ return usb_gadget_map_request(&r8a66597->gadget, &req->req, dma->dir);
}
static void sudmac_free_channel(struct r8a66597 *r8a66597,
@@ -677,9 +673,7 @@ static void sudmac_free_channel(struct r8a66597 *r8a66597,
if (!r8a66597_is_sudmac(r8a66597))
return;
- dma_unmap_single(r8a66597_to_dev(ep->r8a66597),
- req->req.dma, req->req.length,
- ep->dma->dir ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ usb_gadget_unmap_request(&r8a66597->gadget, &req->req, ep->dma->dir);
r8a66597_bclr(r8a66597, DREQE, ep->fifosel);
r8a66597_change_curpipe(r8a66597, 0, 0, ep->fifosel);
diff --git a/drivers/usb/gadget/rndis.c b/drivers/usb/gadget/rndis.c
index d3cdffea9c8a..73a934a170d1 100644
--- a/drivers/usb/gadget/rndis.c
+++ b/drivers/usb/gadget/rndis.c
@@ -34,7 +34,6 @@
#include <asm/io.h>
#include <asm/byteorder.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
diff --git a/drivers/usb/gadget/s3c-hsotg.c b/drivers/usb/gadget/s3c-hsotg.c
index 69295ba9d99a..105b206cd844 100644
--- a/drivers/usb/gadget/s3c-hsotg.c
+++ b/drivers/usb/gadget/s3c-hsotg.c
@@ -340,7 +340,7 @@ static void s3c_hsotg_init_fifo(struct s3c_hsotg *hsotg)
/* currently we allocate TX FIFOs for all possible endpoints,
* and assume that they are all the same size. */
- for (ep = 0; ep <= 15; ep++) {
+ for (ep = 1; ep <= 15; ep++) {
val = addr;
val |= size << S3C_DPTXFSIZn_DPTxFSize_SHIFT;
addr += size;
@@ -741,7 +741,7 @@ static void s3c_hsotg_start_req(struct s3c_hsotg *hsotg,
/* write size / packets */
writel(epsize, hsotg->regs + epsize_reg);
- if (using_dma(hsotg)) {
+ if (using_dma(hsotg) && !continuing) {
unsigned int dma_reg;
/* write DMA address to control register, buffer already
@@ -1696,10 +1696,12 @@ static void s3c_hsotg_set_ep_maxpacket(struct s3c_hsotg *hsotg,
reg |= mpsval;
writel(reg, regs + S3C_DIEPCTL(ep));
- reg = readl(regs + S3C_DOEPCTL(ep));
- reg &= ~S3C_DxEPCTL_MPS_MASK;
- reg |= mpsval;
- writel(reg, regs + S3C_DOEPCTL(ep));
+ if (ep) {
+ reg = readl(regs + S3C_DOEPCTL(ep));
+ reg &= ~S3C_DxEPCTL_MPS_MASK;
+ reg |= mpsval;
+ writel(reg, regs + S3C_DOEPCTL(ep));
+ }
return;
@@ -1919,7 +1921,8 @@ static void s3c_hsotg_epint(struct s3c_hsotg *hsotg, unsigned int idx,
ints & S3C_DIEPMSK_TxFIFOEmpty) {
dev_dbg(hsotg->dev, "%s: ep%d: TxFIFOEmpty\n",
__func__, idx);
- s3c_hsotg_trytx(hsotg, hs_ep);
+ if (!using_dma(hsotg))
+ s3c_hsotg_trytx(hsotg, hs_ep);
}
}
}
diff --git a/drivers/usb/gadget/s3c-hsudc.c b/drivers/usb/gadget/s3c-hsudc.c
index df8661d266cb..cef9b82ff911 100644
--- a/drivers/usb/gadget/s3c-hsudc.c
+++ b/drivers/usb/gadget/s3c-hsudc.c
@@ -30,6 +30,7 @@
#include <linux/prefetch.h>
#include <linux/platform_data/s3c-hsudc.h>
#include <linux/regulator/consumer.h>
+#include <linux/pm_runtime.h>
#include <mach/regs-s3c2443-clock.h>
@@ -145,7 +146,7 @@ struct s3c_hsudc {
struct usb_gadget_driver *driver;
struct device *dev;
struct s3c24xx_hsudc_platdata *pd;
- struct otg_transceiver *transceiver;
+ struct usb_phy *transceiver;
struct regulator_bulk_data supplies[ARRAY_SIZE(s3c_hsudc_supply_names)];
spinlock_t lock;
void __iomem *regs;
@@ -759,7 +760,7 @@ static int s3c_hsudc_ep_enable(struct usb_ep *_ep,
unsigned long flags;
u32 ecr = 0;
- hsep = container_of(_ep, struct s3c_hsudc_ep, ep);
+ hsep = our_ep(_ep);
if (!_ep || !desc || hsep->desc || _ep->name == ep0name
|| desc->bDescriptorType != USB_DT_ENDPOINT
|| hsep->bEndpointAddress != desc->bEndpointAddress
@@ -816,6 +817,7 @@ static int s3c_hsudc_ep_disable(struct usb_ep *_ep)
s3c_hsudc_nuke_ep(hsep, -ESHUTDOWN);
hsep->desc = 0;
+ hsep->ep.desc = NULL;
hsep->stopped = 1;
spin_unlock_irqrestore(&hsudc->lock, flags);
@@ -853,7 +855,7 @@ static void s3c_hsudc_free_request(struct usb_ep *ep, struct usb_request *_req)
{
struct s3c_hsudc_req *hsreq;
- hsreq = container_of(_req, struct s3c_hsudc_req, req);
+ hsreq = our_req(_req);
WARN_ON(!list_empty(&hsreq->queue));
kfree(hsreq);
}
@@ -876,12 +878,12 @@ static int s3c_hsudc_queue(struct usb_ep *_ep, struct usb_request *_req,
u32 offset;
u32 csr;
- hsreq = container_of(_req, struct s3c_hsudc_req, req);
+ hsreq = our_req(_req);
if ((!_req || !_req->complete || !_req->buf ||
!list_empty(&hsreq->queue)))
return -EINVAL;
- hsep = container_of(_ep, struct s3c_hsudc_ep, ep);
+ hsep = our_ep(_ep);
hsudc = hsep->dev;
if (!hsudc->driver || hsudc->gadget.speed == USB_SPEED_UNKNOWN)
return -ESHUTDOWN;
@@ -935,7 +937,7 @@ static int s3c_hsudc_dequeue(struct usb_ep *_ep, struct usb_request *_req)
struct s3c_hsudc_req *hsreq;
unsigned long flags;
- hsep = container_of(_ep, struct s3c_hsudc_ep, ep);
+ hsep = our_ep(_ep);
if (!_ep || hsep->ep.name == ep0name)
return -EINVAL;
@@ -1005,6 +1007,7 @@ static void s3c_hsudc_initep(struct s3c_hsudc *hsudc,
hsep->ep.ops = &s3c_hsudc_ep_ops;
hsep->fifo = hsudc->regs + S3C_BR(epnum);
hsep->desc = 0;
+ hsep->ep.desc = NULL;
hsep->stopped = 0;
hsep->wedge = 0;
@@ -1166,7 +1169,8 @@ static int s3c_hsudc_start(struct usb_gadget *gadget,
/* connect to bus through transceiver */
if (hsudc->transceiver) {
- ret = otg_set_peripheral(hsudc->transceiver, &hsudc->gadget);
+ ret = otg_set_peripheral(hsudc->transceiver->otg,
+ &hsudc->gadget);
if (ret) {
dev_err(hsudc->dev, "%s: can't bind to transceiver\n",
hsudc->gadget.name);
@@ -1178,6 +1182,9 @@ static int s3c_hsudc_start(struct usb_gadget *gadget,
dev_info(hsudc->dev, "bound driver %s\n", driver->driver.name);
s3c_hsudc_reconfig(hsudc);
+
+ pm_runtime_get_sync(hsudc->dev);
+
s3c_hsudc_init_phy();
if (hsudc->pd->gpio_init)
hsudc->pd->gpio_init();
@@ -1208,13 +1215,16 @@ static int s3c_hsudc_stop(struct usb_gadget *gadget,
hsudc->gadget.dev.driver = NULL;
hsudc->gadget.speed = USB_SPEED_UNKNOWN;
s3c_hsudc_uninit_phy();
+
+ pm_runtime_put(hsudc->dev);
+
if (hsudc->pd->gpio_uninit)
hsudc->pd->gpio_uninit();
s3c_hsudc_stop_activity(hsudc);
spin_unlock_irqrestore(&hsudc->lock, flags);
if (hsudc->transceiver)
- (void) otg_set_peripheral(hsudc->transceiver, NULL);
+ (void) otg_set_peripheral(hsudc->transceiver->otg, NULL);
disable_irq(hsudc->irq);
@@ -1243,7 +1253,7 @@ static int s3c_hsudc_vbus_draw(struct usb_gadget *gadget, unsigned mA)
return -ENODEV;
if (hsudc->transceiver)
- return otg_set_power(hsudc->transceiver, mA);
+ return usb_phy_set_power(hsudc->transceiver, mA);
return -EOPNOTSUPP;
}
@@ -1275,7 +1285,7 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
hsudc->dev = dev;
hsudc->pd = pdev->dev.platform_data;
- hsudc->transceiver = otg_get_transceiver();
+ hsudc->transceiver = usb_get_transceiver();
for (i = 0; i < ARRAY_SIZE(hsudc->supplies); i++)
hsudc->supplies[i].supply = s3c_hsudc_supply_names[i];
@@ -1362,6 +1372,8 @@ static int __devinit s3c_hsudc_probe(struct platform_device *pdev)
if (ret)
goto err_add_udc;
+ pm_runtime_enable(dev);
+
return 0;
err_add_udc:
device_unregister(&hsudc->gadget.dev);
@@ -1377,7 +1389,7 @@ err_remap:
release_mem_region(res->start, resource_size(res));
err_res:
if (hsudc->transceiver)
- otg_put_transceiver(hsudc->transceiver);
+ usb_put_transceiver(hsudc->transceiver);
regulator_bulk_free(ARRAY_SIZE(hsudc->supplies), hsudc->supplies);
err_supplies:
diff --git a/drivers/usb/gadget/s3c2410_udc.c b/drivers/usb/gadget/s3c2410_udc.c
index 3f87cb9344bb..195524cde6c3 100644
--- a/drivers/usb/gadget/s3c2410_udc.c
+++ b/drivers/usb/gadget/s3c2410_udc.c
@@ -37,7 +37,6 @@
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#include <mach/irqs.h>
@@ -1148,6 +1147,7 @@ static int s3c2410_udc_ep_disable(struct usb_ep *_ep)
dprintk(DEBUG_NORMAL, "ep_disable: %s\n", _ep->name);
ep->desc = NULL;
+ ep->ep.desc = NULL;
ep->halted = 1;
s3c2410_udc_nuke (ep->dev, ep, -ESHUTDOWN);
@@ -1630,6 +1630,7 @@ static void s3c2410_udc_reinit(struct s3c2410_udc *dev)
ep->dev = dev;
ep->desc = NULL;
+ ep->ep.desc = NULL;
ep->halted = 0;
INIT_LIST_HEAD (&ep->queue);
}
diff --git a/drivers/usb/gadget/serial.c b/drivers/usb/gadget/serial.c
index ad9e5b2df642..665c07422c26 100644
--- a/drivers/usb/gadget/serial.c
+++ b/drivers/usb/gadget/serial.c
@@ -242,7 +242,7 @@ static struct usb_composite_driver gserial_driver = {
.name = "g_serial",
.dev = &device_desc,
.strings = dev_strings,
- .max_speed = USB_SPEED_HIGH,
+ .max_speed = USB_SPEED_SUPER,
};
static int __init init(void)
diff --git a/drivers/usb/gadget/storage_common.c b/drivers/usb/gadget/storage_common.c
index 85ea14e2545e..8081ca3a70a2 100644
--- a/drivers/usb/gadget/storage_common.c
+++ b/drivers/usb/gadget/storage_common.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2003-2008 Alan Stern
* Copyeight (C) 2009 Samsung Electronics
- * Author: Michal Nazarewicz (m.nazarewicz@samsung.com)
+ * Author: Michal Nazarewicz (mina86@mina86.com)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -145,48 +145,8 @@
#endif /* DUMP_MSGS */
-
-
-
-
/*-------------------------------------------------------------------------*/
-/* Bulk-only data structures */
-
-/* Command Block Wrapper */
-struct fsg_bulk_cb_wrap {
- __le32 Signature; /* Contains 'USBC' */
- u32 Tag; /* Unique per command id */
- __le32 DataTransferLength; /* Size of the data */
- u8 Flags; /* Direction in bit 7 */
- u8 Lun; /* LUN (normally 0) */
- u8 Length; /* Of the CDB, <= MAX_COMMAND_SIZE */
- u8 CDB[16]; /* Command Data Block */
-};
-
-#define USB_BULK_CB_WRAP_LEN 31
-#define USB_BULK_CB_SIG 0x43425355 /* Spells out USBC */
-#define USB_BULK_IN_FLAG 0x80
-
-/* Command Status Wrapper */
-struct bulk_cs_wrap {
- __le32 Signature; /* Should = 'USBS' */
- u32 Tag; /* Same as original command */
- __le32 Residue; /* Amount not transferred */
- u8 Status; /* See below */
-};
-
-#define USB_BULK_CS_WRAP_LEN 13
-#define USB_BULK_CS_SIG 0x53425355 /* Spells out 'USBS' */
-#define USB_STATUS_PASS 0
-#define USB_STATUS_FAIL 1
-#define USB_STATUS_PHASE_ERROR 2
-
-/* Bulk-only class specific requests */
-#define USB_BULK_RESET_REQUEST 0xff
-#define USB_BULK_GET_MAX_LUN_REQUEST 0xfe
-
-
/* CBI Interrupt data structure */
struct interrupt_data {
u8 bType;
diff --git a/drivers/usb/gadget/u_serial.c b/drivers/usb/gadget/u_serial.c
index 6597a6813e43..6c23938d2711 100644
--- a/drivers/usb/gadget/u_serial.c
+++ b/drivers/usb/gadget/u_serial.c
@@ -725,9 +725,6 @@ static int gs_open(struct tty_struct *tty, struct file *file)
struct gs_port *port;
int status;
- if (port_num < 0 || port_num >= n_ports)
- return -ENXIO;
-
do {
mutex_lock(&ports[port_num].lock);
port = ports[port_num].port;
@@ -1087,7 +1084,6 @@ int __init gserial_setup(struct usb_gadget *g, unsigned count)
if (!gs_tty_driver)
return -ENOMEM;
- gs_tty_driver->owner = THIS_MODULE;
gs_tty_driver->driver_name = "g_serial";
gs_tty_driver->name = PREFIX;
/* uses dynamically assigned dev_t values */
diff --git a/drivers/usb/gadget/u_audio.c b/drivers/usb/gadget/u_uac1.c
index 59ffe1ecf1c9..af9898982059 100644
--- a/drivers/usb/gadget/u_audio.c
+++ b/drivers/usb/gadget/u_uac1.c
@@ -1,5 +1,5 @@
/*
- * u_audio.c -- ALSA audio utilities for Gadget stack
+ * u_uac1.c -- ALSA audio utilities for Gadget stack
*
* Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
* Copyright (C) 2008 Analog Devices, Inc
@@ -17,7 +17,7 @@
#include <linux/random.h>
#include <linux/syscalls.h>
-#include "u_audio.h"
+#include "u_uac1.h"
/*
* This component encapsulates the ALSA devices for USB audio gadget
diff --git a/drivers/usb/gadget/u_audio.h b/drivers/usb/gadget/u_uac1.h
index 08ffce3298e6..18c2e729faf6 100644
--- a/drivers/usb/gadget/u_audio.h
+++ b/drivers/usb/gadget/u_uac1.h
@@ -1,5 +1,5 @@
/*
- * u_audio.h -- interface to USB gadget "ALSA AUDIO" utilities
+ * u_uac1.h -- interface to USB gadget "ALSA AUDIO" utilities
*
* Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
* Copyright (C) 2008 Analog Devices, Inc
diff --git a/drivers/usb/gadget/udc-core.c b/drivers/usb/gadget/udc-core.c
index 0b0d12ccc487..2fa9865babed 100644
--- a/drivers/usb/gadget/udc-core.c
+++ b/drivers/usb/gadget/udc-core.c
@@ -22,6 +22,7 @@
#include <linux/device.h>
#include <linux/list.h>
#include <linux/err.h>
+#include <linux/dma-mapping.h>
#include <linux/usb/ch9.h>
#include <linux/usb/gadget.h>
@@ -49,6 +50,57 @@ static DEFINE_MUTEX(udc_lock);
/* ------------------------------------------------------------------------- */
+int usb_gadget_map_request(struct usb_gadget *gadget,
+ struct usb_request *req, int is_in)
+{
+ if (req->length == 0)
+ return 0;
+
+ if (req->num_sgs) {
+ int mapped;
+
+ mapped = dma_map_sg(&gadget->dev, req->sg, req->num_sgs,
+ is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ if (mapped == 0) {
+ dev_err(&gadget->dev, "failed to map SGs\n");
+ return -EFAULT;
+ }
+
+ req->num_mapped_sgs = mapped;
+ } else {
+ req->dma = dma_map_single(&gadget->dev, req->buf, req->length,
+ is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+ if (dma_mapping_error(&gadget->dev, req->dma)) {
+ dev_err(&gadget->dev, "failed to map buffer\n");
+ return -EFAULT;
+ }
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_map_request);
+
+void usb_gadget_unmap_request(struct usb_gadget *gadget,
+ struct usb_request *req, int is_in)
+{
+ if (req->length == 0)
+ return;
+
+ if (req->num_mapped_sgs) {
+ dma_unmap_sg(&gadget->dev, req->sg, req->num_mapped_sgs,
+ is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+ req->num_mapped_sgs = 0;
+ } else {
+ dma_unmap_single(&gadget->dev, req->dma, req->length,
+ is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ }
+}
+EXPORT_SYMBOL_GPL(usb_gadget_unmap_request);
+
+/* ------------------------------------------------------------------------- */
+
/**
* usb_gadget_start - tells usb device controller to start up
* @gadget: The gadget we want to get started
@@ -212,8 +264,8 @@ static void usb_gadget_remove_driver(struct usb_udc *udc)
if (udc_is_newstyle(udc)) {
udc->driver->disconnect(udc->gadget);
udc->driver->unbind(udc->gadget);
- usb_gadget_udc_stop(udc->gadget, udc->driver);
usb_gadget_disconnect(udc->gadget);
+ usb_gadget_udc_stop(udc->gadget, udc->driver);
} else {
usb_gadget_stop(udc->gadget, udc->driver);
}
@@ -359,8 +411,12 @@ static ssize_t usb_udc_softconn_store(struct device *dev,
struct usb_udc *udc = container_of(dev, struct usb_udc, dev);
if (sysfs_streq(buf, "connect")) {
+ if (udc_is_newstyle(udc))
+ usb_gadget_udc_start(udc->gadget, udc->driver);
usb_gadget_connect(udc->gadget);
} else if (sysfs_streq(buf, "disconnect")) {
+ if (udc_is_newstyle(udc))
+ usb_gadget_udc_stop(udc->gadget, udc->driver);
usb_gadget_disconnect(udc->gadget);
} else {
dev_err(dev, "unsupported command '%s'\n", buf);
diff --git a/drivers/usb/gadget/uvc_queue.c b/drivers/usb/gadget/uvc_queue.c
index d776adb2da67..0cdf89d32a15 100644
--- a/drivers/usb/gadget/uvc_queue.c
+++ b/drivers/usb/gadget/uvc_queue.c
@@ -543,11 +543,11 @@ done:
return ret;
}
+/* called with queue->irqlock held.. */
static struct uvc_buffer *
uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf)
{
struct uvc_buffer *nextbuf;
- unsigned long flags;
if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) &&
buf->buf.length != buf->buf.bytesused) {
@@ -556,14 +556,12 @@ uvc_queue_next_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf)
return buf;
}
- spin_lock_irqsave(&queue->irqlock, flags);
list_del(&buf->queue);
if (!list_empty(&queue->irqqueue))
nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
queue);
else
nextbuf = NULL;
- spin_unlock_irqrestore(&queue->irqlock, flags);
buf->buf.sequence = queue->sequence++;
do_gettimeofday(&buf->buf.timestamp);
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 353cdd488b93..f788eb86707c 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -27,6 +27,10 @@ config USB_XHCI_HCD
To compile this driver as a module, choose M here: the
module will be called xhci-hcd.
+config USB_XHCI_PLATFORM
+ tristate
+ depends on USB_XHCI_HCD
+
config USB_XHCI_HCD_DEBUGGING
bool "Debugging for the xHCI host controller"
depends on USB_XHCI_HCD
@@ -196,7 +200,7 @@ config USB_EHCI_S5P
config USB_EHCI_MV
bool "EHCI support for Marvell on-chip controller"
- depends on USB_EHCI_HCD
+ depends on USB_EHCI_HCD && (ARCH_PXA || ARCH_MMP)
select USB_EHCI_ROOT_HUB_TT
---help---
Enables support for Marvell (including PXA and MMP series) on-chip
@@ -218,11 +222,15 @@ config USB_CNS3XXX_EHCI
support.
config USB_EHCI_ATH79
- bool "EHCI support for AR7XXX/AR9XXX SoCs"
+ bool "EHCI support for AR7XXX/AR9XXX SoCs (DEPRECATED)"
depends on USB_EHCI_HCD && (SOC_AR71XX || SOC_AR724X || SOC_AR913X || SOC_AR933X)
select USB_EHCI_ROOT_HUB_TT
+ select USB_EHCI_HCD_PLATFORM
default y
---help---
+ This option is deprecated now and the driver was removed, use
+ USB_EHCI_HCD_PLATFORM instead.
+
Enables support for the built-in EHCI controller present
on the Atheros AR7XXX/AR9XXX SoCs.
@@ -312,10 +320,14 @@ config USB_OHCI_HCD_OMAP3
OMAP3 and later chips.
config USB_OHCI_ATH79
- bool "USB OHCI support for the Atheros AR71XX/AR7240 SoCs"
+ bool "USB OHCI support for the Atheros AR71XX/AR7240 SoCs (DEPRECATED)"
depends on USB_OHCI_HCD && (SOC_AR71XX || SOC_AR724X)
+ select USB_OHCI_HCD_PLATFORM
default y
help
+ This option is deprecated now and the driver was removed, use
+ USB_OHCI_HCD_PLATFORM instead.
+
Enables support for the built-in OHCI controller present on the
Atheros AR71XX/AR7240 SoCs.
@@ -393,6 +405,26 @@ config USB_CNS3XXX_OHCI
Enable support for the CNS3XXX SOC's on-chip OHCI controller.
It is needed for low-speed USB 1.0 device support.
+config USB_OHCI_HCD_PLATFORM
+ bool "Generic OHCI driver for a platform device"
+ depends on USB_OHCI_HCD && EXPERIMENTAL
+ default n
+ ---help---
+ Adds an OHCI host driver for a generic platform device, which
+ provieds a memory space and an irq.
+
+ If unsure, say N.
+
+config USB_EHCI_HCD_PLATFORM
+ bool "Generic EHCI driver for a platform device"
+ depends on USB_EHCI_HCD && EXPERIMENTAL
+ default n
+ ---help---
+ Adds an EHCI host driver for a generic platform device, which
+ provieds a memory space and an irq.
+
+ If unsure, say N.
+
config USB_OHCI_BIG_ENDIAN_DESC
bool
depends on USB_OHCI_HCD
@@ -606,10 +638,3 @@ config USB_OCTEON_OHCI
config USB_OCTEON2_COMMON
bool
default y if USB_OCTEON_EHCI || USB_OCTEON_OHCI
-
-config USB_PXA168_EHCI
- bool "Marvell PXA168 on-chip EHCI HCD support"
- depends on USB_EHCI_HCD && ARCH_MMP
- help
- Enable support for Marvell PXA168 SoC's on-chip EHCI
- host controller
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index 7ca290fcb070..0982bcc140bd 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -15,6 +15,10 @@ xhci-hcd-y := xhci.o xhci-mem.o
xhci-hcd-y += xhci-ring.o xhci-hub.o xhci-dbg.o
xhci-hcd-$(CONFIG_PCI) += xhci-pci.o
+ifneq ($(CONFIG_USB_XHCI_PLATFORM), )
+ xhci-hcd-y += xhci-plat.o
+endif
+
obj-$(CONFIG_USB_WHCI_HCD) += whci/
obj-$(CONFIG_PCI) += pci-quirks.o
diff --git a/drivers/usb/host/ehci-ath79.c b/drivers/usb/host/ehci-ath79.c
deleted file mode 100644
index f1424f9bc363..000000000000
--- a/drivers/usb/host/ehci-ath79.c
+++ /dev/null
@@ -1,208 +0,0 @@
-/*
- * Bus Glue for Atheros AR7XXX/AR9XXX built-in EHCI controller.
- *
- * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
- * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
- *
- * Parts of this file are based on Atheros' 2.6.15 BSP
- * Copyright (C) 2007 Atheros Communications, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- */
-
-#include <linux/platform_device.h>
-
-enum {
- EHCI_ATH79_IP_V1 = 0,
- EHCI_ATH79_IP_V2,
-};
-
-static const struct platform_device_id ehci_ath79_id_table[] = {
- {
- .name = "ar71xx-ehci",
- .driver_data = EHCI_ATH79_IP_V1,
- },
- {
- .name = "ar724x-ehci",
- .driver_data = EHCI_ATH79_IP_V2,
- },
- {
- .name = "ar913x-ehci",
- .driver_data = EHCI_ATH79_IP_V2,
- },
- {
- .name = "ar933x-ehci",
- .driver_data = EHCI_ATH79_IP_V2,
- },
- {
- /* terminating entry */
- },
-};
-
-MODULE_DEVICE_TABLE(platform, ehci_ath79_id_table);
-
-static int ehci_ath79_init(struct usb_hcd *hcd)
-{
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- struct platform_device *pdev = to_platform_device(hcd->self.controller);
- const struct platform_device_id *id;
- int ret;
-
- id = platform_get_device_id(pdev);
- if (!id) {
- dev_err(hcd->self.controller, "missing device id\n");
- return -EINVAL;
- }
-
- switch (id->driver_data) {
- case EHCI_ATH79_IP_V1:
- ehci->has_synopsys_hc_bug = 1;
-
- ehci->caps = hcd->regs;
- ehci->regs = hcd->regs +
- HC_LENGTH(ehci,
- ehci_readl(ehci, &ehci->caps->hc_capbase));
- break;
-
- case EHCI_ATH79_IP_V2:
- hcd->has_tt = 1;
-
- ehci->caps = hcd->regs + 0x100;
- ehci->regs = hcd->regs + 0x100 +
- HC_LENGTH(ehci,
- ehci_readl(ehci, &ehci->caps->hc_capbase));
- break;
-
- default:
- BUG();
- }
-
- dbg_hcs_params(ehci, "reset");
- dbg_hcc_params(ehci, "reset");
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
- ehci->sbrn = 0x20;
-
- ehci_reset(ehci);
-
- ret = ehci_init(hcd);
- if (ret)
- return ret;
-
- ehci_port_power(ehci, 0);
-
- return 0;
-}
-
-static const struct hc_driver ehci_ath79_hc_driver = {
- .description = hcd_name,
- .product_desc = "Atheros built-in EHCI controller",
- .hcd_priv_size = sizeof(struct ehci_hcd),
- .irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
-
- .reset = ehci_ath79_init,
- .start = ehci_run,
- .stop = ehci_stop,
- .shutdown = ehci_shutdown,
-
- .urb_enqueue = ehci_urb_enqueue,
- .urb_dequeue = ehci_urb_dequeue,
- .endpoint_disable = ehci_endpoint_disable,
- .endpoint_reset = ehci_endpoint_reset,
-
- .get_frame_number = ehci_get_frame,
-
- .hub_status_data = ehci_hub_status_data,
- .hub_control = ehci_hub_control,
-
- .relinquish_port = ehci_relinquish_port,
- .port_handed_over = ehci_port_handed_over,
-
- .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
-};
-
-static int ehci_ath79_probe(struct platform_device *pdev)
-{
- struct usb_hcd *hcd;
- struct resource *res;
- int irq;
- int ret;
-
- if (usb_disabled())
- return -ENODEV;
-
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res) {
- dev_dbg(&pdev->dev, "no IRQ specified\n");
- return -ENODEV;
- }
- irq = res->start;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_dbg(&pdev->dev, "no base address specified\n");
- return -ENODEV;
- }
-
- hcd = usb_create_hcd(&ehci_ath79_hc_driver, &pdev->dev,
- dev_name(&pdev->dev));
- if (!hcd)
- return -ENOMEM;
-
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
-
- if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
- dev_dbg(&pdev->dev, "controller already in use\n");
- ret = -EBUSY;
- goto err_put_hcd;
- }
-
- hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
- if (!hcd->regs) {
- dev_dbg(&pdev->dev, "error mapping memory\n");
- ret = -EFAULT;
- goto err_release_region;
- }
-
- ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
- if (ret)
- goto err_iounmap;
-
- return 0;
-
-err_iounmap:
- iounmap(hcd->regs);
-
-err_release_region:
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err_put_hcd:
- usb_put_hcd(hcd);
- return ret;
-}
-
-static int ehci_ath79_remove(struct platform_device *pdev)
-{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
- usb_remove_hcd(hcd);
- iounmap(hcd->regs);
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
- usb_put_hcd(hcd);
-
- return 0;
-}
-
-static struct platform_driver ehci_ath79_driver = {
- .probe = ehci_ath79_probe,
- .remove = ehci_ath79_remove,
- .id_table = ehci_ath79_id_table,
- .driver = {
- .owner = THIS_MODULE,
- .name = "ath79-ehci",
- }
-};
-
-MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ath79-ehci");
diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index a5a3ef1f0096..cf14c95a6700 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -13,6 +13,8 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
/* interface and function clocks */
static struct clk *iclk, *fclk;
@@ -115,6 +117,8 @@ static const struct hc_driver ehci_atmel_hc_driver = {
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
+static u64 at91_ehci_dma_mask = DMA_BIT_MASK(32);
+
static int __devinit ehci_atmel_drv_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd;
@@ -137,6 +141,13 @@ static int __devinit ehci_atmel_drv_probe(struct platform_device *pdev)
goto fail_create_hcd;
}
+ /* Right now device-tree probed devices don't get dma_mask set.
+ * Since shared usb code relies on it, set it here for now.
+ * Once we have dma capability bindings this can go away.
+ */
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &at91_ehci_dma_mask;
+
hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
if (!hcd) {
retval = -ENOMEM;
@@ -225,9 +236,21 @@ static int __devexit ehci_atmel_drv_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id atmel_ehci_dt_ids[] = {
+ { .compatible = "atmel,at91sam9g45-ehci" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_ehci_dt_ids);
+#endif
+
static struct platform_driver ehci_atmel_driver = {
.probe = ehci_atmel_drv_probe,
.remove = __devexit_p(ehci_atmel_drv_remove),
.shutdown = usb_hcd_platform_shutdown,
- .driver.name = "atmel-ehci",
+ .driver = {
+ .name = "atmel-ehci",
+ .of_match_table = of_match_ptr(atmel_ehci_dt_ids),
+ },
};
diff --git a/drivers/usb/host/ehci-dbg.c b/drivers/usb/host/ehci-dbg.c
index d6d74d2e09f4..680e1a31fb87 100644
--- a/drivers/usb/host/ehci-dbg.c
+++ b/drivers/usb/host/ehci-dbg.c
@@ -107,7 +107,7 @@ static void dbg_hcc_params (struct ehci_hcd *ehci, char *label)
HCC_PER_PORT_CHANGE_EVENT(params) ? " ppce" : "",
HCC_HW_PREFETCH(params) ? " hw prefetch" : "",
HCC_32FRAME_PERIODIC_LIST(params) ?
- " 32 peridic list" : "");
+ " 32 periodic list" : "");
}
}
#else
@@ -352,7 +352,6 @@ static int debug_async_open(struct inode *, struct file *);
static int debug_periodic_open(struct inode *, struct file *);
static int debug_registers_open(struct inode *, struct file *);
static int debug_async_open(struct inode *, struct file *);
-static int debug_lpm_open(struct inode *, struct file *);
static ssize_t debug_lpm_read(struct file *file, char __user *user_buf,
size_t count, loff_t *ppos);
static ssize_t debug_lpm_write(struct file *file, const char __user *buffer,
@@ -385,7 +384,7 @@ static const struct file_operations debug_registers_fops = {
};
static const struct file_operations debug_lpm_fops = {
.owner = THIS_MODULE,
- .open = debug_lpm_open,
+ .open = simple_open,
.read = debug_lpm_read,
.write = debug_lpm_write,
.release = debug_lpm_close,
@@ -970,12 +969,6 @@ static int debug_registers_open(struct inode *inode, struct file *file)
return file->private_data ? 0 : -ENOMEM;
}
-static int debug_lpm_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
- return 0;
-}
-
static int debug_lpm_close(struct inode *inode, struct file *file)
{
return 0;
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index c26a82e83f6e..d0a84bd3f3eb 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -142,12 +142,12 @@ static int usb_hcd_fsl_probe(const struct hc_driver *driver,
if (pdata->operating_mode == FSL_USB2_DR_OTG) {
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- ehci->transceiver = otg_get_transceiver();
+ ehci->transceiver = usb_get_transceiver();
dev_dbg(&pdev->dev, "hcd=0x%p ehci=0x%p, transceiver=0x%p\n",
hcd, ehci, ehci->transceiver);
if (ehci->transceiver) {
- retval = otg_set_host(ehci->transceiver,
+ retval = otg_set_host(ehci->transceiver->otg,
&ehci_to_hcd(ehci)->self);
if (retval) {
if (ehci->transceiver)
@@ -194,7 +194,7 @@ static void usb_hcd_fsl_remove(struct usb_hcd *hcd,
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
if (ehci->transceiver) {
- otg_set_host(ehci->transceiver, NULL);
+ otg_set_host(ehci->transceiver->otg, NULL);
put_device(ehci->transceiver->dev);
}
@@ -216,6 +216,11 @@ static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
unsigned int port_offset)
{
u32 portsc;
+ struct usb_hcd *hcd = ehci_to_hcd(ehci);
+ void __iomem *non_ehci = hcd->regs;
+ struct fsl_usb2_platform_data *pdata;
+
+ pdata = hcd->self.controller->platform_data;
portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]);
portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);
@@ -231,6 +236,10 @@ static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
portsc |= PORT_PTS_PTW;
/* fall through */
case FSL_USB2_PHY_UTMI:
+ /* enable UTMI PHY */
+ if (pdata->have_sysif_regs)
+ setbits32(non_ehci + FSL_SOC_USB_CTRL,
+ CTRL_UTMI_PHY_EN);
portsc |= PORT_PTS_UTMI;
break;
case FSL_USB2_PHY_NONE:
@@ -239,7 +248,7 @@ static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
ehci_writel(ehci, portsc, &ehci->regs->port_status[port_offset]);
}
-static int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
+static void ehci_fsl_usb_setup(struct ehci_hcd *ehci)
{
struct usb_hcd *hcd = ehci_to_hcd(ehci);
struct fsl_usb2_platform_data *pdata;
@@ -252,21 +261,18 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
if (pdata->have_sysif_regs) {
temp = in_be32(non_ehci + FSL_SOC_USB_CTRL);
out_be32(non_ehci + FSL_SOC_USB_CTRL, temp | 0x00000004);
- out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0000001b);
- }
-#if defined(CONFIG_PPC32) && !defined(CONFIG_NOT_COHERENT_CACHE)
- /*
- * Turn on cache snooping hardware, since some PowerPC platforms
- * wholly rely on hardware to deal with cache coherent
- */
+ /*
+ * Turn on cache snooping hardware, since some PowerPC platforms
+ * wholly rely on hardware to deal with cache coherent
+ */
- /* Setup Snooping for all the 4GB space */
- /* SNOOP1 starts from 0x0, size 2G */
- out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0 | SNOOP_SIZE_2GB);
- /* SNOOP2 starts from 0x80000000, size 2G */
- out_be32(non_ehci + FSL_SOC_USB_SNOOP2, 0x80000000 | SNOOP_SIZE_2GB);
-#endif
+ /* Setup Snooping for all the 4GB space */
+ /* SNOOP1 starts from 0x0, size 2G */
+ out_be32(non_ehci + FSL_SOC_USB_SNOOP1, 0x0 | SNOOP_SIZE_2GB);
+ /* SNOOP2 starts from 0x80000000, size 2G */
+ out_be32(non_ehci + FSL_SOC_USB_SNOOP2, 0x80000000 | SNOOP_SIZE_2GB);
+ }
if ((pdata->operating_mode == FSL_USB2_DR_HOST) ||
(pdata->operating_mode == FSL_USB2_DR_OTG))
@@ -299,19 +305,12 @@ static int ehci_fsl_usb_setup(struct ehci_hcd *ehci)
#endif
out_be32(non_ehci + FSL_SOC_USB_SICTRL, 0x00000001);
}
-
- if (!(in_be32(non_ehci + FSL_SOC_USB_CTRL) & CTRL_PHY_CLK_VALID)) {
- printk(KERN_WARNING "fsl-ehci: USB PHY clock invalid\n");
- return -ENODEV;
- }
- return 0;
}
/* called after powerup, by probe or system-pm "wakeup" */
static int ehci_fsl_reinit(struct ehci_hcd *ehci)
{
- if (ehci_fsl_usb_setup(ehci))
- return -ENODEV;
+ ehci_fsl_usb_setup(ehci);
ehci_port_power(ehci, 0);
return 0;
@@ -323,7 +322,9 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
int retval;
struct fsl_usb2_platform_data *pdata;
+ struct device *dev;
+ dev = hcd->self.controller;
pdata = hcd->self.controller->platform_data;
ehci->big_endian_desc = pdata->big_endian_desc;
ehci->big_endian_mmio = pdata->big_endian_mmio;
@@ -353,6 +354,16 @@ static int ehci_fsl_setup(struct usb_hcd *hcd)
ehci_reset(ehci);
+ if (of_device_is_compatible(dev->parent->of_node,
+ "fsl,mpc5121-usb2-dr")) {
+ /*
+ * set SBUSCFG:AHBBRST so that control msgs don't
+ * fail when doing heavy PATA writes.
+ */
+ ehci_writel(ehci, SBUSCFG_INCR8,
+ hcd->regs + FSL_SOC_USB_SBUSCFG);
+ }
+
retval = ehci_fsl_reinit(ehci);
return retval;
}
@@ -476,6 +487,8 @@ static int ehci_fsl_mpc512x_drv_resume(struct device *dev)
ehci_writel(ehci, ISIPHYCTRL_PXE | ISIPHYCTRL_PHYE,
hcd->regs + FSL_SOC_USB_ISIPHYCTRL);
+ ehci_writel(ehci, SBUSCFG_INCR8, hcd->regs + FSL_SOC_USB_SBUSCFG);
+
/* restore EHCI registers */
ehci_writel(ehci, pdata->pm_command, &ehci->regs->command);
ehci_writel(ehci, pdata->pm_intr_enable, &ehci->regs->intr_enable);
diff --git a/drivers/usb/host/ehci-fsl.h b/drivers/usb/host/ehci-fsl.h
index bdf43e2adc51..863fb0c080d7 100644
--- a/drivers/usb/host/ehci-fsl.h
+++ b/drivers/usb/host/ehci-fsl.h
@@ -19,6 +19,8 @@
#define _EHCI_FSL_H
/* offsets for the non-ehci registers in the FSL SOC USB controller */
+#define FSL_SOC_USB_SBUSCFG 0x90
+#define SBUSCFG_INCR8 0x02 /* INCR8, specified */
#define FSL_SOC_USB_ULPIVP 0x170
#define FSL_SOC_USB_PORTSC1 0x184
#define PORT_PTS_MSK (3<<30)
@@ -45,6 +47,7 @@
#define FSL_SOC_USB_PRICTRL 0x40c /* NOTE: big-endian */
#define FSL_SOC_USB_SICTRL 0x410 /* NOTE: big-endian */
#define FSL_SOC_USB_CTRL 0x500 /* NOTE: big-endian */
+#define CTRL_UTMI_PHY_EN (1<<9)
#define CTRL_PHY_CLK_VALID (1 << 17)
#define SNOOP_SIZE_2GB 0x1e
#endif /* _EHCI_FSL_H */
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index a007a9fe0f87..4a3bc5b7a06f 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -45,7 +45,6 @@
#include <asm/byteorder.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#if defined(CONFIG_PPC_PS3)
@@ -348,6 +347,8 @@ static int ehci_reset (struct ehci_hcd *ehci)
if (ehci->debug)
dbgp_external_startup();
+ ehci->port_c_suspend = ehci->suspended_ports =
+ ehci->resuming_ports = 0;
return retval;
}
@@ -857,8 +858,13 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
goto dead;
}
+ /*
+ * We don't use STS_FLR, but some controllers don't like it to
+ * remain on, so mask it out along with the other status bits.
+ */
+ masked_status = status & (INTR_MASK | STS_FLR);
+
/* Shared IRQ? */
- masked_status = status & INTR_MASK;
if (!masked_status || unlikely(ehci->rh_state == EHCI_RH_HALTED)) {
spin_unlock(&ehci->lock);
return IRQ_NONE;
@@ -909,7 +915,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
pcd_status = status;
/* resume root hub? */
- if (!(cmd & CMD_RUN))
+ if (ehci->rh_state == EHCI_RH_SUSPENDED)
usb_hcd_resume_root_hub(hcd);
/* get per-port change detect bits */
@@ -940,6 +946,7 @@ static irqreturn_t ehci_irq (struct usb_hcd *hcd)
* like usb_port_resume() does.
*/
ehci->reset_done[i] = jiffies + msecs_to_jiffies(25);
+ set_bit(i, &ehci->resuming_ports);
ehci_dbg (ehci, "port %d remote wakeup\n", i + 1);
mod_timer(&hcd->rh_timer, ehci->reset_done[i]);
}
@@ -1351,21 +1358,11 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER s5p_ehci_driver
#endif
-#ifdef CONFIG_USB_EHCI_ATH79
-#include "ehci-ath79.c"
-#define PLATFORM_DRIVER ehci_ath79_driver
-#endif
-
#ifdef CONFIG_SPARC_LEON
#include "ehci-grlib.c"
#define PLATFORM_DRIVER ehci_grlib_driver
#endif
-#ifdef CONFIG_USB_PXA168_EHCI
-#include "ehci-pxa168.c"
-#define PLATFORM_DRIVER ehci_pxa168_driver
-#endif
-
#ifdef CONFIG_CPU_XLR
#include "ehci-xls.c"
#define PLATFORM_DRIVER ehci_xls_driver
@@ -1376,6 +1373,16 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ehci_mv_driver
#endif
+#ifdef CONFIG_MACH_LOONGSON1
+#include "ehci-ls1x.c"
+#define PLATFORM_DRIVER ehci_ls1x_driver
+#endif
+
+#ifdef CONFIG_USB_EHCI_HCD_PLATFORM
+#include "ehci-platform.c"
+#define PLATFORM_DRIVER ehci_platform_driver
+#endif
+
#if !defined(PCI_DRIVER) && !defined(PLATFORM_DRIVER) && \
!defined(PS3_SYSTEM_BUS_DRIVER) && !defined(OF_PLATFORM_DRIVER) && \
!defined(XILINX_OF_PLATFORM_DRIVER)
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 77bbb2357e47..38fe07623152 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -107,7 +107,7 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
ehci->owned_ports = 0;
}
-static int ehci_port_change(struct ehci_hcd *ehci)
+static int __maybe_unused ehci_port_change(struct ehci_hcd *ehci)
{
int i = HCS_N_PORTS(ehci->hcs_params);
@@ -223,15 +223,10 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
* remote wakeup, we must fail the suspend.
*/
if (hcd->self.root_hub->do_remote_wakeup) {
- port = HCS_N_PORTS(ehci->hcs_params);
- while (port--) {
- if (ehci->reset_done[port] != 0) {
- spin_unlock_irq(&ehci->lock);
- ehci_dbg(ehci, "suspend failed because "
- "port %d is resuming\n",
- port + 1);
- return -EBUSY;
- }
+ if (ehci->resuming_ports) {
+ spin_unlock_irq(&ehci->lock);
+ ehci_dbg(ehci, "suspend failed because a port is resuming\n");
+ return -EBUSY;
}
}
@@ -554,16 +549,12 @@ static int
ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
{
struct ehci_hcd *ehci = hcd_to_ehci (hcd);
- u32 temp, status = 0;
+ u32 temp, status;
u32 mask;
int ports, i, retval = 1;
unsigned long flags;
u32 ppcd = 0;
- /* if !USB_SUSPEND, root hub timers won't get shut down ... */
- if (ehci->rh_state != EHCI_RH_RUNNING)
- return 0;
-
/* init status to no-changes */
buf [0] = 0;
ports = HCS_N_PORTS (ehci->hcs_params);
@@ -572,6 +563,11 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
retval++;
}
+ /* Inform the core about resumes-in-progress by returning
+ * a non-zero value even if there are no status changes.
+ */
+ status = ehci->resuming_ports;
+
/* Some boards (mostly VIA?) report bogus overcurrent indications,
* causing massive log spam unless we completely ignore them. It
* may be relevant that VIA VT8235 controllers, where PORT_POWER is
@@ -727,7 +723,7 @@ static int ehci_hub_control (
#ifdef CONFIG_USB_OTG
if ((hcd->self.otg_port == (wIndex + 1))
&& hcd->self.b_hnp_enable) {
- otg_start_hnp(ehci->transceiver);
+ otg_start_hnp(ehci->transceiver->otg);
break;
}
#endif
@@ -846,6 +842,7 @@ static int ehci_hub_control (
ehci_writel(ehci,
temp & ~(PORT_RWC_BITS | PORT_RESUME),
status_reg);
+ clear_bit(wIndex, &ehci->resuming_ports);
retval = handshake(ehci, status_reg,
PORT_RESUME, 0, 2000 /* 2msec */);
if (retval != 0) {
@@ -864,6 +861,7 @@ static int ehci_hub_control (
ehci->reset_done[wIndex])) {
status |= USB_PORT_STAT_C_RESET << 16;
ehci->reset_done [wIndex] = 0;
+ clear_bit(wIndex, &ehci->resuming_ports);
/* force reset to complete */
ehci_writel(ehci, temp & ~(PORT_RWC_BITS | PORT_RESET),
@@ -884,8 +882,10 @@ static int ehci_hub_control (
ehci_readl(ehci, status_reg));
}
- if (!(temp & (PORT_RESUME|PORT_RESET)))
+ if (!(temp & (PORT_RESUME|PORT_RESET))) {
ehci->reset_done[wIndex] = 0;
+ clear_bit(wIndex, &ehci->resuming_ports);
+ }
/* transfer dedicated ports to the companion hc */
if ((temp & PORT_CONNECT) &&
@@ -920,6 +920,7 @@ static int ehci_hub_control (
status |= USB_PORT_STAT_SUSPEND;
} else if (test_bit(wIndex, &ehci->suspended_ports)) {
clear_bit(wIndex, &ehci->suspended_ports);
+ clear_bit(wIndex, &ehci->resuming_ports);
ehci->reset_done[wIndex] = 0;
if (temp & PORT_PE)
set_bit(wIndex, &ehci->port_c_suspend);
@@ -1076,7 +1077,8 @@ error_exit:
return retval;
}
-static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum)
+static void __maybe_unused ehci_relinquish_port(struct usb_hcd *hcd,
+ int portnum)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
@@ -1085,7 +1087,8 @@ static void ehci_relinquish_port(struct usb_hcd *hcd, int portnum)
set_owner(ehci, --portnum, PORT_OWNER);
}
-static int ehci_port_handed_over(struct usb_hcd *hcd, int portnum)
+static int __maybe_unused ehci_port_handed_over(struct usb_hcd *hcd,
+ int portnum)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
u32 __iomem *reg;
diff --git a/drivers/usb/host/ehci-ls1x.c b/drivers/usb/host/ehci-ls1x.c
new file mode 100644
index 000000000000..a283e59709d6
--- /dev/null
+++ b/drivers/usb/host/ehci-ls1x.c
@@ -0,0 +1,159 @@
+/*
+ * Bus Glue for Loongson LS1X built-in EHCI controller.
+ *
+ * Copyright (c) 2012 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ */
+
+
+#include <linux/platform_device.h>
+
+static int ehci_ls1x_reset(struct usb_hcd *hcd)
+{
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int ret;
+
+ ehci->caps = hcd->regs;
+
+ ret = ehci_setup(hcd);
+ if (ret)
+ return ret;
+
+ ehci_port_power(ehci, 0);
+
+ return 0;
+}
+
+static const struct hc_driver ehci_ls1x_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "LOONGSON1 EHCI",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = ehci_ls1x_reset,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ehci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static int ehci_hcd_ls1x_probe(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd;
+ struct resource *res;
+ int irq;
+ int ret;
+
+ pr_debug("initializing loongson1 ehci USB Controller\n");
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev,
+ "Found HC with no IRQ. Check %s setup!\n",
+ dev_name(&pdev->dev));
+ return -ENODEV;
+ }
+ irq = res->start;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev,
+ "Found HC with no register addr. Check %s setup!\n",
+ dev_name(&pdev->dev));
+ return -ENODEV;
+ }
+
+ hcd = usb_create_hcd(&ehci_ls1x_hc_driver, &pdev->dev,
+ dev_name(&pdev->dev));
+ if (!hcd)
+ return -ENOMEM;
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ dev_dbg(&pdev->dev, "controller already in use\n");
+ ret = -EBUSY;
+ goto err_put_hcd;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (hcd->regs == NULL) {
+ dev_dbg(&pdev->dev, "error mapping memory\n");
+ ret = -EFAULT;
+ goto err_release_region;
+ }
+
+ ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
+ if (ret)
+ goto err_iounmap;
+
+ return ret;
+
+err_iounmap:
+ iounmap(hcd->regs);
+err_release_region:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_put_hcd:
+ usb_put_hcd(hcd);
+ return ret;
+}
+
+static int ehci_hcd_ls1x_remove(struct platform_device *pdev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+
+ return 0;
+}
+
+static struct platform_driver ehci_ls1x_driver = {
+ .probe = ehci_hcd_ls1x_probe,
+ .remove = ehci_hcd_ls1x_remove,
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver = {
+ .name = "ls1x-ehci",
+ .owner = THIS_MODULE,
+ },
+};
+
+MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ls1x-ehci");
diff --git a/drivers/usb/host/ehci-msm.c b/drivers/usb/host/ehci-msm.c
index 592d5f76803e..9803a55fd5f4 100644
--- a/drivers/usb/host/ehci-msm.c
+++ b/drivers/usb/host/ehci-msm.c
@@ -32,7 +32,7 @@
#define MSM_USB_BASE (hcd->regs)
-static struct otg_transceiver *otg;
+static struct usb_phy *phy;
static int ehci_msm_reset(struct usb_hcd *hcd)
{
@@ -145,14 +145,14 @@ static int ehci_msm_probe(struct platform_device *pdev)
* powering up VBUS, mapping of registers address space and power
* management.
*/
- otg = otg_get_transceiver();
- if (!otg) {
+ phy = usb_get_transceiver();
+ if (!phy) {
dev_err(&pdev->dev, "unable to find transceiver\n");
ret = -ENODEV;
goto unmap;
}
- ret = otg_set_host(otg, &hcd->self);
+ ret = otg_set_host(phy->otg, &hcd->self);
if (ret < 0) {
dev_err(&pdev->dev, "unable to register with transceiver\n");
goto put_transceiver;
@@ -169,7 +169,7 @@ static int ehci_msm_probe(struct platform_device *pdev)
return 0;
put_transceiver:
- otg_put_transceiver(otg);
+ usb_put_transceiver(phy);
unmap:
iounmap(hcd->regs);
put_hcd:
@@ -186,8 +186,8 @@ static int __devexit ehci_msm_remove(struct platform_device *pdev)
pm_runtime_disable(&pdev->dev);
pm_runtime_set_suspended(&pdev->dev);
- otg_set_host(otg, NULL);
- otg_put_transceiver(otg);
+ otg_set_host(phy->otg, NULL);
+ usb_put_transceiver(phy);
usb_put_hcd(hcd);
diff --git a/drivers/usb/host/ehci-mv.c b/drivers/usb/host/ehci-mv.c
index 52a604fb9321..a936bbcff8f4 100644
--- a/drivers/usb/host/ehci-mv.c
+++ b/drivers/usb/host/ehci-mv.c
@@ -28,7 +28,7 @@ struct ehci_hcd_mv {
void __iomem *cap_regs;
void __iomem *op_regs;
- struct otg_transceiver *otg;
+ struct usb_phy *otg;
struct mv_usb_platform_data *pdata;
@@ -253,7 +253,7 @@ static int mv_ehci_probe(struct platform_device *pdev)
ehci_mv->mode = pdata->mode;
if (ehci_mv->mode == MV_USB_MODE_OTG) {
#ifdef CONFIG_USB_OTG_UTILS
- ehci_mv->otg = otg_get_transceiver();
+ ehci_mv->otg = usb_get_transceiver();
if (!ehci_mv->otg) {
dev_err(&pdev->dev,
"unable to find transceiver\n");
@@ -261,7 +261,7 @@ static int mv_ehci_probe(struct platform_device *pdev)
goto err_disable_clk;
}
- retval = otg_set_host(ehci_mv->otg, &hcd->self);
+ retval = otg_set_host(ehci_mv->otg->otg, &hcd->self);
if (retval < 0) {
dev_err(&pdev->dev,
"unable to register with transceiver\n");
@@ -303,7 +303,7 @@ err_set_vbus:
#ifdef CONFIG_USB_OTG_UTILS
err_put_transceiver:
if (ehci_mv->otg)
- otg_put_transceiver(ehci_mv->otg);
+ usb_put_transceiver(ehci_mv->otg);
#endif
err_disable_clk:
mv_ehci_disable(ehci_mv);
@@ -332,8 +332,8 @@ static int mv_ehci_remove(struct platform_device *pdev)
usb_remove_hcd(hcd);
if (ehci_mv->otg) {
- otg_set_host(ehci_mv->otg, NULL);
- otg_put_transceiver(ehci_mv->otg);
+ otg_set_host(ehci_mv->otg->otg, NULL);
+ usb_put_transceiver(ehci_mv->otg);
}
if (ehci_mv->mode == MV_USB_MODE_HOST) {
diff --git a/drivers/usb/host/ehci-mxc.c b/drivers/usb/host/ehci-mxc.c
index 55978fcfa4b2..a797d51ecbe8 100644
--- a/drivers/usb/host/ehci-mxc.c
+++ b/drivers/usb/host/ehci-mxc.c
@@ -220,13 +220,13 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
/* Initialize the transceiver */
if (pdata->otg) {
pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET;
- ret = otg_init(pdata->otg);
+ ret = usb_phy_init(pdata->otg);
if (ret) {
dev_err(dev, "unable to init transceiver, probably missing\n");
ret = -ENODEV;
goto err_add;
}
- ret = otg_set_vbus(pdata->otg, 1);
+ ret = otg_set_vbus(pdata->otg->otg, 1);
if (ret) {
dev_err(dev, "unable to enable vbus on transceiver\n");
goto err_add;
@@ -247,9 +247,11 @@ static int ehci_mxc_drv_probe(struct platform_device *pdev)
* It's in violation of USB specs
*/
if (machine_is_mx51_efikamx() || machine_is_mx51_efikasb()) {
- flags = otg_io_read(pdata->otg, ULPI_OTG_CTRL);
+ flags = usb_phy_io_read(pdata->otg,
+ ULPI_OTG_CTRL);
flags |= ULPI_OTG_CTRL_CHRGVBUS;
- ret = otg_io_write(pdata->otg, flags, ULPI_OTG_CTRL);
+ ret = usb_phy_io_write(pdata->otg, flags,
+ ULPI_OTG_CTRL);
if (ret) {
dev_err(dev, "unable to set CHRVBUS\n");
goto err_add;
@@ -297,7 +299,7 @@ static int __exit ehci_mxc_drv_remove(struct platform_device *pdev)
pdata->exit(pdev);
if (pdata->otg)
- otg_shutdown(pdata->otg);
+ usb_phy_shutdown(pdata->otg);
usb_remove_hcd(hcd);
iounmap(hcd->regs);
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index bba9850f32f0..5c78f9e71466 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -42,6 +42,7 @@
#include <plat/usb.h>
#include <linux/regulator/consumer.h>
#include <linux/pm_runtime.h>
+#include <linux/gpio.h>
/* EHCI Register Set */
#define EHCI_INSNREG04 (0xA0)
@@ -191,6 +192,19 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
}
}
+ if (pdata->phy_reset) {
+ if (gpio_is_valid(pdata->reset_gpio_port[0]))
+ gpio_request_one(pdata->reset_gpio_port[0],
+ GPIOF_OUT_INIT_LOW, "USB1 PHY reset");
+
+ if (gpio_is_valid(pdata->reset_gpio_port[1]))
+ gpio_request_one(pdata->reset_gpio_port[1],
+ GPIOF_OUT_INIT_LOW, "USB2 PHY reset");
+
+ /* Hold the PHY in RESET for enough time till DIR is high */
+ udelay(10);
+ }
+
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
@@ -237,6 +251,19 @@ static int ehci_hcd_omap_probe(struct platform_device *pdev)
/* root ports should always stay powered */
ehci_port_power(omap_ehci, 1);
+ if (pdata->phy_reset) {
+ /* Hold the PHY in RESET for enough time till
+ * PHY is settled and ready
+ */
+ udelay(10);
+
+ if (gpio_is_valid(pdata->reset_gpio_port[0]))
+ gpio_set_value(pdata->reset_gpio_port[0], 1);
+
+ if (gpio_is_valid(pdata->reset_gpio_port[1]))
+ gpio_set_value(pdata->reset_gpio_port[1], 1);
+ }
+
return 0;
err_add_hcd:
@@ -259,8 +286,9 @@ err_io:
*/
static int ehci_hcd_omap_remove(struct platform_device *pdev)
{
- struct device *dev = &pdev->dev;
- struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct device *dev = &pdev->dev;
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct ehci_hcd_omap_platform_data *pdata = dev->platform_data;
usb_remove_hcd(hcd);
disable_put_regulator(dev->platform_data);
@@ -269,6 +297,13 @@ static int ehci_hcd_omap_remove(struct platform_device *pdev)
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
+ if (pdata->phy_reset) {
+ if (gpio_is_valid(pdata->reset_gpio_port[0]))
+ gpio_free(pdata->reset_gpio_port[0]);
+
+ if (gpio_is_valid(pdata->reset_gpio_port[1]))
+ gpio_free(pdata->reset_gpio_port[1]);
+ }
return 0;
}
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
new file mode 100644
index 000000000000..d238b4e24bb6
--- /dev/null
+++ b/drivers/usb/host/ehci-platform.c
@@ -0,0 +1,198 @@
+/*
+ * Generic platform ehci driver
+ *
+ * Copyright 2007 Steven Brown <sbrown@cortland.com>
+ * Copyright 2010-2012 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Derived from the ohci-ssb driver
+ * Copyright 2007 Michael Buesch <m@bues.ch>
+ *
+ * Derived from the EHCI-PCI driver
+ * Copyright (c) 2000-2004 by David Brownell
+ *
+ * Derived from the ohci-pci driver
+ * Copyright 1999 Roman Weissgaerber
+ * Copyright 2000-2002 David Brownell
+ * Copyright 1999 Linus Torvalds
+ * Copyright 1999 Gregory P. Smith
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+#include <linux/platform_device.h>
+#include <linux/usb/ehci_pdriver.h>
+
+static int ehci_platform_reset(struct usb_hcd *hcd)
+{
+ struct platform_device *pdev = to_platform_device(hcd->self.controller);
+ struct usb_ehci_pdata *pdata = pdev->dev.platform_data;
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ int retval;
+
+ hcd->has_tt = pdata->has_tt;
+ ehci->has_synopsys_hc_bug = pdata->has_synopsys_hc_bug;
+ ehci->big_endian_desc = pdata->big_endian_desc;
+ ehci->big_endian_mmio = pdata->big_endian_mmio;
+
+ ehci->caps = hcd->regs + pdata->caps_offset;
+ retval = ehci_setup(hcd);
+ if (retval)
+ return retval;
+
+ if (pdata->port_power_on)
+ ehci_port_power(ehci, 1);
+ if (pdata->port_power_off)
+ ehci_port_power(ehci, 0);
+
+ return 0;
+}
+
+static const struct hc_driver ehci_platform_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "Generic Platform EHCI Controller",
+ .hcd_priv_size = sizeof(struct ehci_hcd),
+
+ .irq = ehci_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+
+ .reset = ehci_platform_reset,
+ .start = ehci_run,
+ .stop = ehci_stop,
+ .shutdown = ehci_shutdown,
+
+ .urb_enqueue = ehci_urb_enqueue,
+ .urb_dequeue = ehci_urb_dequeue,
+ .endpoint_disable = ehci_endpoint_disable,
+ .endpoint_reset = ehci_endpoint_reset,
+
+ .get_frame_number = ehci_get_frame,
+
+ .hub_status_data = ehci_hub_status_data,
+ .hub_control = ehci_hub_control,
+#if defined(CONFIG_PM)
+ .bus_suspend = ehci_bus_suspend,
+ .bus_resume = ehci_bus_resume,
+#endif
+ .relinquish_port = ehci_relinquish_port,
+ .port_handed_over = ehci_port_handed_over,
+
+ .update_device = ehci_update_device,
+
+ .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
+};
+
+static int __devinit ehci_platform_probe(struct platform_device *dev)
+{
+ struct usb_hcd *hcd;
+ struct resource *res_mem;
+ int irq;
+ int err = -ENOMEM;
+
+ BUG_ON(!dev->dev.platform_data);
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ irq = platform_get_irq(dev, 0);
+ if (irq < 0) {
+ pr_err("no irq provieded");
+ return irq;
+ }
+ res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!res_mem) {
+ pr_err("no memory recourse provieded");
+ return -ENXIO;
+ }
+
+ hcd = usb_create_hcd(&ehci_platform_hc_driver, &dev->dev,
+ dev_name(&dev->dev));
+ if (!hcd)
+ return -ENOMEM;
+
+ hcd->rsrc_start = res_mem->start;
+ hcd->rsrc_len = resource_size(res_mem);
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ pr_err("controller already in use");
+ err = -EBUSY;
+ goto err_put_hcd;
+ }
+
+ hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs)
+ goto err_release_region;
+ err = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ if (err)
+ goto err_iounmap;
+
+ platform_set_drvdata(dev, hcd);
+
+ return err;
+
+err_iounmap:
+ iounmap(hcd->regs);
+err_release_region:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_put_hcd:
+ usb_put_hcd(hcd);
+ return err;
+}
+
+static int __devexit ehci_platform_remove(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ platform_set_drvdata(dev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int ehci_platform_suspend(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ bool wakeup = device_may_wakeup(dev);
+
+ ehci_prepare_ports_for_controller_suspend(hcd_to_ehci(hcd), wakeup);
+ return 0;
+}
+
+static int ehci_platform_resume(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+ ehci_prepare_ports_for_controller_resume(hcd_to_ehci(hcd));
+ return 0;
+}
+
+#else /* !CONFIG_PM */
+#define ehci_platform_suspend NULL
+#define ehci_platform_resume NULL
+#endif /* CONFIG_PM */
+
+static const struct platform_device_id ehci_platform_table[] = {
+ { "ehci-platform", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, ehci_platform_table);
+
+static const struct dev_pm_ops ehci_platform_pm_ops = {
+ .suspend = ehci_platform_suspend,
+ .resume = ehci_platform_resume,
+};
+
+static struct platform_driver ehci_platform_driver = {
+ .id_table = ehci_platform_table,
+ .probe = ehci_platform_probe,
+ .remove = __devexit_p(ehci_platform_remove),
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ehci-platform",
+ .pm = &ehci_platform_pm_ops,
+ }
+};
diff --git a/drivers/usb/host/ehci-pxa168.c b/drivers/usb/host/ehci-pxa168.c
deleted file mode 100644
index 8d0e7a22e711..000000000000
--- a/drivers/usb/host/ehci-pxa168.c
+++ /dev/null
@@ -1,363 +0,0 @@
-/*
- * drivers/usb/host/ehci-pxa168.c
- *
- * Tanmay Upadhyay <tanmay.upadhyay@einfochips.com>
- *
- * Based on drivers/usb/host/ehci-orion.c
- *
- * This file is licensed under the terms of the GNU General Public
- * License version 2. This program is licensed "as is" without any
- * warranty of any kind, whether express or implied.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <mach/pxa168.h>
-
-#define USB_PHY_CTRL_REG 0x4
-#define USB_PHY_PLL_REG 0x8
-#define USB_PHY_TX_REG 0xc
-
-#define FBDIV_SHIFT 4
-
-#define ICP_SHIFT 12
-#define ICP_15 2
-#define ICP_20 3
-#define ICP_25 4
-
-#define KVCO_SHIFT 15
-
-#define PLLCALI12_SHIFT 25
-#define CALI12_VDD 0
-#define CALI12_09 1
-#define CALI12_10 2
-#define CALI12_11 3
-
-#define PLLVDD12_SHIFT 27
-#define VDD12_VDD 0
-#define VDD12_10 1
-#define VDD12_11 2
-#define VDD12_12 3
-
-#define PLLVDD18_SHIFT 29
-#define VDD18_19 0
-#define VDD18_20 1
-#define VDD18_21 2
-#define VDD18_22 3
-
-
-#define PLL_READY (1 << 23)
-#define VCOCAL_START (1 << 21)
-#define REG_RCAL_START (1 << 12)
-
-struct pxa168_usb_drv_data {
- struct ehci_hcd ehci;
- struct clk *pxa168_usb_clk;
- struct resource *usb_phy_res;
- void __iomem *usb_phy_reg_base;
-};
-
-static int ehci_pxa168_setup(struct usb_hcd *hcd)
-{
- struct ehci_hcd *ehci = hcd_to_ehci(hcd);
- int retval;
-
- ehci_reset(ehci);
- retval = ehci_halt(ehci);
- if (retval)
- return retval;
-
- /*
- * data structure init
- */
- retval = ehci_init(hcd);
- if (retval)
- return retval;
-
- hcd->has_tt = 1;
-
- ehci_port_power(ehci, 0);
-
- return retval;
-}
-
-static const struct hc_driver ehci_pxa168_hc_driver = {
- .description = hcd_name,
- .product_desc = "Marvell PXA168 EHCI",
- .hcd_priv_size = sizeof(struct pxa168_usb_drv_data),
-
- /*
- * generic hardware linkage
- */
- .irq = ehci_irq,
- .flags = HCD_MEMORY | HCD_USB2,
-
- /*
- * basic lifecycle operations
- */
- .reset = ehci_pxa168_setup,
- .start = ehci_run,
- .stop = ehci_stop,
- .shutdown = ehci_shutdown,
-
- /*
- * managing i/o requests and associated device resources
- */
- .urb_enqueue = ehci_urb_enqueue,
- .urb_dequeue = ehci_urb_dequeue,
- .endpoint_disable = ehci_endpoint_disable,
- .endpoint_reset = ehci_endpoint_reset,
-
- /*
- * scheduling support
- */
- .get_frame_number = ehci_get_frame,
-
- /*
- * root hub support
- */
- .hub_status_data = ehci_hub_status_data,
- .hub_control = ehci_hub_control,
- .bus_suspend = ehci_bus_suspend,
- .bus_resume = ehci_bus_resume,
- .relinquish_port = ehci_relinquish_port,
- .port_handed_over = ehci_port_handed_over,
-
- .clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
-};
-
-static int pxa168_usb_phy_init(struct platform_device *pdev)
-{
- struct resource *res;
- void __iomem *usb_phy_reg_base;
- struct pxa168_usb_pdata *pdata;
- struct pxa168_usb_drv_data *drv_data;
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
- unsigned long reg_val;
- int pll_retry_cont = 10000, err = 0;
-
- drv_data = (struct pxa168_usb_drv_data *)hcd->hcd_priv;
- pdata = (struct pxa168_usb_pdata *)pdev->dev.platform_data;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!res) {
- dev_err(&pdev->dev,
- "Found HC with no PHY register addr. Check %s setup!\n",
- dev_name(&pdev->dev));
- return -ENODEV;
- }
-
- if (!request_mem_region(res->start, resource_size(res),
- ehci_pxa168_hc_driver.description)) {
- dev_dbg(&pdev->dev, "controller already in use\n");
- return -EBUSY;
- }
-
- usb_phy_reg_base = ioremap(res->start, resource_size(res));
- if (usb_phy_reg_base == NULL) {
- dev_dbg(&pdev->dev, "error mapping memory\n");
- err = -EFAULT;
- goto err1;
- }
- drv_data->usb_phy_reg_base = usb_phy_reg_base;
- drv_data->usb_phy_res = res;
-
- /* If someone wants to init USB phy in board specific way */
- if (pdata && pdata->phy_init)
- return pdata->phy_init(usb_phy_reg_base);
-
- /* Power up the PHY and PLL */
- writel(readl(usb_phy_reg_base + USB_PHY_CTRL_REG) | 0x3,
- usb_phy_reg_base + USB_PHY_CTRL_REG);
-
- /* Configure PHY PLL */
- reg_val = readl(usb_phy_reg_base + USB_PHY_PLL_REG) & ~(0x7e03ffff);
- reg_val |= (VDD18_22 << PLLVDD18_SHIFT | VDD12_12 << PLLVDD12_SHIFT |
- CALI12_11 << PLLCALI12_SHIFT | 3 << KVCO_SHIFT |
- ICP_15 << ICP_SHIFT | 0xee << FBDIV_SHIFT | 0xb);
- writel(reg_val, usb_phy_reg_base + USB_PHY_PLL_REG);
-
- /* Make sure PHY PLL is ready */
- while (!(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & PLL_READY)) {
- if (!(pll_retry_cont--)) {
- dev_dbg(&pdev->dev, "USB PHY PLL not ready\n");
- err = -EIO;
- goto err2;
- }
- }
-
- /* Toggle VCOCAL_START bit of U2PLL for PLL calibration */
- udelay(200);
- writel(readl(usb_phy_reg_base + USB_PHY_PLL_REG) | VCOCAL_START,
- usb_phy_reg_base + USB_PHY_PLL_REG);
- udelay(40);
- writel(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & ~VCOCAL_START,
- usb_phy_reg_base + USB_PHY_PLL_REG);
-
- /* Toggle REG_RCAL_START bit of U2PTX for impedance calibration */
- udelay(400);
- writel(readl(usb_phy_reg_base + USB_PHY_TX_REG) | REG_RCAL_START,
- usb_phy_reg_base + USB_PHY_TX_REG);
- udelay(40);
- writel(readl(usb_phy_reg_base + USB_PHY_TX_REG) & ~REG_RCAL_START,
- usb_phy_reg_base + USB_PHY_TX_REG);
-
- /* Make sure PHY PLL is ready again */
- pll_retry_cont = 0;
- while (!(readl(usb_phy_reg_base + USB_PHY_PLL_REG) & PLL_READY)) {
- if (!(pll_retry_cont--)) {
- dev_dbg(&pdev->dev, "USB PHY PLL not ready\n");
- err = -EIO;
- goto err2;
- }
- }
-
- return 0;
-err2:
- iounmap(usb_phy_reg_base);
-err1:
- release_mem_region(res->start, resource_size(res));
- return err;
-}
-
-static int __devinit ehci_pxa168_drv_probe(struct platform_device *pdev)
-{
- struct resource *res;
- struct usb_hcd *hcd;
- struct ehci_hcd *ehci;
- struct pxa168_usb_drv_data *drv_data;
- void __iomem *regs;
- int irq, err = 0;
-
- if (usb_disabled())
- return -ENODEV;
-
- pr_debug("Initializing pxa168-SoC USB Host Controller\n");
-
- irq = platform_get_irq(pdev, 0);
- if (irq <= 0) {
- dev_err(&pdev->dev,
- "Found HC with no IRQ. Check %s setup!\n",
- dev_name(&pdev->dev));
- err = -ENODEV;
- goto err1;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev,
- "Found HC with no register addr. Check %s setup!\n",
- dev_name(&pdev->dev));
- err = -ENODEV;
- goto err1;
- }
-
- if (!request_mem_region(res->start, resource_size(res),
- ehci_pxa168_hc_driver.description)) {
- dev_dbg(&pdev->dev, "controller already in use\n");
- err = -EBUSY;
- goto err1;
- }
-
- regs = ioremap(res->start, resource_size(res));
- if (regs == NULL) {
- dev_dbg(&pdev->dev, "error mapping memory\n");
- err = -EFAULT;
- goto err2;
- }
-
- hcd = usb_create_hcd(&ehci_pxa168_hc_driver,
- &pdev->dev, dev_name(&pdev->dev));
- if (!hcd) {
- err = -ENOMEM;
- goto err3;
- }
-
- drv_data = (struct pxa168_usb_drv_data *)hcd->hcd_priv;
-
- /* Enable USB clock */
- drv_data->pxa168_usb_clk = clk_get(&pdev->dev, "PXA168-USBCLK");
- if (IS_ERR(drv_data->pxa168_usb_clk)) {
- dev_err(&pdev->dev, "Couldn't get USB clock\n");
- err = PTR_ERR(drv_data->pxa168_usb_clk);
- goto err4;
- }
- clk_enable(drv_data->pxa168_usb_clk);
-
- err = pxa168_usb_phy_init(pdev);
- if (err) {
- dev_err(&pdev->dev, "USB PHY initialization failed\n");
- goto err5;
- }
-
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
- hcd->regs = regs;
-
- 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));
- ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
- hcd->has_tt = 1;
- ehci->sbrn = 0x20;
-
- err = usb_add_hcd(hcd, irq, IRQF_SHARED | IRQF_DISABLED);
- if (err)
- goto err5;
-
- return 0;
-
-err5:
- clk_disable(drv_data->pxa168_usb_clk);
- clk_put(drv_data->pxa168_usb_clk);
-err4:
- usb_put_hcd(hcd);
-err3:
- iounmap(regs);
-err2:
- release_mem_region(res->start, resource_size(res));
-err1:
- dev_err(&pdev->dev, "init %s fail, %d\n",
- dev_name(&pdev->dev), err);
-
- return err;
-}
-
-static int __exit ehci_pxa168_drv_remove(struct platform_device *pdev)
-{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
- struct pxa168_usb_drv_data *drv_data =
- (struct pxa168_usb_drv_data *)hcd->hcd_priv;
-
- usb_remove_hcd(hcd);
-
- /* Power down PHY & PLL */
- writel(readl(drv_data->usb_phy_reg_base + USB_PHY_CTRL_REG) & (~0x3),
- drv_data->usb_phy_reg_base + USB_PHY_CTRL_REG);
-
- clk_disable(drv_data->pxa168_usb_clk);
- clk_put(drv_data->pxa168_usb_clk);
-
- iounmap(hcd->regs);
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-
- iounmap(drv_data->usb_phy_reg_base);
- release_mem_region(drv_data->usb_phy_res->start,
- resource_size(drv_data->usb_phy_res));
-
- usb_put_hcd(hcd);
-
- return 0;
-}
-
-MODULE_ALIAS("platform:pxa168-ehci");
-
-static struct platform_driver ehci_pxa168_driver = {
- .probe = ehci_pxa168_drv_probe,
- .remove = __exit_p(ehci_pxa168_drv_remove),
- .shutdown = usb_hcd_platform_shutdown,
- .driver.name = "pxa168-ehci",
-};
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c
index 293f7412992e..f098e2a291a0 100644
--- a/drivers/usb/host/ehci-s5p.c
+++ b/drivers/usb/host/ehci-s5p.c
@@ -17,6 +17,15 @@
#include <plat/ehci.h>
#include <plat/usb-phy.h>
+#define EHCI_INSNREG00(base) (base + 0x90)
+#define EHCI_INSNREG00_ENA_INCR16 (0x1 << 25)
+#define EHCI_INSNREG00_ENA_INCR8 (0x1 << 24)
+#define EHCI_INSNREG00_ENA_INCR4 (0x1 << 23)
+#define EHCI_INSNREG00_ENA_INCRX_ALIGN (0x1 << 22)
+#define EHCI_INSNREG00_ENABLE_DMA_BURST \
+ (EHCI_INSNREG00_ENA_INCR16 | EHCI_INSNREG00_ENA_INCR8 | \
+ EHCI_INSNREG00_ENA_INCR4 | EHCI_INSNREG00_ENA_INCRX_ALIGN)
+
struct s5p_ehci_hcd {
struct device *dev;
struct usb_hcd *hcd;
@@ -128,6 +137,9 @@ static int __devinit s5p_ehci_probe(struct platform_device *pdev)
ehci->regs = hcd->regs +
HC_LENGTH(ehci, readl(&ehci->caps->hc_capbase));
+ /* DMA burst Enable */
+ writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
+
dbg_hcs_params(ehci, "reset");
dbg_hcc_params(ehci, "reset");
@@ -234,6 +246,9 @@ static int s5p_ehci_resume(struct device *dev)
if (pdata && pdata->phy_init)
pdata->phy_init(pdev, S5P_USB_PHY_HOST);
+ /* DMA burst Enable */
+ writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs));
+
if (time_before(jiffies, ehci->next_statechange))
msleep(100);
diff --git a/drivers/usb/host/ehci-spear.c b/drivers/usb/host/ehci-spear.c
index b115b0b76e33..6e928559169c 100644
--- a/drivers/usb/host/ehci-spear.c
+++ b/drivers/usb/host/ehci-spear.c
@@ -11,8 +11,10 @@
* more details.
*/
-#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/pm.h>
struct spear_ehci {
struct ehci_hcd ehci;
@@ -90,6 +92,82 @@ static const struct hc_driver ehci_spear_hc_driver = {
.clear_tt_buffer_complete = ehci_clear_tt_buffer_complete,
};
+#ifdef CONFIG_PM
+static int ehci_spear_drv_suspend(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+ unsigned long flags;
+ int rc = 0;
+
+ if (time_before(jiffies, ehci->next_statechange))
+ msleep(10);
+
+ /*
+ * Root hub was already suspended. Disable irq emission and mark HW
+ * unaccessible. The PM and USB cores make sure that the root hub is
+ * either suspended or stopped.
+ */
+ spin_lock_irqsave(&ehci->lock, flags);
+ ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
+ ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+ ehci_readl(ehci, &ehci->regs->intr_enable);
+ spin_unlock_irqrestore(&ehci->lock, flags);
+
+ return rc;
+}
+
+static int ehci_spear_drv_resume(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+
+ if (time_before(jiffies, ehci->next_statechange))
+ msleep(100);
+
+ if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
+ int mask = INTR_MASK;
+
+ ehci_prepare_ports_for_controller_resume(ehci);
+
+ if (!hcd->self.root_hub->do_remote_wakeup)
+ mask &= ~STS_PCD;
+
+ ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+ ehci_readl(ehci, &ehci->regs->intr_enable);
+ return 0;
+ }
+
+ usb_root_hub_lost_power(hcd->self.root_hub);
+
+ /*
+ * Else reset, to cope with power loss or flush-to-storage style
+ * "resume" having let BIOS kick in during reboot.
+ */
+ ehci_halt(ehci);
+ ehci_reset(ehci);
+
+ /* emptying the schedule aborts any urbs */
+ spin_lock_irq(&ehci->lock);
+ if (ehci->reclaim)
+ end_unlink_async(ehci);
+
+ ehci_work(ehci);
+ spin_unlock_irq(&ehci->lock);
+
+ ehci_writel(ehci, ehci->command, &ehci->regs->command);
+ ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+ ehci_readl(ehci, &ehci->regs->command); /* unblock posted writes */
+
+ /* here we "know" root ports should always stay powered */
+ ehci_port_power(ehci, 1);
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+static SIMPLE_DEV_PM_OPS(ehci_spear_pm_ops, ehci_spear_drv_suspend,
+ ehci_spear_drv_resume);
+
static int spear_ehci_hcd_drv_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd ;
@@ -205,7 +283,8 @@ static struct platform_driver spear_ehci_hcd_driver = {
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "spear-ehci",
- .bus = &platform_bus_type
+ .bus = &platform_bus_type,
+ .pm = &ehci_spear_pm_ops,
}
};
diff --git a/drivers/usb/host/ehci-tegra.c b/drivers/usb/host/ehci-tegra.c
index dbc7fe8ca9e7..86183366647f 100644
--- a/drivers/usb/host/ehci-tegra.c
+++ b/drivers/usb/host/ehci-tegra.c
@@ -35,7 +35,7 @@ struct tegra_ehci_hcd {
struct tegra_usb_phy *phy;
struct clk *clk;
struct clk *emc_clk;
- struct otg_transceiver *transceiver;
+ struct usb_phy *transceiver;
int host_resumed;
int bus_suspended;
int port_resuming;
@@ -224,6 +224,7 @@ static int tegra_ehci_hub_control(
temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
/* start resume signalling */
ehci_writel(ehci, temp | PORT_RESUME, status_reg);
+ set_bit(wIndex-1, &ehci->resuming_ports);
spin_unlock_irqrestore(&ehci->lock, flags);
msleep(20);
@@ -236,6 +237,7 @@ static int tegra_ehci_hub_control(
pr_err("%s: timeout waiting for SUSPEND\n", __func__);
ehci->reset_done[wIndex-1] = 0;
+ clear_bit(wIndex-1, &ehci->resuming_ports);
tegra->port_resuming = 1;
goto done;
@@ -729,13 +731,12 @@ static int tegra_ehci_probe(struct platform_device *pdev)
err = -ENODEV;
goto fail;
}
- set_irq_flags(irq, IRQF_VALID);
#ifdef CONFIG_USB_OTG_UTILS
if (pdata->operating_mode == TEGRA_USB_OTG) {
- tegra->transceiver = otg_get_transceiver();
+ tegra->transceiver = usb_get_transceiver();
if (tegra->transceiver)
- otg_set_host(tegra->transceiver, &hcd->self);
+ otg_set_host(tegra->transceiver->otg, &hcd->self);
}
#endif
@@ -750,8 +751,8 @@ static int tegra_ehci_probe(struct platform_device *pdev)
fail:
#ifdef CONFIG_USB_OTG_UTILS
if (tegra->transceiver) {
- otg_set_host(tegra->transceiver, NULL);
- otg_put_transceiver(tegra->transceiver);
+ otg_set_host(tegra->transceiver->otg, NULL);
+ usb_put_transceiver(tegra->transceiver);
}
#endif
tegra_usb_phy_close(tegra->phy);
@@ -808,8 +809,8 @@ static int tegra_ehci_remove(struct platform_device *pdev)
#ifdef CONFIG_USB_OTG_UTILS
if (tegra->transceiver) {
- otg_set_host(tegra->transceiver, NULL);
- otg_put_transceiver(tegra->transceiver);
+ otg_set_host(tegra->transceiver->otg, NULL);
+ usb_put_transceiver(tegra->transceiver);
}
#endif
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 0a5fda73b3f2..2694ed6558d2 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -117,6 +117,8 @@ struct ehci_hcd { /* one per controller */
the change-suspend feature turned on */
unsigned long suspended_ports; /* which ports are
suspended */
+ unsigned long resuming_ports; /* which ports have
+ started to resume */
/* per-HC memory pools (could be per-bus, but ...) */
struct dma_pool *qh_pool; /* qh per active urb */
@@ -176,7 +178,7 @@ struct ehci_hcd { /* one per controller */
/*
* OTG controllers and transceivers need software interaction
*/
- struct otg_transceiver *transceiver;
+ struct usb_phy *transceiver;
};
/* convert between an HCD pointer and the corresponding EHCI_HCD */
diff --git a/drivers/usb/host/fsl-mph-dr-of.c b/drivers/usb/host/fsl-mph-dr-of.c
index 7916e56a725e..ab333ac6071d 100644
--- a/drivers/usb/host/fsl-mph-dr-of.c
+++ b/drivers/usb/host/fsl-mph-dr-of.c
@@ -94,7 +94,6 @@ struct platform_device * __devinit fsl_usb2_device_register(
pdev->dev.parent = &ofdev->dev;
pdev->dev.coherent_dma_mask = ofdev->dev.coherent_dma_mask;
- pdev->dev.dma_mask = &pdev->archdata.dma_mask;
*pdev->dev.dma_mask = *ofdev->dev.dma_mask;
retval = platform_device_add_data(pdev, pdata, sizeof(*pdata));
diff --git a/drivers/usb/host/imx21-dbg.c b/drivers/usb/host/imx21-dbg.c
index 6d7533427163..ec98ecee3517 100644
--- a/drivers/usb/host/imx21-dbg.c
+++ b/drivers/usb/host/imx21-dbg.c
@@ -239,7 +239,7 @@ static int debug_status_show(struct seq_file *s, void *v)
"ETDs allocated: %d/%d (max=%d)\n"
"ETDs in use sw: %d\n"
"ETDs in use hw: %d\n"
- "DMEM alocated: %d/%d (max=%d)\n"
+ "DMEM allocated: %d/%d (max=%d)\n"
"DMEM blocks: %d\n"
"Queued waiting for ETD: %d\n"
"Queued waiting for DMEM: %d\n",
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index d91e5f211a76..9e65e3091c8a 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -70,7 +70,6 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/byteorder.h>
#include "isp116x.h"
@@ -1569,6 +1568,9 @@ static int __devinit isp116x_probe(struct platform_device *pdev)
int ret = 0;
unsigned long irqflags;
+ if (usb_disabled())
+ return -ENODEV;
+
if (pdev->num_resources < 3) {
ret = -ENODEV;
goto err1;
@@ -1708,22 +1710,4 @@ static struct platform_driver isp116x_driver = {
},
};
-/*-----------------------------------------------------------------*/
-
-static int __init isp116x_init(void)
-{
- if (usb_disabled())
- return -ENODEV;
-
- INFO("driver %s, %s\n", hcd_name, DRIVER_VERSION);
- return platform_driver_register(&isp116x_driver);
-}
-
-module_init(isp116x_init);
-
-static void __exit isp116x_cleanup(void)
-{
- platform_driver_unregister(&isp116x_driver);
-}
-
-module_exit(isp116x_cleanup);
+module_platform_driver(isp116x_driver);
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c
index e5fd8aa57af1..2ed112d3e159 100644
--- a/drivers/usb/host/isp1362-hcd.c
+++ b/drivers/usb/host/isp1362-hcd.c
@@ -84,7 +84,6 @@
#include <linux/prefetch.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
@@ -2693,6 +2692,9 @@ static int __devinit isp1362_probe(struct platform_device *pdev)
struct resource *irq_res;
unsigned int irq_flags = 0;
+ if (usb_disabled())
+ return -ENODEV;
+
/* basic sanity checks first. board-specific init logic should
* have initialized this the three resources and probably board
* specific platform_data. we don't probe for IRQs, and do only
@@ -2864,19 +2866,4 @@ static struct platform_driver isp1362_driver = {
},
};
-/*-------------------------------------------------------------------------*/
-
-static int __init isp1362_init(void)
-{
- if (usb_disabled())
- return -ENODEV;
- pr_info("driver %s, %s\n", hcd_name, DRIVER_VERSION);
- return platform_driver_register(&isp1362_driver);
-}
-module_init(isp1362_init);
-
-static void __exit isp1362_cleanup(void)
-{
- platform_driver_unregister(&isp1362_driver);
-}
-module_exit(isp1362_cleanup);
+module_platform_driver(isp1362_driver);
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index 77afabc77f9b..13ebeca8e73e 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -14,6 +14,8 @@
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/of_gpio.h>
#include <mach/hardware.h>
#include <asm/gpio.h>
@@ -25,6 +27,10 @@
#error "CONFIG_ARCH_AT91 must be defined."
#endif
+#define valid_port(index) ((index) >= 0 && (index) < AT91_MAX_USBH_PORTS)
+#define at91_for_each_port(index) \
+ for ((index) = 0; (index) < AT91_MAX_USBH_PORTS; (index)++)
+
/* interface and function clocks; sometimes also an AHB clock */
static struct clk *iclk, *fclk, *hclk;
static int clocked;
@@ -88,7 +94,7 @@ static void at91_stop_hc(struct platform_device *pdev)
/*-------------------------------------------------------------------------*/
-static void usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *);
+static void __devexit usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *);
/* configure so an HC device and id are always provided */
/* always called with process context; sleeping is OK */
@@ -102,7 +108,7 @@ static void usb_hcd_at91_remove (struct usb_hcd *, struct platform_device *);
* then invokes the start() method for the HCD associated with it
* through the hotplug entry's driver_data.
*/
-static int usb_hcd_at91_probe(const struct hc_driver *driver,
+static int __devinit usb_hcd_at91_probe(const struct hc_driver *driver,
struct platform_device *pdev)
{
int retval;
@@ -197,7 +203,7 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
* context, "rmmod" or something similar.
*
*/
-static void usb_hcd_at91_remove(struct usb_hcd *hcd,
+static void __devexit usb_hcd_at91_remove(struct usb_hcd *hcd,
struct platform_device *pdev)
{
usb_remove_hcd(hcd);
@@ -238,26 +244,26 @@ ohci_at91_start (struct usb_hcd *hcd)
static void ohci_at91_usb_set_power(struct at91_usbh_data *pdata, int port, int enable)
{
- if (port < 0 || port >= 2)
+ if (!valid_port(port))
return;
if (!gpio_is_valid(pdata->vbus_pin[port]))
return;
gpio_set_value(pdata->vbus_pin[port],
- !pdata->vbus_pin_active_low[port] ^ enable);
+ pdata->vbus_pin_active_low[port] ^ enable);
}
static int ohci_at91_usb_get_power(struct at91_usbh_data *pdata, int port)
{
- if (port < 0 || port >= 2)
+ if (!valid_port(port))
return -EINVAL;
if (!gpio_is_valid(pdata->vbus_pin[port]))
return -EINVAL;
return gpio_get_value(pdata->vbus_pin[port]) ^
- !pdata->vbus_pin_active_low[port];
+ pdata->vbus_pin_active_low[port];
}
/*
@@ -269,9 +275,9 @@ static int ohci_at91_hub_status_data(struct usb_hcd *hcd, char *buf)
int length = ohci_hub_status_data(hcd, buf);
int port;
- for (port = 0; port < ARRAY_SIZE(pdata->overcurrent_pin); port++) {
+ at91_for_each_port(port) {
if (pdata->overcurrent_changed[port]) {
- if (! length)
+ if (!length)
length = 1;
buf[0] |= 1 << (port + 1);
}
@@ -295,11 +301,17 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
"ohci_at91_hub_control(%p,0x%04x,0x%04x,0x%04x,%p,%04x)\n",
hcd, typeReq, wValue, wIndex, buf, wLength);
+ wIndex--;
+
switch (typeReq) {
case SetPortFeature:
if (wValue == USB_PORT_FEAT_POWER) {
dev_dbg(hcd->self.controller, "SetPortFeat: POWER\n");
- ohci_at91_usb_set_power(pdata, wIndex - 1, 1);
+ if (valid_port(wIndex)) {
+ ohci_at91_usb_set_power(pdata, wIndex, 1);
+ ret = 0;
+ }
+
goto out;
}
break;
@@ -310,9 +322,9 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
dev_dbg(hcd->self.controller,
"ClearPortFeature: C_OVER_CURRENT\n");
- if (wIndex == 1 || wIndex == 2) {
- pdata->overcurrent_changed[wIndex-1] = 0;
- pdata->overcurrent_status[wIndex-1] = 0;
+ if (valid_port(wIndex)) {
+ pdata->overcurrent_changed[wIndex] = 0;
+ pdata->overcurrent_status[wIndex] = 0;
}
goto out;
@@ -321,9 +333,8 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
dev_dbg(hcd->self.controller,
"ClearPortFeature: OVER_CURRENT\n");
- if (wIndex == 1 || wIndex == 2) {
- pdata->overcurrent_status[wIndex-1] = 0;
- }
+ if (valid_port(wIndex))
+ pdata->overcurrent_status[wIndex] = 0;
goto out;
@@ -331,15 +342,15 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
dev_dbg(hcd->self.controller,
"ClearPortFeature: POWER\n");
- if (wIndex == 1 || wIndex == 2) {
- ohci_at91_usb_set_power(pdata, wIndex - 1, 0);
+ if (valid_port(wIndex)) {
+ ohci_at91_usb_set_power(pdata, wIndex, 0);
return 0;
}
}
break;
}
- ret = ohci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
+ ret = ohci_hub_control(hcd, typeReq, wValue, wIndex + 1, buf, wLength);
if (ret)
goto out;
@@ -375,18 +386,15 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
dev_dbg(hcd->self.controller, "GetPortStatus(%d)\n", wIndex);
- if (wIndex == 1 || wIndex == 2) {
- if (! ohci_at91_usb_get_power(pdata, wIndex-1)) {
+ if (valid_port(wIndex)) {
+ if (!ohci_at91_usb_get_power(pdata, wIndex))
*data &= ~cpu_to_le32(RH_PS_PPS);
- }
- if (pdata->overcurrent_changed[wIndex-1]) {
+ if (pdata->overcurrent_changed[wIndex])
*data |= cpu_to_le32(RH_PS_OCIC);
- }
- if (pdata->overcurrent_status[wIndex-1]) {
+ if (pdata->overcurrent_status[wIndex])
*data |= cpu_to_le32(RH_PS_POCI);
- }
}
}
@@ -448,13 +456,14 @@ static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data)
/* From the GPIO notifying the over-current situation, find
* out the corresponding port */
- gpio = irq_to_gpio(irq);
- for (port = 0; port < ARRAY_SIZE(pdata->overcurrent_pin); port++) {
- if (pdata->overcurrent_pin[port] == gpio)
+ at91_for_each_port(port) {
+ if (gpio_to_irq(pdata->overcurrent_pin[port]) == irq) {
+ gpio = pdata->overcurrent_pin[port];
break;
+ }
}
- if (port == ARRAY_SIZE(pdata->overcurrent_pin)) {
+ if (port == AT91_MAX_USBH_PORTS) {
dev_err(& pdev->dev, "overcurrent interrupt from unknown GPIO\n");
return IRQ_HANDLED;
}
@@ -464,7 +473,7 @@ static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data)
/* When notified of an over-current situation, disable power
on the corresponding port, and mark this port in
over-current. */
- if (! val) {
+ if (!val) {
ohci_at91_usb_set_power(pdata, port, 0);
pdata->overcurrent_status[port] = 1;
pdata->overcurrent_changed[port] = 1;
@@ -476,34 +485,133 @@ static irqreturn_t ohci_hcd_at91_overcurrent_irq(int irq, void *data)
return IRQ_HANDLED;
}
+#ifdef CONFIG_OF
+static const struct of_device_id at91_ohci_dt_ids[] = {
+ { .compatible = "atmel,at91rm9200-ohci" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, at91_ohci_dt_ids);
+
+static u64 at91_ohci_dma_mask = DMA_BIT_MASK(32);
+
+static int __devinit ohci_at91_of_init(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int i, gpio;
+ enum of_gpio_flags flags;
+ struct at91_usbh_data *pdata;
+ u32 ports;
+
+ if (!np)
+ return 0;
+
+ /* Right now device-tree probed devices don't get dma_mask set.
+ * Since shared usb code relies on it, set it here for now.
+ * Once we have dma capability bindings this can go away.
+ */
+ if (!pdev->dev.dma_mask)
+ pdev->dev.dma_mask = &at91_ohci_dma_mask;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ if (!of_property_read_u32(np, "num-ports", &ports))
+ pdata->ports = ports;
+
+ at91_for_each_port(i) {
+ gpio = of_get_named_gpio_flags(np, "atmel,vbus-gpio", i, &flags);
+ pdata->vbus_pin[i] = gpio;
+ if (!gpio_is_valid(gpio))
+ continue;
+ pdata->vbus_pin_active_low[i] = flags & OF_GPIO_ACTIVE_LOW;
+ }
+
+ at91_for_each_port(i)
+ pdata->overcurrent_pin[i] =
+ of_get_named_gpio_flags(np, "atmel,oc-gpio", i, &flags);
+
+ pdev->dev.platform_data = pdata;
+
+ return 0;
+}
+#else
+static int __devinit ohci_at91_of_init(struct platform_device *pdev)
+{
+ return 0;
+}
+#endif
+
/*-------------------------------------------------------------------------*/
-static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
+static int __devinit ohci_hcd_at91_drv_probe(struct platform_device *pdev)
{
- struct at91_usbh_data *pdata = pdev->dev.platform_data;
+ struct at91_usbh_data *pdata;
int i;
+ int gpio;
+ int ret;
+
+ ret = ohci_at91_of_init(pdev);
+ if (ret)
+ return ret;
+
+ pdata = pdev->dev.platform_data;
if (pdata) {
- for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) {
+ at91_for_each_port(i) {
if (!gpio_is_valid(pdata->vbus_pin[i]))
continue;
- gpio_request(pdata->vbus_pin[i], "ohci_vbus");
+ gpio = pdata->vbus_pin[i];
+
+ ret = gpio_request(gpio, "ohci_vbus");
+ if (ret) {
+ dev_err(&pdev->dev,
+ "can't request vbus gpio %d\n", gpio);
+ continue;
+ }
+ ret = gpio_direction_output(gpio,
+ !pdata->vbus_pin_active_low[i]);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "can't put vbus gpio %d as output %d\n",
+ gpio, !pdata->vbus_pin_active_low[i]);
+ gpio_free(gpio);
+ continue;
+ }
+
ohci_at91_usb_set_power(pdata, i, 1);
}
- for (i = 0; i < ARRAY_SIZE(pdata->overcurrent_pin); i++) {
- int ret;
-
+ at91_for_each_port(i) {
if (!gpio_is_valid(pdata->overcurrent_pin[i]))
continue;
- gpio_request(pdata->overcurrent_pin[i], "ohci_overcurrent");
+ gpio = pdata->overcurrent_pin[i];
+
+ ret = gpio_request(gpio, "ohci_overcurrent");
+ if (ret) {
+ dev_err(&pdev->dev,
+ "can't request overcurrent gpio %d\n",
+ gpio);
+ continue;
+ }
+
+ ret = gpio_direction_input(gpio);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "can't configure overcurrent gpio %d as input\n",
+ gpio);
+ gpio_free(gpio);
+ continue;
+ }
- ret = request_irq(gpio_to_irq(pdata->overcurrent_pin[i]),
+ ret = request_irq(gpio_to_irq(gpio),
ohci_hcd_at91_overcurrent_irq,
IRQF_SHARED, "ohci_overcurrent", pdev);
if (ret) {
- gpio_free(pdata->overcurrent_pin[i]);
- dev_warn(& pdev->dev, "cannot get GPIO IRQ for overcurrent\n");
+ gpio_free(gpio);
+ dev_err(&pdev->dev,
+ "can't get gpio IRQ for overcurrent\n");
}
}
}
@@ -512,20 +620,20 @@ static int ohci_hcd_at91_drv_probe(struct platform_device *pdev)
return usb_hcd_at91_probe(&ohci_at91_hc_driver, pdev);
}
-static int ohci_hcd_at91_drv_remove(struct platform_device *pdev)
+static int __devexit ohci_hcd_at91_drv_remove(struct platform_device *pdev)
{
struct at91_usbh_data *pdata = pdev->dev.platform_data;
int i;
if (pdata) {
- for (i = 0; i < ARRAY_SIZE(pdata->vbus_pin); i++) {
+ at91_for_each_port(i) {
if (!gpio_is_valid(pdata->vbus_pin[i]))
continue;
ohci_at91_usb_set_power(pdata, i, 0);
gpio_free(pdata->vbus_pin[i]);
}
- for (i = 0; i < ARRAY_SIZE(pdata->overcurrent_pin); i++) {
+ at91_for_each_port(i) {
if (!gpio_is_valid(pdata->overcurrent_pin[i]))
continue;
free_irq(gpio_to_irq(pdata->overcurrent_pin[i]), pdev);
@@ -588,12 +696,13 @@ MODULE_ALIAS("platform:at91_ohci");
static struct platform_driver ohci_hcd_at91_driver = {
.probe = ohci_hcd_at91_drv_probe,
- .remove = ohci_hcd_at91_drv_remove,
+ .remove = __devexit_p(ohci_hcd_at91_drv_remove),
.shutdown = usb_hcd_platform_shutdown,
.suspend = ohci_hcd_at91_drv_suspend,
.resume = ohci_hcd_at91_drv_resume,
.driver = {
.name = "at91_ohci",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(at91_ohci_dt_ids),
},
};
diff --git a/drivers/usb/host/ohci-ath79.c b/drivers/usb/host/ohci-ath79.c
deleted file mode 100644
index 18d574d6958b..000000000000
--- a/drivers/usb/host/ohci-ath79.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * OHCI HCD (Host Controller Driver) for USB.
- *
- * Bus Glue for Atheros AR71XX/AR724X built-in OHCI controller.
- *
- * Copyright (C) 2008-2011 Gabor Juhos <juhosg@openwrt.org>
- * Copyright (C) 2008 Imre Kaloz <kaloz@openwrt.org>
- *
- * Parts of this file are based on Atheros' 2.6.15 BSP
- * Copyright (C) 2007 Atheros Communications, Inc.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 as published
- * by the Free Software Foundation.
- */
-
-#include <linux/platform_device.h>
-
-static int __devinit ohci_ath79_start(struct usb_hcd *hcd)
-{
- struct ohci_hcd *ohci = hcd_to_ohci(hcd);
- int ret;
-
- ret = ohci_init(ohci);
- if (ret < 0)
- return ret;
-
- ret = ohci_run(ohci);
- if (ret < 0)
- goto err;
-
- return 0;
-
-err:
- ohci_stop(hcd);
- return ret;
-}
-
-static const struct hc_driver ohci_ath79_hc_driver = {
- .description = hcd_name,
- .product_desc = "Atheros built-in OHCI controller",
- .hcd_priv_size = sizeof(struct ohci_hcd),
-
- .irq = ohci_irq,
- .flags = HCD_USB11 | HCD_MEMORY,
-
- .start = ohci_ath79_start,
- .stop = ohci_stop,
- .shutdown = ohci_shutdown,
-
- .urb_enqueue = ohci_urb_enqueue,
- .urb_dequeue = ohci_urb_dequeue,
- .endpoint_disable = ohci_endpoint_disable,
-
- /*
- * scheduling support
- */
- .get_frame_number = ohci_get_frame,
-
- /*
- * root hub support
- */
- .hub_status_data = ohci_hub_status_data,
- .hub_control = ohci_hub_control,
- .start_port_reset = ohci_start_port_reset,
-};
-
-static int ohci_ath79_probe(struct platform_device *pdev)
-{
- struct usb_hcd *hcd;
- struct resource *res;
- int irq;
- int ret;
-
- if (usb_disabled())
- return -ENODEV;
-
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!res) {
- dev_dbg(&pdev->dev, "no IRQ specified\n");
- return -ENODEV;
- }
- irq = res->start;
-
- hcd = usb_create_hcd(&ohci_ath79_hc_driver, &pdev->dev,
- dev_name(&pdev->dev));
- if (!hcd)
- return -ENOMEM;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_dbg(&pdev->dev, "no base address specified\n");
- ret = -ENODEV;
- goto err_put_hcd;
- }
- hcd->rsrc_start = res->start;
- hcd->rsrc_len = resource_size(res);
-
- if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
- dev_dbg(&pdev->dev, "controller already in use\n");
- ret = -EBUSY;
- goto err_put_hcd;
- }
-
- hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
- if (!hcd->regs) {
- dev_dbg(&pdev->dev, "error mapping memory\n");
- ret = -EFAULT;
- goto err_release_region;
- }
-
- ohci_hcd_init(hcd_to_ohci(hcd));
-
- ret = usb_add_hcd(hcd, irq, 0);
- if (ret)
- goto err_stop_hcd;
-
- return 0;
-
-err_stop_hcd:
- iounmap(hcd->regs);
-err_release_region:
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-err_put_hcd:
- usb_put_hcd(hcd);
- return ret;
-}
-
-static int ohci_ath79_remove(struct platform_device *pdev)
-{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
- usb_remove_hcd(hcd);
- iounmap(hcd->regs);
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
- usb_put_hcd(hcd);
-
- return 0;
-}
-
-static struct platform_driver ohci_hcd_ath79_driver = {
- .probe = ohci_ath79_probe,
- .remove = ohci_ath79_remove,
- .shutdown = usb_hcd_platform_shutdown,
- .driver = {
- .name = "ath79-ohci",
- .owner = THIS_MODULE,
- },
-};
-
-MODULE_ALIAS(PLATFORM_MODULE_PREFIX "ath79-ohci");
diff --git a/drivers/usb/host/ohci-exynos.c b/drivers/usb/host/ohci-exynos.c
index 55aa35aa3d7b..37bb20ebb6fc 100644
--- a/drivers/usb/host/ohci-exynos.c
+++ b/drivers/usb/host/ohci-exynos.c
@@ -212,12 +212,10 @@ static int exynos_ohci_suspend(struct device *dev)
* mark HW unaccessible, bail out if RH has been resumed. Use
* the spinlock to properly synchronize with possible pending
* RH suspend or resume activity.
- *
- * This is still racy as hcd->state is manipulated outside of
- * any locks =P But that will be a different fix.
*/
spin_lock_irqsave(&ohci->lock, flags);
- if (hcd->state != HC_STATE_SUSPENDED && hcd->state != HC_STATE_HALT) {
+ if (ohci->rh_state != OHCI_RH_SUSPENDED &&
+ ohci->rh_state != OHCI_RH_HALTED) {
rc = -EINVAL;
goto fail;
}
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 34b9edd86651..235171f29460 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -42,7 +42,6 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#include <asm/byteorder.h>
@@ -899,7 +898,7 @@ static void ohci_stop (struct usb_hcd *hcd)
ohci_usb_reset (ohci);
ohci_writel (ohci, OHCI_INTR_MIE, &ohci->regs->intrdisable);
free_irq(hcd->irq, hcd);
- hcd->irq = -1;
+ hcd->irq = 0;
if (quirk_zfmicro(ohci))
del_timer(&ohci->unlink_watchdog);
@@ -1000,7 +999,7 @@ MODULE_LICENSE ("GPL");
#define SA1111_DRIVER ohci_hcd_sa1111_driver
#endif
-#if defined(CONFIG_ARCH_S3C2410) || defined(CONFIG_ARCH_S3C64XX)
+#if defined(CONFIG_ARCH_S3C24XX) || defined(CONFIG_ARCH_S3C64XX)
#include "ohci-s3c2410.c"
#define PLATFORM_DRIVER ohci_hcd_s3c2410_driver
#endif
@@ -1050,9 +1049,9 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ohci_hcd_at91_driver
#endif
-#ifdef CONFIG_ARCH_PNX4008
-#include "ohci-pnx4008.c"
-#define PLATFORM_DRIVER usb_hcd_pnx4008_driver
+#if defined(CONFIG_ARCH_PNX4008) || defined(CONFIG_ARCH_LPC32XX)
+#include "ohci-nxp.c"
+#define PLATFORM_DRIVER usb_hcd_nxp_driver
#endif
#ifdef CONFIG_ARCH_DAVINCI_DA8XX
@@ -1111,16 +1110,16 @@ MODULE_LICENSE ("GPL");
#define PLATFORM_DRIVER ohci_hcd_cns3xxx_driver
#endif
-#ifdef CONFIG_USB_OHCI_ATH79
-#include "ohci-ath79.c"
-#define PLATFORM_DRIVER ohci_hcd_ath79_driver
-#endif
-
#ifdef CONFIG_CPU_XLR
#include "ohci-xls.c"
#define PLATFORM_DRIVER ohci_xls_driver
#endif
+#ifdef CONFIG_USB_OHCI_HCD_PLATFORM
+#include "ohci-platform.c"
+#define PLATFORM_DRIVER ohci_platform_driver
+#endif
+
#if !defined(PCI_DRIVER) && \
!defined(PLATFORM_DRIVER) && \
!defined(OMAP1_PLATFORM_DRIVER) && \
diff --git a/drivers/usb/host/ohci-pnx4008.c b/drivers/usb/host/ohci-nxp.c
index 0013db7bdf92..6618de1d881d 100644
--- a/drivers/usb/host/ohci-pnx4008.c
+++ b/drivers/usb/host/ohci-nxp.c
@@ -1,7 +1,9 @@
/*
- * drivers/usb/host/ohci-pnx4008.c
+ * driver for NXP USB Host devices
*
- * driver for Philips PNX4008 USB Host
+ * Currently supported OHCI host devices:
+ * - Philips PNX4008
+ * - NXP LPC32xx
*
* Authors: Dmitry Chigirev <source@mvista.com>
* Vitaly Wool <vitalywool@gmail.com>
@@ -22,20 +24,24 @@
#include <linux/i2c.h>
#include <mach/hardware.h>
+#include <asm/mach-types.h>
#include <asm/io.h>
#include <mach/platform.h>
#include <mach/irqs.h>
#include <asm/gpio.h>
-#define USB_CTRL IO_ADDRESS(PNX4008_PWRMAN_BASE + 0x64)
+#define USB_CONFIG_BASE 0x31020000
+#define PWRMAN_BASE 0x40004000
+
+#define USB_CTRL IO_ADDRESS(PWRMAN_BASE + 0x64)
/* USB_CTRL bit defines */
#define USB_SLAVE_HCLK_EN (1 << 24)
#define USB_HOST_NEED_CLK_EN (1 << 21)
-#define USB_OTG_CLK_CTRL IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0xFF4)
-#define USB_OTG_CLK_STAT IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0xFF8)
+#define USB_OTG_CLK_CTRL IO_ADDRESS(USB_CONFIG_BASE + 0xFF4)
+#define USB_OTG_CLK_STAT IO_ADDRESS(USB_CONFIG_BASE + 0xFF8)
/* USB_OTG_CLK_CTRL bit defines */
#define AHB_M_CLOCK_ON (1 << 4)
@@ -44,7 +50,7 @@
#define DEV_CLOCK_ON (1 << 1)
#define HOST_CLOCK_ON (1 << 0)
-#define USB_OTG_STAT_CONTROL IO_ADDRESS(PNX4008_USB_CONFIG_BASE + 0x110)
+#define USB_OTG_STAT_CONTROL IO_ADDRESS(USB_CONFIG_BASE + 0x110)
/* USB_OTG_STAT_CONTROL bit defines */
#define TRANSPARENT_I2C_EN (1 << 7)
@@ -98,6 +104,15 @@
#define ISP1301_I2C_INTERRUPT_RISING 0xE
#define ISP1301_I2C_REG_CLEAR_ADDR 1
+/* On LPC32xx, those are undefined */
+#ifndef start_int_set_falling_edge
+#define start_int_set_falling_edge(irq)
+#define start_int_set_rising_edge(irq)
+#define start_int_ack(irq)
+#define start_int_mask(irq)
+#define start_int_umask(irq)
+#endif
+
static struct i2c_driver isp1301_driver;
static struct i2c_client *isp1301_i2c_client;
@@ -121,73 +136,129 @@ static int isp1301_remove(struct i2c_client *client)
}
static const struct i2c_device_id isp1301_id[] = {
- { "isp1301_pnx", 0 },
+ { "isp1301_nxp", 0 },
{ }
};
static struct i2c_driver isp1301_driver = {
.driver = {
- .name = "isp1301_pnx",
+ .name = "isp1301_nxp",
},
.probe = isp1301_probe,
.remove = isp1301_remove,
.id_table = isp1301_id,
};
-static void i2c_write(u8 buf, u8 subaddr)
-{
- char tmpbuf[2];
-
- tmpbuf[0] = subaddr; /*register number */
- tmpbuf[1] = buf; /*register data */
- i2c_master_send(isp1301_i2c_client, &tmpbuf[0], 2);
-}
-
-static void isp1301_configure(void)
+static void isp1301_configure_pnx4008(void)
{
/* PNX4008 only supports DAT_SE0 USB mode */
/* PNX4008 R2A requires setting the MAX603 to output 3.6V */
/* Power up externel charge-pump */
- i2c_write(MC1_DAT_SE0 | MC1_SPEED_REG, ISP1301_I2C_MODE_CONTROL_1);
- i2c_write(~(MC1_DAT_SE0 | MC1_SPEED_REG),
- ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR);
- i2c_write(MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL,
- ISP1301_I2C_MODE_CONTROL_2);
- i2c_write(~(MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL),
- ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR);
- i2c_write(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN,
- ISP1301_I2C_OTG_CONTROL_1);
- i2c_write(~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN),
- ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR);
- i2c_write(0xFF,
- ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR);
- i2c_write(0xFF,
- ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR);
- i2c_write(0xFF,
- ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR);
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ ISP1301_I2C_MODE_CONTROL_1, MC1_DAT_SE0 | MC1_SPEED_REG);
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR,
+ ~(MC1_DAT_SE0 | MC1_SPEED_REG));
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ ISP1301_I2C_MODE_CONTROL_2,
+ MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL);
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR,
+ ~(MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL));
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_1, OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN);
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR,
+ ~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN));
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR, 0xFF);
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR,
+ 0xFF);
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR,
+ 0xFF);
+}
+static void isp1301_configure_lpc32xx(void)
+{
+ /* LPC32XX only supports DAT_SE0 USB mode */
+ /* This sequence is important */
+
+ /* Disable transparent UART mode first */
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ (ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR),
+ MC1_UART_EN);
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ (ISP1301_I2C_MODE_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR),
+ ~MC1_SPEED_REG);
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ ISP1301_I2C_MODE_CONTROL_1, MC1_SPEED_REG);
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ (ISP1301_I2C_MODE_CONTROL_2 | ISP1301_I2C_REG_CLEAR_ADDR),
+ ~0);
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ ISP1301_I2C_MODE_CONTROL_2,
+ (MC2_BI_DI | MC2_PSW_EN | MC2_SPD_SUSP_CTRL));
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ (ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR), ~0);
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ ISP1301_I2C_MODE_CONTROL_1, MC1_DAT_SE0);
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_1,
+ (OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN));
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ (ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR),
+ (OTG1_DM_PULLUP | OTG1_DP_PULLUP));
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ ISP1301_I2C_INTERRUPT_LATCH | ISP1301_I2C_REG_CLEAR_ADDR, ~0);
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ ISP1301_I2C_INTERRUPT_FALLING | ISP1301_I2C_REG_CLEAR_ADDR,
+ ~0);
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ ISP1301_I2C_INTERRUPT_RISING | ISP1301_I2C_REG_CLEAR_ADDR, ~0);
+
+ /* Enable usb_need_clk clock after transceiver is initialized */
+ __raw_writel((__raw_readl(USB_CTRL) | (1 << 22)), USB_CTRL);
+
+ printk(KERN_INFO "ISP1301 Vendor ID : 0x%04x\n",
+ i2c_smbus_read_word_data(isp1301_i2c_client, 0x00));
+ printk(KERN_INFO "ISP1301 Product ID : 0x%04x\n",
+ i2c_smbus_read_word_data(isp1301_i2c_client, 0x02));
+ printk(KERN_INFO "ISP1301 Version ID : 0x%04x\n",
+ i2c_smbus_read_word_data(isp1301_i2c_client, 0x14));
+}
+
+static void isp1301_configure(void)
+{
+ if (machine_is_pnx4008())
+ isp1301_configure_pnx4008();
+ else
+ isp1301_configure_lpc32xx();
}
static inline void isp1301_vbus_on(void)
{
- i2c_write(OTG1_VBUS_DRV, ISP1301_I2C_OTG_CONTROL_1);
+ i2c_smbus_write_byte_data(isp1301_i2c_client, ISP1301_I2C_OTG_CONTROL_1,
+ OTG1_VBUS_DRV);
}
static inline void isp1301_vbus_off(void)
{
- i2c_write(OTG1_VBUS_DRV,
- ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR);
+ i2c_smbus_write_byte_data(isp1301_i2c_client,
+ ISP1301_I2C_OTG_CONTROL_1 | ISP1301_I2C_REG_CLEAR_ADDR,
+ OTG1_VBUS_DRV);
}
-static void pnx4008_start_hc(void)
+static void nxp_start_hc(void)
{
unsigned long tmp = __raw_readl(USB_OTG_STAT_CONTROL) | HOST_EN;
__raw_writel(tmp, USB_OTG_STAT_CONTROL);
isp1301_vbus_on();
}
-static void pnx4008_stop_hc(void)
+static void nxp_stop_hc(void)
{
unsigned long tmp;
isp1301_vbus_off();
@@ -195,7 +266,7 @@ static void pnx4008_stop_hc(void)
__raw_writel(tmp, USB_OTG_STAT_CONTROL);
}
-static int __devinit ohci_pnx4008_start(struct usb_hcd *hcd)
+static int __devinit ohci_nxp_start(struct usb_hcd *hcd)
{
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
int ret;
@@ -211,9 +282,9 @@ static int __devinit ohci_pnx4008_start(struct usb_hcd *hcd)
return 0;
}
-static const struct hc_driver ohci_pnx4008_hc_driver = {
+static const struct hc_driver ohci_nxp_hc_driver = {
.description = hcd_name,
- .product_desc = "pnx4008 OHCI",
+ .product_desc = "nxp OHCI",
/*
* generic hardware linkage
@@ -225,7 +296,7 @@ static const struct hc_driver ohci_pnx4008_hc_driver = {
/*
* basic lifecycle operations
*/
- .start = ohci_pnx4008_start,
+ .start = ohci_nxp_start,
.stop = ohci_stop,
.shutdown = ohci_shutdown,
@@ -255,54 +326,58 @@ static const struct hc_driver ohci_pnx4008_hc_driver = {
#define USB_CLOCK_MASK (AHB_M_CLOCK_ON| OTG_CLOCK_ON | HOST_CLOCK_ON | I2C_CLOCK_ON)
-static void pnx4008_set_usb_bits(void)
+static void nxp_set_usb_bits(void)
{
- start_int_set_falling_edge(SE_USB_OTG_ATX_INT_N);
- start_int_ack(SE_USB_OTG_ATX_INT_N);
- start_int_umask(SE_USB_OTG_ATX_INT_N);
-
- start_int_set_rising_edge(SE_USB_OTG_TIMER_INT);
- start_int_ack(SE_USB_OTG_TIMER_INT);
- start_int_umask(SE_USB_OTG_TIMER_INT);
-
- start_int_set_rising_edge(SE_USB_I2C_INT);
- start_int_ack(SE_USB_I2C_INT);
- start_int_umask(SE_USB_I2C_INT);
-
- start_int_set_rising_edge(SE_USB_INT);
- start_int_ack(SE_USB_INT);
- start_int_umask(SE_USB_INT);
-
- start_int_set_rising_edge(SE_USB_NEED_CLK_INT);
- start_int_ack(SE_USB_NEED_CLK_INT);
- start_int_umask(SE_USB_NEED_CLK_INT);
-
- start_int_set_rising_edge(SE_USB_AHB_NEED_CLK_INT);
- start_int_ack(SE_USB_AHB_NEED_CLK_INT);
- start_int_umask(SE_USB_AHB_NEED_CLK_INT);
+ if (machine_is_pnx4008()) {
+ start_int_set_falling_edge(SE_USB_OTG_ATX_INT_N);
+ start_int_ack(SE_USB_OTG_ATX_INT_N);
+ start_int_umask(SE_USB_OTG_ATX_INT_N);
+
+ start_int_set_rising_edge(SE_USB_OTG_TIMER_INT);
+ start_int_ack(SE_USB_OTG_TIMER_INT);
+ start_int_umask(SE_USB_OTG_TIMER_INT);
+
+ start_int_set_rising_edge(SE_USB_I2C_INT);
+ start_int_ack(SE_USB_I2C_INT);
+ start_int_umask(SE_USB_I2C_INT);
+
+ start_int_set_rising_edge(SE_USB_INT);
+ start_int_ack(SE_USB_INT);
+ start_int_umask(SE_USB_INT);
+
+ start_int_set_rising_edge(SE_USB_NEED_CLK_INT);
+ start_int_ack(SE_USB_NEED_CLK_INT);
+ start_int_umask(SE_USB_NEED_CLK_INT);
+
+ start_int_set_rising_edge(SE_USB_AHB_NEED_CLK_INT);
+ start_int_ack(SE_USB_AHB_NEED_CLK_INT);
+ start_int_umask(SE_USB_AHB_NEED_CLK_INT);
+ }
}
-static void pnx4008_unset_usb_bits(void)
+static void nxp_unset_usb_bits(void)
{
- start_int_mask(SE_USB_OTG_ATX_INT_N);
- start_int_mask(SE_USB_OTG_TIMER_INT);
- start_int_mask(SE_USB_I2C_INT);
- start_int_mask(SE_USB_INT);
- start_int_mask(SE_USB_NEED_CLK_INT);
- start_int_mask(SE_USB_AHB_NEED_CLK_INT);
+ if (machine_is_pnx4008()) {
+ start_int_mask(SE_USB_OTG_ATX_INT_N);
+ start_int_mask(SE_USB_OTG_TIMER_INT);
+ start_int_mask(SE_USB_I2C_INT);
+ start_int_mask(SE_USB_INT);
+ start_int_mask(SE_USB_NEED_CLK_INT);
+ start_int_mask(SE_USB_AHB_NEED_CLK_INT);
+ }
}
-static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
+static int __devinit usb_hcd_nxp_probe(struct platform_device *pdev)
{
struct usb_hcd *hcd = 0;
struct ohci_hcd *ohci;
- const struct hc_driver *driver = &ohci_pnx4008_hc_driver;
+ const struct hc_driver *driver = &ohci_nxp_hc_driver;
struct i2c_adapter *i2c_adap;
struct i2c_board_info i2c_info;
int ret = 0, irq;
- dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (pnx4008)\n", hcd_name);
+ dev_dbg(&pdev->dev, "%s: " DRIVER_DESC " (nxp)\n", hcd_name);
if (usb_disabled()) {
err("USB is disabled");
ret = -ENODEV;
@@ -327,7 +402,7 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
}
i2c_adap = i2c_get_adapter(2);
memset(&i2c_info, 0, sizeof(struct i2c_board_info));
- strlcpy(i2c_info.type, "isp1301_pnx", I2C_NAME_SIZE);
+ strlcpy(i2c_info.type, "isp1301_nxp", I2C_NAME_SIZE);
isp1301_i2c_client = i2c_new_probed_device(i2c_adap, &i2c_info,
normal_i2c, NULL);
i2c_put_adapter(i2c_adap);
@@ -375,7 +450,7 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
}
/* Set all USB bits in the Start Enable register */
- pnx4008_set_usb_bits();
+ nxp_set_usb_bits();
hcd->rsrc_start = pdev->resource[0].start;
hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
@@ -392,7 +467,7 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
goto out4;
}
- pnx4008_start_hc();
+ nxp_start_hc();
platform_set_drvdata(pdev, hcd);
ohci = hcd_to_ohci(hcd);
ohci_hcd_init(ohci);
@@ -402,9 +477,9 @@ static int __devinit usb_hcd_pnx4008_probe(struct platform_device *pdev)
if (ret == 0)
return ret;
- pnx4008_stop_hc();
+ nxp_stop_hc();
out4:
- pnx4008_unset_usb_bits();
+ nxp_unset_usb_bits();
usb_put_hcd(hcd);
out3:
clk_disable(usb_clk);
@@ -419,15 +494,15 @@ out:
return ret;
}
-static int usb_hcd_pnx4008_remove(struct platform_device *pdev)
+static int usb_hcd_nxp_remove(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
usb_remove_hcd(hcd);
- pnx4008_stop_hc();
+ nxp_stop_hc();
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
- pnx4008_unset_usb_bits();
+ nxp_unset_usb_bits();
clk_disable(usb_clk);
clk_put(usb_clk);
i2c_unregister_device(isp1301_i2c_client);
@@ -442,12 +517,12 @@ static int usb_hcd_pnx4008_remove(struct platform_device *pdev)
/* work with hotplug and coldplug */
MODULE_ALIAS("platform:usb-ohci");
-static struct platform_driver usb_hcd_pnx4008_driver = {
+static struct platform_driver usb_hcd_nxp_driver = {
.driver = {
.name = "usb-ohci",
.owner = THIS_MODULE,
},
- .probe = usb_hcd_pnx4008_probe,
- .remove = usb_hcd_pnx4008_remove,
+ .probe = usb_hcd_nxp_probe,
+ .remove = usb_hcd_nxp_remove,
};
diff --git a/drivers/usb/host/ohci-omap.c b/drivers/usb/host/ohci-omap.c
index db3968656d21..96451e41ee8a 100644
--- a/drivers/usb/host/ohci-omap.c
+++ b/drivers/usb/host/ohci-omap.c
@@ -171,7 +171,7 @@ static void start_hnp(struct ohci_hcd *ohci)
unsigned long flags;
u32 l;
- otg_start_hnp(ohci->transceiver);
+ otg_start_hnp(ohci->transceiver->otg);
local_irq_save(flags);
ohci->transceiver->state = OTG_STATE_A_SUSPEND;
@@ -210,9 +210,9 @@ static int ohci_omap_init(struct usb_hcd *hcd)
#ifdef CONFIG_USB_OTG
if (need_transceiver) {
- ohci->transceiver = otg_get_transceiver();
+ ohci->transceiver = usb_get_transceiver();
if (ohci->transceiver) {
- int status = otg_set_host(ohci->transceiver,
+ int status = otg_set_host(ohci->transceiver->otg,
&ohci_to_hcd(ohci)->self);
dev_dbg(hcd->self.controller, "init %s transceiver, status %d\n",
ohci->transceiver->label, status);
@@ -404,7 +404,7 @@ usb_hcd_omap_remove (struct usb_hcd *hcd, struct platform_device *pdev)
usb_remove_hcd(hcd);
if (ohci->transceiver) {
- (void) otg_set_host(ohci->transceiver, 0);
+ (void) otg_set_host(ohci->transceiver->otg, 0);
put_device(ohci->transceiver->dev);
}
if (machine_is_omap_osk())
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
new file mode 100644
index 000000000000..ec5c6791c8b4
--- /dev/null
+++ b/drivers/usb/host/ohci-platform.c
@@ -0,0 +1,194 @@
+/*
+ * Generic platform ohci driver
+ *
+ * Copyright 2007 Michael Buesch <m@bues.ch>
+ * Copyright 2011-2012 Hauke Mehrtens <hauke@hauke-m.de>
+ *
+ * Derived from the OCHI-SSB driver
+ * Derived from the OHCI-PCI driver
+ * Copyright 1999 Roman Weissgaerber
+ * Copyright 2000-2002 David Brownell
+ * Copyright 1999 Linus Torvalds
+ * Copyright 1999 Gregory P. Smith
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+#include <linux/platform_device.h>
+#include <linux/usb/ohci_pdriver.h>
+
+static int ohci_platform_reset(struct usb_hcd *hcd)
+{
+ struct platform_device *pdev = to_platform_device(hcd->self.controller);
+ struct usb_ohci_pdata *pdata = pdev->dev.platform_data;
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int err;
+
+ if (pdata->big_endian_desc)
+ ohci->flags |= OHCI_QUIRK_BE_DESC;
+ if (pdata->big_endian_mmio)
+ ohci->flags |= OHCI_QUIRK_BE_MMIO;
+ if (pdata->no_big_frame_no)
+ ohci->flags |= OHCI_QUIRK_FRAME_NO;
+
+ ohci_hcd_init(ohci);
+ err = ohci_init(ohci);
+
+ return err;
+}
+
+static int ohci_platform_start(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int err;
+
+ err = ohci_run(ohci);
+ if (err < 0) {
+ ohci_err(ohci, "can't start\n");
+ ohci_stop(hcd);
+ }
+
+ return err;
+}
+
+static const struct hc_driver ohci_platform_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "Generic Platform OHCI Controller",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+
+ .irq = ohci_irq,
+ .flags = HCD_MEMORY | HCD_USB11,
+
+ .reset = ohci_platform_reset,
+ .start = ohci_platform_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ .get_frame_number = ohci_get_frame,
+
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+#ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
+#endif
+
+ .start_port_reset = ohci_start_port_reset,
+};
+
+static int __devinit ohci_platform_probe(struct platform_device *dev)
+{
+ struct usb_hcd *hcd;
+ struct resource *res_mem;
+ int irq;
+ int err = -ENOMEM;
+
+ BUG_ON(!dev->dev.platform_data);
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ irq = platform_get_irq(dev, 0);
+ if (irq < 0) {
+ pr_err("no irq provieded");
+ return irq;
+ }
+
+ res_mem = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!res_mem) {
+ pr_err("no memory recourse provieded");
+ return -ENXIO;
+ }
+
+ hcd = usb_create_hcd(&ohci_platform_hc_driver, &dev->dev,
+ dev_name(&dev->dev));
+ if (!hcd)
+ return -ENOMEM;
+
+ hcd->rsrc_start = res_mem->start;
+ hcd->rsrc_len = resource_size(res_mem);
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+ pr_err("controller already in use");
+ err = -EBUSY;
+ goto err_put_hcd;
+ }
+
+ hcd->regs = ioremap_nocache(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs)
+ goto err_release_region;
+ err = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ if (err)
+ goto err_iounmap;
+
+ platform_set_drvdata(dev, hcd);
+
+ return err;
+
+err_iounmap:
+ iounmap(hcd->regs);
+err_release_region:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+err_put_hcd:
+ usb_put_hcd(hcd);
+ return err;
+}
+
+static int __devexit ohci_platform_remove(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+ usb_put_hcd(hcd);
+ platform_set_drvdata(dev, NULL);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+
+static int ohci_platform_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int ohci_platform_resume(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+
+ ohci_finish_controller_resume(hcd);
+ return 0;
+}
+
+#else /* !CONFIG_PM */
+#define ohci_platform_suspend NULL
+#define ohci_platform_resume NULL
+#endif /* CONFIG_PM */
+
+static const struct platform_device_id ohci_platform_table[] = {
+ { "ohci-platform", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, ohci_platform_table);
+
+static const struct dev_pm_ops ohci_platform_pm_ops = {
+ .suspend = ohci_platform_suspend,
+ .resume = ohci_platform_resume,
+};
+
+static struct platform_driver ohci_platform_driver = {
+ .id_table = ohci_platform_table,
+ .probe = ohci_platform_probe,
+ .remove = __devexit_p(ohci_platform_remove),
+ .shutdown = usb_hcd_platform_shutdown,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ohci-platform",
+ .pm = &ohci_platform_pm_ops,
+ }
+};
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c
index 6313e4439f37..c31b2815be1c 100644
--- a/drivers/usb/host/ohci-pxa27x.c
+++ b/drivers/usb/host/ohci-pxa27x.c
@@ -23,6 +23,7 @@
#include <linux/signal.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
+#include <mach/hardware.h>
#include <mach/ohci.h>
#include <mach/pxa3xx-u2d.h>
@@ -218,7 +219,7 @@ static int pxa27x_start_hc(struct pxa27x_ohci *ohci, struct device *dev)
inf = dev->platform_data;
- clk_enable(ohci->clk);
+ clk_prepare_enable(ohci->clk);
pxa27x_reset_hc(ohci);
@@ -268,7 +269,7 @@ static void pxa27x_stop_hc(struct pxa27x_ohci *ohci, struct device *dev)
__raw_writel(uhccoms, ohci->mmio_base + UHCCOMS);
udelay(10);
- clk_disable(ohci->clk);
+ clk_disable_unprepare(ohci->clk);
}
diff --git a/drivers/usb/host/ohci-sa1111.c b/drivers/usb/host/ohci-sa1111.c
index 4bde4f9821ba..e1004fb37bd9 100644
--- a/drivers/usb/host/ohci-sa1111.c
+++ b/drivers/usb/host/ohci-sa1111.c
@@ -16,29 +16,115 @@
#include <mach/hardware.h>
#include <asm/mach-types.h>
#include <mach/assabet.h>
-#include <mach/badge4.h>
#include <asm/hardware/sa1111.h>
#ifndef CONFIG_SA1111
#error "This file is SA-1111 bus glue. CONFIG_SA1111 must be defined."
#endif
-extern int usb_disabled(void);
+#define USB_STATUS 0x0118
+#define USB_RESET 0x011c
+#define USB_IRQTEST 0x0120
+
+#define USB_RESET_FORCEIFRESET (1 << 0)
+#define USB_RESET_FORCEHCRESET (1 << 1)
+#define USB_RESET_CLKGENRESET (1 << 2)
+#define USB_RESET_SIMSCALEDOWN (1 << 3)
+#define USB_RESET_USBINTTEST (1 << 4)
+#define USB_RESET_SLEEPSTBYEN (1 << 5)
+#define USB_RESET_PWRSENSELOW (1 << 6)
+#define USB_RESET_PWRCTRLLOW (1 << 7)
+
+#define USB_STATUS_IRQHCIRMTWKUP (1 << 7)
+#define USB_STATUS_IRQHCIBUFFACC (1 << 8)
+#define USB_STATUS_NIRQHCIM (1 << 9)
+#define USB_STATUS_NHCIMFCLR (1 << 10)
+#define USB_STATUS_USBPWRSENSE (1 << 11)
-/*-------------------------------------------------------------------------*/
+#if 0
+static void dump_hci_status(struct usb_hcd *hcd, const char *label)
+{
+ unsigned long status = sa1111_readl(hcd->regs + USB_STATUS);
+
+ dbg("%s USB_STATUS = { %s%s%s%s%s}", label,
+ ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""),
+ ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""),
+ ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "),
+ ((status & USB_STATUS_NHCIMFCLR) ? "" : "HCIMFCLR "),
+ ((status & USB_STATUS_USBPWRSENSE) ? "USBPWRSENSE " : ""));
+}
+#endif
-static void sa1111_start_hc(struct sa1111_dev *dev)
+static int ohci_sa1111_reset(struct usb_hcd *hcd)
{
- unsigned int usb_rst = 0;
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+
+ ohci_hcd_init(ohci);
+ return ohci_init(ohci);
+}
- printk(KERN_DEBUG "%s: starting SA-1111 OHCI USB Controller\n",
- __FILE__);
+static int __devinit ohci_sa1111_start(struct usb_hcd *hcd)
+{
+ struct ohci_hcd *ohci = hcd_to_ohci(hcd);
+ int ret;
-#ifdef CONFIG_SA1100_BADGE4
- if (machine_is_badge4()) {
- badge4_set_5V(BADGE4_5V_USB, 1);
+ ret = ohci_run(ohci);
+ if (ret < 0) {
+ ohci_err(ohci, "can't start\n");
+ ohci_stop(hcd);
}
+ return ret;
+}
+
+static const struct hc_driver ohci_sa1111_hc_driver = {
+ .description = hcd_name,
+ .product_desc = "SA-1111 OHCI",
+ .hcd_priv_size = sizeof(struct ohci_hcd),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = ohci_irq,
+ .flags = HCD_USB11 | HCD_MEMORY,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = ohci_sa1111_reset,
+ .start = ohci_sa1111_start,
+ .stop = ohci_stop,
+ .shutdown = ohci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = ohci_urb_enqueue,
+ .urb_dequeue = ohci_urb_dequeue,
+ .endpoint_disable = ohci_endpoint_disable,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = ohci_get_frame,
+
+ /*
+ * root hub support
+ */
+ .hub_status_data = ohci_hub_status_data,
+ .hub_control = ohci_hub_control,
+#ifdef CONFIG_PM
+ .bus_suspend = ohci_bus_suspend,
+ .bus_resume = ohci_bus_resume,
#endif
+ .start_port_reset = ohci_start_port_reset,
+};
+
+static int sa1111_start_hc(struct sa1111_dev *dev)
+{
+ unsigned int usb_rst = 0;
+ int ret;
+
+ dev_dbg(&dev->dev, "starting SA-1111 OHCI USB Controller\n");
if (machine_is_xp860() ||
machine_has_neponset() ||
@@ -51,220 +137,121 @@ static void sa1111_start_hc(struct sa1111_dev *dev)
* host controller in reset.
*/
sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
- dev->mapbase + SA1111_USB_RESET);
+ dev->mapbase + USB_RESET);
/*
* Now, carefully enable the USB clock, and take
* the USB host controller out of reset.
*/
- sa1111_enable_device(dev);
- udelay(11);
- sa1111_writel(usb_rst, dev->mapbase + SA1111_USB_RESET);
+ ret = sa1111_enable_device(dev);
+ if (ret == 0) {
+ udelay(11);
+ sa1111_writel(usb_rst, dev->mapbase + USB_RESET);
+ }
+
+ return ret;
}
static void sa1111_stop_hc(struct sa1111_dev *dev)
{
unsigned int usb_rst;
- printk(KERN_DEBUG "%s: stopping SA-1111 OHCI USB Controller\n",
- __FILE__);
+
+ dev_dbg(&dev->dev, "stopping SA-1111 OHCI USB Controller\n");
/*
* Put the USB host controller into reset.
*/
- usb_rst = sa1111_readl(dev->mapbase + SA1111_USB_RESET);
+ usb_rst = sa1111_readl(dev->mapbase + USB_RESET);
sa1111_writel(usb_rst | USB_RESET_FORCEIFRESET | USB_RESET_FORCEHCRESET,
- dev->mapbase + SA1111_USB_RESET);
+ dev->mapbase + USB_RESET);
/*
* Stop the USB clock.
*/
sa1111_disable_device(dev);
-
-#ifdef CONFIG_SA1100_BADGE4
- if (machine_is_badge4()) {
- /* Disable power to the USB bus */
- badge4_set_5V(BADGE4_5V_USB, 0);
- }
-#endif
-}
-
-
-/*-------------------------------------------------------------------------*/
-
-#if 0
-static void dump_hci_status(struct usb_hcd *hcd, const char *label)
-{
- unsigned long status = sa1111_readl(hcd->regs + SA1111_USB_STATUS);
-
- dbg ("%s USB_STATUS = { %s%s%s%s%s}", label,
- ((status & USB_STATUS_IRQHCIRMTWKUP) ? "IRQHCIRMTWKUP " : ""),
- ((status & USB_STATUS_IRQHCIBUFFACC) ? "IRQHCIBUFFACC " : ""),
- ((status & USB_STATUS_NIRQHCIM) ? "" : "IRQHCIM "),
- ((status & USB_STATUS_NHCIMFCLR) ? "" : "HCIMFCLR "),
- ((status & USB_STATUS_USBPWRSENSE) ? "USBPWRSENSE " : ""));
}
-#endif
-
-/*-------------------------------------------------------------------------*/
-
-/* configure so an HC device and id are always provided */
-/* always called with process context; sleeping is OK */
-
/**
- * usb_hcd_sa1111_probe - initialize SA-1111-based HCDs
- * Context: !in_interrupt()
+ * ohci_hcd_sa1111_probe - initialize SA-1111-based HCDs
*
* Allocates basic resources for this USB host controller, and
- * then invokes the start() method for the HCD associated with it
- * through the hotplug entry's driver_data.
- *
- * Store this function in the HCD's struct pci_driver as probe().
+ * then invokes the start() method for the HCD associated with it.
*/
-int usb_hcd_sa1111_probe (const struct hc_driver *driver,
- struct sa1111_dev *dev)
+static int ohci_hcd_sa1111_probe(struct sa1111_dev *dev)
{
struct usb_hcd *hcd;
- int retval;
+ int ret;
- hcd = usb_create_hcd (driver, &dev->dev, "sa1111");
+ if (usb_disabled())
+ return -ENODEV;
+
+ hcd = usb_create_hcd(&ohci_sa1111_hc_driver, &dev->dev, "sa1111");
if (!hcd)
return -ENOMEM;
+
hcd->rsrc_start = dev->res.start;
hcd->rsrc_len = resource_size(&dev->res);
if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
dbg("request_mem_region failed");
- retval = -EBUSY;
+ ret = -EBUSY;
goto err1;
}
+
hcd->regs = dev->mapbase;
- sa1111_start_hc(dev);
- ohci_hcd_init(hcd_to_ohci(hcd));
+ ret = sa1111_start_hc(dev);
+ if (ret)
+ goto err2;
- retval = usb_add_hcd(hcd, dev->irq[1], 0);
- if (retval == 0)
- return retval;
+ ret = usb_add_hcd(hcd, dev->irq[1], 0);
+ if (ret == 0)
+ return ret;
sa1111_stop_hc(dev);
+ err2:
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err1:
usb_put_hcd(hcd);
- return retval;
+ return ret;
}
-
-/* may be called without controller electrically present */
-/* may be called with controller, bus, and devices active */
-
/**
- * usb_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs
+ * ohci_hcd_sa1111_remove - shutdown processing for SA-1111-based HCDs
* @dev: USB Host Controller being removed
- * Context: !in_interrupt()
- *
- * Reverses the effect of usb_hcd_sa1111_probe(), first invoking
- * the HCD's stop() method. It is always called from a thread
- * context, normally "rmmod", "apmd", or something similar.
*
+ * Reverses the effect of ohci_hcd_sa1111_probe(), first invoking
+ * the HCD's stop() method.
*/
-void usb_hcd_sa1111_remove (struct usb_hcd *hcd, struct sa1111_dev *dev)
+static int ohci_hcd_sa1111_remove(struct sa1111_dev *dev)
{
+ struct usb_hcd *hcd = sa1111_get_drvdata(dev);
+
usb_remove_hcd(hcd);
sa1111_stop_hc(dev);
release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
usb_put_hcd(hcd);
-}
-
-/*-------------------------------------------------------------------------*/
-static int __devinit
-ohci_sa1111_start (struct usb_hcd *hcd)
-{
- struct ohci_hcd *ohci = hcd_to_ohci (hcd);
- int ret;
-
- if ((ret = ohci_init(ohci)) < 0)
- return ret;
-
- if ((ret = ohci_run (ohci)) < 0) {
- err ("can't start %s", hcd->self.bus_name);
- ohci_stop (hcd);
- return ret;
- }
return 0;
}
-/*-------------------------------------------------------------------------*/
-
-static const struct hc_driver ohci_sa1111_hc_driver = {
- .description = hcd_name,
- .product_desc = "SA-1111 OHCI",
- .hcd_priv_size = sizeof(struct ohci_hcd),
-
- /*
- * generic hardware linkage
- */
- .irq = ohci_irq,
- .flags = HCD_USB11 | HCD_MEMORY,
-
- /*
- * basic lifecycle operations
- */
- .start = ohci_sa1111_start,
- .stop = ohci_stop,
-
- /*
- * managing i/o requests and associated device resources
- */
- .urb_enqueue = ohci_urb_enqueue,
- .urb_dequeue = ohci_urb_dequeue,
- .endpoint_disable = ohci_endpoint_disable,
-
- /*
- * scheduling support
- */
- .get_frame_number = ohci_get_frame,
-
- /*
- * root hub support
- */
- .hub_status_data = ohci_hub_status_data,
- .hub_control = ohci_hub_control,
-#ifdef CONFIG_PM
- .bus_suspend = ohci_bus_suspend,
- .bus_resume = ohci_bus_resume,
-#endif
- .start_port_reset = ohci_start_port_reset,
-};
-
-/*-------------------------------------------------------------------------*/
-
-static int ohci_hcd_sa1111_drv_probe(struct sa1111_dev *dev)
-{
- int ret;
-
- if (usb_disabled())
- return -ENODEV;
-
- ret = usb_hcd_sa1111_probe(&ohci_sa1111_hc_driver, dev);
- return ret;
-}
-
-static int ohci_hcd_sa1111_drv_remove(struct sa1111_dev *dev)
+static void ohci_hcd_sa1111_shutdown(struct sa1111_dev *dev)
{
struct usb_hcd *hcd = sa1111_get_drvdata(dev);
- usb_hcd_sa1111_remove(hcd, dev);
- return 0;
+ if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+ hcd->driver->shutdown(hcd);
+ sa1111_stop_hc(dev);
+ }
}
static struct sa1111_driver ohci_hcd_sa1111_driver = {
.drv = {
.name = "sa1111-ohci",
+ .owner = THIS_MODULE,
},
.devid = SA1111_DEVID_USB,
- .probe = ohci_hcd_sa1111_drv_probe,
- .remove = ohci_hcd_sa1111_drv_remove,
+ .probe = ohci_hcd_sa1111_probe,
+ .remove = ohci_hcd_sa1111_remove,
+ .shutdown = ohci_hcd_sa1111_shutdown,
};
-
diff --git a/drivers/usb/host/ohci.h b/drivers/usb/host/ohci.h
index 8ff6f7ea96fd..1b19aea25a2b 100644
--- a/drivers/usb/host/ohci.h
+++ b/drivers/usb/host/ohci.h
@@ -376,7 +376,7 @@ struct ohci_hcd {
* OTG controllers and transceivers need software interaction;
* other external transceivers should be software-transparent
*/
- struct otg_transceiver *transceiver;
+ struct usb_phy *transceiver;
void (*start_hnp)(struct ohci_hcd *ohci);
/*
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index 015c7c62ed49..3b38030b02a8 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -40,7 +40,6 @@
#include <linux/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/unaligned.h>
#include <linux/irq.h>
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 7732d69e49e0..32dada8c8b4f 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -825,9 +825,13 @@ static void __devinit quirk_usb_handoff_xhci(struct pci_dev *pdev)
}
}
- /* Disable any BIOS SMIs */
- writel(XHCI_LEGACY_DISABLE_SMI,
- base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
+ val = readl(base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
+ /* Mask off (turn off) any enabled SMIs */
+ val &= XHCI_LEGACY_DISABLE_SMI;
+ /* Mask all SMI events bits, RW1C */
+ val |= XHCI_LEGACY_SMI_EVENTS;
+ /* Disable any BIOS SMIs and clear all SMI events*/
+ writel(val, base + ext_cap_offset + XHCI_LEGACY_CONTROL_OFFSET);
if (usb_is_intel_switchable_xhci(pdev))
usb_enable_xhci_ports(pdev);
@@ -893,4 +897,5 @@ static void __devinit quirk_usb_early_handoff(struct pci_dev *pdev)
quirk_usb_handoff_xhci(pdev);
pci_disable_device(pdev);
}
-DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, quirk_usb_early_handoff);
+DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
+ PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff);
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index e84ca1928dbf..2bf1320dc9c3 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -2428,6 +2428,9 @@ static int __devinit r8a66597_probe(struct platform_device *pdev)
int i;
unsigned long irq_trigger;
+ if (usb_disabled())
+ return -ENODEV;
+
if (pdev->dev.dma_mask) {
ret = -EINVAL;
dev_err(&pdev->dev, "dma not supported\n");
@@ -2552,20 +2555,4 @@ static struct platform_driver r8a66597_driver = {
},
};
-static int __init r8a66597_init(void)
-{
- if (usb_disabled())
- return -ENODEV;
-
- printk(KERN_INFO KBUILD_MODNAME ": driver %s, %s\n", hcd_name,
- DRIVER_VERSION);
- return platform_driver_register(&r8a66597_driver);
-}
-module_init(r8a66597_init);
-
-static void __exit r8a66597_cleanup(void)
-{
- platform_driver_unregister(&r8a66597_driver);
-}
-module_exit(r8a66597_cleanup);
-
+module_platform_driver(r8a66597_driver);
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 961d6638d8f9..91ce1c02e617 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -51,7 +51,6 @@
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/byteorder.h>
#include <asm/unaligned.h>
@@ -1632,6 +1631,9 @@ sl811h_probe(struct platform_device *dev)
u8 tmp, ioaddr = 0;
unsigned long irqflags;
+ if (usb_disabled())
+ return -ENODEV;
+
/* basic sanity checks first. board-specific init logic should
* have initialized these three resources and probably board
* specific platform_data. we don't probe for IRQs, and do only
@@ -1817,20 +1819,4 @@ struct platform_driver sl811h_driver = {
};
EXPORT_SYMBOL(sl811h_driver);
-/*-------------------------------------------------------------------------*/
-
-static int __init sl811h_init(void)
-{
- if (usb_disabled())
- return -ENODEV;
-
- INFO("driver %s, %s\n", hcd_name, DRIVER_VERSION);
- return platform_driver_register(&sl811h_driver);
-}
-module_init(sl811h_init);
-
-static void __exit sl811h_cleanup(void)
-{
- platform_driver_unregister(&sl811h_driver);
-}
-module_exit(sl811h_cleanup);
+module_platform_driver(sl811h_driver);
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 16dd6a6abf00..dbbd1ba25224 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -55,7 +55,6 @@
#include <linux/mutex.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include <asm/byteorder.h>
/* FIXME ohci.h is ONLY for internal use by the OHCI driver.
diff --git a/drivers/usb/host/uhci-hcd.c b/drivers/usb/host/uhci-hcd.c
index 6b5eb1017e2c..e4db350602b8 100644
--- a/drivers/usb/host/uhci-hcd.c
+++ b/drivers/usb/host/uhci-hcd.c
@@ -45,7 +45,6 @@
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/irq.h>
-#include <asm/system.h>
#include "uhci-hcd.h"
@@ -565,6 +564,9 @@ static int uhci_start(struct usb_hcd *hcd)
struct dentry __maybe_unused *dentry;
hcd->uses_new_polling = 1;
+ /* Accept arbitrarily long scatter-gather lists */
+ if (!(hcd->driver->flags & HCD_LOCAL_MEM))
+ hcd->self.sg_tablesize = ~0;
spin_lock_init(&uhci->lock);
setup_timer(&uhci->fsbr_timer, uhci_fsbr_timeout,
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
index 045cde4cbc3d..768d54295a20 100644
--- a/drivers/usb/host/uhci-hub.c
+++ b/drivers/usb/host/uhci-hub.c
@@ -196,11 +196,12 @@ static int uhci_hub_status_data(struct usb_hcd *hcd, char *buf)
status = get_hub_status_data(uhci, buf);
switch (uhci->rh_state) {
- case UHCI_RH_SUSPENDING:
case UHCI_RH_SUSPENDED:
/* if port change, ask to be resumed */
- if (status || uhci->resuming_ports)
+ if (status || uhci->resuming_ports) {
+ status = 1;
usb_hcd_resume_root_hub(hcd);
+ }
break;
case UHCI_RH_AUTO_STOPPED:
diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c
index e9b0f043455d..4b436f5a4171 100644
--- a/drivers/usb/host/xhci-dbg.c
+++ b/drivers/usb/host/xhci-dbg.c
@@ -119,7 +119,7 @@ static void xhci_print_command_reg(struct xhci_hcd *xhci)
xhci_dbg(xhci, " Event Interrupts %s\n",
(temp & CMD_EIE) ? "enabled " : "disabled");
xhci_dbg(xhci, " Host System Error Interrupts %s\n",
- (temp & CMD_EIE) ? "enabled " : "disabled");
+ (temp & CMD_HSEIE) ? "enabled " : "disabled");
xhci_dbg(xhci, " HC has %sfinished light reset\n",
(temp & CMD_LRESET) ? "not " : "");
}
diff --git a/drivers/usb/host/xhci-ext-caps.h b/drivers/usb/host/xhci-ext-caps.h
index c7f33123d4c0..377f4242dabb 100644
--- a/drivers/usb/host/xhci-ext-caps.h
+++ b/drivers/usb/host/xhci-ext-caps.h
@@ -62,8 +62,9 @@
/* USB Legacy Support Control and Status Register - section 7.1.2 */
/* Add this offset, plus the value of xECP in HCCPARAMS to the base address */
#define XHCI_LEGACY_CONTROL_OFFSET (0x04)
-/* bits 1:2, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */
-#define XHCI_LEGACY_DISABLE_SMI ((0x3 << 1) + (0xff << 5) + (0x7 << 17))
+/* bits 1:3, 5:12, and 17:19 need to be preserved; bits 21:28 should be zero */
+#define XHCI_LEGACY_DISABLE_SMI ((0x7 << 1) + (0xff << 5) + (0x7 << 17))
+#define XHCI_LEGACY_SMI_EVENTS (0x7 << 29)
/* USB 2.0 xHCI 0.96 L1C capability - section 7.2.2.1.3.2 */
#define XHCI_L1C (1 << 16)
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 557b6f32db86..673ad120c43e 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -422,6 +422,32 @@ void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
xhci_writel(xhci, temp, port_array[port_id]);
}
+void xhci_set_remote_wake_mask(struct xhci_hcd *xhci,
+ __le32 __iomem **port_array, int port_id, u16 wake_mask)
+{
+ u32 temp;
+
+ temp = xhci_readl(xhci, port_array[port_id]);
+ temp = xhci_port_state_to_neutral(temp);
+
+ if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_CONNECT)
+ temp |= PORT_WKCONN_E;
+ else
+ temp &= ~PORT_WKCONN_E;
+
+ if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT)
+ temp |= PORT_WKDISC_E;
+ else
+ temp &= ~PORT_WKDISC_E;
+
+ if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT)
+ temp |= PORT_WKOC_E;
+ else
+ temp &= ~PORT_WKOC_E;
+
+ xhci_writel(xhci, temp, port_array[port_id]);
+}
+
/* Test and clear port RWC bit */
void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array,
int port_id, u32 port_bit)
@@ -448,6 +474,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
int slot_id;
struct xhci_bus_state *bus_state;
u16 link_state = 0;
+ u16 wake_mask = 0;
max_ports = xhci_get_ports(hcd, &port_array);
bus_state = &xhci->bus_state[hcd_index(hcd)];
@@ -593,6 +620,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
case SetPortFeature:
if (wValue == USB_PORT_FEAT_LINK_STATE)
link_state = (wIndex & 0xff00) >> 3;
+ if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK)
+ wake_mask = wIndex & 0xff00;
wIndex &= 0xff;
if (!wIndex || wIndex > max_ports)
goto error;
@@ -703,6 +732,14 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
temp = xhci_readl(xhci, port_array[wIndex]);
xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp);
break;
+ case USB_PORT_FEAT_REMOTE_WAKE_MASK:
+ xhci_set_remote_wake_mask(xhci, port_array,
+ wIndex, wake_mask);
+ temp = xhci_readl(xhci, port_array[wIndex]);
+ xhci_dbg(xhci, "set port remote wake mask, "
+ "actual port %d status = 0x%x\n",
+ wIndex, temp);
+ break;
case USB_PORT_FEAT_BH_PORT_RESET:
temp |= PORT_WR;
xhci_writel(xhci, temp, port_array[wIndex]);
@@ -883,6 +920,10 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
t2 |= PORT_LINK_STROBE | XDEV_U3;
set_bit(port_index, &bus_state->bus_suspended);
}
+ /* USB core sets remote wake mask for USB 3.0 hubs,
+ * including the USB 3.0 roothub, but only if CONFIG_USB_SUSPEND
+ * is enabled, so also enable remote wake here.
+ */
if (hcd->self.root_hub->do_remote_wakeup) {
if (t1 & PORT_CONNECT) {
t2 |= PORT_WKOC_E | PORT_WKDISC_E;
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 383fc857491c..68eaa908ac8e 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -34,10 +34,12 @@
* Section 4.11.1.1:
* "All components of all Command and Transfer TRBs shall be initialized to '0'"
*/
-static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, gfp_t flags)
+static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci,
+ unsigned int cycle_state, gfp_t flags)
{
struct xhci_segment *seg;
dma_addr_t dma;
+ int i;
seg = kzalloc(sizeof *seg, flags);
if (!seg)
@@ -50,6 +52,11 @@ static struct xhci_segment *xhci_segment_alloc(struct xhci_hcd *xhci, gfp_t flag
}
memset(seg->trbs, 0, SEGMENT_SIZE);
+ /* If the cycle state is 0, set the cycle bit to 1 for all the TRBs */
+ if (cycle_state == 0) {
+ for (i = 0; i < TRBS_PER_SEGMENT; i++)
+ seg->trbs[i].link.control |= TRB_CYCLE;
+ }
seg->dma = dma;
seg->next = NULL;
@@ -65,6 +72,20 @@ static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg)
kfree(seg);
}
+static void xhci_free_segments_for_ring(struct xhci_hcd *xhci,
+ struct xhci_segment *first)
+{
+ struct xhci_segment *seg;
+
+ seg = first->next;
+ while (seg != first) {
+ struct xhci_segment *next = seg->next;
+ xhci_segment_free(xhci, seg);
+ seg = next;
+ }
+ xhci_segment_free(xhci, first);
+}
+
/*
* Make the prev segment point to the next segment.
*
@@ -73,14 +94,14 @@ static void xhci_segment_free(struct xhci_hcd *xhci, struct xhci_segment *seg)
* related flags, such as End TRB, Toggle Cycle, and no snoop.
*/
static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
- struct xhci_segment *next, bool link_trbs, bool isoc)
+ struct xhci_segment *next, enum xhci_ring_type type)
{
u32 val;
if (!prev || !next)
return;
prev->next = next;
- if (link_trbs) {
+ if (type != TYPE_EVENT) {
prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr =
cpu_to_le64(next->dma);
@@ -91,35 +112,55 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
/* Always set the chain bit with 0.95 hardware */
/* Set chain bit for isoc rings on AMD 0.96 host */
if (xhci_link_trb_quirk(xhci) ||
- (isoc && (xhci->quirks & XHCI_AMD_0x96_HOST)))
+ (type == TYPE_ISOC &&
+ (xhci->quirks & XHCI_AMD_0x96_HOST)))
val |= TRB_CHAIN;
prev->trbs[TRBS_PER_SEGMENT-1].link.control = cpu_to_le32(val);
}
}
+/*
+ * Link the ring to the new segments.
+ * Set Toggle Cycle for the new ring if needed.
+ */
+static void xhci_link_rings(struct xhci_hcd *xhci, struct xhci_ring *ring,
+ struct xhci_segment *first, struct xhci_segment *last,
+ unsigned int num_segs)
+{
+ struct xhci_segment *next;
+
+ if (!ring || !first || !last)
+ return;
+
+ next = ring->enq_seg->next;
+ xhci_link_segments(xhci, ring->enq_seg, first, ring->type);
+ xhci_link_segments(xhci, last, next, ring->type);
+ ring->num_segs += num_segs;
+ ring->num_trbs_free += (TRBS_PER_SEGMENT - 1) * num_segs;
+
+ if (ring->type != TYPE_EVENT && ring->enq_seg == ring->last_seg) {
+ ring->last_seg->trbs[TRBS_PER_SEGMENT-1].link.control
+ &= ~cpu_to_le32(LINK_TOGGLE);
+ last->trbs[TRBS_PER_SEGMENT-1].link.control
+ |= cpu_to_le32(LINK_TOGGLE);
+ ring->last_seg = last;
+ }
+}
+
/* XXX: Do we need the hcd structure in all these functions? */
void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring)
{
- struct xhci_segment *seg;
- struct xhci_segment *first_seg;
-
if (!ring)
return;
- if (ring->first_seg) {
- first_seg = ring->first_seg;
- seg = first_seg->next;
- while (seg != first_seg) {
- struct xhci_segment *next = seg->next;
- xhci_segment_free(xhci, seg);
- seg = next;
- }
- xhci_segment_free(xhci, first_seg);
- ring->first_seg = NULL;
- }
+
+ if (ring->first_seg)
+ xhci_free_segments_for_ring(xhci, ring->first_seg);
+
kfree(ring);
}
-static void xhci_initialize_ring_info(struct xhci_ring *ring)
+static void xhci_initialize_ring_info(struct xhci_ring *ring,
+ unsigned int cycle_state)
{
/* The ring is empty, so the enqueue pointer == dequeue pointer */
ring->enqueue = ring->first_seg->trbs;
@@ -129,11 +170,53 @@ static void xhci_initialize_ring_info(struct xhci_ring *ring)
/* The ring is initialized to 0. The producer must write 1 to the cycle
* bit to handover ownership of the TRB, so PCS = 1. The consumer must
* compare CCS to the cycle bit to check ownership, so CCS = 1.
+ *
+ * New rings are initialized with cycle state equal to 1; if we are
+ * handling ring expansion, set the cycle state equal to the old ring.
*/
- ring->cycle_state = 1;
+ ring->cycle_state = cycle_state;
/* Not necessary for new rings, but needed for re-initialized rings */
ring->enq_updates = 0;
ring->deq_updates = 0;
+
+ /*
+ * Each segment has a link TRB, and leave an extra TRB for SW
+ * accounting purpose
+ */
+ ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1;
+}
+
+/* Allocate segments and link them for a ring */
+static int xhci_alloc_segments_for_ring(struct xhci_hcd *xhci,
+ struct xhci_segment **first, struct xhci_segment **last,
+ unsigned int num_segs, unsigned int cycle_state,
+ enum xhci_ring_type type, gfp_t flags)
+{
+ struct xhci_segment *prev;
+
+ prev = xhci_segment_alloc(xhci, cycle_state, flags);
+ if (!prev)
+ return -ENOMEM;
+ num_segs--;
+
+ *first = prev;
+ while (num_segs > 0) {
+ struct xhci_segment *next;
+
+ next = xhci_segment_alloc(xhci, cycle_state, flags);
+ if (!next) {
+ xhci_free_segments_for_ring(xhci, *first);
+ return -ENOMEM;
+ }
+ xhci_link_segments(xhci, prev, next, type);
+
+ prev = next;
+ num_segs--;
+ }
+ xhci_link_segments(xhci, prev, *first, type);
+ *last = prev;
+
+ return 0;
}
/**
@@ -144,44 +227,34 @@ static void xhci_initialize_ring_info(struct xhci_ring *ring)
* See section 4.9.1 and figures 15 and 16.
*/
static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
- unsigned int num_segs, bool link_trbs, bool isoc, gfp_t flags)
+ unsigned int num_segs, unsigned int cycle_state,
+ enum xhci_ring_type type, gfp_t flags)
{
struct xhci_ring *ring;
- struct xhci_segment *prev;
+ int ret;
ring = kzalloc(sizeof *(ring), flags);
if (!ring)
return NULL;
+ ring->num_segs = num_segs;
INIT_LIST_HEAD(&ring->td_list);
+ ring->type = type;
if (num_segs == 0)
return ring;
- ring->first_seg = xhci_segment_alloc(xhci, flags);
- if (!ring->first_seg)
+ ret = xhci_alloc_segments_for_ring(xhci, &ring->first_seg,
+ &ring->last_seg, num_segs, cycle_state, type, flags);
+ if (ret)
goto fail;
- num_segs--;
- prev = ring->first_seg;
- while (num_segs > 0) {
- struct xhci_segment *next;
-
- next = xhci_segment_alloc(xhci, flags);
- if (!next)
- goto fail;
- xhci_link_segments(xhci, prev, next, link_trbs, isoc);
-
- prev = next;
- num_segs--;
- }
- xhci_link_segments(xhci, prev, ring->first_seg, link_trbs, isoc);
-
- if (link_trbs) {
+ /* Only event ring does not use link TRB */
+ if (type != TYPE_EVENT) {
/* See section 4.9.2.1 and 6.4.4.1 */
- prev->trbs[TRBS_PER_SEGMENT-1].link.control |=
+ ring->last_seg->trbs[TRBS_PER_SEGMENT - 1].link.control |=
cpu_to_le32(LINK_TOGGLE);
}
- xhci_initialize_ring_info(ring);
+ xhci_initialize_ring_info(ring, cycle_state);
return ring;
fail:
@@ -217,23 +290,64 @@ void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
* pointers to the beginning of the ring.
*/
static void xhci_reinit_cached_ring(struct xhci_hcd *xhci,
- struct xhci_ring *ring, bool isoc)
+ struct xhci_ring *ring, unsigned int cycle_state,
+ enum xhci_ring_type type)
{
struct xhci_segment *seg = ring->first_seg;
+ int i;
+
do {
memset(seg->trbs, 0,
sizeof(union xhci_trb)*TRBS_PER_SEGMENT);
+ if (cycle_state == 0) {
+ for (i = 0; i < TRBS_PER_SEGMENT; i++)
+ seg->trbs[i].link.control |= TRB_CYCLE;
+ }
/* All endpoint rings have link TRBs */
- xhci_link_segments(xhci, seg, seg->next, 1, isoc);
+ xhci_link_segments(xhci, seg, seg->next, type);
seg = seg->next;
} while (seg != ring->first_seg);
- xhci_initialize_ring_info(ring);
+ ring->type = type;
+ xhci_initialize_ring_info(ring, cycle_state);
/* td list should be empty since all URBs have been cancelled,
* but just in case...
*/
INIT_LIST_HEAD(&ring->td_list);
}
+/*
+ * Expand an existing ring.
+ * Look for a cached ring or allocate a new ring which has same segment numbers
+ * and link the two rings.
+ */
+int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
+ unsigned int num_trbs, gfp_t flags)
+{
+ struct xhci_segment *first;
+ struct xhci_segment *last;
+ unsigned int num_segs;
+ unsigned int num_segs_needed;
+ int ret;
+
+ num_segs_needed = (num_trbs + (TRBS_PER_SEGMENT - 1) - 1) /
+ (TRBS_PER_SEGMENT - 1);
+
+ /* Allocate number of segments we needed, or double the ring size */
+ num_segs = ring->num_segs > num_segs_needed ?
+ ring->num_segs : num_segs_needed;
+
+ ret = xhci_alloc_segments_for_ring(xhci, &first, &last,
+ num_segs, ring->cycle_state, ring->type, flags);
+ if (ret)
+ return -ENOMEM;
+
+ xhci_link_rings(xhci, ring, first, last, num_segs);
+ xhci_dbg(xhci, "ring expansion succeed, now has %d segments\n",
+ ring->num_segs);
+
+ return 0;
+}
+
#define CTX_SIZE(_hcc) (HCC_64BYTE_CONTEXT(_hcc) ? 64 : 32)
static struct xhci_container_ctx *xhci_alloc_container_ctx(struct xhci_hcd *xhci,
@@ -528,7 +642,7 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
*/
for (cur_stream = 1; cur_stream < num_streams; cur_stream++) {
stream_info->stream_rings[cur_stream] =
- xhci_ring_alloc(xhci, 1, true, false, mem_flags);
+ xhci_ring_alloc(xhci, 2, 1, TYPE_STREAM, mem_flags);
cur_ring = stream_info->stream_rings[cur_stream];
if (!cur_ring)
goto cleanup_rings;
@@ -862,7 +976,7 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
}
/* Allocate endpoint 0 ring */
- dev->eps[0].ring = xhci_ring_alloc(xhci, 1, true, false, flags);
+ dev->eps[0].ring = xhci_ring_alloc(xhci, 2, 1, TYPE_CTRL, flags);
if (!dev->eps[0].ring)
goto fail;
@@ -1300,24 +1414,16 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
struct xhci_ring *ep_ring;
unsigned int max_packet;
unsigned int max_burst;
+ enum xhci_ring_type type;
u32 max_esit_payload;
ep_index = xhci_get_endpoint_index(&ep->desc);
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
+ type = usb_endpoint_type(&ep->desc);
/* Set up the endpoint ring */
- /*
- * Isochronous endpoint ring needs bigger size because one isoc URB
- * carries multiple packets and it will insert multiple tds to the
- * ring.
- * This should be replaced with dynamic ring resizing in the future.
- */
- if (usb_endpoint_xfer_isoc(&ep->desc))
- virt_dev->eps[ep_index].new_ring =
- xhci_ring_alloc(xhci, 8, true, true, mem_flags);
- else
- virt_dev->eps[ep_index].new_ring =
- xhci_ring_alloc(xhci, 1, true, false, mem_flags);
+ virt_dev->eps[ep_index].new_ring =
+ xhci_ring_alloc(xhci, 2, 1, type, mem_flags);
if (!virt_dev->eps[ep_index].new_ring) {
/* Attempt to use the ring cache */
if (virt_dev->num_rings_cached == 0)
@@ -1327,7 +1433,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
virt_dev->ring_cache[virt_dev->num_rings_cached] = NULL;
virt_dev->num_rings_cached--;
xhci_reinit_cached_ring(xhci, virt_dev->eps[ep_index].new_ring,
- usb_endpoint_xfer_isoc(&ep->desc) ? true : false);
+ 1, type);
}
virt_dev->eps[ep_index].skip = false;
ep_ring = virt_dev->eps[ep_index].new_ring;
@@ -1690,11 +1796,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
int i;
/* Free the Event Ring Segment Table and the actual Event Ring */
- if (xhci->ir_set) {
- xhci_writel(xhci, 0, &xhci->ir_set->erst_size);
- xhci_write_64(xhci, 0, &xhci->ir_set->erst_base);
- xhci_write_64(xhci, 0, &xhci->ir_set->erst_dequeue);
- }
size = sizeof(struct xhci_erst_entry)*(xhci->erst.num_entries);
if (xhci->erst.entries)
dma_free_coherent(&pdev->dev, size,
@@ -1706,7 +1807,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci->event_ring = NULL;
xhci_dbg(xhci, "Freed event ring\n");
- xhci_write_64(xhci, 0, &xhci->op_regs->cmd_ring);
if (xhci->cmd_ring)
xhci_ring_free(xhci, xhci->cmd_ring);
xhci->cmd_ring = NULL;
@@ -1735,7 +1835,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci)
xhci->medium_streams_pool = NULL;
xhci_dbg(xhci, "Freed medium stream array pool\n");
- xhci_write_64(xhci, 0, &xhci->op_regs->dcbaa_ptr);
if (xhci->dcbaa)
dma_free_coherent(&pdev->dev, sizeof(*xhci->dcbaa),
xhci->dcbaa, xhci->dcbaa->dma);
@@ -2157,7 +2256,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
unsigned int val, val2;
u64 val_64;
struct xhci_segment *seg;
- u32 page_size;
+ u32 page_size, temp;
int i;
page_size = xhci_readl(xhci, &xhci->op_regs->page_size);
@@ -2235,7 +2334,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
goto fail;
/* Set up the command ring to have one segments for now. */
- xhci->cmd_ring = xhci_ring_alloc(xhci, 1, true, false, flags);
+ xhci->cmd_ring = xhci_ring_alloc(xhci, 1, 1, TYPE_COMMAND, flags);
if (!xhci->cmd_ring)
goto fail;
xhci_dbg(xhci, "Allocated command ring at %p\n", xhci->cmd_ring);
@@ -2266,7 +2365,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
* the event ring segment table (ERST). Section 4.9.3.
*/
xhci_dbg(xhci, "// Allocating event ring\n");
- xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, false, false,
+ xhci->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT,
flags);
if (!xhci->event_ring)
goto fail;
@@ -2340,10 +2439,21 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
INIT_LIST_HEAD(&xhci->lpm_failed_devs);
+ /* Enable USB 3.0 device notifications for function remote wake, which
+ * is necessary for allowing USB 3.0 devices to do remote wakeup from
+ * U3 (device suspend).
+ */
+ temp = xhci_readl(xhci, &xhci->op_regs->dev_notification);
+ temp &= ~DEV_NOTE_MASK;
+ temp |= DEV_NOTE_FWAKE;
+ xhci_writel(xhci, temp, &xhci->op_regs->dev_notification);
+
return 0;
fail:
xhci_warn(xhci, "Couldn't initialize memory\n");
+ xhci_halt(xhci);
+ xhci_reset(xhci);
xhci_mem_cleanup(xhci);
return -ENOMEM;
}
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index ef98b38626fb..7a856a767e77 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -95,6 +95,8 @@ static void xhci_pci_quirks(struct device *dev, struct xhci_hcd *xhci)
xhci->quirks |= XHCI_RESET_ON_RESUME;
xhci_dbg(xhci, "QUIRK: Resetting on resume\n");
}
+ if (pdev->vendor == PCI_VENDOR_ID_VIA)
+ xhci->quirks |= XHCI_RESET_ON_RESUME;
}
/* called during probe() after chip reset completes */
@@ -326,7 +328,7 @@ int __init xhci_register_pci(void)
return pci_register_driver(&xhci_pci_driver);
}
-void __exit xhci_unregister_pci(void)
+void xhci_unregister_pci(void)
{
pci_unregister_driver(&xhci_pci_driver);
}
diff --git a/drivers/usb/host/xhci-plat.c b/drivers/usb/host/xhci-plat.c
new file mode 100644
index 000000000000..689bc18b051d
--- /dev/null
+++ b/drivers/usb/host/xhci-plat.c
@@ -0,0 +1,205 @@
+/*
+ * xhci-plat.c - xHCI host controller driver platform Bus Glue.
+ *
+ * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com
+ * Author: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * A lot of code borrowed from the Linux xHCI driver.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "xhci.h"
+
+static void xhci_plat_quirks(struct device *dev, struct xhci_hcd *xhci)
+{
+ /*
+ * As of now platform drivers don't provide MSI support so we ensure
+ * here that the generic code does not try to make a pci_dev from our
+ * dev struct in order to setup MSI
+ */
+ xhci->quirks |= XHCI_BROKEN_MSI;
+}
+
+/* called during probe() after chip reset completes */
+static int xhci_plat_setup(struct usb_hcd *hcd)
+{
+ return xhci_gen_setup(hcd, xhci_plat_quirks);
+}
+
+static const struct hc_driver xhci_plat_xhci_driver = {
+ .description = "xhci-hcd",
+ .product_desc = "xHCI Host Controller",
+ .hcd_priv_size = sizeof(struct xhci_hcd *),
+
+ /*
+ * generic hardware linkage
+ */
+ .irq = xhci_irq,
+ .flags = HCD_MEMORY | HCD_USB3 | HCD_SHARED,
+
+ /*
+ * basic lifecycle operations
+ */
+ .reset = xhci_plat_setup,
+ .start = xhci_run,
+ .stop = xhci_stop,
+ .shutdown = xhci_shutdown,
+
+ /*
+ * managing i/o requests and associated device resources
+ */
+ .urb_enqueue = xhci_urb_enqueue,
+ .urb_dequeue = xhci_urb_dequeue,
+ .alloc_dev = xhci_alloc_dev,
+ .free_dev = xhci_free_dev,
+ .alloc_streams = xhci_alloc_streams,
+ .free_streams = xhci_free_streams,
+ .add_endpoint = xhci_add_endpoint,
+ .drop_endpoint = xhci_drop_endpoint,
+ .endpoint_reset = xhci_endpoint_reset,
+ .check_bandwidth = xhci_check_bandwidth,
+ .reset_bandwidth = xhci_reset_bandwidth,
+ .address_device = xhci_address_device,
+ .update_hub_device = xhci_update_hub_device,
+ .reset_device = xhci_discover_or_reset_device,
+
+ /*
+ * scheduling support
+ */
+ .get_frame_number = xhci_get_frame,
+
+ /* Root hub support */
+ .hub_control = xhci_hub_control,
+ .hub_status_data = xhci_hub_status_data,
+ .bus_suspend = xhci_bus_suspend,
+ .bus_resume = xhci_bus_resume,
+};
+
+static int xhci_plat_probe(struct platform_device *pdev)
+{
+ const struct hc_driver *driver;
+ struct xhci_hcd *xhci;
+ struct resource *res;
+ struct usb_hcd *hcd;
+ int ret;
+ int irq;
+
+ if (usb_disabled())
+ return -ENODEV;
+
+ driver = &xhci_plat_xhci_driver;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return -ENODEV;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+
+ hcd = usb_create_hcd(driver, &pdev->dev, dev_name(&pdev->dev));
+ if (!hcd)
+ return -ENOMEM;
+
+ hcd->rsrc_start = res->start;
+ hcd->rsrc_len = resource_size(res);
+
+ if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len,
+ driver->description)) {
+ dev_dbg(&pdev->dev, "controller already in use\n");
+ ret = -EBUSY;
+ goto put_hcd;
+ }
+
+ hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+ if (!hcd->regs) {
+ dev_dbg(&pdev->dev, "error mapping memory\n");
+ ret = -EFAULT;
+ goto release_mem_region;
+ }
+
+ ret = usb_add_hcd(hcd, irq, IRQF_SHARED);
+ if (ret)
+ goto unmap_registers;
+
+ /* USB 2.0 roothub is stored in the platform_device now. */
+ hcd = dev_get_drvdata(&pdev->dev);
+ xhci = hcd_to_xhci(hcd);
+ xhci->shared_hcd = usb_create_shared_hcd(driver, &pdev->dev,
+ dev_name(&pdev->dev), hcd);
+ if (!xhci->shared_hcd) {
+ ret = -ENOMEM;
+ goto dealloc_usb2_hcd;
+ }
+
+ /*
+ * Set the xHCI pointer before xhci_plat_setup() (aka hcd_driver.reset)
+ * is called by usb_add_hcd().
+ */
+ *((struct xhci_hcd **) xhci->shared_hcd->hcd_priv) = xhci;
+
+ ret = usb_add_hcd(xhci->shared_hcd, irq, IRQF_SHARED);
+ if (ret)
+ goto put_usb3_hcd;
+
+ return 0;
+
+put_usb3_hcd:
+ usb_put_hcd(xhci->shared_hcd);
+
+dealloc_usb2_hcd:
+ usb_remove_hcd(hcd);
+
+unmap_registers:
+ iounmap(hcd->regs);
+
+release_mem_region:
+ release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+
+put_hcd:
+ usb_put_hcd(hcd);
+
+ return ret;
+}
+
+static int xhci_plat_remove(struct platform_device *dev)
+{
+ struct usb_hcd *hcd = platform_get_drvdata(dev);
+ struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+ usb_remove_hcd(xhci->shared_hcd);
+ usb_put_hcd(xhci->shared_hcd);
+
+ usb_remove_hcd(hcd);
+ iounmap(hcd->regs);
+ usb_put_hcd(hcd);
+ kfree(xhci);
+
+ return 0;
+}
+
+static struct platform_driver usb_xhci_driver = {
+ .probe = xhci_plat_probe,
+ .remove = xhci_plat_remove,
+ .driver = {
+ .name = "xhci-hcd",
+ },
+};
+MODULE_ALIAS("platform:xhci-hcd");
+
+int xhci_register_plat(void)
+{
+ return platform_driver_register(&usb_xhci_driver);
+}
+
+void xhci_unregister_plat(void)
+{
+ platform_driver_unregister(&usb_xhci_driver);
+}
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index b62037bff688..3d9422f16a20 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -143,17 +143,25 @@ static void next_trb(struct xhci_hcd *xhci,
* See Cycle bit rules. SW is the consumer for the event ring only.
* Don't make a ring full of link TRBs. That would be dumb and this would loop.
*/
-static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer)
+static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring)
{
- union xhci_trb *next = ++(ring->dequeue);
+ union xhci_trb *next;
unsigned long long addr;
ring->deq_updates++;
+
+ /* If this is not event ring, there is one more usable TRB */
+ if (ring->type != TYPE_EVENT &&
+ !last_trb(xhci, ring, ring->deq_seg, ring->dequeue))
+ ring->num_trbs_free++;
+ next = ++(ring->dequeue);
+
/* Update the dequeue pointer further if that was a link TRB or we're at
* the end of an event ring segment (which doesn't have link TRBS)
*/
while (last_trb(xhci, ring, ring->deq_seg, next)) {
- if (consumer && last_trb_on_last_seg(xhci, ring, ring->deq_seg, next)) {
+ if (ring->type == TYPE_EVENT && last_trb_on_last_seg(xhci,
+ ring, ring->deq_seg, next)) {
ring->cycle_state = (ring->cycle_state ? 0 : 1);
}
ring->deq_seg = ring->deq_seg->next;
@@ -181,13 +189,17 @@ static void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring, bool consumer
* prepare_transfer()?
*/
static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
- bool consumer, bool more_trbs_coming, bool isoc)
+ bool more_trbs_coming)
{
u32 chain;
union xhci_trb *next;
unsigned long long addr;
chain = le32_to_cpu(ring->enqueue->generic.field[3]) & TRB_CHAIN;
+ /* If this is not event ring, there is one less usable TRB */
+ if (ring->type != TYPE_EVENT &&
+ !last_trb(xhci, ring, ring->enq_seg, ring->enqueue))
+ ring->num_trbs_free--;
next = ++(ring->enqueue);
ring->enq_updates++;
@@ -195,35 +207,35 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
* the end of an event ring segment (which doesn't have link TRBS)
*/
while (last_trb(xhci, ring, ring->enq_seg, next)) {
- if (!consumer) {
- if (ring != xhci->event_ring) {
- /*
- * If the caller doesn't plan on enqueueing more
- * TDs before ringing the doorbell, then we
- * don't want to give the link TRB to the
- * hardware just yet. We'll give the link TRB
- * back in prepare_ring() just before we enqueue
- * the TD at the top of the ring.
- */
- if (!chain && !more_trbs_coming)
- break;
+ if (ring->type != TYPE_EVENT) {
+ /*
+ * If the caller doesn't plan on enqueueing more
+ * TDs before ringing the doorbell, then we
+ * don't want to give the link TRB to the
+ * hardware just yet. We'll give the link TRB
+ * back in prepare_ring() just before we enqueue
+ * the TD at the top of the ring.
+ */
+ if (!chain && !more_trbs_coming)
+ break;
- /* If we're not dealing with 0.95 hardware or
- * isoc rings on AMD 0.96 host,
- * carry over the chain bit of the previous TRB
- * (which may mean the chain bit is cleared).
- */
- if (!(isoc && (xhci->quirks & XHCI_AMD_0x96_HOST))
+ /* If we're not dealing with 0.95 hardware or
+ * isoc rings on AMD 0.96 host,
+ * carry over the chain bit of the previous TRB
+ * (which may mean the chain bit is cleared).
+ */
+ if (!(ring->type == TYPE_ISOC &&
+ (xhci->quirks & XHCI_AMD_0x96_HOST))
&& !xhci_link_trb_quirk(xhci)) {
- next->link.control &=
- cpu_to_le32(~TRB_CHAIN);
- next->link.control |=
- cpu_to_le32(chain);
- }
- /* Give this link TRB to the hardware */
- wmb();
- next->link.control ^= cpu_to_le32(TRB_CYCLE);
+ next->link.control &=
+ cpu_to_le32(~TRB_CHAIN);
+ next->link.control |=
+ cpu_to_le32(chain);
}
+ /* Give this link TRB to the hardware */
+ wmb();
+ next->link.control ^= cpu_to_le32(TRB_CYCLE);
+
/* Toggle the cycle bit after the last ring segment. */
if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
ring->cycle_state = (ring->cycle_state ? 0 : 1);
@@ -237,55 +249,23 @@ static void inc_enq(struct xhci_hcd *xhci, struct xhci_ring *ring,
}
/*
- * Check to see if there's room to enqueue num_trbs on the ring. See rules
- * above.
- * FIXME: this would be simpler and faster if we just kept track of the number
- * of free TRBs in a ring.
+ * Check to see if there's room to enqueue num_trbs on the ring and make sure
+ * enqueue pointer will not advance into dequeue segment. See rules above.
*/
-static int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
+static inline int room_on_ring(struct xhci_hcd *xhci, struct xhci_ring *ring,
unsigned int num_trbs)
{
- int i;
- union xhci_trb *enq = ring->enqueue;
- struct xhci_segment *enq_seg = ring->enq_seg;
- struct xhci_segment *cur_seg;
- unsigned int left_on_ring;
-
- /* If we are currently pointing to a link TRB, advance the
- * enqueue pointer before checking for space */
- while (last_trb(xhci, ring, enq_seg, enq)) {
- enq_seg = enq_seg->next;
- enq = enq_seg->trbs;
- }
-
- /* Check if ring is empty */
- if (enq == ring->dequeue) {
- /* Can't use link trbs */
- left_on_ring = TRBS_PER_SEGMENT - 1;
- for (cur_seg = enq_seg->next; cur_seg != enq_seg;
- cur_seg = cur_seg->next)
- left_on_ring += TRBS_PER_SEGMENT - 1;
-
- /* Always need one TRB free in the ring. */
- left_on_ring -= 1;
- if (num_trbs > left_on_ring) {
- xhci_warn(xhci, "Not enough room on ring; "
- "need %u TRBs, %u TRBs left\n",
- num_trbs, left_on_ring);
- return 0;
- }
- return 1;
- }
- /* Make sure there's an extra empty TRB available */
- for (i = 0; i <= num_trbs; ++i) {
- if (enq == ring->dequeue)
+ int num_trbs_in_deq_seg;
+
+ if (ring->num_trbs_free < num_trbs)
+ return 0;
+
+ if (ring->type != TYPE_COMMAND && ring->type != TYPE_EVENT) {
+ num_trbs_in_deq_seg = ring->dequeue - ring->deq_seg->trbs;
+ if (ring->num_trbs_free < num_trbs + num_trbs_in_deq_seg)
return 0;
- enq++;
- while (last_trb(xhci, ring, enq_seg, enq)) {
- enq_seg = enq_seg->next;
- enq = enq_seg->trbs;
- }
}
+
return 1;
}
@@ -892,6 +872,43 @@ void xhci_stop_endpoint_command_watchdog(unsigned long arg)
xhci_dbg(xhci, "xHCI host controller is dead.\n");
}
+
+static void update_ring_for_set_deq_completion(struct xhci_hcd *xhci,
+ struct xhci_virt_device *dev,
+ struct xhci_ring *ep_ring,
+ unsigned int ep_index)
+{
+ union xhci_trb *dequeue_temp;
+ int num_trbs_free_temp;
+ bool revert = false;
+
+ num_trbs_free_temp = ep_ring->num_trbs_free;
+ dequeue_temp = ep_ring->dequeue;
+
+ while (ep_ring->dequeue != dev->eps[ep_index].queued_deq_ptr) {
+ /* We have more usable TRBs */
+ ep_ring->num_trbs_free++;
+ ep_ring->dequeue++;
+ if (last_trb(xhci, ep_ring, ep_ring->deq_seg,
+ ep_ring->dequeue)) {
+ if (ep_ring->dequeue ==
+ dev->eps[ep_index].queued_deq_ptr)
+ break;
+ ep_ring->deq_seg = ep_ring->deq_seg->next;
+ ep_ring->dequeue = ep_ring->deq_seg->trbs;
+ }
+ if (ep_ring->dequeue == dequeue_temp) {
+ revert = true;
+ break;
+ }
+ }
+
+ if (revert) {
+ xhci_dbg(xhci, "Unable to find new dequeue pointer\n");
+ ep_ring->num_trbs_free = num_trbs_free_temp;
+ }
+}
+
/*
* When we get a completion for a Set Transfer Ring Dequeue Pointer command,
* we need to clear the set deq pending flag in the endpoint ring state, so that
@@ -973,8 +990,8 @@ static void handle_set_deq_completion(struct xhci_hcd *xhci,
/* Update the ring's dequeue segment and dequeue pointer
* to reflect the new position.
*/
- ep_ring->deq_seg = dev->eps[ep_index].queued_deq_seg;
- ep_ring->dequeue = dev->eps[ep_index].queued_deq_ptr;
+ update_ring_for_set_deq_completion(xhci, dev,
+ ep_ring, ep_index);
} else {
xhci_warn(xhci, "Mismatch between completed Set TR Deq "
"Ptr command & xHCI internal state.\n");
@@ -1185,7 +1202,7 @@ bandwidth_change:
xhci->error_bitmask |= 1 << 6;
break;
}
- inc_deq(xhci, xhci->cmd_ring, false);
+ inc_deq(xhci, xhci->cmd_ring);
}
static void handle_vendor_event(struct xhci_hcd *xhci,
@@ -1237,6 +1254,26 @@ static unsigned int find_faked_portnum_from_hw_portnum(struct usb_hcd *hcd,
return num_similar_speed_ports;
}
+static void handle_device_notification(struct xhci_hcd *xhci,
+ union xhci_trb *event)
+{
+ u32 slot_id;
+ struct usb_device *udev;
+
+ slot_id = TRB_TO_SLOT_ID(event->generic.field[3]);
+ if (!xhci->devs[slot_id]) {
+ xhci_warn(xhci, "Device Notification event for "
+ "unused slot %u\n", slot_id);
+ return;
+ }
+
+ xhci_dbg(xhci, "Device Wake Notification event for slot ID %u\n",
+ slot_id);
+ udev = xhci->devs[slot_id]->udev;
+ if (udev && udev->parent)
+ usb_wakeup_notification(udev->parent, udev->portnum);
+}
+
static void handle_port_status(struct xhci_hcd *xhci,
union xhci_trb *event)
{
@@ -1321,20 +1358,21 @@ static void handle_port_status(struct xhci_hcd *xhci,
}
if (DEV_SUPERSPEED(temp)) {
- xhci_dbg(xhci, "resume SS port %d\n", port_id);
+ xhci_dbg(xhci, "remote wake SS port %d\n", port_id);
+ /* Set a flag to say the port signaled remote wakeup,
+ * so we can tell the difference between the end of
+ * device and host initiated resume.
+ */
+ bus_state->port_remote_wakeup |= 1 << faked_port_index;
+ xhci_test_and_clear_bit(xhci, port_array,
+ faked_port_index, PORT_PLC);
xhci_set_link_state(xhci, port_array, faked_port_index,
XDEV_U0);
- slot_id = xhci_find_slot_id_by_port(hcd, xhci,
- faked_port_index + 1);
- if (!slot_id) {
- xhci_dbg(xhci, "slot_id is zero\n");
- goto cleanup;
- }
- xhci_ring_device(xhci, slot_id);
- xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
- /* Clear PORT_PLC */
- xhci_test_and_clear_bit(xhci, port_array,
- faked_port_index, PORT_PLC);
+ /* Need to wait until the next link state change
+ * indicates the device is actually in U0.
+ */
+ bogus_port_status = true;
+ goto cleanup;
} else {
xhci_dbg(xhci, "resume HS port %d\n", port_id);
bus_state->resume_done[faked_port_index] = jiffies +
@@ -1345,13 +1383,39 @@ static void handle_port_status(struct xhci_hcd *xhci,
}
}
+ if ((temp & PORT_PLC) && (temp & PORT_PLS_MASK) == XDEV_U0 &&
+ DEV_SUPERSPEED(temp)) {
+ xhci_dbg(xhci, "resume SS port %d finished\n", port_id);
+ /* We've just brought the device into U0 through either the
+ * Resume state after a device remote wakeup, or through the
+ * U3Exit state after a host-initiated resume. If it's a device
+ * initiated remote wake, don't pass up the link state change,
+ * so the roothub behavior is consistent with external
+ * USB 3.0 hub behavior.
+ */
+ slot_id = xhci_find_slot_id_by_port(hcd, xhci,
+ faked_port_index + 1);
+ if (slot_id && xhci->devs[slot_id])
+ xhci_ring_device(xhci, slot_id);
+ if (bus_state->port_remote_wakeup && (1 << faked_port_index)) {
+ bus_state->port_remote_wakeup &=
+ ~(1 << faked_port_index);
+ xhci_test_and_clear_bit(xhci, port_array,
+ faked_port_index, PORT_PLC);
+ usb_wakeup_notification(hcd->self.root_hub,
+ faked_port_index + 1);
+ bogus_port_status = true;
+ goto cleanup;
+ }
+ }
+
if (hcd->speed != HCD_USB3)
xhci_test_and_clear_bit(xhci, port_array, faked_port_index,
PORT_PLC);
cleanup:
/* Update event ring dequeue pointer before dropping the lock */
- inc_deq(xhci, xhci->event_ring, true);
+ inc_deq(xhci, xhci->event_ring);
/* Don't make the USB core poll the roothub if we got a bad port status
* change event. Besides, at that point we can't tell which roothub
@@ -1546,8 +1610,8 @@ static int finish_td(struct xhci_hcd *xhci, struct xhci_td *td,
} else {
/* Update ring dequeue pointer */
while (ep_ring->dequeue != td->last_trb)
- inc_deq(xhci, ep_ring, false);
- inc_deq(xhci, ep_ring, false);
+ inc_deq(xhci, ep_ring);
+ inc_deq(xhci, ep_ring);
}
td_cleanup:
@@ -1795,8 +1859,8 @@ static int skip_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
/* Update ring dequeue pointer */
while (ep_ring->dequeue != td->last_trb)
- inc_deq(xhci, ep_ring, false);
- inc_deq(xhci, ep_ring, false);
+ inc_deq(xhci, ep_ring);
+ inc_deq(xhci, ep_ring);
return finish_td(xhci, td, NULL, event, ep, status, true);
}
@@ -2183,7 +2247,7 @@ cleanup:
* Will roll back to continue process missed tds.
*/
if (trb_comp_code == COMP_MISSED_INT || !ep->skip) {
- inc_deq(xhci, xhci->event_ring, true);
+ inc_deq(xhci, xhci->event_ring);
}
if (ret) {
@@ -2277,6 +2341,9 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
else
update_ptrs = 0;
break;
+ case TRB_TYPE(TRB_DEV_NOTE):
+ handle_device_notification(xhci, event);
+ break;
default:
if ((le32_to_cpu(event->event_cmd.flags) & TRB_TYPE_BITMASK) >=
TRB_TYPE(48))
@@ -2295,7 +2362,7 @@ static int xhci_handle_event(struct xhci_hcd *xhci)
if (update_ptrs)
/* Update SW event ring dequeue pointer */
- inc_deq(xhci, xhci->event_ring, true);
+ inc_deq(xhci, xhci->event_ring);
/* Are there more items on the event ring? Caller will call us again to
* check.
@@ -2346,11 +2413,11 @@ hw_died:
/* FIXME when MSI-X is supported and there are multiple vectors */
/* Clear the MSI-X event interrupt status */
- if (hcd->irq != -1) {
+ if (hcd->irq) {
u32 irq_pending;
/* Acknowledge the PCI interrupt */
irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending);
- irq_pending |= 0x3;
+ irq_pending |= IMAN_IP;
xhci_writel(xhci, irq_pending, &xhci->ir_set->irq_pending);
}
@@ -2411,7 +2478,7 @@ irqreturn_t xhci_msi_irq(int irq, struct usb_hcd *hcd)
* prepare_transfer()?
*/
static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
- bool consumer, bool more_trbs_coming, bool isoc,
+ bool more_trbs_coming,
u32 field1, u32 field2, u32 field3, u32 field4)
{
struct xhci_generic_trb *trb;
@@ -2421,7 +2488,7 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
trb->field[1] = cpu_to_le32(field2);
trb->field[2] = cpu_to_le32(field3);
trb->field[3] = cpu_to_le32(field4);
- inc_enq(xhci, ring, consumer, more_trbs_coming, isoc);
+ inc_enq(xhci, ring, more_trbs_coming);
}
/*
@@ -2429,8 +2496,10 @@ static void queue_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
* FIXME allocate segments if the ring is full.
*/
static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
- u32 ep_state, unsigned int num_trbs, bool isoc, gfp_t mem_flags)
+ u32 ep_state, unsigned int num_trbs, gfp_t mem_flags)
{
+ unsigned int num_trbs_needed;
+
/* Make sure the endpoint has been added to xHC schedule */
switch (ep_state) {
case EP_STATE_DISABLED:
@@ -2458,11 +2527,25 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
*/
return -EINVAL;
}
- if (!room_on_ring(xhci, ep_ring, num_trbs)) {
- /* FIXME allocate more room */
- xhci_err(xhci, "ERROR no room on ep ring\n");
- return -ENOMEM;
- }
+
+ while (1) {
+ if (room_on_ring(xhci, ep_ring, num_trbs))
+ break;
+
+ if (ep_ring == xhci->cmd_ring) {
+ xhci_err(xhci, "Do not support expand command ring\n");
+ return -ENOMEM;
+ }
+
+ xhci_dbg(xhci, "ERROR no room on ep ring, "
+ "try ring expansion\n");
+ num_trbs_needed = num_trbs - ep_ring->num_trbs_free;
+ if (xhci_ring_expansion(xhci, ep_ring, num_trbs_needed,
+ mem_flags)) {
+ xhci_err(xhci, "Ring expansion failed\n");
+ return -ENOMEM;
+ }
+ };
if (enqueue_is_link_trb(ep_ring)) {
struct xhci_ring *ring = ep_ring;
@@ -2474,8 +2557,9 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
/* If we're not dealing with 0.95 hardware or isoc rings
* on AMD 0.96 host, clear the chain bit.
*/
- if (!xhci_link_trb_quirk(xhci) && !(isoc &&
- (xhci->quirks & XHCI_AMD_0x96_HOST)))
+ if (!xhci_link_trb_quirk(xhci) &&
+ !(ring->type == TYPE_ISOC &&
+ (xhci->quirks & XHCI_AMD_0x96_HOST)))
next->link.control &= cpu_to_le32(~TRB_CHAIN);
else
next->link.control |= cpu_to_le32(TRB_CHAIN);
@@ -2503,7 +2587,6 @@ static int prepare_transfer(struct xhci_hcd *xhci,
unsigned int num_trbs,
struct urb *urb,
unsigned int td_index,
- bool isoc,
gfp_t mem_flags)
{
int ret;
@@ -2521,7 +2604,7 @@ static int prepare_transfer(struct xhci_hcd *xhci,
ret = prepare_ring(xhci, ep_ring,
le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK,
- num_trbs, isoc, mem_flags);
+ num_trbs, mem_flags);
if (ret)
return ret;
@@ -2651,7 +2734,7 @@ int xhci_queue_intr_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
urb->dev->speed == USB_SPEED_FULL)
urb->interval /= 8;
}
- return xhci_queue_bulk_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index);
+ return xhci_queue_bulk_tx(xhci, mem_flags, urb, slot_id, ep_index);
}
/*
@@ -2731,7 +2814,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
trb_buff_len = prepare_transfer(xhci, xhci->devs[slot_id],
ep_index, urb->stream_id,
- num_trbs, urb, 0, false, mem_flags);
+ num_trbs, urb, 0, mem_flags);
if (trb_buff_len < 0)
return trb_buff_len;
@@ -2819,7 +2902,7 @@ static int queue_bulk_sg_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
more_trbs_coming = true;
else
more_trbs_coming = false;
- queue_trb(xhci, ep_ring, false, more_trbs_coming, false,
+ queue_trb(xhci, ep_ring, more_trbs_coming,
lower_32_bits(addr),
upper_32_bits(addr),
length_field,
@@ -2901,7 +2984,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
ret = prepare_transfer(xhci, xhci->devs[slot_id],
ep_index, urb->stream_id,
- num_trbs, urb, 0, false, mem_flags);
+ num_trbs, urb, 0, mem_flags);
if (ret < 0)
return ret;
@@ -2973,7 +3056,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
more_trbs_coming = true;
else
more_trbs_coming = false;
- queue_trb(xhci, ep_ring, false, more_trbs_coming, false,
+ queue_trb(xhci, ep_ring, more_trbs_coming,
lower_32_bits(addr),
upper_32_bits(addr),
length_field,
@@ -3030,7 +3113,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
num_trbs++;
ret = prepare_transfer(xhci, xhci->devs[slot_id],
ep_index, urb->stream_id,
- num_trbs, urb, 0, false, mem_flags);
+ num_trbs, urb, 0, mem_flags);
if (ret < 0)
return ret;
@@ -3063,7 +3146,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
}
}
- queue_trb(xhci, ep_ring, false, true, false,
+ queue_trb(xhci, ep_ring, true,
setup->bRequestType | setup->bRequest << 8 | le16_to_cpu(setup->wValue) << 16,
le16_to_cpu(setup->wIndex) | le16_to_cpu(setup->wLength) << 16,
TRB_LEN(8) | TRB_INTR_TARGET(0),
@@ -3083,7 +3166,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
if (urb->transfer_buffer_length > 0) {
if (setup->bRequestType & USB_DIR_IN)
field |= TRB_DIR_IN;
- queue_trb(xhci, ep_ring, false, true, false,
+ queue_trb(xhci, ep_ring, true,
lower_32_bits(urb->transfer_dma),
upper_32_bits(urb->transfer_dma),
length_field,
@@ -3099,7 +3182,7 @@ int xhci_queue_ctrl_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
field = 0;
else
field = TRB_DIR_IN;
- queue_trb(xhci, ep_ring, false, false, false,
+ queue_trb(xhci, ep_ring, false,
0,
0,
TRB_INTR_TARGET(0),
@@ -3239,8 +3322,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
trbs_per_td = count_isoc_trbs_needed(xhci, urb, i);
ret = prepare_transfer(xhci, xhci->devs[slot_id], ep_index,
- urb->stream_id, trbs_per_td, urb, i, true,
- mem_flags);
+ urb->stream_id, trbs_per_td, urb, i, mem_flags);
if (ret < 0) {
if (i == 0)
return ret;
@@ -3310,7 +3392,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
remainder |
TRB_INTR_TARGET(0);
- queue_trb(xhci, ep_ring, false, more_trbs_coming, true,
+ queue_trb(xhci, ep_ring, more_trbs_coming,
lower_32_bits(addr),
upper_32_bits(addr),
length_field,
@@ -3357,6 +3439,7 @@ cleanup:
ep_ring->enqueue = urb_priv->td[0]->first_trb;
ep_ring->enq_seg = urb_priv->td[0]->start_seg;
ep_ring->cycle_state = start_cycle;
+ ep_ring->num_trbs_free = ep_ring->num_trbs_free_temp;
usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
return ret;
}
@@ -3393,7 +3476,7 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
* Do not insert any td of the urb to the ring if the check failed.
*/
ret = prepare_ring(xhci, ep_ring, le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK,
- num_trbs, true, mem_flags);
+ num_trbs, mem_flags);
if (ret)
return ret;
@@ -3429,7 +3512,9 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
urb->dev->speed == USB_SPEED_FULL)
urb->interval /= 8;
}
- return xhci_queue_isoc_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index);
+ ep_ring->num_trbs_free_temp = ep_ring->num_trbs_free;
+
+ return xhci_queue_isoc_tx(xhci, mem_flags, urb, slot_id, ep_index);
}
/**** Command Ring Operations ****/
@@ -3452,7 +3537,7 @@ static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2,
reserved_trbs++;
ret = prepare_ring(xhci, xhci->cmd_ring, EP_STATE_RUNNING,
- reserved_trbs, false, GFP_ATOMIC);
+ reserved_trbs, GFP_ATOMIC);
if (ret < 0) {
xhci_err(xhci, "ERR: No room for command on command ring\n");
if (command_must_succeed)
@@ -3460,8 +3545,8 @@ static int queue_command(struct xhci_hcd *xhci, u32 field1, u32 field2,
"unfailable commands failed.\n");
return ret;
}
- queue_trb(xhci, xhci->cmd_ring, false, false, false, field1, field2,
- field3, field4 | xhci->cmd_ring->cycle_state);
+ queue_trb(xhci, xhci->cmd_ring, false, field1, field2, field3,
+ field4 | xhci->cmd_ring->cycle_state);
return 0;
}
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index c939f5fdef9e..36641a7f2371 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -106,6 +106,9 @@ int xhci_halt(struct xhci_hcd *xhci)
STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC);
if (!ret)
xhci->xhc_state |= XHCI_STATE_HALTED;
+ else
+ xhci_warn(xhci, "Host not halted after %u microseconds.\n",
+ XHCI_MAX_HALT_USEC);
return ret;
}
@@ -224,13 +227,13 @@ static void xhci_free_irq(struct xhci_hcd *xhci)
int ret;
/* return if using legacy interrupt */
- if (xhci_to_hcd(xhci)->irq >= 0)
+ if (xhci_to_hcd(xhci)->irq > 0)
return;
ret = xhci_free_msi(xhci);
if (!ret)
return;
- if (pdev->irq >= 0)
+ if (pdev->irq > 0)
free_irq(pdev->irq, xhci_to_hcd(xhci));
return;
@@ -341,7 +344,7 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd)
/* unregister the legacy interrupt */
if (hcd->irq)
free_irq(hcd->irq, hcd);
- hcd->irq = -1;
+ hcd->irq = 0;
ret = xhci_setup_msix(xhci);
if (ret)
@@ -349,7 +352,7 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd)
ret = xhci_setup_msi(xhci);
if (!ret)
- /* hcd->irq is -1, we have MSI */
+ /* hcd->irq is 0, we have MSI */
return 0;
if (!pdev->irq) {
@@ -664,11 +667,11 @@ static void xhci_save_registers(struct xhci_hcd *xhci)
xhci->s3.dev_nt = xhci_readl(xhci, &xhci->op_regs->dev_notification);
xhci->s3.dcbaa_ptr = xhci_read_64(xhci, &xhci->op_regs->dcbaa_ptr);
xhci->s3.config_reg = xhci_readl(xhci, &xhci->op_regs->config_reg);
- xhci->s3.irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending);
- xhci->s3.irq_control = xhci_readl(xhci, &xhci->ir_set->irq_control);
xhci->s3.erst_size = xhci_readl(xhci, &xhci->ir_set->erst_size);
xhci->s3.erst_base = xhci_read_64(xhci, &xhci->ir_set->erst_base);
xhci->s3.erst_dequeue = xhci_read_64(xhci, &xhci->ir_set->erst_dequeue);
+ xhci->s3.irq_pending = xhci_readl(xhci, &xhci->ir_set->irq_pending);
+ xhci->s3.irq_control = xhci_readl(xhci, &xhci->ir_set->irq_control);
}
static void xhci_restore_registers(struct xhci_hcd *xhci)
@@ -677,10 +680,11 @@ static void xhci_restore_registers(struct xhci_hcd *xhci)
xhci_writel(xhci, xhci->s3.dev_nt, &xhci->op_regs->dev_notification);
xhci_write_64(xhci, xhci->s3.dcbaa_ptr, &xhci->op_regs->dcbaa_ptr);
xhci_writel(xhci, xhci->s3.config_reg, &xhci->op_regs->config_reg);
- xhci_writel(xhci, xhci->s3.irq_pending, &xhci->ir_set->irq_pending);
- xhci_writel(xhci, xhci->s3.irq_control, &xhci->ir_set->irq_control);
xhci_writel(xhci, xhci->s3.erst_size, &xhci->ir_set->erst_size);
xhci_write_64(xhci, xhci->s3.erst_base, &xhci->ir_set->erst_base);
+ xhci_write_64(xhci, xhci->s3.erst_dequeue, &xhci->ir_set->erst_dequeue);
+ xhci_writel(xhci, xhci->s3.irq_pending, &xhci->ir_set->irq_pending);
+ xhci_writel(xhci, xhci->s3.irq_control, &xhci->ir_set->irq_control);
}
static void xhci_set_cmd_ring_deq(struct xhci_hcd *xhci)
@@ -729,6 +733,7 @@ static void xhci_clear_command_ring(struct xhci_hcd *xhci)
ring->enq_seg = ring->deq_seg;
ring->enqueue = ring->dequeue;
+ ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1;
/*
* Ring is now zeroed, so the HW should look for change of ownership
* when the cycle bit is set to 1.
@@ -3614,26 +3619,38 @@ static int xhci_besl_encoding[16] = {125, 150, 200, 300, 400, 500, 1000, 2000,
3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000};
/* Calculate HIRD/BESL for USB2 PORTPMSC*/
-static int xhci_calculate_hird_besl(int u2del, bool use_besl)
+static int xhci_calculate_hird_besl(struct xhci_hcd *xhci,
+ struct usb_device *udev)
{
- int hird;
+ int u2del, besl, besl_host;
+ int besl_device = 0;
+ u32 field;
+
+ u2del = HCS_U2_LATENCY(xhci->hcs_params3);
+ field = le32_to_cpu(udev->bos->ext_cap->bmAttributes);
- if (use_besl) {
- for (hird = 0; hird < 16; hird++) {
- if (xhci_besl_encoding[hird] >= u2del)
+ if (field & USB_BESL_SUPPORT) {
+ for (besl_host = 0; besl_host < 16; besl_host++) {
+ if (xhci_besl_encoding[besl_host] >= u2del)
break;
}
+ /* Use baseline BESL value as default */
+ if (field & USB_BESL_BASELINE_VALID)
+ besl_device = USB_GET_BESL_BASELINE(field);
+ else if (field & USB_BESL_DEEP_VALID)
+ besl_device = USB_GET_BESL_DEEP(field);
} else {
if (u2del <= 50)
- hird = 0;
+ besl_host = 0;
else
- hird = (u2del - 51) / 75 + 1;
-
- if (hird > 15)
- hird = 15;
+ besl_host = (u2del - 51) / 75 + 1;
}
- return hird;
+ besl = besl_host + besl_device;
+ if (besl > 15)
+ besl = 15;
+
+ return besl;
}
static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd,
@@ -3646,7 +3663,7 @@ static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd,
u32 temp, dev_id;
unsigned int port_num;
unsigned long flags;
- int u2del, hird;
+ int hird;
int ret;
if (hcd->speed == HCD_USB3 || !xhci->sw_lpm_support ||
@@ -3692,12 +3709,7 @@ static int xhci_usb2_software_lpm_test(struct usb_hcd *hcd,
* HIRD or BESL shoule be used. See USB2.0 LPM errata.
*/
pm_addr = port_array[port_num] + 1;
- u2del = HCS_U2_LATENCY(xhci->hcs_params3);
- if (le32_to_cpu(udev->bos->ext_cap->bmAttributes) & (1 << 2))
- hird = xhci_calculate_hird_besl(u2del, 1);
- else
- hird = xhci_calculate_hird_besl(u2del, 0);
-
+ hird = xhci_calculate_hird_besl(xhci, udev);
temp = PORT_L1DS(udev->slot_id) | PORT_HIRD(hird);
xhci_writel(xhci, temp, pm_addr);
@@ -3776,7 +3788,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
u32 temp;
unsigned int port_num;
unsigned long flags;
- int u2del, hird;
+ int hird;
if (hcd->speed == HCD_USB3 || !xhci->hw_lpm_support ||
!udev->lpm_capable)
@@ -3799,11 +3811,7 @@ int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
xhci_dbg(xhci, "%s port %d USB2 hardware LPM\n",
enable ? "enable" : "disable", port_num);
- u2del = HCS_U2_LATENCY(xhci->hcs_params3);
- if (le32_to_cpu(udev->bos->ext_cap->bmAttributes) & (1 << 2))
- hird = xhci_calculate_hird_besl(u2del, 1);
- else
- hird = xhci_calculate_hird_besl(u2del, 0);
+ hird = xhci_calculate_hird_besl(xhci, udev);
if (enable) {
temp &= ~PORT_HIRD_MASK;
@@ -3964,7 +3972,8 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
int retval;
u32 temp;
- hcd->self.sg_tablesize = TRBS_PER_SEGMENT - 2;
+ /* Accept arbitrarily long scatter-gather lists */
+ hcd->self.sg_tablesize = ~0;
if (usb_hcd_is_primary_hcd(hcd)) {
xhci = kzalloc(sizeof(struct xhci_hcd), GFP_KERNEL);
@@ -4059,6 +4068,11 @@ static int __init xhci_hcd_init(void)
printk(KERN_DEBUG "Problem registering PCI driver.");
return retval;
}
+ retval = xhci_register_plat();
+ if (retval < 0) {
+ printk(KERN_DEBUG "Problem registering platform driver.");
+ goto unreg_pci;
+ }
/*
* Check the compiler generated sizes of structures that must be laid
* out in specific ways for hardware access.
@@ -4078,11 +4092,15 @@ static int __init xhci_hcd_init(void)
BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8);
BUILD_BUG_ON(sizeof(struct xhci_doorbell_array) != 256*32/8);
return 0;
+unreg_pci:
+ xhci_unregister_pci();
+ return retval;
}
module_init(xhci_hcd_init);
static void __exit xhci_hcd_cleanup(void)
{
xhci_unregister_pci();
+ xhci_unregister_plat();
}
module_exit(xhci_hcd_cleanup);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index fb99c8379142..3d69c4b2b542 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -205,6 +205,10 @@ struct xhci_op_regs {
#define CMD_PM_INDEX (1 << 11)
/* bits 12:31 are reserved (and should be preserved on writes). */
+/* IMAN - Interrupt Management Register */
+#define IMAN_IP (1 << 1)
+#define IMAN_IE (1 << 0)
+
/* USBSTS - USB status - status bitmasks */
/* HC not running - set to 1 when run/stop bit is cleared. */
#define STS_HALT XHCI_STS_HALT
@@ -1223,10 +1227,7 @@ union xhci_trb {
/* Allow two commands + a link TRB, along with any reserved command TRBs */
#define MAX_RSVD_CMD_TRBS (TRBS_PER_SEGMENT - 3)
#define SEGMENT_SIZE (TRBS_PER_SEGMENT*16)
-/* SEGMENT_SHIFT should be log2(SEGMENT_SIZE).
- * Change this if you change TRBS_PER_SEGMENT!
- */
-#define SEGMENT_SHIFT 10
+#define SEGMENT_SHIFT (__ffs(SEGMENT_SIZE))
/* TRB buffer pointers can't cross 64KB boundaries */
#define TRB_MAX_BUFF_SHIFT 16
#define TRB_MAX_BUFF_SIZE (1 << TRB_MAX_BUFF_SHIFT)
@@ -1253,8 +1254,19 @@ struct xhci_dequeue_state {
int new_cycle_state;
};
+enum xhci_ring_type {
+ TYPE_CTRL = 0,
+ TYPE_ISOC,
+ TYPE_BULK,
+ TYPE_INTR,
+ TYPE_STREAM,
+ TYPE_COMMAND,
+ TYPE_EVENT,
+};
+
struct xhci_ring {
struct xhci_segment *first_seg;
+ struct xhci_segment *last_seg;
union xhci_trb *enqueue;
struct xhci_segment *enq_seg;
unsigned int enq_updates;
@@ -1269,6 +1281,10 @@ struct xhci_ring {
*/
u32 cycle_state;
unsigned int stream_id;
+ unsigned int num_segs;
+ unsigned int num_trbs_free;
+ unsigned int num_trbs_free_temp;
+ enum xhci_ring_type type;
bool last_td_was_short;
};
@@ -1344,6 +1360,7 @@ struct xhci_bus_state {
/* ports suspend status arrays - max 31 ports for USB2, 15 for USB3 */
u32 port_c_suspend;
u32 suspended_ports;
+ u32 port_remote_wakeup;
unsigned long resume_done[USB_MAXCHILDREN];
};
@@ -1609,6 +1626,8 @@ int xhci_endpoint_init(struct xhci_hcd *xhci, struct xhci_virt_device *virt_dev,
struct usb_device *udev, struct usb_host_endpoint *ep,
gfp_t mem_flags);
void xhci_ring_free(struct xhci_hcd *xhci, struct xhci_ring *ring);
+int xhci_ring_expansion(struct xhci_hcd *xhci, struct xhci_ring *ring,
+ unsigned int num_trbs, gfp_t flags);
void xhci_free_or_cache_endpoint_ring(struct xhci_hcd *xhci,
struct xhci_virt_device *virt_dev,
unsigned int ep_index);
@@ -1648,6 +1667,17 @@ static inline int xhci_register_pci(void) { return 0; }
static inline void xhci_unregister_pci(void) {}
#endif
+#if defined(CONFIG_USB_XHCI_PLATFORM) \
+ || defined(CONFIG_USB_XHCI_PLATFORM_MODULE)
+int xhci_register_plat(void);
+void xhci_unregister_plat(void);
+#else
+static inline int xhci_register_plat(void)
+{ return 0; }
+static inline void xhci_unregister_plat(void)
+{ }
+#endif
+
/* xHCI host controller glue */
typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
void xhci_quiesce(struct xhci_hcd *xhci);
diff --git a/drivers/usb/misc/usbtest.c b/drivers/usb/misc/usbtest.c
index 959145baf3cf..9dcb68f04f03 100644
--- a/drivers/usb/misc/usbtest.c
+++ b/drivers/usb/misc/usbtest.c
@@ -423,7 +423,7 @@ alloc_sglist(int nents, int max, int vary)
unsigned i;
unsigned size = max;
- sg = kmalloc(nents * sizeof *sg, GFP_KERNEL);
+ sg = kmalloc_array(nents, sizeof *sg, GFP_KERNEL);
if (!sg)
return NULL;
sg_init_table(sg, nents);
@@ -904,6 +904,9 @@ test_ctrl_queue(struct usbtest_dev *dev, struct usbtest_param *param)
struct ctrl_ctx context;
int i;
+ if (param->sglen == 0 || param->iterations > UINT_MAX / param->sglen)
+ return -EOPNOTSUPP;
+
spin_lock_init(&context.lock);
context.dev = dev;
init_completion(&context.complete);
@@ -1981,8 +1984,6 @@ usbtest_ioctl(struct usb_interface *intf, unsigned int code, void *buf)
/* queued control messaging */
case 10:
- if (param->sglen == 0)
- break;
retval = 0;
dev_info(&intf->dev,
"TEST 10: queue %d control calls, %d times\n",
@@ -2276,6 +2277,8 @@ usbtest_probe(struct usb_interface *intf, const struct usb_device_id *id)
if (status < 0) {
WARNING(dev, "couldn't get endpoints, %d\n",
status);
+ kfree(dev->buf);
+ kfree(dev);
return status;
}
/* may find bulk or ISO pipes */
diff --git a/drivers/usb/misc/yurex.c b/drivers/usb/misc/yurex.c
index 897edda42270..70201462e19c 100644
--- a/drivers/usb/misc/yurex.c
+++ b/drivers/usb/misc/yurex.c
@@ -99,9 +99,7 @@ static void yurex_delete(struct kref *kref)
usb_put_dev(dev->udev);
if (dev->cntl_urb) {
usb_kill_urb(dev->cntl_urb);
- if (dev->cntl_req)
- usb_free_coherent(dev->udev, YUREX_BUF_SIZE,
- dev->cntl_req, dev->cntl_urb->setup_dma);
+ kfree(dev->cntl_req);
if (dev->cntl_buffer)
usb_free_coherent(dev->udev, YUREX_BUF_SIZE,
dev->cntl_buffer, dev->cntl_urb->transfer_dma);
@@ -234,9 +232,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
}
/* allocate buffer for control req */
- dev->cntl_req = usb_alloc_coherent(dev->udev, YUREX_BUF_SIZE,
- GFP_KERNEL,
- &dev->cntl_urb->setup_dma);
+ dev->cntl_req = kmalloc(YUREX_BUF_SIZE, GFP_KERNEL);
if (!dev->cntl_req) {
err("Could not allocate cntl_req");
goto error;
@@ -286,7 +282,7 @@ static int yurex_probe(struct usb_interface *interface, const struct usb_device_
usb_rcvintpipe(dev->udev, dev->int_in_endpointAddr),
dev->int_buffer, YUREX_BUF_SIZE, yurex_interrupt,
dev, 1);
- dev->cntl_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+ dev->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
if (usb_submit_urb(dev->urb, GFP_KERNEL)) {
retval = -EIO;
err("Could not submitting URB");
diff --git a/drivers/usb/musb/am35x.c b/drivers/usb/musb/am35x.c
index e233d2b7d335..9f3eda91ea4d 100644
--- a/drivers/usb/musb/am35x.c
+++ b/drivers/usb/musb/am35x.c
@@ -226,6 +226,7 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
struct device *dev = musb->controller;
struct musb_hdrc_platform_data *plat = dev->platform_data;
struct omap_musb_board_data *data = plat->board_data;
+ struct usb_otg *otg = musb->xceiv->otg;
unsigned long flags;
irqreturn_t ret = IRQ_NONE;
u32 epintr, usbintr;
@@ -289,14 +290,14 @@ static irqreturn_t am35x_musb_interrupt(int irq, void *hci)
WARNING("VBUS error workaround (delay coming)\n");
} else if (is_host_enabled(musb) && drvvbus) {
MUSB_HST_MODE(musb);
- musb->xceiv->default_a = 1;
+ otg->default_a = 1;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
portstate(musb->port1_status |= USB_PORT_STAT_POWER);
del_timer(&otg_workaround);
} else {
musb->is_active = 0;
MUSB_DEV_MODE(musb);
- musb->xceiv->default_a = 0;
+ otg->default_a = 0;
musb->xceiv->state = OTG_STATE_B_IDLE;
portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
}
@@ -363,7 +364,7 @@ static int am35x_musb_init(struct musb *musb)
return -ENODEV;
usb_nop_xceiv_register();
- musb->xceiv = otg_get_transceiver();
+ musb->xceiv = usb_get_transceiver();
if (!musb->xceiv)
return -ENODEV;
@@ -405,7 +406,7 @@ static int am35x_musb_exit(struct musb *musb)
if (data->set_phy_power)
data->set_phy_power(0);
- otg_put_transceiver(musb->xceiv);
+ usb_put_transceiver(musb->xceiv);
usb_nop_xceiv_unregister();
return 0;
@@ -456,7 +457,7 @@ static const struct musb_platform_ops am35x_ops = {
static u64 am35x_dmamask = DMA_BIT_MASK(32);
-static int __init am35x_probe(struct platform_device *pdev)
+static int __devinit am35x_probe(struct platform_device *pdev)
{
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
struct platform_device *musb;
@@ -561,7 +562,7 @@ err0:
return ret;
}
-static int __exit am35x_remove(struct platform_device *pdev)
+static int __devexit am35x_remove(struct platform_device *pdev)
{
struct am35x_glue *glue = platform_get_drvdata(pdev);
@@ -630,7 +631,8 @@ static struct dev_pm_ops am35x_pm_ops = {
#endif
static struct platform_driver am35x_driver = {
- .remove = __exit_p(am35x_remove),
+ .probe = am35x_probe,
+ .remove = __devexit_p(am35x_remove),
.driver = {
.name = "musb-am35x",
.pm = DEV_PM_OPS,
@@ -643,9 +645,9 @@ MODULE_LICENSE("GPL v2");
static int __init am35x_init(void)
{
- return platform_driver_probe(&am35x_driver, am35x_probe);
+ return platform_driver_register(&am35x_driver);
}
-subsys_initcall(am35x_init);
+module_init(am35x_init);
static void __exit am35x_exit(void)
{
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index 5e7cfba5b079..a087ed6c3be9 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -317,7 +317,7 @@ static void bfin_musb_set_vbus(struct musb *musb, int is_on)
musb_readb(musb->mregs, MUSB_DEVCTL));
}
-static int bfin_musb_set_power(struct otg_transceiver *x, unsigned mA)
+static int bfin_musb_set_power(struct usb_phy *x, unsigned mA)
{
return 0;
}
@@ -415,7 +415,7 @@ static int bfin_musb_init(struct musb *musb)
gpio_direction_output(musb->config->gpio_vrsel, 0);
usb_nop_xceiv_register();
- musb->xceiv = otg_get_transceiver();
+ musb->xceiv = usb_get_transceiver();
if (!musb->xceiv) {
gpio_free(musb->config->gpio_vrsel);
return -ENODEV;
@@ -440,7 +440,7 @@ static int bfin_musb_exit(struct musb *musb)
{
gpio_free(musb->config->gpio_vrsel);
- otg_put_transceiver(musb->xceiv);
+ usb_put_transceiver(musb->xceiv);
usb_nop_xceiv_unregister();
return 0;
}
@@ -463,7 +463,7 @@ static const struct musb_platform_ops bfin_ops = {
static u64 bfin_dmamask = DMA_BIT_MASK(32);
-static int __init bfin_probe(struct platform_device *pdev)
+static int __devinit bfin_probe(struct platform_device *pdev)
{
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
struct platform_device *musb;
@@ -525,7 +525,7 @@ err0:
return ret;
}
-static int __exit bfin_remove(struct platform_device *pdev)
+static int __devexit bfin_remove(struct platform_device *pdev)
{
struct bfin_glue *glue = platform_get_drvdata(pdev);
@@ -575,6 +575,7 @@ static struct dev_pm_ops bfin_pm_ops = {
#endif
static struct platform_driver bfin_driver = {
+ .probe = bfin_probe,
.remove = __exit_p(bfin_remove),
.driver = {
.name = "musb-blackfin",
@@ -588,9 +589,9 @@ MODULE_LICENSE("GPL v2");
static int __init bfin_init(void)
{
- return platform_driver_probe(&bfin_driver, bfin_probe);
+ return platform_driver_register(&bfin_driver);
}
-subsys_initcall(bfin_init);
+module_init(bfin_init);
static void __exit bfin_exit(void)
{
diff --git a/drivers/usb/musb/da8xx.c b/drivers/usb/musb/da8xx.c
index 2613bfdb09b6..8bd9566f3fbb 100644
--- a/drivers/usb/musb/da8xx.c
+++ b/drivers/usb/musb/da8xx.c
@@ -294,6 +294,7 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
{
struct musb *musb = hci;
void __iomem *reg_base = musb->ctrl_base;
+ struct usb_otg *otg = musb->xceiv->otg;
unsigned long flags;
irqreturn_t ret = IRQ_NONE;
u32 status;
@@ -351,14 +352,14 @@ static irqreturn_t da8xx_musb_interrupt(int irq, void *hci)
WARNING("VBUS error workaround (delay coming)\n");
} else if (is_host_enabled(musb) && drvvbus) {
MUSB_HST_MODE(musb);
- musb->xceiv->default_a = 1;
+ otg->default_a = 1;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
portstate(musb->port1_status |= USB_PORT_STAT_POWER);
del_timer(&otg_workaround);
} else {
musb->is_active = 0;
MUSB_DEV_MODE(musb);
- musb->xceiv->default_a = 0;
+ otg->default_a = 0;
musb->xceiv->state = OTG_STATE_B_IDLE;
portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
}
@@ -424,7 +425,7 @@ static int da8xx_musb_init(struct musb *musb)
goto fail;
usb_nop_xceiv_register();
- musb->xceiv = otg_get_transceiver();
+ musb->xceiv = usb_get_transceiver();
if (!musb->xceiv)
goto fail;
@@ -457,7 +458,7 @@ static int da8xx_musb_exit(struct musb *musb)
phy_off();
- otg_put_transceiver(musb->xceiv);
+ usb_put_transceiver(musb->xceiv);
usb_nop_xceiv_unregister();
return 0;
@@ -478,7 +479,7 @@ static const struct musb_platform_ops da8xx_ops = {
static u64 da8xx_dmamask = DMA_BIT_MASK(32);
-static int __init da8xx_probe(struct platform_device *pdev)
+static int __devinit da8xx_probe(struct platform_device *pdev)
{
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
struct platform_device *musb;
@@ -562,7 +563,7 @@ err0:
return ret;
}
-static int __exit da8xx_remove(struct platform_device *pdev)
+static int __devexit da8xx_remove(struct platform_device *pdev)
{
struct da8xx_glue *glue = platform_get_drvdata(pdev);
@@ -576,7 +577,8 @@ static int __exit da8xx_remove(struct platform_device *pdev)
}
static struct platform_driver da8xx_driver = {
- .remove = __exit_p(da8xx_remove),
+ .probe = da8xx_probe,
+ .remove = __devexit_p(da8xx_remove),
.driver = {
.name = "musb-da8xx",
},
@@ -588,9 +590,9 @@ MODULE_LICENSE("GPL v2");
static int __init da8xx_init(void)
{
- return platform_driver_probe(&da8xx_driver, da8xx_probe);
+ return platform_driver_register(&da8xx_driver);
}
-subsys_initcall(da8xx_init);
+module_init(da8xx_init);
static void __exit da8xx_exit(void)
{
diff --git a/drivers/usb/musb/davinci.c b/drivers/usb/musb/davinci.c
index 7c569f51212a..97ab975fa442 100644
--- a/drivers/usb/musb/davinci.c
+++ b/drivers/usb/musb/davinci.c
@@ -265,6 +265,7 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
unsigned long flags;
irqreturn_t retval = IRQ_NONE;
struct musb *musb = __hci;
+ struct usb_otg *otg = musb->xceiv->otg;
void __iomem *tibase = musb->ctrl_base;
struct cppi *cppi;
u32 tmp;
@@ -331,14 +332,14 @@ static irqreturn_t davinci_musb_interrupt(int irq, void *__hci)
WARNING("VBUS error workaround (delay coming)\n");
} else if (is_host_enabled(musb) && drvvbus) {
MUSB_HST_MODE(musb);
- musb->xceiv->default_a = 1;
+ otg->default_a = 1;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
portstate(musb->port1_status |= USB_PORT_STAT_POWER);
del_timer(&otg_workaround);
} else {
musb->is_active = 0;
MUSB_DEV_MODE(musb);
- musb->xceiv->default_a = 0;
+ otg->default_a = 0;
musb->xceiv->state = OTG_STATE_B_IDLE;
portstate(musb->port1_status &= ~USB_PORT_STAT_POWER);
}
@@ -383,7 +384,7 @@ static int davinci_musb_init(struct musb *musb)
u32 revision;
usb_nop_xceiv_register();
- musb->xceiv = otg_get_transceiver();
+ musb->xceiv = usb_get_transceiver();
if (!musb->xceiv)
return -ENODEV;
@@ -442,7 +443,7 @@ static int davinci_musb_init(struct musb *musb)
return 0;
fail:
- otg_put_transceiver(musb->xceiv);
+ usb_put_transceiver(musb->xceiv);
usb_nop_xceiv_unregister();
return -ENODEV;
}
@@ -464,7 +465,7 @@ static int davinci_musb_exit(struct musb *musb)
davinci_musb_source_power(musb, 0 /*off*/, 1);
/* delay, to avoid problems with module reload */
- if (is_host_enabled(musb) && musb->xceiv->default_a) {
+ if (is_host_enabled(musb) && musb->xceiv->otg->default_a) {
int maxdelay = 30;
u8 devctl, warn = 0;
@@ -491,7 +492,7 @@ static int davinci_musb_exit(struct musb *musb)
phy_off();
- otg_put_transceiver(musb->xceiv);
+ usb_put_transceiver(musb->xceiv);
usb_nop_xceiv_unregister();
return 0;
@@ -511,7 +512,7 @@ static const struct musb_platform_ops davinci_ops = {
static u64 davinci_dmamask = DMA_BIT_MASK(32);
-static int __init davinci_probe(struct platform_device *pdev)
+static int __devinit davinci_probe(struct platform_device *pdev)
{
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
struct platform_device *musb;
@@ -594,7 +595,7 @@ err0:
return ret;
}
-static int __exit davinci_remove(struct platform_device *pdev)
+static int __devexit davinci_remove(struct platform_device *pdev)
{
struct davinci_glue *glue = platform_get_drvdata(pdev);
@@ -608,7 +609,8 @@ static int __exit davinci_remove(struct platform_device *pdev)
}
static struct platform_driver davinci_driver = {
- .remove = __exit_p(davinci_remove),
+ .probe = davinci_probe,
+ .remove = __devexit_p(davinci_remove),
.driver = {
.name = "musb-davinci",
},
@@ -620,9 +622,9 @@ MODULE_LICENSE("GPL v2");
static int __init davinci_init(void)
{
- return platform_driver_probe(&davinci_driver, davinci_probe);
+ return platform_driver_register(&davinci_driver);
}
-subsys_initcall(davinci_init);
+module_init(davinci_init);
static void __exit davinci_exit(void)
{
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 3d11cf64ebd1..66aaccf04490 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -131,12 +131,15 @@ static inline struct musb *dev_to_musb(struct device *dev)
/*-------------------------------------------------------------------------*/
#ifndef CONFIG_BLACKFIN
-static int musb_ulpi_read(struct otg_transceiver *otg, u32 offset)
+static int musb_ulpi_read(struct usb_phy *phy, u32 offset)
{
- void __iomem *addr = otg->io_priv;
+ void __iomem *addr = phy->io_priv;
int i = 0;
u8 r;
u8 power;
+ int ret;
+
+ pm_runtime_get_sync(phy->io_dev);
/* Make sure the transceiver is not in low power mode */
power = musb_readb(addr, MUSB_POWER);
@@ -154,24 +157,33 @@ static int musb_ulpi_read(struct otg_transceiver *otg, u32 offset)
while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL)
& MUSB_ULPI_REG_CMPLT)) {
i++;
- if (i == 10000)
- return -ETIMEDOUT;
+ if (i == 10000) {
+ ret = -ETIMEDOUT;
+ goto out;
+ }
}
r = musb_readb(addr, MUSB_ULPI_REG_CONTROL);
r &= ~MUSB_ULPI_REG_CMPLT;
musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r);
- return musb_readb(addr, MUSB_ULPI_REG_DATA);
+ ret = musb_readb(addr, MUSB_ULPI_REG_DATA);
+
+out:
+ pm_runtime_put(phy->io_dev);
+
+ return ret;
}
-static int musb_ulpi_write(struct otg_transceiver *otg,
- u32 offset, u32 data)
+static int musb_ulpi_write(struct usb_phy *phy, u32 offset, u32 data)
{
- void __iomem *addr = otg->io_priv;
+ void __iomem *addr = phy->io_priv;
int i = 0;
u8 r = 0;
u8 power;
+ int ret = 0;
+
+ pm_runtime_get_sync(phy->io_dev);
/* Make sure the transceiver is not in low power mode */
power = musb_readb(addr, MUSB_POWER);
@@ -185,22 +197,27 @@ static int musb_ulpi_write(struct otg_transceiver *otg,
while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL)
& MUSB_ULPI_REG_CMPLT)) {
i++;
- if (i == 10000)
- return -ETIMEDOUT;
+ if (i == 10000) {
+ ret = -ETIMEDOUT;
+ goto out;
+ }
}
r = musb_readb(addr, MUSB_ULPI_REG_CONTROL);
r &= ~MUSB_ULPI_REG_CMPLT;
musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r);
- return 0;
+out:
+ pm_runtime_put(phy->io_dev);
+
+ return ret;
}
#else
#define musb_ulpi_read NULL
#define musb_ulpi_write NULL
#endif
-static struct otg_io_access_ops musb_ulpi_access = {
+static struct usb_phy_io_ops musb_ulpi_access = {
.read = musb_ulpi_read,
.write = musb_ulpi_write,
};
@@ -414,6 +431,7 @@ void musb_hnp_stop(struct musb *musb)
static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
u8 devctl, u8 power)
{
+ struct usb_otg *otg = musb->xceiv->otg;
irqreturn_t handled = IRQ_NONE;
dev_dbg(musb->controller, "<== Power=%02x, DevCtl=%02x, int_usb=0x%x\n", power, devctl,
@@ -626,7 +644,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
case OTG_STATE_B_PERIPHERAL:
musb_g_suspend(musb);
musb->is_active = is_otg_enabled(musb)
- && musb->xceiv->gadget->b_hnp_enable;
+ && otg->gadget->b_hnp_enable;
if (musb->is_active) {
musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
dev_dbg(musb->controller, "HNP: Setting timer for b_ase0_brst\n");
@@ -643,7 +661,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
case OTG_STATE_A_HOST:
musb->xceiv->state = OTG_STATE_A_SUSPEND;
musb->is_active = is_otg_enabled(musb)
- && musb->xceiv->host->b_hnp_enable;
+ && otg->host->b_hnp_enable;
break;
case OTG_STATE_B_HOST:
/* Transition to B_PERIPHERAL, see 6.8.2.6 p 44 */
@@ -1017,12 +1035,12 @@ static void musb_shutdown(struct platform_device *pdev)
|| defined(CONFIG_USB_MUSB_OMAP2PLUS_MODULE) \
|| defined(CONFIG_USB_MUSB_AM35X) \
|| defined(CONFIG_USB_MUSB_AM35X_MODULE)
-static ushort __initdata fifo_mode = 4;
+static ushort __devinitdata fifo_mode = 4;
#elif defined(CONFIG_USB_MUSB_UX500) \
|| defined(CONFIG_USB_MUSB_UX500_MODULE)
-static ushort __initdata fifo_mode = 5;
+static ushort __devinitdata fifo_mode = 5;
#else
-static ushort __initdata fifo_mode = 2;
+static ushort __devinitdata fifo_mode = 2;
#endif
/* "modprobe ... fifo_mode=1" etc */
@@ -1035,7 +1053,7 @@ MODULE_PARM_DESC(fifo_mode, "initial endpoint configuration");
*/
/* mode 0 - fits in 2KB */
-static struct musb_fifo_cfg __initdata mode_0_cfg[] = {
+static struct musb_fifo_cfg __devinitdata mode_0_cfg[] = {
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, },
@@ -1044,7 +1062,7 @@ static struct musb_fifo_cfg __initdata mode_0_cfg[] = {
};
/* mode 1 - fits in 4KB */
-static struct musb_fifo_cfg __initdata mode_1_cfg[] = {
+static struct musb_fifo_cfg __devinitdata mode_1_cfg[] = {
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, },
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, },
{ .hw_ep_num = 2, .style = FIFO_RXTX, .maxpacket = 512, .mode = BUF_DOUBLE, },
@@ -1053,7 +1071,7 @@ static struct musb_fifo_cfg __initdata mode_1_cfg[] = {
};
/* mode 2 - fits in 4KB */
-static struct musb_fifo_cfg __initdata mode_2_cfg[] = {
+static struct musb_fifo_cfg __devinitdata mode_2_cfg[] = {
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
@@ -1063,7 +1081,7 @@ static struct musb_fifo_cfg __initdata mode_2_cfg[] = {
};
/* mode 3 - fits in 4KB */
-static struct musb_fifo_cfg __initdata mode_3_cfg[] = {
+static struct musb_fifo_cfg __devinitdata mode_3_cfg[] = {
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, .mode = BUF_DOUBLE, },
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, .mode = BUF_DOUBLE, },
{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
@@ -1073,7 +1091,7 @@ static struct musb_fifo_cfg __initdata mode_3_cfg[] = {
};
/* mode 4 - fits in 16KB */
-static struct musb_fifo_cfg __initdata mode_4_cfg[] = {
+static struct musb_fifo_cfg __devinitdata mode_4_cfg[] = {
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
@@ -1104,7 +1122,7 @@ static struct musb_fifo_cfg __initdata mode_4_cfg[] = {
};
/* mode 5 - fits in 8KB */
-static struct musb_fifo_cfg __initdata mode_5_cfg[] = {
+static struct musb_fifo_cfg __devinitdata mode_5_cfg[] = {
{ .hw_ep_num = 1, .style = FIFO_TX, .maxpacket = 512, },
{ .hw_ep_num = 1, .style = FIFO_RX, .maxpacket = 512, },
{ .hw_ep_num = 2, .style = FIFO_TX, .maxpacket = 512, },
@@ -1140,7 +1158,7 @@ static struct musb_fifo_cfg __initdata mode_5_cfg[] = {
*
* returns negative errno or offset for next fifo.
*/
-static int __init
+static int __devinit
fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep,
const struct musb_fifo_cfg *cfg, u16 offset)
{
@@ -1211,11 +1229,11 @@ fifo_setup(struct musb *musb, struct musb_hw_ep *hw_ep,
return offset + (maxpacket << ((c_size & MUSB_FIFOSZ_DPB) ? 1 : 0));
}
-static struct musb_fifo_cfg __initdata ep0_cfg = {
+static struct musb_fifo_cfg __devinitdata ep0_cfg = {
.style = FIFO_RXTX, .maxpacket = 64,
};
-static int __init ep_config_from_table(struct musb *musb)
+static int __devinit ep_config_from_table(struct musb *musb)
{
const struct musb_fifo_cfg *cfg;
unsigned i, n;
@@ -1306,7 +1324,7 @@ done:
* ep_config_from_hw - when MUSB_C_DYNFIFO_DEF is false
* @param musb the controller
*/
-static int __init ep_config_from_hw(struct musb *musb)
+static int __devinit ep_config_from_hw(struct musb *musb)
{
u8 epnum = 0;
struct musb_hw_ep *hw_ep;
@@ -1353,7 +1371,7 @@ enum { MUSB_CONTROLLER_MHDRC, MUSB_CONTROLLER_HDRC, };
/* Initialize MUSB (M)HDRC part of the USB hardware subsystem;
* configure endpoints, or take their config from silicon
*/
-static int __init musb_core_init(u16 musb_type, struct musb *musb)
+static int __devinit musb_core_init(u16 musb_type, struct musb *musb)
{
u8 reg;
char *type;
@@ -1589,7 +1607,7 @@ irqreturn_t musb_interrupt(struct musb *musb)
EXPORT_SYMBOL_GPL(musb_interrupt);
#ifndef CONFIG_MUSB_PIO_ONLY
-static bool __initdata use_dma = 1;
+static bool __devinitdata use_dma = 1;
/* "modprobe ... use_dma=0" etc */
module_param(use_dma, bool, 0);
@@ -1777,7 +1795,7 @@ static void musb_irq_work(struct work_struct *data)
* Init support
*/
-static struct musb *__init
+static struct musb *__devinit
allocate_instance(struct device *dev,
struct musb_hdrc_config *config, void __iomem *mbase)
{
@@ -1853,7 +1871,7 @@ static void musb_free(struct musb *musb)
* @mregs: virtual address of controller registers,
* not yet corrected for platform-specific offsets
*/
-static int __init
+static int __devinit
musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
{
int status;
@@ -1904,14 +1922,17 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
if (!musb->isr) {
status = -ENODEV;
- goto fail3;
+ goto fail2;
}
if (!musb->xceiv->io_ops) {
+ musb->xceiv->io_dev = musb->controller;
musb->xceiv->io_priv = musb->mregs;
musb->xceiv->io_ops = &musb_ulpi_access;
}
+ pm_runtime_get_sync(musb->controller);
+
#ifndef CONFIG_MUSB_PIO_ONLY
if (use_dma && dev->dma_mask) {
struct dma_controller *c;
@@ -1961,11 +1982,11 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
if (is_host_enabled(musb)) {
struct usb_hcd *hcd = musb_to_hcd(musb);
- otg_set_host(musb->xceiv, &hcd->self);
+ otg_set_host(musb->xceiv->otg, &hcd->self);
if (is_otg_enabled(musb))
hcd->self.otg_port = 1;
- musb->xceiv->host = &hcd->self;
+ musb->xceiv->otg->host = &hcd->self;
hcd->power_budget = 2 * (plat->power ? : 250);
/* program PHY to use external vBus if required */
@@ -1984,10 +2005,10 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
struct usb_hcd *hcd = musb_to_hcd(musb);
MUSB_HST_MODE(musb);
- musb->xceiv->default_a = 1;
+ musb->xceiv->otg->default_a = 1;
musb->xceiv->state = OTG_STATE_A_IDLE;
- status = usb_add_hcd(musb_to_hcd(musb), -1, 0);
+ status = usb_add_hcd(musb_to_hcd(musb), 0, 0);
hcd->self.uses_pio_for_control = 1;
dev_dbg(musb->controller, "%s mode, status %d, devctl %02x %c\n",
@@ -1999,7 +2020,7 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
} else /* peripheral is enabled */ {
MUSB_DEV_MODE(musb);
- musb->xceiv->default_a = 0;
+ musb->xceiv->otg->default_a = 0;
musb->xceiv->state = OTG_STATE_B_IDLE;
status = musb_gadget_setup(musb);
@@ -2023,6 +2044,8 @@ musb_init_controller(struct device *dev, int nIrq, void __iomem *ctrl)
goto fail5;
#endif
+ pm_runtime_put(musb->controller);
+
dev_info(dev, "USB %s mode controller at %p using %s, IRQ %d\n",
({char *s;
switch (musb->board_mode) {
@@ -2047,6 +2070,9 @@ fail4:
musb_gadget_cleanup(musb);
fail3:
+ pm_runtime_put_sync(musb->controller);
+
+fail2:
if (musb->irq_wake)
device_init_wakeup(dev, 0);
musb_platform_exit(musb);
@@ -2073,7 +2099,7 @@ fail0:
static u64 *orig_dma_mask;
#endif
-static int __init musb_probe(struct platform_device *pdev)
+static int __devinit musb_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int irq = platform_get_irq_byname(pdev, "mc");
@@ -2102,7 +2128,7 @@ static int __init musb_probe(struct platform_device *pdev)
return status;
}
-static int __exit musb_remove(struct platform_device *pdev)
+static int __devexit musb_remove(struct platform_device *pdev)
{
struct musb *musb = dev_to_musb(&pdev->dev);
void __iomem *ctrl_base = musb->ctrl_base;
@@ -2112,11 +2138,9 @@ static int __exit musb_remove(struct platform_device *pdev)
* - Peripheral mode: peripheral is deactivated (or never-activated)
* - OTG mode: both roles are deactivated (or never-activated)
*/
- pm_runtime_get_sync(musb->controller);
musb_exit_debugfs(musb);
musb_shutdown(pdev);
- pm_runtime_put(musb->controller);
musb_free(musb);
iounmap(ctrl_base);
device_init_wakeup(&pdev->dev, 0);
@@ -2364,7 +2388,8 @@ static struct platform_driver musb_driver = {
.owner = THIS_MODULE,
.pm = MUSB_DEV_PM_OPS,
},
- .remove = __exit_p(musb_remove),
+ .probe = musb_probe,
+ .remove = __devexit_p(musb_remove),
.shutdown = musb_shutdown,
};
@@ -2380,13 +2405,9 @@ static int __init musb_init(void)
", "
"otg (peripheral+host)",
musb_driver_name);
- return platform_driver_probe(&musb_driver, musb_probe);
+ return platform_driver_register(&musb_driver);
}
-
-/* make us init after usbcore and i2c (transceivers, regulators, etc)
- * and before usb gadget and host-side drivers start to register
- */
-fs_initcall(musb_init);
+module_init(musb_init);
static void __exit musb_cleanup(void)
{
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index 3d28fb8a2dc9..93de517a32a0 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -372,7 +372,7 @@ struct musb {
u16 int_rx;
u16 int_tx;
- struct otg_transceiver *xceiv;
+ struct usb_phy *xceiv;
u8 xceiv_event;
int nIrq;
diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c
index 13d9af9bf920..40a37c91cc10 100644
--- a/drivers/usb/musb/musb_debugfs.c
+++ b/drivers/usb/musb/musb_debugfs.c
@@ -235,29 +235,29 @@ static const struct file_operations musb_test_mode_fops = {
.release = single_release,
};
-int __init musb_init_debugfs(struct musb *musb)
+int __devinit musb_init_debugfs(struct musb *musb)
{
struct dentry *root;
struct dentry *file;
int ret;
root = debugfs_create_dir("musb", NULL);
- if (IS_ERR(root)) {
- ret = PTR_ERR(root);
+ if (!root) {
+ ret = -ENOMEM;
goto err0;
}
file = debugfs_create_file("regdump", S_IRUGO, root, musb,
&musb_regdump_fops);
- if (IS_ERR(file)) {
- ret = PTR_ERR(file);
+ if (!file) {
+ ret = -ENOMEM;
goto err1;
}
file = debugfs_create_file("testmode", S_IRUGO | S_IWUSR,
root, musb, &musb_test_mode_fops);
- if (IS_ERR(file)) {
- ret = PTR_ERR(file);
+ if (!file) {
+ ret = -ENOMEM;
goto err1;
}
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index ac3d2eec20fe..f42c29b11f71 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -574,6 +574,15 @@ void musb_g_tx(struct musb *musb, u8 epnum)
if (request->actual == request->length) {
musb_g_giveback(musb_ep, request, 0);
+ /*
+ * In the giveback function the MUSB lock is
+ * released and acquired after sometime. During
+ * this time period the INDEX register could get
+ * changed by the gadget_queue function especially
+ * on SMP systems. Reselect the INDEX to be sure
+ * we are reading/modifying the right registers
+ */
+ musb_ep_select(mbase, epnum);
req = musb_ep->desc ? next_request(musb_ep) : NULL;
if (!req) {
dev_dbg(musb->controller, "%s idle now\n",
@@ -983,6 +992,15 @@ void musb_g_rx(struct musb *musb, u8 epnum)
}
#endif
musb_g_giveback(musb_ep, request, 0);
+ /*
+ * In the giveback function the MUSB lock is
+ * released and acquired after sometime. During
+ * this time period the INDEX register could get
+ * changed by the gadget_queue function especially
+ * on SMP systems. Reselect the INDEX to be sure
+ * we are reading/modifying the right registers
+ */
+ musb_ep_select(mbase, epnum);
req = next_request(musb_ep);
if (!req)
@@ -1624,7 +1642,7 @@ static int musb_gadget_wakeup(struct usb_gadget *gadget)
}
spin_unlock_irqrestore(&musb->lock, flags);
- otg_start_srp(musb->xceiv);
+ otg_start_srp(musb->xceiv->otg);
spin_lock_irqsave(&musb->lock, flags);
/* Block idling for at least 1s */
@@ -1703,7 +1721,7 @@ static int musb_gadget_vbus_draw(struct usb_gadget *gadget, unsigned mA)
if (!musb->xceiv->set_power)
return -EOPNOTSUPP;
- return otg_set_power(musb->xceiv, mA);
+ return usb_phy_set_power(musb->xceiv, mA);
}
static int musb_gadget_pullup(struct usb_gadget *gadget, int is_on)
@@ -1762,7 +1780,7 @@ static void musb_gadget_release(struct device *dev)
}
-static void __init
+static void __devinit
init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)
{
struct musb_hw_ep *hw_ep = musb->endpoints + epnum;
@@ -1799,7 +1817,7 @@ init_peripheral_ep(struct musb *musb, struct musb_ep *ep, u8 epnum, int is_in)
* Initialize the endpoints exposed to peripheral drivers, with backlinks
* to the rest of the driver state.
*/
-static inline void __init musb_g_init_endpoints(struct musb *musb)
+static inline void __devinit musb_g_init_endpoints(struct musb *musb)
{
u8 epnum;
struct musb_hw_ep *hw_ep;
@@ -1832,7 +1850,7 @@ static inline void __init musb_g_init_endpoints(struct musb *musb)
/* called once during driver setup to initialize and link into
* the driver model; memory is zeroed.
*/
-int __init musb_gadget_setup(struct musb *musb)
+int __devinit musb_gadget_setup(struct musb *musb)
{
int status;
@@ -1898,6 +1916,7 @@ static int musb_gadget_start(struct usb_gadget *g,
struct usb_gadget_driver *driver)
{
struct musb *musb = gadget_to_musb(g);
+ struct usb_otg *otg = musb->xceiv->otg;
unsigned long flags;
int retval = -EINVAL;
@@ -1914,7 +1933,7 @@ static int musb_gadget_start(struct usb_gadget *g,
spin_lock_irqsave(&musb->lock, flags);
musb->is_active = 1;
- otg_set_peripheral(musb->xceiv, &musb->g);
+ otg_set_peripheral(otg, &musb->g);
musb->xceiv->state = OTG_STATE_B_IDLE;
/*
@@ -1938,15 +1957,15 @@ static int musb_gadget_start(struct usb_gadget *g,
* handles power budgeting ... this way also
* ensures HdrcStart is indirectly called.
*/
- retval = usb_add_hcd(musb_to_hcd(musb), -1, 0);
+ retval = usb_add_hcd(musb_to_hcd(musb), 0, 0);
if (retval < 0) {
dev_dbg(musb->controller, "add_hcd failed, %d\n", retval);
goto err2;
}
if ((musb->xceiv->last_event == USB_EVENT_ID)
- && musb->xceiv->set_vbus)
- otg_set_vbus(musb->xceiv, 1);
+ && otg->set_vbus)
+ otg_set_vbus(otg, 1);
hcd->self.uses_pio_for_control = 1;
}
@@ -2028,7 +2047,7 @@ static int musb_gadget_stop(struct usb_gadget *g,
musb->xceiv->state = OTG_STATE_UNDEFINED;
stop_activity(musb, driver);
- otg_set_peripheral(musb->xceiv, NULL);
+ otg_set_peripheral(musb->xceiv->otg, NULL);
dev_dbg(musb->controller, "unregistering driver %s\n", driver->function);
diff --git a/drivers/usb/musb/musb_host.c b/drivers/usb/musb/musb_host.c
index 79cb0af779fa..ef8d744800ac 100644
--- a/drivers/usb/musb/musb_host.c
+++ b/drivers/usb/musb/musb_host.c
@@ -2098,7 +2098,7 @@ static int musb_cleanup_urb(struct urb *urb, struct musb_qh *qh)
}
/* turn off DMA requests, discard state, stop polling ... */
- if (is_in) {
+ if (ep->epnum && is_in) {
/* giveback saves bulk toggle */
csr = musb_h_flush_rxfifo(ep, 0);
diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
index e9f80adc45a4..22ec3e379980 100644
--- a/drivers/usb/musb/musb_virthub.c
+++ b/drivers/usb/musb/musb_virthub.c
@@ -47,6 +47,7 @@
static void musb_port_suspend(struct musb *musb, bool do_suspend)
{
+ struct usb_otg *otg = musb->xceiv->otg;
u8 power;
void __iomem *mbase = musb->mregs;
@@ -81,7 +82,7 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend)
case OTG_STATE_A_HOST:
musb->xceiv->state = OTG_STATE_A_SUSPEND;
musb->is_active = is_otg_enabled(musb)
- && musb->xceiv->host->b_hnp_enable;
+ && otg->host->b_hnp_enable;
if (musb->is_active)
mod_timer(&musb->otg_timer, jiffies
+ msecs_to_jiffies(
@@ -91,7 +92,7 @@ static void musb_port_suspend(struct musb *musb, bool do_suspend)
case OTG_STATE_B_HOST:
musb->xceiv->state = OTG_STATE_B_WAIT_ACON;
musb->is_active = is_otg_enabled(musb)
- && musb->xceiv->host->b_hnp_enable;
+ && otg->host->b_hnp_enable;
musb_platform_try_idle(musb, 0);
break;
default:
@@ -179,6 +180,8 @@ static void musb_port_reset(struct musb *musb, bool do_reset)
void musb_root_disconnect(struct musb *musb)
{
+ struct usb_otg *otg = musb->xceiv->otg;
+
musb->port1_status = USB_PORT_STAT_POWER
| (USB_PORT_STAT_C_CONNECTION << 16);
@@ -188,7 +191,7 @@ void musb_root_disconnect(struct musb *musb)
switch (musb->xceiv->state) {
case OTG_STATE_A_SUSPEND:
if (is_otg_enabled(musb)
- && musb->xceiv->host->b_hnp_enable) {
+ && otg->host->b_hnp_enable) {
musb->xceiv->state = OTG_STATE_A_PERIPHERAL;
musb->g.is_a_peripheral = 1;
break;
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index df719eae3b03..c7785e81254c 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -132,6 +132,7 @@ static void omap2430_musb_try_idle(struct musb *musb, unsigned long timeout)
static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
{
+ struct usb_otg *otg = musb->xceiv->otg;
u8 devctl;
unsigned long timeout = jiffies + msecs_to_jiffies(1000);
int ret = 1;
@@ -163,11 +164,11 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
}
}
- if (ret && musb->xceiv->set_vbus)
- otg_set_vbus(musb->xceiv, 1);
+ if (ret && otg->set_vbus)
+ otg_set_vbus(otg, 1);
} else {
musb->is_active = 1;
- musb->xceiv->default_a = 1;
+ otg->default_a = 1;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
devctl |= MUSB_DEVCTL_SESSION;
MUSB_HST_MODE(musb);
@@ -179,7 +180,7 @@ static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
* jumping right to B_IDLE...
*/
- musb->xceiv->default_a = 0;
+ otg->default_a = 0;
musb->xceiv->state = OTG_STATE_B_IDLE;
devctl &= ~MUSB_DEVCTL_SESSION;
@@ -246,7 +247,7 @@ static void musb_otg_notifier_work(struct work_struct *data_notifier_work)
if (!is_otg_enabled(musb) || musb->gadget_driver) {
pm_runtime_get_sync(musb->controller);
- otg_init(musb->xceiv);
+ usb_phy_init(musb->xceiv);
omap2430_musb_set_vbus(musb, 1);
}
break;
@@ -256,7 +257,7 @@ static void musb_otg_notifier_work(struct work_struct *data_notifier_work)
if (musb->gadget_driver)
pm_runtime_get_sync(musb->controller);
- otg_init(musb->xceiv);
+ usb_phy_init(musb->xceiv);
break;
case USB_EVENT_NONE:
@@ -269,10 +270,10 @@ static void musb_otg_notifier_work(struct work_struct *data_notifier_work)
}
if (data->interface_type == MUSB_INTERFACE_UTMI) {
- if (musb->xceiv->set_vbus)
- otg_set_vbus(musb->xceiv, 0);
+ if (musb->xceiv->otg->set_vbus)
+ otg_set_vbus(musb->xceiv->otg, 0);
}
- otg_shutdown(musb->xceiv);
+ usb_phy_shutdown(musb->xceiv);
break;
default:
dev_dbg(musb->controller, "ID float\n");
@@ -281,7 +282,8 @@ static void musb_otg_notifier_work(struct work_struct *data_notifier_work)
static int omap2430_musb_init(struct musb *musb)
{
- u32 l, status = 0;
+ u32 l;
+ int status = 0;
struct device *dev = musb->controller;
struct musb_hdrc_platform_data *plat = dev->platform_data;
struct omap_musb_board_data *data = plat->board_data;
@@ -290,7 +292,7 @@ static int omap2430_musb_init(struct musb *musb)
* up through ULPI. TWL4030-family PMICs include one,
* which needs a driver, drivers aren't always needed.
*/
- musb->xceiv = otg_get_transceiver();
+ musb->xceiv = usb_get_transceiver();
if (!musb->xceiv) {
pr_err("HS USB OTG: no transceiver configured\n");
return -ENODEV;
@@ -300,7 +302,7 @@ static int omap2430_musb_init(struct musb *musb)
status = pm_runtime_get_sync(dev);
if (status < 0) {
- dev_err(dev, "pm_runtime_get_sync FAILED");
+ dev_err(dev, "pm_runtime_get_sync FAILED %d\n", status);
goto err1;
}
@@ -325,13 +327,14 @@ static int omap2430_musb_init(struct musb *musb)
musb_readl(musb->mregs, OTG_SIMENABLE));
musb->nb.notifier_call = musb_otg_notifications;
- status = otg_register_notifier(musb->xceiv, &musb->nb);
+ status = usb_register_notifier(musb->xceiv, &musb->nb);
if (status)
dev_dbg(musb->controller, "notification register failed\n");
setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
+ pm_runtime_put_noidle(musb->controller);
return 0;
err1:
@@ -349,7 +352,7 @@ static void omap2430_musb_enable(struct musb *musb)
switch (musb->xceiv->last_event) {
case USB_EVENT_ID:
- otg_init(musb->xceiv);
+ usb_phy_init(musb->xceiv);
if (data->interface_type != MUSB_INTERFACE_UTMI)
break;
devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
@@ -368,7 +371,7 @@ static void omap2430_musb_enable(struct musb *musb)
break;
case USB_EVENT_VBUS:
- otg_init(musb->xceiv);
+ usb_phy_init(musb->xceiv);
break;
default:
@@ -379,7 +382,7 @@ static void omap2430_musb_enable(struct musb *musb)
static void omap2430_musb_disable(struct musb *musb)
{
if (musb->xceiv->last_event)
- otg_shutdown(musb->xceiv);
+ usb_phy_shutdown(musb->xceiv);
}
static int omap2430_musb_exit(struct musb *musb)
@@ -388,7 +391,7 @@ static int omap2430_musb_exit(struct musb *musb)
cancel_work_sync(&musb->otg_notifier_work);
omap2430_low_level_exit(musb);
- otg_put_transceiver(musb->xceiv);
+ usb_put_transceiver(musb->xceiv);
return 0;
}
@@ -408,7 +411,7 @@ static const struct musb_platform_ops omap2430_ops = {
static u64 omap2430_dmamask = DMA_BIT_MASK(32);
-static int __init omap2430_probe(struct platform_device *pdev)
+static int __devinit omap2430_probe(struct platform_device *pdev)
{
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
struct platform_device *musb;
@@ -451,14 +454,14 @@ static int __init omap2430_probe(struct platform_device *pdev)
goto err2;
}
+ pm_runtime_enable(&pdev->dev);
+
ret = platform_device_add(musb);
if (ret) {
dev_err(&pdev->dev, "failed to register musb device\n");
goto err2;
}
- pm_runtime_enable(&pdev->dev);
-
return 0;
err2:
@@ -471,13 +474,12 @@ err0:
return ret;
}
-static int __exit omap2430_remove(struct platform_device *pdev)
+static int __devexit omap2430_remove(struct platform_device *pdev)
{
struct omap2430_glue *glue = platform_get_drvdata(pdev);
platform_device_del(glue->musb);
platform_device_put(glue->musb);
- pm_runtime_put(&pdev->dev);
kfree(glue);
return 0;
@@ -490,11 +492,13 @@ static int omap2430_runtime_suspend(struct device *dev)
struct omap2430_glue *glue = dev_get_drvdata(dev);
struct musb *musb = glue_to_musb(glue);
- musb->context.otg_interfsel = musb_readl(musb->mregs,
- OTG_INTERFSEL);
+ if (musb) {
+ musb->context.otg_interfsel = musb_readl(musb->mregs,
+ OTG_INTERFSEL);
- omap2430_low_level_exit(musb);
- otg_set_suspend(musb->xceiv, 1);
+ omap2430_low_level_exit(musb);
+ usb_phy_set_suspend(musb->xceiv, 1);
+ }
return 0;
}
@@ -504,11 +508,13 @@ static int omap2430_runtime_resume(struct device *dev)
struct omap2430_glue *glue = dev_get_drvdata(dev);
struct musb *musb = glue_to_musb(glue);
- omap2430_low_level_init(musb);
- musb_writel(musb->mregs, OTG_INTERFSEL,
- musb->context.otg_interfsel);
+ if (musb) {
+ omap2430_low_level_init(musb);
+ musb_writel(musb->mregs, OTG_INTERFSEL,
+ musb->context.otg_interfsel);
- otg_set_suspend(musb->xceiv, 0);
+ usb_phy_set_suspend(musb->xceiv, 0);
+ }
return 0;
}
@@ -524,7 +530,8 @@ static struct dev_pm_ops omap2430_pm_ops = {
#endif
static struct platform_driver omap2430_driver = {
- .remove = __exit_p(omap2430_remove),
+ .probe = omap2430_probe,
+ .remove = __devexit_p(omap2430_remove),
.driver = {
.name = "musb-omap2430",
.pm = DEV_PM_OPS,
@@ -537,9 +544,9 @@ MODULE_LICENSE("GPL v2");
static int __init omap2430_init(void)
{
- return platform_driver_probe(&omap2430_driver, omap2430_probe);
+ return platform_driver_register(&omap2430_driver);
}
-subsys_initcall(omap2430_init);
+module_init(omap2430_init);
static void __exit omap2430_exit(void)
{
diff --git a/drivers/usb/musb/tusb6010.c b/drivers/usb/musb/tusb6010.c
index 1f405616e6cd..de1355946a83 100644
--- a/drivers/usb/musb/tusb6010.c
+++ b/drivers/usb/musb/tusb6010.c
@@ -277,7 +277,7 @@ static struct musb *the_musb;
* mode), or low power Default-B sessions, something else supplies power.
* Caller must take care of locking.
*/
-static int tusb_draw_power(struct otg_transceiver *x, unsigned mA)
+static int tusb_draw_power(struct usb_phy *x, unsigned mA)
{
struct musb *musb = the_musb;
void __iomem *tbase = musb->ctrl_base;
@@ -293,7 +293,7 @@ static int tusb_draw_power(struct otg_transceiver *x, unsigned mA)
* The actual current usage would be very board-specific. For now,
* it's simpler to just use an aggregate (also board-specific).
*/
- if (x->default_a || mA < (musb->min_power << 1))
+ if (x->otg->default_a || mA < (musb->min_power << 1))
mA = 0;
reg = musb_readl(tbase, TUSB_PRCM_MNGMT);
@@ -510,6 +510,7 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on)
void __iomem *tbase = musb->ctrl_base;
u32 conf, prcm, timer;
u8 devctl;
+ struct usb_otg *otg = musb->xceiv->otg;
/* HDRC controls CPEN, but beware current surges during device
* connect. They can trigger transient overcurrent conditions
@@ -522,7 +523,7 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on)
if (is_on) {
timer = OTG_TIMER_MS(OTG_TIME_A_WAIT_VRISE);
- musb->xceiv->default_a = 1;
+ otg->default_a = 1;
musb->xceiv->state = OTG_STATE_A_WAIT_VRISE;
devctl |= MUSB_DEVCTL_SESSION;
@@ -548,11 +549,11 @@ static void tusb_musb_set_vbus(struct musb *musb, int is_on)
musb->xceiv->state = OTG_STATE_A_IDLE;
}
musb->is_active = 0;
- musb->xceiv->default_a = 1;
+ otg->default_a = 1;
MUSB_HST_MODE(musb);
} else {
musb->is_active = 0;
- musb->xceiv->default_a = 0;
+ otg->default_a = 0;
musb->xceiv->state = OTG_STATE_B_IDLE;
MUSB_DEV_MODE(musb);
}
@@ -644,6 +645,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
{
u32 otg_stat = musb_readl(tbase, TUSB_DEV_OTG_STAT);
unsigned long idle_timeout = 0;
+ struct usb_otg *otg = musb->xceiv->otg;
/* ID pin */
if ((int_src & TUSB_INT_SRC_ID_STATUS_CHNG)) {
@@ -654,7 +656,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
else
default_a = is_host_enabled(musb);
dev_dbg(musb->controller, "Default-%c\n", default_a ? 'A' : 'B');
- musb->xceiv->default_a = default_a;
+ otg->default_a = default_a;
tusb_musb_set_vbus(musb, default_a);
/* Don't allow idling immediately */
@@ -666,7 +668,7 @@ tusb_otg_ints(struct musb *musb, u32 int_src, void __iomem *tbase)
if (int_src & TUSB_INT_SRC_VBUS_SENSE_CHNG) {
/* B-dev state machine: no vbus ~= disconnect */
- if ((is_otg_enabled(musb) && !musb->xceiv->default_a)
+ if ((is_otg_enabled(musb) && !otg->default_a)
|| !is_host_enabled(musb)) {
/* ? musb_root_disconnect(musb); */
musb->port1_status &=
@@ -1076,7 +1078,7 @@ static int tusb_musb_init(struct musb *musb)
int ret;
usb_nop_xceiv_register();
- musb->xceiv = otg_get_transceiver();
+ musb->xceiv = usb_get_transceiver();
if (!musb->xceiv)
return -ENODEV;
@@ -1128,7 +1130,7 @@ done:
if (sync)
iounmap(sync);
- otg_put_transceiver(musb->xceiv);
+ usb_put_transceiver(musb->xceiv);
usb_nop_xceiv_unregister();
}
return ret;
@@ -1144,7 +1146,7 @@ static int tusb_musb_exit(struct musb *musb)
iounmap(musb->sync_va);
- otg_put_transceiver(musb->xceiv);
+ usb_put_transceiver(musb->xceiv);
usb_nop_xceiv_unregister();
return 0;
}
@@ -1165,7 +1167,7 @@ static const struct musb_platform_ops tusb_ops = {
static u64 tusb_dmamask = DMA_BIT_MASK(32);
-static int __init tusb_probe(struct platform_device *pdev)
+static int __devinit tusb_probe(struct platform_device *pdev)
{
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
struct platform_device *musb;
@@ -1227,7 +1229,7 @@ err0:
return ret;
}
-static int __exit tusb_remove(struct platform_device *pdev)
+static int __devexit tusb_remove(struct platform_device *pdev)
{
struct tusb6010_glue *glue = platform_get_drvdata(pdev);
@@ -1239,7 +1241,8 @@ static int __exit tusb_remove(struct platform_device *pdev)
}
static struct platform_driver tusb_driver = {
- .remove = __exit_p(tusb_remove),
+ .probe = tusb_probe,
+ .remove = __devexit_p(tusb_remove),
.driver = {
.name = "musb-tusb",
},
@@ -1251,9 +1254,9 @@ MODULE_LICENSE("GPL v2");
static int __init tusb_init(void)
{
- return platform_driver_probe(&tusb_driver, tusb_probe);
+ return platform_driver_register(&tusb_driver);
}
-subsys_initcall(tusb_init);
+module_init(tusb_init);
static void __exit tusb_exit(void)
{
diff --git a/drivers/usb/musb/ux500.c b/drivers/usb/musb/ux500.c
index f7e04bf34a13..aa09dd417b94 100644
--- a/drivers/usb/musb/ux500.c
+++ b/drivers/usb/musb/ux500.c
@@ -37,7 +37,7 @@ struct ux500_glue {
static int ux500_musb_init(struct musb *musb)
{
- musb->xceiv = otg_get_transceiver();
+ musb->xceiv = usb_get_transceiver();
if (!musb->xceiv) {
pr_err("HS USB OTG: no transceiver configured\n");
return -ENODEV;
@@ -48,7 +48,7 @@ static int ux500_musb_init(struct musb *musb)
static int ux500_musb_exit(struct musb *musb)
{
- otg_put_transceiver(musb->xceiv);
+ usb_put_transceiver(musb->xceiv);
return 0;
}
@@ -58,7 +58,7 @@ static const struct musb_platform_ops ux500_ops = {
.exit = ux500_musb_exit,
};
-static int __init ux500_probe(struct platform_device *pdev)
+static int __devinit ux500_probe(struct platform_device *pdev)
{
struct musb_hdrc_platform_data *pdata = pdev->dev.platform_data;
struct platform_device *musb;
@@ -141,7 +141,7 @@ err0:
return ret;
}
-static int __exit ux500_remove(struct platform_device *pdev)
+static int __devexit ux500_remove(struct platform_device *pdev)
{
struct ux500_glue *glue = platform_get_drvdata(pdev);
@@ -160,7 +160,7 @@ static int ux500_suspend(struct device *dev)
struct ux500_glue *glue = dev_get_drvdata(dev);
struct musb *musb = glue_to_musb(glue);
- otg_set_suspend(musb->xceiv, 1);
+ usb_phy_set_suspend(musb->xceiv, 1);
clk_disable(glue->clk);
return 0;
@@ -178,7 +178,7 @@ static int ux500_resume(struct device *dev)
return ret;
}
- otg_set_suspend(musb->xceiv, 0);
+ usb_phy_set_suspend(musb->xceiv, 0);
return 0;
}
@@ -194,7 +194,8 @@ static const struct dev_pm_ops ux500_pm_ops = {
#endif
static struct platform_driver ux500_driver = {
- .remove = __exit_p(ux500_remove),
+ .probe = ux500_probe,
+ .remove = __devexit_p(ux500_remove),
.driver = {
.name = "musb-ux500",
.pm = DEV_PM_OPS,
@@ -207,9 +208,9 @@ MODULE_LICENSE("GPL v2");
static int __init ux500_init(void)
{
- return platform_driver_probe(&ux500_driver, ux500_probe);
+ return platform_driver_register(&ux500_driver);
}
-subsys_initcall(ux500_init);
+module_init(ux500_init);
static void __exit ux500_exit(void)
{
diff --git a/drivers/usb/musb/ux500_dma.c b/drivers/usb/musb/ux500_dma.c
index 97cb45916c43..d05c7fbbb703 100644
--- a/drivers/usb/musb/ux500_dma.c
+++ b/drivers/usb/musb/ux500_dma.c
@@ -115,12 +115,12 @@ static bool ux500_configure_channel(struct dma_channel *channel,
slave_conf.dst_addr = usb_fifo_addr;
slave_conf.dst_addr_width = addr_width;
slave_conf.dst_maxburst = 16;
+ slave_conf.device_fc = false;
dma_chan->device->device_control(dma_chan, DMA_SLAVE_CONFIG,
(unsigned long) &slave_conf);
- dma_desc = dma_chan->device->
- device_prep_slave_sg(dma_chan, &sg, 1, direction,
+ dma_desc = dmaengine_prep_slave_sg(dma_chan, &sg, 1, direction,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!dma_desc)
return false;
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
index 735ef4c2339a..5c87db06b598 100644
--- a/drivers/usb/otg/Kconfig
+++ b/drivers/usb/otg/Kconfig
@@ -23,7 +23,7 @@ config USB_GPIO_VBUS
select USB_OTG_UTILS
help
Provides simple GPIO VBUS sensing for controllers with an
- internal transceiver via the otg_transceiver interface, and
+ internal transceiver via the usb_phy interface, and
optionally control of a D+ pullup GPIO as well as a VBUS
current limit regulator.
diff --git a/drivers/usb/otg/ab8500-usb.c b/drivers/usb/otg/ab8500-usb.c
index 74fe6e62e0f7..a84af677dc59 100644
--- a/drivers/usb/otg/ab8500-usb.c
+++ b/drivers/usb/otg/ab8500-usb.c
@@ -68,7 +68,7 @@ enum ab8500_usb_link_status {
};
struct ab8500_usb {
- struct otg_transceiver otg;
+ struct usb_phy phy;
struct device *dev;
int irq_num_id_rise;
int irq_num_id_fall;
@@ -82,9 +82,9 @@ struct ab8500_usb {
int rev;
};
-static inline struct ab8500_usb *xceiv_to_ab(struct otg_transceiver *x)
+static inline struct ab8500_usb *phy_to_ab(struct usb_phy *x)
{
- return container_of(x, struct ab8500_usb, otg);
+ return container_of(x, struct ab8500_usb, phy);
}
static void ab8500_usb_wd_workaround(struct ab8500_usb *ab)
@@ -153,7 +153,7 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab)
u8 reg;
enum ab8500_usb_link_status lsts;
void *v = NULL;
- enum usb_xceiv_events event;
+ enum usb_phy_events event;
abx500_get_register_interruptible(ab->dev,
AB8500_USB,
@@ -169,8 +169,8 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab)
/* TODO: Disable regulators. */
ab8500_usb_host_phy_dis(ab);
ab8500_usb_peri_phy_dis(ab);
- ab->otg.state = OTG_STATE_B_IDLE;
- ab->otg.default_a = false;
+ ab->phy.state = OTG_STATE_B_IDLE;
+ ab->phy.otg->default_a = false;
ab->vbus_draw = 0;
event = USB_EVENT_NONE;
break;
@@ -181,22 +181,22 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab)
case USB_LINK_HOST_CHG_NM:
case USB_LINK_HOST_CHG_HS:
case USB_LINK_HOST_CHG_HS_CHIRP:
- if (ab->otg.gadget) {
+ if (ab->phy.otg->gadget) {
/* TODO: Enable regulators. */
ab8500_usb_peri_phy_en(ab);
- v = ab->otg.gadget;
+ v = ab->phy.otg->gadget;
}
event = USB_EVENT_VBUS;
break;
case USB_LINK_HM_IDGND:
- if (ab->otg.host) {
+ if (ab->phy.otg->host) {
/* TODO: Enable regulators. */
ab8500_usb_host_phy_en(ab);
- v = ab->otg.host;
+ v = ab->phy.otg->host;
}
- ab->otg.state = OTG_STATE_A_IDLE;
- ab->otg.default_a = true;
+ ab->phy.state = OTG_STATE_A_IDLE;
+ ab->phy.otg->default_a = true;
event = USB_EVENT_ID;
break;
@@ -212,7 +212,7 @@ static int ab8500_usb_link_status_update(struct ab8500_usb *ab)
break;
}
- atomic_notifier_call_chain(&ab->otg.notifier, event, v);
+ atomic_notifier_call_chain(&ab->phy.notifier, event, v);
return 0;
}
@@ -262,27 +262,27 @@ static void ab8500_usb_phy_disable_work(struct work_struct *work)
struct ab8500_usb *ab = container_of(work, struct ab8500_usb,
phy_dis_work);
- if (!ab->otg.host)
+ if (!ab->phy.otg->host)
ab8500_usb_host_phy_dis(ab);
- if (!ab->otg.gadget)
+ if (!ab->phy.otg->gadget)
ab8500_usb_peri_phy_dis(ab);
}
-static int ab8500_usb_set_power(struct otg_transceiver *otg, unsigned mA)
+static int ab8500_usb_set_power(struct usb_phy *phy, unsigned mA)
{
struct ab8500_usb *ab;
- if (!otg)
+ if (!phy)
return -ENODEV;
- ab = xceiv_to_ab(otg);
+ ab = phy_to_ab(phy);
ab->vbus_draw = mA;
if (mA)
- atomic_notifier_call_chain(&ab->otg.notifier,
- USB_EVENT_ENUMERATED, ab->otg.gadget);
+ atomic_notifier_call_chain(&ab->phy.notifier,
+ USB_EVENT_ENUMERATED, ab->phy.otg->gadget);
return 0;
}
@@ -290,21 +290,21 @@ static int ab8500_usb_set_power(struct otg_transceiver *otg, unsigned mA)
* ab->vbus_draw.
*/
-static int ab8500_usb_set_suspend(struct otg_transceiver *x, int suspend)
+static int ab8500_usb_set_suspend(struct usb_phy *x, int suspend)
{
/* TODO */
return 0;
}
-static int ab8500_usb_set_peripheral(struct otg_transceiver *otg,
- struct usb_gadget *gadget)
+static int ab8500_usb_set_peripheral(struct usb_otg *otg,
+ struct usb_gadget *gadget)
{
struct ab8500_usb *ab;
if (!otg)
return -ENODEV;
- ab = xceiv_to_ab(otg);
+ ab = phy_to_ab(otg->phy);
/* Some drivers call this function in atomic context.
* Do not update ab8500 registers directly till this
@@ -313,11 +313,11 @@ static int ab8500_usb_set_peripheral(struct otg_transceiver *otg,
if (!gadget) {
/* TODO: Disable regulators. */
- ab->otg.gadget = NULL;
+ otg->gadget = NULL;
schedule_work(&ab->phy_dis_work);
} else {
- ab->otg.gadget = gadget;
- ab->otg.state = OTG_STATE_B_IDLE;
+ otg->gadget = gadget;
+ otg->phy->state = OTG_STATE_B_IDLE;
/* Phy will not be enabled if cable is already
* plugged-in. Schedule to enable phy.
@@ -329,15 +329,14 @@ static int ab8500_usb_set_peripheral(struct otg_transceiver *otg,
return 0;
}
-static int ab8500_usb_set_host(struct otg_transceiver *otg,
- struct usb_bus *host)
+static int ab8500_usb_set_host(struct usb_otg *otg, struct usb_bus *host)
{
struct ab8500_usb *ab;
if (!otg)
return -ENODEV;
- ab = xceiv_to_ab(otg);
+ ab = phy_to_ab(otg->phy);
/* Some drivers call this function in atomic context.
* Do not update ab8500 registers directly till this
@@ -346,10 +345,10 @@ static int ab8500_usb_set_host(struct otg_transceiver *otg,
if (!host) {
/* TODO: Disable regulators. */
- ab->otg.host = NULL;
+ otg->host = NULL;
schedule_work(&ab->phy_dis_work);
} else {
- ab->otg.host = host;
+ otg->host = host;
/* Phy will not be enabled if cable is already
* plugged-in. Schedule to enable phy.
* Use same delay to avoid any race condition.
@@ -472,6 +471,7 @@ static int ab8500_usb_v2_res_setup(struct platform_device *pdev,
static int __devinit ab8500_usb_probe(struct platform_device *pdev)
{
struct ab8500_usb *ab;
+ struct usb_otg *otg;
int err;
int rev;
@@ -488,19 +488,28 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev)
if (!ab)
return -ENOMEM;
+ otg = kzalloc(sizeof *otg, GFP_KERNEL);
+ if (!otg) {
+ kfree(ab);
+ return -ENOMEM;
+ }
+
ab->dev = &pdev->dev;
ab->rev = rev;
- ab->otg.dev = ab->dev;
- ab->otg.label = "ab8500";
- ab->otg.state = OTG_STATE_UNDEFINED;
- ab->otg.set_host = ab8500_usb_set_host;
- ab->otg.set_peripheral = ab8500_usb_set_peripheral;
- ab->otg.set_suspend = ab8500_usb_set_suspend;
- ab->otg.set_power = ab8500_usb_set_power;
+ ab->phy.dev = ab->dev;
+ ab->phy.otg = otg;
+ ab->phy.label = "ab8500";
+ ab->phy.set_suspend = ab8500_usb_set_suspend;
+ ab->phy.set_power = ab8500_usb_set_power;
+ ab->phy.state = OTG_STATE_UNDEFINED;
+
+ otg->phy = &ab->phy;
+ otg->set_host = ab8500_usb_set_host;
+ otg->set_peripheral = ab8500_usb_set_peripheral;
platform_set_drvdata(pdev, ab);
- ATOMIC_INIT_NOTIFIER_HEAD(&ab->otg.notifier);
+ ATOMIC_INIT_NOTIFIER_HEAD(&ab->phy.notifier);
/* v1: Wait for link status to become stable.
* all: Updates form set_host and set_peripheral as they are atomic.
@@ -520,7 +529,7 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev)
if (err < 0)
goto fail0;
- err = otg_set_transceiver(&ab->otg);
+ err = usb_set_transceiver(&ab->phy);
if (err) {
dev_err(&pdev->dev, "Can't register transceiver\n");
goto fail1;
@@ -532,6 +541,7 @@ static int __devinit ab8500_usb_probe(struct platform_device *pdev)
fail1:
ab8500_usb_irq_free(ab);
fail0:
+ kfree(otg);
kfree(ab);
return err;
}
@@ -546,13 +556,14 @@ static int __devexit ab8500_usb_remove(struct platform_device *pdev)
cancel_work_sync(&ab->phy_dis_work);
- otg_set_transceiver(NULL);
+ usb_set_transceiver(NULL);
ab8500_usb_host_phy_dis(ab);
ab8500_usb_peri_phy_dis(ab);
platform_set_drvdata(pdev, NULL);
+ kfree(ab->phy.otg);
kfree(ab);
return 0;
diff --git a/drivers/usb/otg/fsl_otg.c b/drivers/usb/otg/fsl_otg.c
index a190850d2d3b..be4a63e8302f 100644
--- a/drivers/usb/otg/fsl_otg.c
+++ b/drivers/usb/otg/fsl_otg.c
@@ -275,7 +275,7 @@ void b_srp_end(unsigned long foo)
fsl_otg_dischrg_vbus(0);
srp_wait_done = 1;
- if ((fsl_otg_dev->otg.state == OTG_STATE_B_SRP_INIT) &&
+ if ((fsl_otg_dev->phy.state == OTG_STATE_B_SRP_INIT) &&
fsl_otg_dev->fsm.b_sess_vld)
fsl_otg_dev->fsm.b_srp_done = 1;
}
@@ -288,7 +288,7 @@ void b_srp_end(unsigned long foo)
void a_wait_enum(unsigned long foo)
{
VDBG("a_wait_enum timeout\n");
- if (!fsl_otg_dev->otg.host->b_hnp_enable)
+ if (!fsl_otg_dev->phy.otg->host->b_hnp_enable)
fsl_otg_add_timer(a_wait_enum_tmr);
else
otg_statemachine(&fsl_otg_dev->fsm);
@@ -452,14 +452,14 @@ void otg_reset_controller(void)
/* Call suspend/resume routines in host driver */
int fsl_otg_start_host(struct otg_fsm *fsm, int on)
{
- struct otg_transceiver *xceiv = fsm->transceiver;
+ struct usb_otg *otg = fsm->otg;
struct device *dev;
- struct fsl_otg *otg_dev = container_of(xceiv, struct fsl_otg, otg);
+ struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
u32 retval = 0;
- if (!xceiv->host)
+ if (!otg->host)
return -ENODEV;
- dev = xceiv->host->controller;
+ dev = otg->host->controller;
/*
* Update a_vbus_vld state as a_vbus_vld int is disabled
@@ -518,14 +518,14 @@ end:
*/
int fsl_otg_start_gadget(struct otg_fsm *fsm, int on)
{
- struct otg_transceiver *xceiv = fsm->transceiver;
+ struct usb_otg *otg = fsm->otg;
struct device *dev;
- if (!xceiv->gadget || !xceiv->gadget->dev.parent)
+ if (!otg->gadget || !otg->gadget->dev.parent)
return -ENODEV;
VDBG("gadget %s\n", on ? "on" : "off");
- dev = xceiv->gadget->dev.parent;
+ dev = otg->gadget->dev.parent;
if (on) {
if (dev->driver->resume)
@@ -542,14 +542,14 @@ int fsl_otg_start_gadget(struct otg_fsm *fsm, int on)
* Called by initialization code of host driver. Register host controller
* to the OTG. Suspend host for OTG role detection.
*/
-static int fsl_otg_set_host(struct otg_transceiver *otg_p, struct usb_bus *host)
+static int fsl_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
{
- struct fsl_otg *otg_dev = container_of(otg_p, struct fsl_otg, otg);
+ struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
- if (!otg_p || otg_dev != fsl_otg_dev)
+ if (!otg || otg_dev != fsl_otg_dev)
return -ENODEV;
- otg_p->host = host;
+ otg->host = host;
otg_dev->fsm.a_bus_drop = 0;
otg_dev->fsm.a_bus_req = 1;
@@ -557,8 +557,8 @@ static int fsl_otg_set_host(struct otg_transceiver *otg_p, struct usb_bus *host)
if (host) {
VDBG("host off......\n");
- otg_p->host->otg_port = fsl_otg_initdata.otg_port;
- otg_p->host->is_b_host = otg_dev->fsm.id;
+ otg->host->otg_port = fsl_otg_initdata.otg_port;
+ otg->host->is_b_host = otg_dev->fsm.id;
/*
* must leave time for khubd to finish its thing
* before yanking the host driver out from under it,
@@ -574,7 +574,7 @@ static int fsl_otg_set_host(struct otg_transceiver *otg_p, struct usb_bus *host)
/* Mini-A cable connected */
struct otg_fsm *fsm = &otg_dev->fsm;
- otg_p->state = OTG_STATE_UNDEFINED;
+ otg->phy->state = OTG_STATE_UNDEFINED;
fsm->protocol = PROTO_UNDEF;
}
}
@@ -587,29 +587,29 @@ static int fsl_otg_set_host(struct otg_transceiver *otg_p, struct usb_bus *host)
}
/* Called by initialization code of udc. Register udc to OTG. */
-static int fsl_otg_set_peripheral(struct otg_transceiver *otg_p,
- struct usb_gadget *gadget)
+static int fsl_otg_set_peripheral(struct usb_otg *otg,
+ struct usb_gadget *gadget)
{
- struct fsl_otg *otg_dev = container_of(otg_p, struct fsl_otg, otg);
+ struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
VDBG("otg_dev 0x%x\n", (int)otg_dev);
VDBG("fsl_otg_dev 0x%x\n", (int)fsl_otg_dev);
- if (!otg_p || otg_dev != fsl_otg_dev)
+ if (!otg || otg_dev != fsl_otg_dev)
return -ENODEV;
if (!gadget) {
- if (!otg_dev->otg.default_a)
- otg_p->gadget->ops->vbus_draw(otg_p->gadget, 0);
- usb_gadget_vbus_disconnect(otg_dev->otg.gadget);
- otg_dev->otg.gadget = 0;
+ if (!otg->default_a)
+ otg->gadget->ops->vbus_draw(otg->gadget, 0);
+ usb_gadget_vbus_disconnect(otg->gadget);
+ otg->gadget = 0;
otg_dev->fsm.b_bus_req = 0;
otg_statemachine(&otg_dev->fsm);
return 0;
}
- otg_p->gadget = gadget;
- otg_p->gadget->is_a_peripheral = !otg_dev->fsm.id;
+ otg->gadget = gadget;
+ otg->gadget->is_a_peripheral = !otg_dev->fsm.id;
otg_dev->fsm.b_bus_req = 1;
@@ -625,11 +625,11 @@ static int fsl_otg_set_peripheral(struct otg_transceiver *otg_p,
}
/* Set OTG port power, only for B-device */
-static int fsl_otg_set_power(struct otg_transceiver *otg_p, unsigned mA)
+static int fsl_otg_set_power(struct usb_phy *phy, unsigned mA)
{
if (!fsl_otg_dev)
return -ENODEV;
- if (otg_p->state == OTG_STATE_B_PERIPHERAL)
+ if (phy->state == OTG_STATE_B_PERIPHERAL)
pr_info("FSL OTG: Draw %d mA\n", mA);
return 0;
@@ -658,12 +658,12 @@ static void fsl_otg_event(struct work_struct *work)
}
/* B-device start SRP */
-static int fsl_otg_start_srp(struct otg_transceiver *otg_p)
+static int fsl_otg_start_srp(struct usb_otg *otg)
{
- struct fsl_otg *otg_dev = container_of(otg_p, struct fsl_otg, otg);
+ struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
- if (!otg_p || otg_dev != fsl_otg_dev
- || otg_p->state != OTG_STATE_B_IDLE)
+ if (!otg || otg_dev != fsl_otg_dev
+ || otg->phy->state != OTG_STATE_B_IDLE)
return -ENODEV;
otg_dev->fsm.b_bus_req = 1;
@@ -673,11 +673,11 @@ static int fsl_otg_start_srp(struct otg_transceiver *otg_p)
}
/* A_host suspend will call this function to start hnp */
-static int fsl_otg_start_hnp(struct otg_transceiver *otg_p)
+static int fsl_otg_start_hnp(struct usb_otg *otg)
{
- struct fsl_otg *otg_dev = container_of(otg_p, struct fsl_otg, otg);
+ struct fsl_otg *otg_dev = container_of(otg->phy, struct fsl_otg, phy);
- if (!otg_p || otg_dev != fsl_otg_dev)
+ if (!otg || otg_dev != fsl_otg_dev)
return -ENODEV;
DBG("start_hnp...n");
@@ -698,7 +698,7 @@ static int fsl_otg_start_hnp(struct otg_transceiver *otg_p)
irqreturn_t fsl_otg_isr(int irq, void *dev_id)
{
struct otg_fsm *fsm = &((struct fsl_otg *)dev_id)->fsm;
- struct otg_transceiver *otg = &((struct fsl_otg *)dev_id)->otg;
+ struct usb_otg *otg = ((struct fsl_otg *)dev_id)->phy.otg;
u32 otg_int_src, otg_sc;
otg_sc = fsl_readl(&usb_dr_regs->otgsc);
@@ -774,6 +774,12 @@ static int fsl_otg_conf(struct platform_device *pdev)
if (!fsl_otg_tc)
return -ENOMEM;
+ fsl_otg_tc->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
+ if (!fsl_otg_tc->phy.otg) {
+ kfree(fsl_otg_tc);
+ return -ENOMEM;
+ }
+
INIT_DELAYED_WORK(&fsl_otg_tc->otg_event, fsl_otg_event);
INIT_LIST_HEAD(&active_timers);
@@ -788,17 +794,19 @@ static int fsl_otg_conf(struct platform_device *pdev)
fsl_otg_tc->fsm.ops = &fsl_otg_ops;
/* initialize the otg structure */
- fsl_otg_tc->otg.label = DRIVER_DESC;
- fsl_otg_tc->otg.set_host = fsl_otg_set_host;
- fsl_otg_tc->otg.set_peripheral = fsl_otg_set_peripheral;
- fsl_otg_tc->otg.set_power = fsl_otg_set_power;
- fsl_otg_tc->otg.start_hnp = fsl_otg_start_hnp;
- fsl_otg_tc->otg.start_srp = fsl_otg_start_srp;
+ fsl_otg_tc->phy.label = DRIVER_DESC;
+ fsl_otg_tc->phy.set_power = fsl_otg_set_power;
+
+ fsl_otg_tc->phy.otg->phy = &fsl_otg_tc->phy;
+ fsl_otg_tc->phy.otg->set_host = fsl_otg_set_host;
+ fsl_otg_tc->phy.otg->set_peripheral = fsl_otg_set_peripheral;
+ fsl_otg_tc->phy.otg->start_hnp = fsl_otg_start_hnp;
+ fsl_otg_tc->phy.otg->start_srp = fsl_otg_start_srp;
fsl_otg_dev = fsl_otg_tc;
/* Store the otg transceiver */
- status = otg_set_transceiver(&fsl_otg_tc->otg);
+ status = usb_set_transceiver(&fsl_otg_tc->phy);
if (status) {
pr_warn(FSL_OTG_NAME ": unable to register OTG transceiver.\n");
goto err;
@@ -807,6 +815,7 @@ static int fsl_otg_conf(struct platform_device *pdev)
return 0;
err:
fsl_otg_uninit_timers();
+ kfree(fsl_otg_tc->phy.otg);
kfree(fsl_otg_tc);
return status;
}
@@ -815,19 +824,19 @@ err:
int usb_otg_start(struct platform_device *pdev)
{
struct fsl_otg *p_otg;
- struct otg_transceiver *otg_trans = otg_get_transceiver();
+ struct usb_phy *otg_trans = usb_get_transceiver();
struct otg_fsm *fsm;
int status;
struct resource *res;
u32 temp;
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
- p_otg = container_of(otg_trans, struct fsl_otg, otg);
+ p_otg = container_of(otg_trans, struct fsl_otg, phy);
fsm = &p_otg->fsm;
/* Initialize the state machine structure with default values */
SET_OTG_STATE(otg_trans, OTG_STATE_UNDEFINED);
- fsm->transceiver = &p_otg->otg;
+ fsm->otg = p_otg->phy.otg;
/* We don't require predefined MEM/IRQ resource index */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -857,9 +866,10 @@ int usb_otg_start(struct platform_device *pdev)
status = request_irq(p_otg->irq, fsl_otg_isr,
IRQF_SHARED, driver_name, p_otg);
if (status) {
- dev_dbg(p_otg->otg.dev, "can't get IRQ %d, error %d\n",
+ dev_dbg(p_otg->phy.dev, "can't get IRQ %d, error %d\n",
p_otg->irq, status);
iounmap(p_otg->dr_mem_map);
+ kfree(p_otg->phy.otg);
kfree(p_otg);
return status;
}
@@ -919,10 +929,10 @@ int usb_otg_start(struct platform_device *pdev)
* Also: record initial state of ID pin
*/
if (fsl_readl(&p_otg->dr_mem_map->otgsc) & OTGSC_STS_USB_ID) {
- p_otg->otg.state = OTG_STATE_UNDEFINED;
+ p_otg->phy.state = OTG_STATE_UNDEFINED;
p_otg->fsm.id = 1;
} else {
- p_otg->otg.state = OTG_STATE_A_IDLE;
+ p_otg->phy.state = OTG_STATE_A_IDLE;
p_otg->fsm.id = 0;
}
@@ -978,7 +988,7 @@ static int show_fsl_usb2_otg_state(struct device *dev,
/* State */
t = scnprintf(next, size,
"OTG state: %s\n\n",
- otg_state_string(fsl_otg_dev->otg.state));
+ otg_state_string(fsl_otg_dev->phy.state));
size -= t;
next += t;
@@ -1124,12 +1134,13 @@ static int __devexit fsl_otg_remove(struct platform_device *pdev)
{
struct fsl_usb2_platform_data *pdata = pdev->dev.platform_data;
- otg_set_transceiver(NULL);
+ usb_set_transceiver(NULL);
free_irq(fsl_otg_dev->irq, fsl_otg_dev);
iounmap((void *)usb_dr_regs);
fsl_otg_uninit_timers();
+ kfree(fsl_otg_dev->phy.otg);
kfree(fsl_otg_dev);
device_remove_file(&pdev->dev, &dev_attr_fsl_usb2_otg_state);
diff --git a/drivers/usb/otg/fsl_otg.h b/drivers/usb/otg/fsl_otg.h
index 3f8ef731aac9..ca266280895d 100644
--- a/drivers/usb/otg/fsl_otg.h
+++ b/drivers/usb/otg/fsl_otg.h
@@ -369,7 +369,7 @@ inline struct fsl_otg_timer *otg_timer_initializer
}
struct fsl_otg {
- struct otg_transceiver otg;
+ struct usb_phy phy;
struct otg_fsm fsm;
struct usb_dr_mmap *dr_mem_map;
struct delayed_work otg_event;
diff --git a/drivers/usb/otg/gpio_vbus.c b/drivers/usb/otg/gpio_vbus.c
index fb644c107ded..3ece43a2e4c1 100644
--- a/drivers/usb/otg/gpio_vbus.c
+++ b/drivers/usb/otg/gpio_vbus.c
@@ -32,7 +32,7 @@
* Needs to be loaded before the UDC driver that will use it.
*/
struct gpio_vbus_data {
- struct otg_transceiver otg;
+ struct usb_phy phy;
struct device *dev;
struct regulator *vbus_draw;
int vbus_draw_enabled;
@@ -98,7 +98,7 @@ static void gpio_vbus_work(struct work_struct *work)
struct gpio_vbus_mach_info *pdata = gpio_vbus->dev->platform_data;
int gpio;
- if (!gpio_vbus->otg.gadget)
+ if (!gpio_vbus->phy.otg->gadget)
return;
/* Peripheral controllers which manage the pullup themselves won't have
@@ -108,8 +108,8 @@ static void gpio_vbus_work(struct work_struct *work)
*/
gpio = pdata->gpio_pullup;
if (is_vbus_powered(pdata)) {
- gpio_vbus->otg.state = OTG_STATE_B_PERIPHERAL;
- usb_gadget_vbus_connect(gpio_vbus->otg.gadget);
+ gpio_vbus->phy.state = OTG_STATE_B_PERIPHERAL;
+ usb_gadget_vbus_connect(gpio_vbus->phy.otg->gadget);
/* drawing a "unit load" is *always* OK, except for OTG */
set_vbus_draw(gpio_vbus, 100);
@@ -124,8 +124,8 @@ static void gpio_vbus_work(struct work_struct *work)
set_vbus_draw(gpio_vbus, 0);
- usb_gadget_vbus_disconnect(gpio_vbus->otg.gadget);
- gpio_vbus->otg.state = OTG_STATE_B_IDLE;
+ usb_gadget_vbus_disconnect(gpio_vbus->phy.otg->gadget);
+ gpio_vbus->phy.state = OTG_STATE_B_IDLE;
}
}
@@ -135,12 +135,13 @@ static irqreturn_t gpio_vbus_irq(int irq, void *data)
struct platform_device *pdev = data;
struct gpio_vbus_mach_info *pdata = pdev->dev.platform_data;
struct gpio_vbus_data *gpio_vbus = platform_get_drvdata(pdev);
+ struct usb_otg *otg = gpio_vbus->phy.otg;
dev_dbg(&pdev->dev, "VBUS %s (gadget: %s)\n",
is_vbus_powered(pdata) ? "supplied" : "inactive",
- gpio_vbus->otg.gadget ? gpio_vbus->otg.gadget->name : "none");
+ otg->gadget ? otg->gadget->name : "none");
- if (gpio_vbus->otg.gadget)
+ if (otg->gadget)
schedule_work(&gpio_vbus->work);
return IRQ_HANDLED;
@@ -149,15 +150,15 @@ static irqreturn_t gpio_vbus_irq(int irq, void *data)
/* OTG transceiver interface */
/* bind/unbind the peripheral controller */
-static int gpio_vbus_set_peripheral(struct otg_transceiver *otg,
- struct usb_gadget *gadget)
+static int gpio_vbus_set_peripheral(struct usb_otg *otg,
+ struct usb_gadget *gadget)
{
struct gpio_vbus_data *gpio_vbus;
struct gpio_vbus_mach_info *pdata;
struct platform_device *pdev;
int gpio, irq;
- gpio_vbus = container_of(otg, struct gpio_vbus_data, otg);
+ gpio_vbus = container_of(otg->phy, struct gpio_vbus_data, phy);
pdev = to_platform_device(gpio_vbus->dev);
pdata = gpio_vbus->dev->platform_data;
irq = gpio_to_irq(pdata->gpio_vbus);
@@ -174,7 +175,7 @@ static int gpio_vbus_set_peripheral(struct otg_transceiver *otg,
set_vbus_draw(gpio_vbus, 0);
usb_gadget_vbus_disconnect(otg->gadget);
- otg->state = OTG_STATE_UNDEFINED;
+ otg->phy->state = OTG_STATE_UNDEFINED;
otg->gadget = NULL;
return 0;
@@ -189,23 +190,23 @@ static int gpio_vbus_set_peripheral(struct otg_transceiver *otg,
}
/* effective for B devices, ignored for A-peripheral */
-static int gpio_vbus_set_power(struct otg_transceiver *otg, unsigned mA)
+static int gpio_vbus_set_power(struct usb_phy *phy, unsigned mA)
{
struct gpio_vbus_data *gpio_vbus;
- gpio_vbus = container_of(otg, struct gpio_vbus_data, otg);
+ gpio_vbus = container_of(phy, struct gpio_vbus_data, phy);
- if (otg->state == OTG_STATE_B_PERIPHERAL)
+ if (phy->state == OTG_STATE_B_PERIPHERAL)
set_vbus_draw(gpio_vbus, mA);
return 0;
}
/* for non-OTG B devices: set/clear transceiver suspend mode */
-static int gpio_vbus_set_suspend(struct otg_transceiver *otg, int suspend)
+static int gpio_vbus_set_suspend(struct usb_phy *phy, int suspend)
{
struct gpio_vbus_data *gpio_vbus;
- gpio_vbus = container_of(otg, struct gpio_vbus_data, otg);
+ gpio_vbus = container_of(phy, struct gpio_vbus_data, phy);
/* draw max 0 mA from vbus in suspend mode; or the previously
* recorded amount of current if not suspended
@@ -213,7 +214,7 @@ static int gpio_vbus_set_suspend(struct otg_transceiver *otg, int suspend)
* NOTE: high powered configs (mA > 100) may draw up to 2.5 mA
* if they're wake-enabled ... we don't handle that yet.
*/
- return gpio_vbus_set_power(otg, suspend ? 0 : gpio_vbus->mA);
+ return gpio_vbus_set_power(phy, suspend ? 0 : gpio_vbus->mA);
}
/* platform driver interface */
@@ -233,13 +234,21 @@ static int __init gpio_vbus_probe(struct platform_device *pdev)
if (!gpio_vbus)
return -ENOMEM;
+ gpio_vbus->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
+ if (!gpio_vbus->phy.otg) {
+ kfree(gpio_vbus);
+ return -ENOMEM;
+ }
+
platform_set_drvdata(pdev, gpio_vbus);
gpio_vbus->dev = &pdev->dev;
- gpio_vbus->otg.label = "gpio-vbus";
- gpio_vbus->otg.state = OTG_STATE_UNDEFINED;
- gpio_vbus->otg.set_peripheral = gpio_vbus_set_peripheral;
- gpio_vbus->otg.set_power = gpio_vbus_set_power;
- gpio_vbus->otg.set_suspend = gpio_vbus_set_suspend;
+ gpio_vbus->phy.label = "gpio-vbus";
+ gpio_vbus->phy.set_power = gpio_vbus_set_power;
+ gpio_vbus->phy.set_suspend = gpio_vbus_set_suspend;
+ gpio_vbus->phy.state = OTG_STATE_UNDEFINED;
+
+ gpio_vbus->phy.otg->phy = &gpio_vbus->phy;
+ gpio_vbus->phy.otg->set_peripheral = gpio_vbus_set_peripheral;
err = gpio_request(gpio, "vbus_detect");
if (err) {
@@ -288,7 +297,7 @@ static int __init gpio_vbus_probe(struct platform_device *pdev)
}
/* only active when a gadget is registered */
- err = otg_set_transceiver(&gpio_vbus->otg);
+ err = usb_set_transceiver(&gpio_vbus->phy);
if (err) {
dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
err);
@@ -304,6 +313,7 @@ err_irq:
gpio_free(pdata->gpio_vbus);
err_gpio:
platform_set_drvdata(pdev, NULL);
+ kfree(gpio_vbus->phy.otg);
kfree(gpio_vbus);
return err;
}
@@ -316,13 +326,14 @@ static int __exit gpio_vbus_remove(struct platform_device *pdev)
regulator_put(gpio_vbus->vbus_draw);
- otg_set_transceiver(NULL);
+ usb_set_transceiver(NULL);
free_irq(gpio_to_irq(gpio), &pdev->dev);
if (gpio_is_valid(pdata->gpio_pullup))
gpio_free(pdata->gpio_pullup);
gpio_free(gpio);
platform_set_drvdata(pdev, NULL);
+ kfree(gpio_vbus->phy.otg);
kfree(gpio_vbus);
return 0;
diff --git a/drivers/usb/otg/isp1301_omap.c b/drivers/usb/otg/isp1301_omap.c
index 8c86787c2f09..70cf5d7bca48 100644
--- a/drivers/usb/otg/isp1301_omap.c
+++ b/drivers/usb/otg/isp1301_omap.c
@@ -52,7 +52,7 @@ MODULE_DESCRIPTION("ISP1301 USB OTG Transceiver Driver");
MODULE_LICENSE("GPL");
struct isp1301 {
- struct otg_transceiver otg;
+ struct usb_phy phy;
struct i2c_client *client;
void (*i2c_release)(struct device *dev);
@@ -236,7 +236,7 @@ isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits)
static inline const char *state_name(struct isp1301 *isp)
{
- return otg_state_string(isp->otg.state);
+ return otg_state_string(isp->phy.state);
}
/*-------------------------------------------------------------------------*/
@@ -251,7 +251,7 @@ static inline const char *state_name(struct isp1301 *isp)
static void power_down(struct isp1301 *isp)
{
- isp->otg.state = OTG_STATE_UNDEFINED;
+ isp->phy.state = OTG_STATE_UNDEFINED;
// isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_GLOBAL_PWR_DN);
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND);
@@ -280,13 +280,13 @@ static int host_suspend(struct isp1301 *isp)
#else
struct device *dev;
- if (!isp->otg.host)
+ if (!isp->phy.otg->host)
return -ENODEV;
/* Currently ASSUMES only the OTG port matters;
* other ports could be active...
*/
- dev = isp->otg.host->controller;
+ dev = isp->phy.otg->host->controller;
return dev->driver->suspend(dev, 3, 0);
#endif
}
@@ -298,20 +298,20 @@ static int host_resume(struct isp1301 *isp)
#else
struct device *dev;
- if (!isp->otg.host)
+ if (!isp->phy.otg->host)
return -ENODEV;
- dev = isp->otg.host->controller;
+ dev = isp->phy.otg->host->controller;
return dev->driver->resume(dev, 0);
#endif
}
static int gadget_suspend(struct isp1301 *isp)
{
- isp->otg.gadget->b_hnp_enable = 0;
- isp->otg.gadget->a_hnp_support = 0;
- isp->otg.gadget->a_alt_hnp_support = 0;
- return usb_gadget_vbus_disconnect(isp->otg.gadget);
+ isp->phy.otg->gadget->b_hnp_enable = 0;
+ isp->phy.otg->gadget->a_hnp_support = 0;
+ isp->phy.otg->gadget->a_alt_hnp_support = 0;
+ return usb_gadget_vbus_disconnect(isp->phy.otg->gadget);
}
/*-------------------------------------------------------------------------*/
@@ -341,19 +341,19 @@ static void a_idle(struct isp1301 *isp, const char *tag)
{
u32 l;
- if (isp->otg.state == OTG_STATE_A_IDLE)
+ if (isp->phy.state == OTG_STATE_A_IDLE)
return;
- isp->otg.default_a = 1;
- if (isp->otg.host) {
- isp->otg.host->is_b_host = 0;
+ isp->phy.otg->default_a = 1;
+ if (isp->phy.otg->host) {
+ isp->phy.otg->host->is_b_host = 0;
host_suspend(isp);
}
- if (isp->otg.gadget) {
- isp->otg.gadget->is_a_peripheral = 1;
+ if (isp->phy.otg->gadget) {
+ isp->phy.otg->gadget->is_a_peripheral = 1;
gadget_suspend(isp);
}
- isp->otg.state = OTG_STATE_A_IDLE;
+ isp->phy.state = OTG_STATE_A_IDLE;
l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS;
omap_writel(l, OTG_CTRL);
isp->last_otg_ctrl = l;
@@ -365,19 +365,19 @@ static void b_idle(struct isp1301 *isp, const char *tag)
{
u32 l;
- if (isp->otg.state == OTG_STATE_B_IDLE)
+ if (isp->phy.state == OTG_STATE_B_IDLE)
return;
- isp->otg.default_a = 0;
- if (isp->otg.host) {
- isp->otg.host->is_b_host = 1;
+ isp->phy.otg->default_a = 0;
+ if (isp->phy.otg->host) {
+ isp->phy.otg->host->is_b_host = 1;
host_suspend(isp);
}
- if (isp->otg.gadget) {
- isp->otg.gadget->is_a_peripheral = 0;
+ if (isp->phy.otg->gadget) {
+ isp->phy.otg->gadget->is_a_peripheral = 0;
gadget_suspend(isp);
}
- isp->otg.state = OTG_STATE_B_IDLE;
+ isp->phy.state = OTG_STATE_B_IDLE;
l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS;
omap_writel(l, OTG_CTRL);
isp->last_otg_ctrl = l;
@@ -478,7 +478,7 @@ static void check_state(struct isp1301 *isp, const char *tag)
default:
break;
}
- if (isp->otg.state == state && !extra)
+ if (isp->phy.state == state && !extra)
return;
pr_debug("otg: %s FSM %s/%02x, %s, %06x\n", tag,
otg_state_string(state), fsm, state_name(isp),
@@ -502,22 +502,23 @@ static void update_otg1(struct isp1301 *isp, u8 int_src)
if (int_src & INTR_SESS_VLD)
otg_ctrl |= OTG_ASESSVLD;
- else if (isp->otg.state == OTG_STATE_A_WAIT_VFALL) {
+ else if (isp->phy.state == OTG_STATE_A_WAIT_VFALL) {
a_idle(isp, "vfall");
otg_ctrl &= ~OTG_CTRL_BITS;
}
if (int_src & INTR_VBUS_VLD)
otg_ctrl |= OTG_VBUSVLD;
if (int_src & INTR_ID_GND) { /* default-A */
- if (isp->otg.state == OTG_STATE_B_IDLE
- || isp->otg.state == OTG_STATE_UNDEFINED) {
+ if (isp->phy.state == OTG_STATE_B_IDLE
+ || isp->phy.state
+ == OTG_STATE_UNDEFINED) {
a_idle(isp, "init");
return;
}
} else { /* default-B */
otg_ctrl |= OTG_ID;
- if (isp->otg.state == OTG_STATE_A_IDLE
- || isp->otg.state == OTG_STATE_UNDEFINED) {
+ if (isp->phy.state == OTG_STATE_A_IDLE
+ || isp->phy.state == OTG_STATE_UNDEFINED) {
b_idle(isp, "init");
return;
}
@@ -551,14 +552,14 @@ static void otg_update_isp(struct isp1301 *isp)
isp->last_otg_ctrl = otg_ctrl;
otg_ctrl = otg_ctrl & OTG_XCEIV_INPUTS;
- switch (isp->otg.state) {
+ switch (isp->phy.state) {
case OTG_STATE_B_IDLE:
case OTG_STATE_B_PERIPHERAL:
case OTG_STATE_B_SRP_INIT:
if (!(otg_ctrl & OTG_PULLUP)) {
// if (otg_ctrl & OTG_B_HNPEN) {
- if (isp->otg.gadget->b_hnp_enable) {
- isp->otg.state = OTG_STATE_B_WAIT_ACON;
+ if (isp->phy.otg->gadget->b_hnp_enable) {
+ isp->phy.state = OTG_STATE_B_WAIT_ACON;
pr_debug(" --> b_wait_acon\n");
}
goto pulldown;
@@ -585,10 +586,10 @@ pulldown:
else clr |= ISP; \
} while (0)
- if (!(isp->otg.host))
+ if (!(isp->phy.otg->host))
otg_ctrl &= ~OTG_DRV_VBUS;
- switch (isp->otg.state) {
+ switch (isp->phy.state) {
case OTG_STATE_A_SUSPEND:
if (otg_ctrl & OTG_DRV_VBUS) {
set |= OTG1_VBUS_DRV;
@@ -599,7 +600,7 @@ pulldown:
/* FALLTHROUGH */
case OTG_STATE_A_VBUS_ERR:
- isp->otg.state = OTG_STATE_A_WAIT_VFALL;
+ isp->phy.state = OTG_STATE_A_WAIT_VFALL;
pr_debug(" --> a_wait_vfall\n");
/* FALLTHROUGH */
case OTG_STATE_A_WAIT_VFALL:
@@ -608,7 +609,7 @@ pulldown:
break;
case OTG_STATE_A_IDLE:
if (otg_ctrl & OTG_DRV_VBUS) {
- isp->otg.state = OTG_STATE_A_WAIT_VRISE;
+ isp->phy.state = OTG_STATE_A_WAIT_VRISE;
pr_debug(" --> a_wait_vrise\n");
}
/* FALLTHROUGH */
@@ -628,17 +629,17 @@ pulldown:
if (otg_change & OTG_PULLUP) {
u32 l;
- switch (isp->otg.state) {
+ switch (isp->phy.state) {
case OTG_STATE_B_IDLE:
if (clr & OTG1_DP_PULLUP)
break;
- isp->otg.state = OTG_STATE_B_PERIPHERAL;
+ isp->phy.state = OTG_STATE_B_PERIPHERAL;
pr_debug(" --> b_peripheral\n");
break;
case OTG_STATE_A_SUSPEND:
if (clr & OTG1_DP_PULLUP)
break;
- isp->otg.state = OTG_STATE_A_PERIPHERAL;
+ isp->phy.state = OTG_STATE_A_PERIPHERAL;
pr_debug(" --> a_peripheral\n");
break;
default:
@@ -659,6 +660,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
u32 otg_ctrl;
int ret = IRQ_NONE;
struct isp1301 *isp = _isp;
+ struct usb_otg *otg = isp->phy.otg;
/* update ISP1301 transceiver from OTG controller */
if (otg_irq & OPRT_CHG) {
@@ -675,7 +677,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
* remote wakeup (SRP, normal) using their own timer
* to give "check cable and A-device" messages.
*/
- if (isp->otg.state == OTG_STATE_B_SRP_INIT)
+ if (isp->phy.state == OTG_STATE_B_SRP_INIT)
b_idle(isp, "srp_timeout");
omap_writew(B_SRP_TMROUT, OTG_IRQ_SRC);
@@ -693,7 +695,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
omap_writel(otg_ctrl, OTG_CTRL);
/* subset of b_peripheral()... */
- isp->otg.state = OTG_STATE_B_PERIPHERAL;
+ isp->phy.state = OTG_STATE_B_PERIPHERAL;
pr_debug(" --> b_peripheral\n");
omap_writew(B_HNP_FAIL, OTG_IRQ_SRC);
@@ -705,9 +707,9 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
state_name(isp), omap_readl(OTG_CTRL));
isp1301_defer_work(isp, WORK_UPDATE_OTG);
- switch (isp->otg.state) {
+ switch (isp->phy.state) {
case OTG_STATE_A_IDLE:
- if (!isp->otg.host)
+ if (!otg->host)
break;
isp1301_defer_work(isp, WORK_HOST_RESUME);
otg_ctrl = omap_readl(OTG_CTRL);
@@ -736,7 +738,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
otg_ctrl |= OTG_BUSDROP;
otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
omap_writel(otg_ctrl, OTG_CTRL);
- isp->otg.state = OTG_STATE_A_WAIT_VFALL;
+ isp->phy.state = OTG_STATE_A_WAIT_VFALL;
omap_writew(A_REQ_TMROUT, OTG_IRQ_SRC);
ret = IRQ_HANDLED;
@@ -750,7 +752,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
otg_ctrl |= OTG_BUSDROP;
otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK & ~OTG_XCEIV_INPUTS;
omap_writel(otg_ctrl, OTG_CTRL);
- isp->otg.state = OTG_STATE_A_VBUS_ERR;
+ isp->phy.state = OTG_STATE_A_VBUS_ERR;
omap_writew(A_VBUS_ERR, OTG_IRQ_SRC);
ret = IRQ_HANDLED;
@@ -771,7 +773,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
/* role is peripheral */
if (otg_ctrl & OTG_DRIVER_SEL) {
- switch (isp->otg.state) {
+ switch (isp->phy.state) {
case OTG_STATE_A_IDLE:
b_idle(isp, __func__);
break;
@@ -787,19 +789,19 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
omap_writel(otg_ctrl | OTG_A_BUSREQ, OTG_CTRL);
}
- if (isp->otg.host) {
- switch (isp->otg.state) {
+ if (otg->host) {
+ switch (isp->phy.state) {
case OTG_STATE_B_WAIT_ACON:
- isp->otg.state = OTG_STATE_B_HOST;
+ isp->phy.state = OTG_STATE_B_HOST;
pr_debug(" --> b_host\n");
kick = 1;
break;
case OTG_STATE_A_WAIT_BCON:
- isp->otg.state = OTG_STATE_A_HOST;
+ isp->phy.state = OTG_STATE_A_HOST;
pr_debug(" --> a_host\n");
break;
case OTG_STATE_A_PERIPHERAL:
- isp->otg.state = OTG_STATE_A_WAIT_BCON;
+ isp->phy.state = OTG_STATE_A_WAIT_BCON;
pr_debug(" --> a_wait_bcon\n");
break;
default:
@@ -813,8 +815,7 @@ static irqreturn_t omap_otg_irq(int irq, void *_isp)
ret = IRQ_HANDLED;
if (kick)
- usb_bus_start_enum(isp->otg.host,
- isp->otg.host->otg_port);
+ usb_bus_start_enum(otg->host, otg->host->otg_port);
}
check_state(isp, __func__);
@@ -930,7 +931,7 @@ static void b_peripheral(struct isp1301 *isp)
l = omap_readl(OTG_CTRL) & OTG_XCEIV_OUTPUTS;
omap_writel(l, OTG_CTRL);
- usb_gadget_vbus_connect(isp->otg.gadget);
+ usb_gadget_vbus_connect(isp->phy.otg->gadget);
#ifdef CONFIG_USB_OTG
enable_vbus_draw(isp, 8);
@@ -940,7 +941,7 @@ static void b_peripheral(struct isp1301 *isp)
/* UDC driver just set OTG_BSESSVLD */
isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLUP);
isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_DP_PULLDOWN);
- isp->otg.state = OTG_STATE_B_PERIPHERAL;
+ isp->phy.state = OTG_STATE_B_PERIPHERAL;
pr_debug(" --> b_peripheral\n");
dump_regs(isp, "2periph");
#endif
@@ -948,8 +949,9 @@ static void b_peripheral(struct isp1301 *isp)
static void isp_update_otg(struct isp1301 *isp, u8 stat)
{
+ struct usb_otg *otg = isp->phy.otg;
u8 isp_stat, isp_bstat;
- enum usb_otg_state state = isp->otg.state;
+ enum usb_otg_state state = isp->phy.state;
if (stat & INTR_BDIS_ACON)
pr_debug("OTG: BDIS_ACON, %s\n", state_name(isp));
@@ -957,7 +959,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
/* start certain state transitions right away */
isp_stat = isp1301_get_u8(isp, ISP1301_INTERRUPT_SOURCE);
if (isp_stat & INTR_ID_GND) {
- if (isp->otg.default_a) {
+ if (otg->default_a) {
switch (state) {
case OTG_STATE_B_IDLE:
a_idle(isp, "idle");
@@ -972,7 +974,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
* when HNP is used.
*/
if (isp_stat & INTR_VBUS_VLD)
- isp->otg.state = OTG_STATE_A_HOST;
+ isp->phy.state = OTG_STATE_A_HOST;
break;
case OTG_STATE_A_WAIT_VFALL:
if (!(isp_stat & INTR_SESS_VLD))
@@ -980,7 +982,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
break;
default:
if (!(isp_stat & INTR_VBUS_VLD))
- isp->otg.state = OTG_STATE_A_VBUS_ERR;
+ isp->phy.state = OTG_STATE_A_VBUS_ERR;
break;
}
isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS);
@@ -989,14 +991,14 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
case OTG_STATE_B_PERIPHERAL:
case OTG_STATE_B_HOST:
case OTG_STATE_B_WAIT_ACON:
- usb_gadget_vbus_disconnect(isp->otg.gadget);
+ usb_gadget_vbus_disconnect(otg->gadget);
break;
default:
break;
}
if (state != OTG_STATE_A_IDLE)
a_idle(isp, "id");
- if (isp->otg.host && state == OTG_STATE_A_IDLE)
+ if (otg->host && state == OTG_STATE_A_IDLE)
isp1301_defer_work(isp, WORK_HOST_RESUME);
isp_bstat = 0;
}
@@ -1006,10 +1008,10 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
/* if user unplugged mini-A end of cable,
* don't bypass A_WAIT_VFALL.
*/
- if (isp->otg.default_a) {
+ if (otg->default_a) {
switch (state) {
default:
- isp->otg.state = OTG_STATE_A_WAIT_VFALL;
+ isp->phy.state = OTG_STATE_A_WAIT_VFALL;
break;
case OTG_STATE_A_WAIT_VFALL:
state = OTG_STATE_A_IDLE;
@@ -1022,7 +1024,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
host_suspend(isp);
isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1,
MC1_BDIS_ACON_EN);
- isp->otg.state = OTG_STATE_B_IDLE;
+ isp->phy.state = OTG_STATE_B_IDLE;
l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK;
l &= ~OTG_CTRL_BITS;
omap_writel(l, OTG_CTRL);
@@ -1033,7 +1035,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
}
isp_bstat = isp1301_get_u8(isp, ISP1301_OTG_STATUS);
- switch (isp->otg.state) {
+ switch (isp->phy.state) {
case OTG_STATE_B_PERIPHERAL:
case OTG_STATE_B_WAIT_ACON:
case OTG_STATE_B_HOST:
@@ -1055,7 +1057,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
omap_writel(l, OTG_CTRL);
/* FALLTHROUGH */
case OTG_STATE_B_IDLE:
- if (isp->otg.gadget && (isp_bstat & OTG_B_SESS_VLD)) {
+ if (otg->gadget && (isp_bstat & OTG_B_SESS_VLD)) {
#ifdef CONFIG_USB_OTG
update_otg1(isp, isp_stat);
update_otg2(isp, isp_bstat);
@@ -1073,7 +1075,7 @@ static void isp_update_otg(struct isp1301 *isp, u8 stat)
}
}
- if (state != isp->otg.state)
+ if (state != isp->phy.state)
pr_debug(" isp, %s -> %s\n",
otg_state_string(state), state_name(isp));
@@ -1131,10 +1133,10 @@ isp1301_work(struct work_struct *work)
* skip A_WAIT_VRISE; hc transitions invisibly
* skip A_WAIT_BCON; same.
*/
- switch (isp->otg.state) {
+ switch (isp->phy.state) {
case OTG_STATE_A_WAIT_BCON:
case OTG_STATE_A_WAIT_VRISE:
- isp->otg.state = OTG_STATE_A_HOST;
+ isp->phy.state = OTG_STATE_A_HOST;
pr_debug(" --> a_host\n");
otg_ctrl = omap_readl(OTG_CTRL);
otg_ctrl |= OTG_A_BUSREQ;
@@ -1143,7 +1145,7 @@ isp1301_work(struct work_struct *work)
omap_writel(otg_ctrl, OTG_CTRL);
break;
case OTG_STATE_B_WAIT_ACON:
- isp->otg.state = OTG_STATE_B_HOST;
+ isp->phy.state = OTG_STATE_B_HOST;
pr_debug(" --> b_host (acon)\n");
break;
case OTG_STATE_B_HOST:
@@ -1204,6 +1206,7 @@ static void isp1301_release(struct device *dev)
/* ugly -- i2c hijacks our memory hook to wait_for_completion() */
if (isp->i2c_release)
isp->i2c_release(dev);
+ kfree(isp->phy.otg);
kfree (isp);
}
@@ -1274,9 +1277,9 @@ static int isp1301_otg_enable(struct isp1301 *isp)
/* add or disable the host device+driver */
static int
-isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
+isp1301_set_host(struct usb_otg *otg, struct usb_bus *host)
{
- struct isp1301 *isp = container_of(otg, struct isp1301, otg);
+ struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy);
if (!otg || isp != the_transceiver)
return -ENODEV;
@@ -1284,21 +1287,21 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
if (!host) {
omap_writew(0, OTG_IRQ_EN);
power_down(isp);
- isp->otg.host = NULL;
+ otg->host = NULL;
return 0;
}
#ifdef CONFIG_USB_OTG
- isp->otg.host = host;
+ otg->host = host;
dev_dbg(&isp->client->dev, "registered host\n");
host_suspend(isp);
- if (isp->otg.gadget)
+ if (otg->gadget)
return isp1301_otg_enable(isp);
return 0;
#elif !defined(CONFIG_USB_GADGET_OMAP)
// FIXME update its refcount
- isp->otg.host = host;
+ otg->host = host;
power_up(isp);
@@ -1330,9 +1333,9 @@ isp1301_set_host(struct otg_transceiver *otg, struct usb_bus *host)
}
static int
-isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
+isp1301_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
{
- struct isp1301 *isp = container_of(otg, struct isp1301, otg);
+ struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy);
#ifndef CONFIG_USB_OTG
u32 l;
#endif
@@ -1342,24 +1345,24 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
if (!gadget) {
omap_writew(0, OTG_IRQ_EN);
- if (!isp->otg.default_a)
+ if (!otg->default_a)
enable_vbus_draw(isp, 0);
- usb_gadget_vbus_disconnect(isp->otg.gadget);
- isp->otg.gadget = NULL;
+ usb_gadget_vbus_disconnect(otg->gadget);
+ otg->gadget = NULL;
power_down(isp);
return 0;
}
#ifdef CONFIG_USB_OTG
- isp->otg.gadget = gadget;
+ otg->gadget = gadget;
dev_dbg(&isp->client->dev, "registered gadget\n");
/* gadget driver may be suspended until vbus_connect () */
- if (isp->otg.host)
+ if (otg->host)
return isp1301_otg_enable(isp);
return 0;
#elif !defined(CONFIG_USB_OHCI_HCD) && !defined(CONFIG_USB_OHCI_HCD_MODULE)
- isp->otg.gadget = gadget;
+ otg->gadget = gadget;
// FIXME update its refcount
l = omap_readl(OTG_CTRL) & OTG_CTRL_MASK;
@@ -1368,7 +1371,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
omap_writel(l, OTG_CTRL);
power_up(isp);
- isp->otg.state = OTG_STATE_B_IDLE;
+ isp->phy.state = OTG_STATE_B_IDLE;
if (machine_is_omap_h2() || machine_is_omap_h3())
isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
@@ -1399,7 +1402,7 @@ isp1301_set_peripheral(struct otg_transceiver *otg, struct usb_gadget *gadget)
/*-------------------------------------------------------------------------*/
static int
-isp1301_set_power(struct otg_transceiver *dev, unsigned mA)
+isp1301_set_power(struct usb_phy *dev, unsigned mA)
{
if (!the_transceiver)
return -ENODEV;
@@ -1409,13 +1412,13 @@ isp1301_set_power(struct otg_transceiver *dev, unsigned mA)
}
static int
-isp1301_start_srp(struct otg_transceiver *dev)
+isp1301_start_srp(struct usb_otg *otg)
{
- struct isp1301 *isp = container_of(dev, struct isp1301, otg);
+ struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy);
u32 otg_ctrl;
- if (!dev || isp != the_transceiver
- || isp->otg.state != OTG_STATE_B_IDLE)
+ if (!otg || isp != the_transceiver
+ || isp->phy.state != OTG_STATE_B_IDLE)
return -ENODEV;
otg_ctrl = omap_readl(OTG_CTRL);
@@ -1425,7 +1428,7 @@ isp1301_start_srp(struct otg_transceiver *dev)
otg_ctrl |= OTG_B_BUSREQ;
otg_ctrl &= ~OTG_A_BUSREQ & OTG_CTRL_MASK;
omap_writel(otg_ctrl, OTG_CTRL);
- isp->otg.state = OTG_STATE_B_SRP_INIT;
+ isp->phy.state = OTG_STATE_B_SRP_INIT;
pr_debug("otg: SRP, %s ... %06x\n", state_name(isp),
omap_readl(OTG_CTRL));
@@ -1436,27 +1439,26 @@ isp1301_start_srp(struct otg_transceiver *dev)
}
static int
-isp1301_start_hnp(struct otg_transceiver *dev)
+isp1301_start_hnp(struct usb_otg *otg)
{
#ifdef CONFIG_USB_OTG
- struct isp1301 *isp = container_of(dev, struct isp1301, otg);
+ struct isp1301 *isp = container_of(otg->phy, struct isp1301, phy);
u32 l;
- if (!dev || isp != the_transceiver)
+ if (!otg || isp != the_transceiver)
return -ENODEV;
- if (isp->otg.default_a && (isp->otg.host == NULL
- || !isp->otg.host->b_hnp_enable))
+ if (otg->default_a && (otg->host == NULL || !otg->host->b_hnp_enable))
return -ENOTCONN;
- if (!isp->otg.default_a && (isp->otg.gadget == NULL
- || !isp->otg.gadget->b_hnp_enable))
+ if (!otg->default_a && (otg->gadget == NULL
+ || !otg->gadget->b_hnp_enable))
return -ENOTCONN;
/* We want hardware to manage most HNP protocol timings.
* So do this part as early as possible...
*/
- switch (isp->otg.state) {
+ switch (isp->phy.state) {
case OTG_STATE_B_HOST:
- isp->otg.state = OTG_STATE_B_PERIPHERAL;
+ isp->phy.state = OTG_STATE_B_PERIPHERAL;
/* caller will suspend next */
break;
case OTG_STATE_A_HOST:
@@ -1466,7 +1468,7 @@ isp1301_start_hnp(struct otg_transceiver *dev)
MC1_BDIS_ACON_EN);
#endif
/* caller must suspend then clear A_BUSREQ */
- usb_gadget_vbus_connect(isp->otg.gadget);
+ usb_gadget_vbus_connect(otg->gadget);
l = omap_readl(OTG_CTRL);
l |= OTG_A_SETB_HNPEN;
omap_writel(l, OTG_CTRL);
@@ -1503,6 +1505,12 @@ isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
if (!isp)
return 0;
+ isp->phy.otg = kzalloc(sizeof *isp->phy.otg, GFP_KERNEL);
+ if (!isp->phy.otg) {
+ kfree(isp);
+ return 0;
+ }
+
INIT_WORK(&isp->work, isp1301_work);
init_timer(&isp->timer);
isp->timer.function = isp1301_timer;
@@ -1576,14 +1584,15 @@ isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
goto fail;
}
- isp->otg.dev = &i2c->dev;
- isp->otg.label = DRIVER_NAME;
+ isp->phy.dev = &i2c->dev;
+ isp->phy.label = DRIVER_NAME;
+ isp->phy.set_power = isp1301_set_power,
- isp->otg.set_host = isp1301_set_host,
- isp->otg.set_peripheral = isp1301_set_peripheral,
- isp->otg.set_power = isp1301_set_power,
- isp->otg.start_srp = isp1301_start_srp,
- isp->otg.start_hnp = isp1301_start_hnp,
+ isp->phy.otg->phy = &isp->phy;
+ isp->phy.otg->set_host = isp1301_set_host,
+ isp->phy.otg->set_peripheral = isp1301_set_peripheral,
+ isp->phy.otg->start_srp = isp1301_start_srp,
+ isp->phy.otg->start_hnp = isp1301_start_hnp,
enable_vbus_draw(isp, 0);
power_down(isp);
@@ -1601,7 +1610,7 @@ isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
dev_dbg(&i2c->dev, "scheduled timer, %d min\n", TIMER_MINUTES);
#endif
- status = otg_set_transceiver(&isp->otg);
+ status = usb_set_transceiver(&isp->phy);
if (status < 0)
dev_err(&i2c->dev, "can't register transceiver, %d\n",
status);
@@ -1609,6 +1618,7 @@ isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
return 0;
fail:
+ kfree(isp->phy.otg);
kfree(isp);
return -ENODEV;
}
@@ -1639,7 +1649,7 @@ subsys_initcall(isp_init);
static void __exit isp_exit(void)
{
if (the_transceiver)
- otg_set_transceiver(NULL);
+ usb_set_transceiver(NULL);
i2c_del_driver(&isp1301_driver);
}
module_exit(isp_exit);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index b276f8fcdeba..1d0347c247d1 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -69,9 +69,9 @@ static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init)
int ret = 0;
if (init) {
- hsusb_vddcx = regulator_get(motg->otg.dev, "HSUSB_VDDCX");
+ hsusb_vddcx = regulator_get(motg->phy.dev, "HSUSB_VDDCX");
if (IS_ERR(hsusb_vddcx)) {
- dev_err(motg->otg.dev, "unable to get hsusb vddcx\n");
+ dev_err(motg->phy.dev, "unable to get hsusb vddcx\n");
return PTR_ERR(hsusb_vddcx);
}
@@ -79,7 +79,7 @@ static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init)
USB_PHY_VDD_DIG_VOL_MIN,
USB_PHY_VDD_DIG_VOL_MAX);
if (ret) {
- dev_err(motg->otg.dev, "unable to set the voltage "
+ dev_err(motg->phy.dev, "unable to set the voltage "
"for hsusb vddcx\n");
regulator_put(hsusb_vddcx);
return ret;
@@ -87,18 +87,18 @@ static int msm_hsusb_init_vddcx(struct msm_otg *motg, int init)
ret = regulator_enable(hsusb_vddcx);
if (ret) {
- dev_err(motg->otg.dev, "unable to enable hsusb vddcx\n");
+ dev_err(motg->phy.dev, "unable to enable hsusb vddcx\n");
regulator_put(hsusb_vddcx);
}
} else {
ret = regulator_set_voltage(hsusb_vddcx, 0,
USB_PHY_VDD_DIG_VOL_MAX);
if (ret)
- dev_err(motg->otg.dev, "unable to set the voltage "
+ dev_err(motg->phy.dev, "unable to set the voltage "
"for hsusb vddcx\n");
ret = regulator_disable(hsusb_vddcx);
if (ret)
- dev_err(motg->otg.dev, "unable to disable hsusb vddcx\n");
+ dev_err(motg->phy.dev, "unable to disable hsusb vddcx\n");
regulator_put(hsusb_vddcx);
}
@@ -111,40 +111,40 @@ static int msm_hsusb_ldo_init(struct msm_otg *motg, int init)
int rc = 0;
if (init) {
- hsusb_3p3 = regulator_get(motg->otg.dev, "HSUSB_3p3");
+ hsusb_3p3 = regulator_get(motg->phy.dev, "HSUSB_3p3");
if (IS_ERR(hsusb_3p3)) {
- dev_err(motg->otg.dev, "unable to get hsusb 3p3\n");
+ dev_err(motg->phy.dev, "unable to get hsusb 3p3\n");
return PTR_ERR(hsusb_3p3);
}
rc = regulator_set_voltage(hsusb_3p3, USB_PHY_3P3_VOL_MIN,
USB_PHY_3P3_VOL_MAX);
if (rc) {
- dev_err(motg->otg.dev, "unable to set voltage level "
+ dev_err(motg->phy.dev, "unable to set voltage level "
"for hsusb 3p3\n");
goto put_3p3;
}
rc = regulator_enable(hsusb_3p3);
if (rc) {
- dev_err(motg->otg.dev, "unable to enable the hsusb 3p3\n");
+ dev_err(motg->phy.dev, "unable to enable the hsusb 3p3\n");
goto put_3p3;
}
- hsusb_1p8 = regulator_get(motg->otg.dev, "HSUSB_1p8");
+ hsusb_1p8 = regulator_get(motg->phy.dev, "HSUSB_1p8");
if (IS_ERR(hsusb_1p8)) {
- dev_err(motg->otg.dev, "unable to get hsusb 1p8\n");
+ dev_err(motg->phy.dev, "unable to get hsusb 1p8\n");
rc = PTR_ERR(hsusb_1p8);
goto disable_3p3;
}
rc = regulator_set_voltage(hsusb_1p8, USB_PHY_1P8_VOL_MIN,
USB_PHY_1P8_VOL_MAX);
if (rc) {
- dev_err(motg->otg.dev, "unable to set voltage level "
+ dev_err(motg->phy.dev, "unable to set voltage level "
"for hsusb 1p8\n");
goto put_1p8;
}
rc = regulator_enable(hsusb_1p8);
if (rc) {
- dev_err(motg->otg.dev, "unable to enable the hsusb 1p8\n");
+ dev_err(motg->phy.dev, "unable to enable the hsusb 1p8\n");
goto put_1p8;
}
@@ -235,9 +235,9 @@ static int msm_hsusb_ldo_set_mode(int on)
return ret < 0 ? ret : 0;
}
-static int ulpi_read(struct otg_transceiver *otg, u32 reg)
+static int ulpi_read(struct usb_phy *phy, u32 reg)
{
- struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+ struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
int cnt = 0;
/* initiate read operation */
@@ -253,16 +253,16 @@ static int ulpi_read(struct otg_transceiver *otg, u32 reg)
}
if (cnt >= ULPI_IO_TIMEOUT_USEC) {
- dev_err(otg->dev, "ulpi_read: timeout %08x\n",
+ dev_err(phy->dev, "ulpi_read: timeout %08x\n",
readl(USB_ULPI_VIEWPORT));
return -ETIMEDOUT;
}
return ULPI_DATA_READ(readl(USB_ULPI_VIEWPORT));
}
-static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
+static int ulpi_write(struct usb_phy *phy, u32 val, u32 reg)
{
- struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+ struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
int cnt = 0;
/* initiate write operation */
@@ -279,13 +279,13 @@ static int ulpi_write(struct otg_transceiver *otg, u32 val, u32 reg)
}
if (cnt >= ULPI_IO_TIMEOUT_USEC) {
- dev_err(otg->dev, "ulpi_write: timeout\n");
+ dev_err(phy->dev, "ulpi_write: timeout\n");
return -ETIMEDOUT;
}
return 0;
}
-static struct otg_io_access_ops msm_otg_io_ops = {
+static struct usb_phy_io_ops msm_otg_io_ops = {
.read = ulpi_read,
.write = ulpi_write,
};
@@ -299,9 +299,9 @@ static void ulpi_init(struct msm_otg *motg)
return;
while (seq[0] >= 0) {
- dev_vdbg(motg->otg.dev, "ulpi: write 0x%02x to 0x%02x\n",
+ dev_vdbg(motg->phy.dev, "ulpi: write 0x%02x to 0x%02x\n",
seq[0], seq[1]);
- ulpi_write(&motg->otg, seq[0], seq[1]);
+ ulpi_write(&motg->phy, seq[0], seq[1]);
seq += 2;
}
}
@@ -313,11 +313,11 @@ static int msm_otg_link_clk_reset(struct msm_otg *motg, bool assert)
if (assert) {
ret = clk_reset(motg->clk, CLK_RESET_ASSERT);
if (ret)
- dev_err(motg->otg.dev, "usb hs_clk assert failed\n");
+ dev_err(motg->phy.dev, "usb hs_clk assert failed\n");
} else {
ret = clk_reset(motg->clk, CLK_RESET_DEASSERT);
if (ret)
- dev_err(motg->otg.dev, "usb hs_clk deassert failed\n");
+ dev_err(motg->phy.dev, "usb hs_clk deassert failed\n");
}
return ret;
}
@@ -328,13 +328,13 @@ static int msm_otg_phy_clk_reset(struct msm_otg *motg)
ret = clk_reset(motg->phy_reset_clk, CLK_RESET_ASSERT);
if (ret) {
- dev_err(motg->otg.dev, "usb phy clk assert failed\n");
+ dev_err(motg->phy.dev, "usb phy clk assert failed\n");
return ret;
}
usleep_range(10000, 12000);
ret = clk_reset(motg->phy_reset_clk, CLK_RESET_DEASSERT);
if (ret)
- dev_err(motg->otg.dev, "usb phy clk deassert failed\n");
+ dev_err(motg->phy.dev, "usb phy clk deassert failed\n");
return ret;
}
@@ -358,7 +358,7 @@ static int msm_otg_phy_reset(struct msm_otg *motg)
writel(val | PORTSC_PTS_ULPI, USB_PORTSC);
for (retries = 3; retries > 0; retries--) {
- ret = ulpi_write(&motg->otg, ULPI_FUNC_CTRL_SUSPENDM,
+ ret = ulpi_write(&motg->phy, ULPI_FUNC_CTRL_SUSPENDM,
ULPI_CLR(ULPI_FUNC_CTRL));
if (!ret)
break;
@@ -375,7 +375,7 @@ static int msm_otg_phy_reset(struct msm_otg *motg)
return ret;
for (retries = 3; retries > 0; retries--) {
- ret = ulpi_read(&motg->otg, ULPI_DEBUG);
+ ret = ulpi_read(&motg->phy, ULPI_DEBUG);
if (ret != -ETIMEDOUT)
break;
ret = msm_otg_phy_clk_reset(motg);
@@ -385,14 +385,14 @@ static int msm_otg_phy_reset(struct msm_otg *motg)
if (!retries)
return -ETIMEDOUT;
- dev_info(motg->otg.dev, "phy_reset: success\n");
+ dev_info(motg->phy.dev, "phy_reset: success\n");
return 0;
}
#define LINK_RESET_TIMEOUT_USEC (250 * 1000)
-static int msm_otg_reset(struct otg_transceiver *otg)
+static int msm_otg_reset(struct usb_phy *phy)
{
- struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+ struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
struct msm_otg_platform_data *pdata = motg->pdata;
int cnt = 0;
int ret;
@@ -401,7 +401,7 @@ static int msm_otg_reset(struct otg_transceiver *otg)
ret = msm_otg_phy_reset(motg);
if (ret) {
- dev_err(otg->dev, "phy_reset failed\n");
+ dev_err(phy->dev, "phy_reset failed\n");
return ret;
}
@@ -435,8 +435,8 @@ static int msm_otg_reset(struct otg_transceiver *otg)
val |= OTGSC_BSVIE;
}
writel(val, USB_OTGSC);
- ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_RISE);
- ulpi_write(otg, ulpi_val, ULPI_USB_INT_EN_FALL);
+ ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_RISE);
+ ulpi_write(phy, ulpi_val, ULPI_USB_INT_EN_FALL);
}
return 0;
@@ -448,8 +448,8 @@ static int msm_otg_reset(struct otg_transceiver *otg)
#ifdef CONFIG_PM_SLEEP
static int msm_otg_suspend(struct msm_otg *motg)
{
- struct otg_transceiver *otg = &motg->otg;
- struct usb_bus *bus = otg->host;
+ struct usb_phy *phy = &motg->phy;
+ struct usb_bus *bus = phy->otg->host;
struct msm_otg_platform_data *pdata = motg->pdata;
int cnt = 0;
@@ -475,10 +475,10 @@ static int msm_otg_suspend(struct msm_otg *motg)
*/
if (motg->pdata->phy_type == CI_45NM_INTEGRATED_PHY) {
- ulpi_read(otg, 0x14);
+ ulpi_read(phy, 0x14);
if (pdata->otg_control == OTG_PHY_CONTROL)
- ulpi_write(otg, 0x01, 0x30);
- ulpi_write(otg, 0x08, 0x09);
+ ulpi_write(phy, 0x01, 0x30);
+ ulpi_write(phy, 0x08, 0x09);
}
/*
@@ -495,8 +495,8 @@ static int msm_otg_suspend(struct msm_otg *motg)
}
if (cnt >= PHY_SUSPEND_TIMEOUT_USEC) {
- dev_err(otg->dev, "Unable to suspend PHY\n");
- msm_otg_reset(otg);
+ dev_err(phy->dev, "Unable to suspend PHY\n");
+ msm_otg_reset(phy);
enable_irq(motg->irq);
return -ETIMEDOUT;
}
@@ -528,7 +528,7 @@ static int msm_otg_suspend(struct msm_otg *motg)
msm_hsusb_config_vddcx(0);
}
- if (device_may_wakeup(otg->dev))
+ if (device_may_wakeup(phy->dev))
enable_irq_wake(motg->irq);
if (bus)
clear_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
@@ -536,15 +536,15 @@ static int msm_otg_suspend(struct msm_otg *motg)
atomic_set(&motg->in_lpm, 1);
enable_irq(motg->irq);
- dev_info(otg->dev, "USB in low power mode\n");
+ dev_info(phy->dev, "USB in low power mode\n");
return 0;
}
static int msm_otg_resume(struct msm_otg *motg)
{
- struct otg_transceiver *otg = &motg->otg;
- struct usb_bus *bus = otg->host;
+ struct usb_phy *phy = &motg->phy;
+ struct usb_bus *bus = phy->otg->host;
int cnt = 0;
unsigned temp;
@@ -592,13 +592,13 @@ static int msm_otg_resume(struct msm_otg *motg)
* PHY. USB state can not be restored. Re-insertion
* of USB cable is the only way to get USB working.
*/
- dev_err(otg->dev, "Unable to resume USB."
+ dev_err(phy->dev, "Unable to resume USB."
"Re-plugin the cable\n");
- msm_otg_reset(otg);
+ msm_otg_reset(phy);
}
skip_phy_resume:
- if (device_may_wakeup(otg->dev))
+ if (device_may_wakeup(phy->dev))
disable_irq_wake(motg->irq);
if (bus)
set_bit(HCD_FLAG_HW_ACCESSIBLE, &(bus_to_hcd(bus))->flags);
@@ -607,11 +607,11 @@ skip_phy_resume:
if (motg->async_int) {
motg->async_int = 0;
- pm_runtime_put(otg->dev);
+ pm_runtime_put(phy->dev);
enable_irq(motg->irq);
}
- dev_info(otg->dev, "USB exited from low power mode\n");
+ dev_info(phy->dev, "USB exited from low power mode\n");
return 0;
}
@@ -623,13 +623,13 @@ static void msm_otg_notify_charger(struct msm_otg *motg, unsigned mA)
return;
/* TODO: Notify PMIC about available current */
- dev_info(motg->otg.dev, "Avail curr from USB = %u\n", mA);
+ dev_info(motg->phy.dev, "Avail curr from USB = %u\n", mA);
motg->cur_power = mA;
}
-static int msm_otg_set_power(struct otg_transceiver *otg, unsigned mA)
+static int msm_otg_set_power(struct usb_phy *phy, unsigned mA)
{
- struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+ struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
/*
* Gadget driver uses set_power method to notify about the
@@ -644,19 +644,19 @@ static int msm_otg_set_power(struct otg_transceiver *otg, unsigned mA)
return 0;
}
-static void msm_otg_start_host(struct otg_transceiver *otg, int on)
+static void msm_otg_start_host(struct usb_phy *phy, int on)
{
- struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+ struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
struct msm_otg_platform_data *pdata = motg->pdata;
struct usb_hcd *hcd;
- if (!otg->host)
+ if (!phy->otg->host)
return;
- hcd = bus_to_hcd(otg->host);
+ hcd = bus_to_hcd(phy->otg->host);
if (on) {
- dev_dbg(otg->dev, "host on\n");
+ dev_dbg(phy->dev, "host on\n");
if (pdata->vbus_power)
pdata->vbus_power(1);
@@ -671,7 +671,7 @@ static void msm_otg_start_host(struct otg_transceiver *otg, int on)
usb_add_hcd(hcd, hcd->irq, IRQF_SHARED);
#endif
} else {
- dev_dbg(otg->dev, "host off\n");
+ dev_dbg(phy->dev, "host off\n");
#ifdef CONFIG_USB
usb_remove_hcd(hcd);
@@ -683,9 +683,9 @@ static void msm_otg_start_host(struct otg_transceiver *otg, int on)
}
}
-static int msm_otg_set_host(struct otg_transceiver *otg, struct usb_bus *host)
+static int msm_otg_set_host(struct usb_otg *otg, struct usb_bus *host)
{
- struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+ struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
struct usb_hcd *hcd;
/*
@@ -693,16 +693,16 @@ static int msm_otg_set_host(struct otg_transceiver *otg, struct usb_bus *host)
* only peripheral configuration.
*/
if (motg->pdata->mode == USB_PERIPHERAL) {
- dev_info(otg->dev, "Host mode is not supported\n");
+ dev_info(otg->phy->dev, "Host mode is not supported\n");
return -ENODEV;
}
if (!host) {
- if (otg->state == OTG_STATE_A_HOST) {
- pm_runtime_get_sync(otg->dev);
- msm_otg_start_host(otg, 0);
+ if (otg->phy->state == OTG_STATE_A_HOST) {
+ pm_runtime_get_sync(otg->phy->dev);
+ msm_otg_start_host(otg->phy, 0);
otg->host = NULL;
- otg->state = OTG_STATE_UNDEFINED;
+ otg->phy->state = OTG_STATE_UNDEFINED;
schedule_work(&motg->sm_work);
} else {
otg->host = NULL;
@@ -715,30 +715,30 @@ static int msm_otg_set_host(struct otg_transceiver *otg, struct usb_bus *host)
hcd->power_budget = motg->pdata->power_budget;
otg->host = host;
- dev_dbg(otg->dev, "host driver registered w/ tranceiver\n");
+ dev_dbg(otg->phy->dev, "host driver registered w/ tranceiver\n");
/*
* Kick the state machine work, if peripheral is not supported
* or peripheral is already registered with us.
*/
if (motg->pdata->mode == USB_HOST || otg->gadget) {
- pm_runtime_get_sync(otg->dev);
+ pm_runtime_get_sync(otg->phy->dev);
schedule_work(&motg->sm_work);
}
return 0;
}
-static void msm_otg_start_peripheral(struct otg_transceiver *otg, int on)
+static void msm_otg_start_peripheral(struct usb_phy *phy, int on)
{
- struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+ struct msm_otg *motg = container_of(phy, struct msm_otg, phy);
struct msm_otg_platform_data *pdata = motg->pdata;
- if (!otg->gadget)
+ if (!phy->otg->gadget)
return;
if (on) {
- dev_dbg(otg->dev, "gadget on\n");
+ dev_dbg(phy->dev, "gadget on\n");
/*
* Some boards have a switch cotrolled by gpio
* to enable/disable internal HUB. Disable internal
@@ -746,36 +746,36 @@ static void msm_otg_start_peripheral(struct otg_transceiver *otg, int on)
*/
if (pdata->setup_gpio)
pdata->setup_gpio(OTG_STATE_B_PERIPHERAL);
- usb_gadget_vbus_connect(otg->gadget);
+ usb_gadget_vbus_connect(phy->otg->gadget);
} else {
- dev_dbg(otg->dev, "gadget off\n");
- usb_gadget_vbus_disconnect(otg->gadget);
+ dev_dbg(phy->dev, "gadget off\n");
+ usb_gadget_vbus_disconnect(phy->otg->gadget);
if (pdata->setup_gpio)
pdata->setup_gpio(OTG_STATE_UNDEFINED);
}
}
-static int msm_otg_set_peripheral(struct otg_transceiver *otg,
- struct usb_gadget *gadget)
+static int msm_otg_set_peripheral(struct usb_otg *otg,
+ struct usb_gadget *gadget)
{
- struct msm_otg *motg = container_of(otg, struct msm_otg, otg);
+ struct msm_otg *motg = container_of(otg->phy, struct msm_otg, phy);
/*
* Fail peripheral registration if this board can support
* only host configuration.
*/
if (motg->pdata->mode == USB_HOST) {
- dev_info(otg->dev, "Peripheral mode is not supported\n");
+ dev_info(otg->phy->dev, "Peripheral mode is not supported\n");
return -ENODEV;
}
if (!gadget) {
- if (otg->state == OTG_STATE_B_PERIPHERAL) {
- pm_runtime_get_sync(otg->dev);
- msm_otg_start_peripheral(otg, 0);
+ if (otg->phy->state == OTG_STATE_B_PERIPHERAL) {
+ pm_runtime_get_sync(otg->phy->dev);
+ msm_otg_start_peripheral(otg->phy, 0);
otg->gadget = NULL;
- otg->state = OTG_STATE_UNDEFINED;
+ otg->phy->state = OTG_STATE_UNDEFINED;
schedule_work(&motg->sm_work);
} else {
otg->gadget = NULL;
@@ -784,14 +784,14 @@ static int msm_otg_set_peripheral(struct otg_transceiver *otg,
return 0;
}
otg->gadget = gadget;
- dev_dbg(otg->dev, "peripheral driver registered w/ tranceiver\n");
+ dev_dbg(otg->phy->dev, "peripheral driver registered w/ tranceiver\n");
/*
* Kick the state machine work, if host is not supported
* or host is already registered with us.
*/
if (motg->pdata->mode == USB_PERIPHERAL || otg->host) {
- pm_runtime_get_sync(otg->dev);
+ pm_runtime_get_sync(otg->phy->dev);
schedule_work(&motg->sm_work);
}
@@ -800,17 +800,17 @@ static int msm_otg_set_peripheral(struct otg_transceiver *otg,
static bool msm_chg_check_secondary_det(struct msm_otg *motg)
{
- struct otg_transceiver *otg = &motg->otg;
+ struct usb_phy *phy = &motg->phy;
u32 chg_det;
bool ret = false;
switch (motg->pdata->phy_type) {
case CI_45NM_INTEGRATED_PHY:
- chg_det = ulpi_read(otg, 0x34);
+ chg_det = ulpi_read(phy, 0x34);
ret = chg_det & (1 << 4);
break;
case SNPS_28NM_INTEGRATED_PHY:
- chg_det = ulpi_read(otg, 0x87);
+ chg_det = ulpi_read(phy, 0x87);
ret = chg_det & 1;
break;
default:
@@ -821,38 +821,38 @@ static bool msm_chg_check_secondary_det(struct msm_otg *motg)
static void msm_chg_enable_secondary_det(struct msm_otg *motg)
{
- struct otg_transceiver *otg = &motg->otg;
+ struct usb_phy *phy = &motg->phy;
u32 chg_det;
switch (motg->pdata->phy_type) {
case CI_45NM_INTEGRATED_PHY:
- chg_det = ulpi_read(otg, 0x34);
+ chg_det = ulpi_read(phy, 0x34);
/* Turn off charger block */
chg_det |= ~(1 << 1);
- ulpi_write(otg, chg_det, 0x34);
+ ulpi_write(phy, chg_det, 0x34);
udelay(20);
/* control chg block via ULPI */
chg_det &= ~(1 << 3);
- ulpi_write(otg, chg_det, 0x34);
+ ulpi_write(phy, chg_det, 0x34);
/* put it in host mode for enabling D- source */
chg_det &= ~(1 << 2);
- ulpi_write(otg, chg_det, 0x34);
+ ulpi_write(phy, chg_det, 0x34);
/* Turn on chg detect block */
chg_det &= ~(1 << 1);
- ulpi_write(otg, chg_det, 0x34);
+ ulpi_write(phy, chg_det, 0x34);
udelay(20);
/* enable chg detection */
chg_det &= ~(1 << 0);
- ulpi_write(otg, chg_det, 0x34);
+ ulpi_write(phy, chg_det, 0x34);
break;
case SNPS_28NM_INTEGRATED_PHY:
/*
* Configure DM as current source, DP as current sink
* and enable battery charging comparators.
*/
- ulpi_write(otg, 0x8, 0x85);
- ulpi_write(otg, 0x2, 0x85);
- ulpi_write(otg, 0x1, 0x85);
+ ulpi_write(phy, 0x8, 0x85);
+ ulpi_write(phy, 0x2, 0x85);
+ ulpi_write(phy, 0x1, 0x85);
break;
default:
break;
@@ -861,17 +861,17 @@ static void msm_chg_enable_secondary_det(struct msm_otg *motg)
static bool msm_chg_check_primary_det(struct msm_otg *motg)
{
- struct otg_transceiver *otg = &motg->otg;
+ struct usb_phy *phy = &motg->phy;
u32 chg_det;
bool ret = false;
switch (motg->pdata->phy_type) {
case CI_45NM_INTEGRATED_PHY:
- chg_det = ulpi_read(otg, 0x34);
+ chg_det = ulpi_read(phy, 0x34);
ret = chg_det & (1 << 4);
break;
case SNPS_28NM_INTEGRATED_PHY:
- chg_det = ulpi_read(otg, 0x87);
+ chg_det = ulpi_read(phy, 0x87);
ret = chg_det & 1;
break;
default:
@@ -882,23 +882,23 @@ static bool msm_chg_check_primary_det(struct msm_otg *motg)
static void msm_chg_enable_primary_det(struct msm_otg *motg)
{
- struct otg_transceiver *otg = &motg->otg;
+ struct usb_phy *phy = &motg->phy;
u32 chg_det;
switch (motg->pdata->phy_type) {
case CI_45NM_INTEGRATED_PHY:
- chg_det = ulpi_read(otg, 0x34);
+ chg_det = ulpi_read(phy, 0x34);
/* enable chg detection */
chg_det &= ~(1 << 0);
- ulpi_write(otg, chg_det, 0x34);
+ ulpi_write(phy, chg_det, 0x34);
break;
case SNPS_28NM_INTEGRATED_PHY:
/*
* Configure DP as current source, DM as current sink
* and enable battery charging comparators.
*/
- ulpi_write(otg, 0x2, 0x85);
- ulpi_write(otg, 0x1, 0x85);
+ ulpi_write(phy, 0x2, 0x85);
+ ulpi_write(phy, 0x1, 0x85);
break;
default:
break;
@@ -907,17 +907,17 @@ static void msm_chg_enable_primary_det(struct msm_otg *motg)
static bool msm_chg_check_dcd(struct msm_otg *motg)
{
- struct otg_transceiver *otg = &motg->otg;
+ struct usb_phy *phy = &motg->phy;
u32 line_state;
bool ret = false;
switch (motg->pdata->phy_type) {
case CI_45NM_INTEGRATED_PHY:
- line_state = ulpi_read(otg, 0x15);
+ line_state = ulpi_read(phy, 0x15);
ret = !(line_state & 1);
break;
case SNPS_28NM_INTEGRATED_PHY:
- line_state = ulpi_read(otg, 0x87);
+ line_state = ulpi_read(phy, 0x87);
ret = line_state & 2;
break;
default:
@@ -928,17 +928,17 @@ static bool msm_chg_check_dcd(struct msm_otg *motg)
static void msm_chg_disable_dcd(struct msm_otg *motg)
{
- struct otg_transceiver *otg = &motg->otg;
+ struct usb_phy *phy = &motg->phy;
u32 chg_det;
switch (motg->pdata->phy_type) {
case CI_45NM_INTEGRATED_PHY:
- chg_det = ulpi_read(otg, 0x34);
+ chg_det = ulpi_read(phy, 0x34);
chg_det &= ~(1 << 5);
- ulpi_write(otg, chg_det, 0x34);
+ ulpi_write(phy, chg_det, 0x34);
break;
case SNPS_28NM_INTEGRATED_PHY:
- ulpi_write(otg, 0x10, 0x86);
+ ulpi_write(phy, 0x10, 0x86);
break;
default:
break;
@@ -947,19 +947,19 @@ static void msm_chg_disable_dcd(struct msm_otg *motg)
static void msm_chg_enable_dcd(struct msm_otg *motg)
{
- struct otg_transceiver *otg = &motg->otg;
+ struct usb_phy *phy = &motg->phy;
u32 chg_det;
switch (motg->pdata->phy_type) {
case CI_45NM_INTEGRATED_PHY:
- chg_det = ulpi_read(otg, 0x34);
+ chg_det = ulpi_read(phy, 0x34);
/* Turn on D+ current source */
chg_det |= (1 << 5);
- ulpi_write(otg, chg_det, 0x34);
+ ulpi_write(phy, chg_det, 0x34);
break;
case SNPS_28NM_INTEGRATED_PHY:
/* Data contact detection enable */
- ulpi_write(otg, 0x10, 0x85);
+ ulpi_write(phy, 0x10, 0x85);
break;
default:
break;
@@ -968,32 +968,32 @@ static void msm_chg_enable_dcd(struct msm_otg *motg)
static void msm_chg_block_on(struct msm_otg *motg)
{
- struct otg_transceiver *otg = &motg->otg;
+ struct usb_phy *phy = &motg->phy;
u32 func_ctrl, chg_det;
/* put the controller in non-driving mode */
- func_ctrl = ulpi_read(otg, ULPI_FUNC_CTRL);
+ func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
- ulpi_write(otg, func_ctrl, ULPI_FUNC_CTRL);
+ ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
switch (motg->pdata->phy_type) {
case CI_45NM_INTEGRATED_PHY:
- chg_det = ulpi_read(otg, 0x34);
+ chg_det = ulpi_read(phy, 0x34);
/* control chg block via ULPI */
chg_det &= ~(1 << 3);
- ulpi_write(otg, chg_det, 0x34);
+ ulpi_write(phy, chg_det, 0x34);
/* Turn on chg detect block */
chg_det &= ~(1 << 1);
- ulpi_write(otg, chg_det, 0x34);
+ ulpi_write(phy, chg_det, 0x34);
udelay(20);
break;
case SNPS_28NM_INTEGRATED_PHY:
/* Clear charger detecting control bits */
- ulpi_write(otg, 0x3F, 0x86);
+ ulpi_write(phy, 0x3F, 0x86);
/* Clear alt interrupt latch and enable bits */
- ulpi_write(otg, 0x1F, 0x92);
- ulpi_write(otg, 0x1F, 0x95);
+ ulpi_write(phy, 0x1F, 0x92);
+ ulpi_write(phy, 0x1F, 0x95);
udelay(100);
break;
default:
@@ -1003,32 +1003,32 @@ static void msm_chg_block_on(struct msm_otg *motg)
static void msm_chg_block_off(struct msm_otg *motg)
{
- struct otg_transceiver *otg = &motg->otg;
+ struct usb_phy *phy = &motg->phy;
u32 func_ctrl, chg_det;
switch (motg->pdata->phy_type) {
case CI_45NM_INTEGRATED_PHY:
- chg_det = ulpi_read(otg, 0x34);
+ chg_det = ulpi_read(phy, 0x34);
/* Turn off charger block */
chg_det |= ~(1 << 1);
- ulpi_write(otg, chg_det, 0x34);
+ ulpi_write(phy, chg_det, 0x34);
break;
case SNPS_28NM_INTEGRATED_PHY:
/* Clear charger detecting control bits */
- ulpi_write(otg, 0x3F, 0x86);
+ ulpi_write(phy, 0x3F, 0x86);
/* Clear alt interrupt latch and enable bits */
- ulpi_write(otg, 0x1F, 0x92);
- ulpi_write(otg, 0x1F, 0x95);
+ ulpi_write(phy, 0x1F, 0x92);
+ ulpi_write(phy, 0x1F, 0x95);
break;
default:
break;
}
/* put the controller in normal mode */
- func_ctrl = ulpi_read(otg, ULPI_FUNC_CTRL);
+ func_ctrl = ulpi_read(phy, ULPI_FUNC_CTRL);
func_ctrl &= ~ULPI_FUNC_CTRL_OPMODE_MASK;
func_ctrl |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
- ulpi_write(otg, func_ctrl, ULPI_FUNC_CTRL);
+ ulpi_write(phy, func_ctrl, ULPI_FUNC_CTRL);
}
#define MSM_CHG_DCD_POLL_TIME (100 * HZ/1000) /* 100 msec */
@@ -1038,14 +1038,14 @@ static void msm_chg_block_off(struct msm_otg *motg)
static void msm_chg_detect_work(struct work_struct *w)
{
struct msm_otg *motg = container_of(w, struct msm_otg, chg_work.work);
- struct otg_transceiver *otg = &motg->otg;
+ struct usb_phy *phy = &motg->phy;
bool is_dcd, tmout, vout;
unsigned long delay;
- dev_dbg(otg->dev, "chg detection work\n");
+ dev_dbg(phy->dev, "chg detection work\n");
switch (motg->chg_state) {
case USB_CHG_STATE_UNDEFINED:
- pm_runtime_get_sync(otg->dev);
+ pm_runtime_get_sync(phy->dev);
msm_chg_block_on(motg);
msm_chg_enable_dcd(motg);
motg->chg_state = USB_CHG_STATE_WAIT_FOR_DCD;
@@ -1088,7 +1088,7 @@ static void msm_chg_detect_work(struct work_struct *w)
motg->chg_state = USB_CHG_STATE_DETECTED;
case USB_CHG_STATE_DETECTED:
msm_chg_block_off(motg);
- dev_dbg(otg->dev, "charger = %d\n", motg->chg_type);
+ dev_dbg(phy->dev, "charger = %d\n", motg->chg_type);
schedule_work(&motg->sm_work);
return;
default:
@@ -1152,22 +1152,22 @@ static void msm_otg_init_sm(struct msm_otg *motg)
static void msm_otg_sm_work(struct work_struct *w)
{
struct msm_otg *motg = container_of(w, struct msm_otg, sm_work);
- struct otg_transceiver *otg = &motg->otg;
+ struct usb_otg *otg = motg->phy.otg;
- switch (otg->state) {
+ switch (otg->phy->state) {
case OTG_STATE_UNDEFINED:
- dev_dbg(otg->dev, "OTG_STATE_UNDEFINED state\n");
- msm_otg_reset(otg);
+ dev_dbg(otg->phy->dev, "OTG_STATE_UNDEFINED state\n");
+ msm_otg_reset(otg->phy);
msm_otg_init_sm(motg);
- otg->state = OTG_STATE_B_IDLE;
+ otg->phy->state = OTG_STATE_B_IDLE;
/* FALL THROUGH */
case OTG_STATE_B_IDLE:
- dev_dbg(otg->dev, "OTG_STATE_B_IDLE state\n");
+ dev_dbg(otg->phy->dev, "OTG_STATE_B_IDLE state\n");
if (!test_bit(ID, &motg->inputs) && otg->host) {
/* disable BSV bit */
writel(readl(USB_OTGSC) & ~OTGSC_BSVIE, USB_OTGSC);
- msm_otg_start_host(otg, 1);
- otg->state = OTG_STATE_A_HOST;
+ msm_otg_start_host(otg->phy, 1);
+ otg->phy->state = OTG_STATE_A_HOST;
} else if (test_bit(B_SESS_VLD, &motg->inputs)) {
switch (motg->chg_state) {
case USB_CHG_STATE_UNDEFINED:
@@ -1182,13 +1182,15 @@ static void msm_otg_sm_work(struct work_struct *w)
case USB_CDP_CHARGER:
msm_otg_notify_charger(motg,
IDEV_CHG_MAX);
- msm_otg_start_peripheral(otg, 1);
- otg->state = OTG_STATE_B_PERIPHERAL;
+ msm_otg_start_peripheral(otg->phy, 1);
+ otg->phy->state
+ = OTG_STATE_B_PERIPHERAL;
break;
case USB_SDP_CHARGER:
msm_otg_notify_charger(motg, IUNIT);
- msm_otg_start_peripheral(otg, 1);
- otg->state = OTG_STATE_B_PERIPHERAL;
+ msm_otg_start_peripheral(otg->phy, 1);
+ otg->phy->state
+ = OTG_STATE_B_PERIPHERAL;
break;
default:
break;
@@ -1204,34 +1206,34 @@ static void msm_otg_sm_work(struct work_struct *w)
* is incremented in charger detection work.
*/
if (cancel_delayed_work_sync(&motg->chg_work)) {
- pm_runtime_put_sync(otg->dev);
- msm_otg_reset(otg);
+ pm_runtime_put_sync(otg->phy->dev);
+ msm_otg_reset(otg->phy);
}
msm_otg_notify_charger(motg, 0);
motg->chg_state = USB_CHG_STATE_UNDEFINED;
motg->chg_type = USB_INVALID_CHARGER;
}
- pm_runtime_put_sync(otg->dev);
+ pm_runtime_put_sync(otg->phy->dev);
break;
case OTG_STATE_B_PERIPHERAL:
- dev_dbg(otg->dev, "OTG_STATE_B_PERIPHERAL state\n");
+ dev_dbg(otg->phy->dev, "OTG_STATE_B_PERIPHERAL state\n");
if (!test_bit(B_SESS_VLD, &motg->inputs) ||
!test_bit(ID, &motg->inputs)) {
msm_otg_notify_charger(motg, 0);
- msm_otg_start_peripheral(otg, 0);
+ msm_otg_start_peripheral(otg->phy, 0);
motg->chg_state = USB_CHG_STATE_UNDEFINED;
motg->chg_type = USB_INVALID_CHARGER;
- otg->state = OTG_STATE_B_IDLE;
- msm_otg_reset(otg);
+ otg->phy->state = OTG_STATE_B_IDLE;
+ msm_otg_reset(otg->phy);
schedule_work(w);
}
break;
case OTG_STATE_A_HOST:
- dev_dbg(otg->dev, "OTG_STATE_A_HOST state\n");
+ dev_dbg(otg->phy->dev, "OTG_STATE_A_HOST state\n");
if (test_bit(ID, &motg->inputs)) {
- msm_otg_start_host(otg, 0);
- otg->state = OTG_STATE_B_IDLE;
- msm_otg_reset(otg);
+ msm_otg_start_host(otg->phy, 0);
+ otg->phy->state = OTG_STATE_B_IDLE;
+ msm_otg_reset(otg->phy);
schedule_work(w);
}
break;
@@ -1243,13 +1245,13 @@ static void msm_otg_sm_work(struct work_struct *w)
static irqreturn_t msm_otg_irq(int irq, void *data)
{
struct msm_otg *motg = data;
- struct otg_transceiver *otg = &motg->otg;
+ struct usb_phy *phy = &motg->phy;
u32 otgsc = 0;
if (atomic_read(&motg->in_lpm)) {
disable_irq_nosync(irq);
motg->async_int = 1;
- pm_runtime_get(otg->dev);
+ pm_runtime_get(phy->dev);
return IRQ_HANDLED;
}
@@ -1262,15 +1264,15 @@ static irqreturn_t msm_otg_irq(int irq, void *data)
set_bit(ID, &motg->inputs);
else
clear_bit(ID, &motg->inputs);
- dev_dbg(otg->dev, "ID set/clear\n");
- pm_runtime_get_noresume(otg->dev);
+ dev_dbg(phy->dev, "ID set/clear\n");
+ pm_runtime_get_noresume(phy->dev);
} else if ((otgsc & OTGSC_BSVIS) && (otgsc & OTGSC_BSVIE)) {
if (otgsc & OTGSC_BSV)
set_bit(B_SESS_VLD, &motg->inputs);
else
clear_bit(B_SESS_VLD, &motg->inputs);
- dev_dbg(otg->dev, "BSV set/clear\n");
- pm_runtime_get_noresume(otg->dev);
+ dev_dbg(phy->dev, "BSV set/clear\n");
+ pm_runtime_get_noresume(phy->dev);
}
writel(otgsc, USB_OTGSC);
@@ -1281,9 +1283,9 @@ static irqreturn_t msm_otg_irq(int irq, void *data)
static int msm_otg_mode_show(struct seq_file *s, void *unused)
{
struct msm_otg *motg = s->private;
- struct otg_transceiver *otg = &motg->otg;
+ struct usb_otg *otg = motg->phy.otg;
- switch (otg->state) {
+ switch (otg->phy->state) {
case OTG_STATE_A_HOST:
seq_printf(s, "host\n");
break;
@@ -1309,7 +1311,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
struct seq_file *s = file->private_data;
struct msm_otg *motg = s->private;
char buf[16];
- struct otg_transceiver *otg = &motg->otg;
+ struct usb_otg *otg = motg->phy.otg;
int status = count;
enum usb_mode_type req_mode;
@@ -1333,7 +1335,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
switch (req_mode) {
case USB_NONE:
- switch (otg->state) {
+ switch (otg->phy->state) {
case OTG_STATE_A_HOST:
case OTG_STATE_B_PERIPHERAL:
set_bit(ID, &motg->inputs);
@@ -1344,7 +1346,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
}
break;
case USB_PERIPHERAL:
- switch (otg->state) {
+ switch (otg->phy->state) {
case OTG_STATE_B_IDLE:
case OTG_STATE_A_HOST:
set_bit(ID, &motg->inputs);
@@ -1355,7 +1357,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
}
break;
case USB_HOST:
- switch (otg->state) {
+ switch (otg->phy->state) {
case OTG_STATE_B_IDLE:
case OTG_STATE_B_PERIPHERAL:
clear_bit(ID, &motg->inputs);
@@ -1368,7 +1370,7 @@ static ssize_t msm_otg_mode_write(struct file *file, const char __user *ubuf,
goto out;
}
- pm_runtime_get_sync(otg->dev);
+ pm_runtime_get_sync(otg->phy->dev);
schedule_work(&motg->sm_work);
out:
return status;
@@ -1414,7 +1416,7 @@ static int __init msm_otg_probe(struct platform_device *pdev)
int ret = 0;
struct resource *res;
struct msm_otg *motg;
- struct otg_transceiver *otg;
+ struct usb_phy *phy;
dev_info(&pdev->dev, "msm_otg probe\n");
if (!pdev->dev.platform_data) {
@@ -1428,9 +1430,15 @@ static int __init msm_otg_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ motg->phy.otg = kzalloc(sizeof(struct usb_otg), GFP_KERNEL);
+ if (!motg->phy.otg) {
+ dev_err(&pdev->dev, "unable to allocate msm_otg\n");
+ return -ENOMEM;
+ }
+
motg->pdata = pdev->dev.platform_data;
- otg = &motg->otg;
- otg->dev = &pdev->dev;
+ phy = &motg->phy;
+ phy->dev = &pdev->dev;
motg->phy_reset_clk = clk_get(&pdev->dev, "usb_phy_clk");
if (IS_ERR(motg->phy_reset_clk)) {
@@ -1538,16 +1546,18 @@ static int __init msm_otg_probe(struct platform_device *pdev)
goto disable_clks;
}
- otg->init = msm_otg_reset;
- otg->set_host = msm_otg_set_host;
- otg->set_peripheral = msm_otg_set_peripheral;
- otg->set_power = msm_otg_set_power;
+ phy->init = msm_otg_reset;
+ phy->set_power = msm_otg_set_power;
+
+ phy->io_ops = &msm_otg_io_ops;
- otg->io_ops = &msm_otg_io_ops;
+ phy->otg->phy = &motg->phy;
+ phy->otg->set_host = msm_otg_set_host;
+ phy->otg->set_peripheral = msm_otg_set_peripheral;
- ret = otg_set_transceiver(&motg->otg);
+ ret = usb_set_transceiver(&motg->phy);
if (ret) {
- dev_err(&pdev->dev, "otg_set_transceiver failed\n");
+ dev_err(&pdev->dev, "usb_set_transceiver failed\n");
goto free_irq;
}
@@ -1591,6 +1601,7 @@ put_clk:
put_phy_reset_clk:
clk_put(motg->phy_reset_clk);
free_motg:
+ kfree(motg->phy.otg);
kfree(motg);
return ret;
}
@@ -1598,10 +1609,10 @@ free_motg:
static int __devexit msm_otg_remove(struct platform_device *pdev)
{
struct msm_otg *motg = platform_get_drvdata(pdev);
- struct otg_transceiver *otg = &motg->otg;
+ struct usb_phy *phy = &motg->phy;
int cnt = 0;
- if (otg->host || otg->gadget)
+ if (phy->otg->host || phy->otg->gadget)
return -EBUSY;
msm_otg_debugfs_cleanup();
@@ -1613,14 +1624,14 @@ static int __devexit msm_otg_remove(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 0);
pm_runtime_disable(&pdev->dev);
- otg_set_transceiver(NULL);
+ usb_set_transceiver(NULL);
free_irq(motg->irq, motg);
/*
* Put PHY in low power mode.
*/
- ulpi_read(otg, 0x14);
- ulpi_write(otg, 0x08, 0x09);
+ ulpi_read(phy, 0x14);
+ ulpi_write(phy, 0x08, 0x09);
writel(readl(USB_PORTSC) | PORTSC_PHCD, USB_PORTSC);
while (cnt < PHY_SUSPEND_TIMEOUT_USEC) {
@@ -1630,7 +1641,7 @@ static int __devexit msm_otg_remove(struct platform_device *pdev)
cnt++;
}
if (cnt >= PHY_SUSPEND_TIMEOUT_USEC)
- dev_err(otg->dev, "Unable to suspend PHY\n");
+ dev_err(phy->dev, "Unable to suspend PHY\n");
clk_disable(motg->pclk);
clk_disable(motg->clk);
@@ -1651,6 +1662,7 @@ static int __devexit msm_otg_remove(struct platform_device *pdev)
if (motg->core_clk)
clk_put(motg->core_clk);
+ kfree(motg->phy.otg);
kfree(motg);
return 0;
@@ -1660,7 +1672,7 @@ static int __devexit msm_otg_remove(struct platform_device *pdev)
static int msm_otg_runtime_idle(struct device *dev)
{
struct msm_otg *motg = dev_get_drvdata(dev);
- struct otg_transceiver *otg = &motg->otg;
+ struct usb_otg *otg = motg->phy.otg;
dev_dbg(dev, "OTG runtime idle\n");
@@ -1670,7 +1682,7 @@ static int msm_otg_runtime_idle(struct device *dev)
* This 1 sec delay also prevents entering into LPM immediately
* after asynchronous interrupt.
*/
- if (otg->state != OTG_STATE_UNDEFINED)
+ if (otg->phy->state != OTG_STATE_UNDEFINED)
pm_schedule_suspend(dev, 1000);
return -EAGAIN;
diff --git a/drivers/usb/otg/mv_otg.c b/drivers/usb/otg/mv_otg.c
index b5fbe1452ab0..6cc6c3ffbb83 100644
--- a/drivers/usb/otg/mv_otg.c
+++ b/drivers/usb/otg/mv_otg.c
@@ -55,16 +55,16 @@ static char *state_string[] = {
"a_vbus_err"
};
-static int mv_otg_set_vbus(struct otg_transceiver *otg, bool on)
+static int mv_otg_set_vbus(struct usb_otg *otg, bool on)
{
- struct mv_otg *mvotg = container_of(otg, struct mv_otg, otg);
+ struct mv_otg *mvotg = container_of(otg->phy, struct mv_otg, phy);
if (mvotg->pdata->set_vbus == NULL)
return -ENODEV;
return mvotg->pdata->set_vbus(on);
}
-static int mv_otg_set_host(struct otg_transceiver *otg,
+static int mv_otg_set_host(struct usb_otg *otg,
struct usb_bus *host)
{
otg->host = host;
@@ -72,7 +72,7 @@ static int mv_otg_set_host(struct otg_transceiver *otg,
return 0;
}
-static int mv_otg_set_peripheral(struct otg_transceiver *otg,
+static int mv_otg_set_peripheral(struct usb_otg *otg,
struct usb_gadget *gadget)
{
otg->gadget = gadget;
@@ -203,7 +203,7 @@ static void mv_otg_init_irq(struct mv_otg *mvotg)
static void mv_otg_start_host(struct mv_otg *mvotg, int on)
{
#ifdef CONFIG_USB
- struct otg_transceiver *otg = &mvotg->otg;
+ struct usb_otg *otg = mvotg->phy.otg;
struct usb_hcd *hcd;
if (!otg->host)
@@ -222,12 +222,12 @@ static void mv_otg_start_host(struct mv_otg *mvotg, int on)
static void mv_otg_start_periphrals(struct mv_otg *mvotg, int on)
{
- struct otg_transceiver *otg = &mvotg->otg;
+ struct usb_otg *otg = mvotg->phy.otg;
if (!otg->gadget)
return;
- dev_info(otg->dev, "gadget %s\n", on ? "on" : "off");
+ dev_info(mvotg->phy.dev, "gadget %s\n", on ? "on" : "off");
if (on)
usb_gadget_vbus_connect(otg->gadget);
@@ -343,69 +343,69 @@ static void mv_otg_update_inputs(struct mv_otg *mvotg)
static void mv_otg_update_state(struct mv_otg *mvotg)
{
struct mv_otg_ctrl *otg_ctrl = &mvotg->otg_ctrl;
- struct otg_transceiver *otg = &mvotg->otg;
- int old_state = otg->state;
+ struct usb_phy *phy = &mvotg->phy;
+ int old_state = phy->state;
switch (old_state) {
case OTG_STATE_UNDEFINED:
- otg->state = OTG_STATE_B_IDLE;
+ phy->state = OTG_STATE_B_IDLE;
/* FALL THROUGH */
case OTG_STATE_B_IDLE:
if (otg_ctrl->id == 0)
- otg->state = OTG_STATE_A_IDLE;
+ phy->state = OTG_STATE_A_IDLE;
else if (otg_ctrl->b_sess_vld)
- otg->state = OTG_STATE_B_PERIPHERAL;
+ phy->state = OTG_STATE_B_PERIPHERAL;
break;
case OTG_STATE_B_PERIPHERAL:
if (!otg_ctrl->b_sess_vld || otg_ctrl->id == 0)
- otg->state = OTG_STATE_B_IDLE;
+ phy->state = OTG_STATE_B_IDLE;
break;
case OTG_STATE_A_IDLE:
if (otg_ctrl->id)
- otg->state = OTG_STATE_B_IDLE;
+ phy->state = OTG_STATE_B_IDLE;
else if (!(otg_ctrl->a_bus_drop) &&
(otg_ctrl->a_bus_req || otg_ctrl->a_srp_det))
- otg->state = OTG_STATE_A_WAIT_VRISE;
+ phy->state = OTG_STATE_A_WAIT_VRISE;
break;
case OTG_STATE_A_WAIT_VRISE:
if (otg_ctrl->a_vbus_vld)
- otg->state = OTG_STATE_A_WAIT_BCON;
+ phy->state = OTG_STATE_A_WAIT_BCON;
break;
case OTG_STATE_A_WAIT_BCON:
if (otg_ctrl->id || otg_ctrl->a_bus_drop
|| otg_ctrl->a_wait_bcon_timeout) {
mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
- otg->state = OTG_STATE_A_WAIT_VFALL;
+ phy->state = OTG_STATE_A_WAIT_VFALL;
otg_ctrl->a_bus_req = 0;
} else if (!otg_ctrl->a_vbus_vld) {
mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
- otg->state = OTG_STATE_A_VBUS_ERR;
+ phy->state = OTG_STATE_A_VBUS_ERR;
} else if (otg_ctrl->b_conn) {
mv_otg_cancel_timer(mvotg, A_WAIT_BCON_TIMER);
mvotg->otg_ctrl.a_wait_bcon_timeout = 0;
- otg->state = OTG_STATE_A_HOST;
+ phy->state = OTG_STATE_A_HOST;
}
break;
case OTG_STATE_A_HOST:
if (otg_ctrl->id || !otg_ctrl->b_conn
|| otg_ctrl->a_bus_drop)
- otg->state = OTG_STATE_A_WAIT_BCON;
+ phy->state = OTG_STATE_A_WAIT_BCON;
else if (!otg_ctrl->a_vbus_vld)
- otg->state = OTG_STATE_A_VBUS_ERR;
+ phy->state = OTG_STATE_A_VBUS_ERR;
break;
case OTG_STATE_A_WAIT_VFALL:
if (otg_ctrl->id
|| (!otg_ctrl->b_conn && otg_ctrl->a_sess_vld)
|| otg_ctrl->a_bus_req)
- otg->state = OTG_STATE_A_IDLE;
+ phy->state = OTG_STATE_A_IDLE;
break;
case OTG_STATE_A_VBUS_ERR:
if (otg_ctrl->id || otg_ctrl->a_clr_err
|| otg_ctrl->a_bus_drop) {
otg_ctrl->a_clr_err = 0;
- otg->state = OTG_STATE_A_WAIT_VFALL;
+ phy->state = OTG_STATE_A_WAIT_VFALL;
}
break;
default:
@@ -416,15 +416,17 @@ static void mv_otg_update_state(struct mv_otg *mvotg)
static void mv_otg_work(struct work_struct *work)
{
struct mv_otg *mvotg;
- struct otg_transceiver *otg;
+ struct usb_phy *phy;
+ struct usb_otg *otg;
int old_state;
mvotg = container_of((struct delayed_work *)work, struct mv_otg, work);
run:
/* work queue is single thread, or we need spin_lock to protect */
- otg = &mvotg->otg;
- old_state = otg->state;
+ phy = &mvotg->phy;
+ otg = phy->otg;
+ old_state = phy->state;
if (!mvotg->active)
return;
@@ -432,14 +434,14 @@ run:
mv_otg_update_inputs(mvotg);
mv_otg_update_state(mvotg);
- if (old_state != otg->state) {
+ if (old_state != phy->state) {
dev_info(&mvotg->pdev->dev, "change from state %s to %s\n",
state_string[old_state],
- state_string[otg->state]);
+ state_string[phy->state]);
- switch (otg->state) {
+ switch (phy->state) {
case OTG_STATE_B_IDLE:
- mvotg->otg.default_a = 0;
+ otg->default_a = 0;
if (old_state == OTG_STATE_B_PERIPHERAL)
mv_otg_start_periphrals(mvotg, 0);
mv_otg_reset(mvotg);
@@ -450,14 +452,14 @@ run:
mv_otg_start_periphrals(mvotg, 1);
break;
case OTG_STATE_A_IDLE:
- mvotg->otg.default_a = 1;
+ otg->default_a = 1;
mv_otg_enable(mvotg);
if (old_state == OTG_STATE_A_WAIT_VFALL)
mv_otg_start_host(mvotg, 0);
mv_otg_reset(mvotg);
break;
case OTG_STATE_A_WAIT_VRISE:
- mv_otg_set_vbus(&mvotg->otg, 1);
+ mv_otg_set_vbus(otg, 1);
break;
case OTG_STATE_A_WAIT_BCON:
if (old_state != OTG_STATE_A_HOST)
@@ -479,7 +481,7 @@ run:
* here. In fact, it need host driver to notify us.
*/
mvotg->otg_ctrl.b_conn = 0;
- mv_otg_set_vbus(&mvotg->otg, 0);
+ mv_otg_set_vbus(otg, 0);
break;
case OTG_STATE_A_VBUS_ERR:
break;
@@ -548,8 +550,8 @@ set_a_bus_req(struct device *dev, struct device_attribute *attr,
return -1;
/* We will use this interface to change to A device */
- if (mvotg->otg.state != OTG_STATE_B_IDLE
- && mvotg->otg.state != OTG_STATE_A_IDLE)
+ if (mvotg->phy.state != OTG_STATE_B_IDLE
+ && mvotg->phy.state != OTG_STATE_A_IDLE)
return -1;
/* The clock may disabled and we need to set irq for ID detected */
@@ -579,7 +581,7 @@ set_a_clr_err(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct mv_otg *mvotg = dev_get_drvdata(dev);
- if (!mvotg->otg.default_a)
+ if (!mvotg->phy.otg->default_a)
return -1;
if (count > 2)
@@ -615,7 +617,7 @@ set_a_bus_drop(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct mv_otg *mvotg = dev_get_drvdata(dev);
- if (!mvotg->otg.default_a)
+ if (!mvotg->phy.otg->default_a)
return -1;
if (count > 2)
@@ -688,9 +690,10 @@ int mv_otg_remove(struct platform_device *pdev)
for (clk_i = 0; clk_i <= mvotg->clknum; clk_i++)
clk_put(mvotg->clk[clk_i]);
- otg_set_transceiver(NULL);
+ usb_set_transceiver(NULL);
platform_set_drvdata(pdev, NULL);
+ kfree(mvotg->phy.otg);
kfree(mvotg);
return 0;
@@ -700,6 +703,7 @@ static int mv_otg_probe(struct platform_device *pdev)
{
struct mv_usb_platform_data *pdata = pdev->dev.platform_data;
struct mv_otg *mvotg;
+ struct usb_otg *otg;
struct resource *r;
int retval = 0, clk_i, i;
size_t size;
@@ -716,6 +720,12 @@ static int mv_otg_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ otg = kzalloc(sizeof *otg, GFP_KERNEL);
+ if (!otg) {
+ kfree(mvotg);
+ return -ENOMEM;
+ }
+
platform_set_drvdata(pdev, mvotg);
mvotg->pdev = pdev;
@@ -741,12 +751,15 @@ static int mv_otg_probe(struct platform_device *pdev)
/* OTG common part */
mvotg->pdev = pdev;
- mvotg->otg.dev = &pdev->dev;
- mvotg->otg.label = driver_name;
- mvotg->otg.set_host = mv_otg_set_host;
- mvotg->otg.set_peripheral = mv_otg_set_peripheral;
- mvotg->otg.set_vbus = mv_otg_set_vbus;
- mvotg->otg.state = OTG_STATE_UNDEFINED;
+ mvotg->phy.dev = &pdev->dev;
+ mvotg->phy.otg = otg;
+ mvotg->phy.label = driver_name;
+ mvotg->phy.state = OTG_STATE_UNDEFINED;
+
+ otg->phy = &mvotg->phy;
+ otg->set_host = mv_otg_set_host;
+ otg->set_peripheral = mv_otg_set_peripheral;
+ otg->set_vbus = mv_otg_set_vbus;
for (i = 0; i < OTG_TIMER_NUM; i++)
init_timer(&mvotg->otg_ctrl.timer[i]);
@@ -840,7 +853,7 @@ static int mv_otg_probe(struct platform_device *pdev)
goto err_disable_clk;
}
- retval = otg_set_transceiver(&mvotg->otg);
+ retval = usb_set_transceiver(&mvotg->phy);
if (retval < 0) {
dev_err(&pdev->dev, "can't register transceiver, %d\n",
retval);
@@ -867,7 +880,7 @@ static int mv_otg_probe(struct platform_device *pdev)
return 0;
err_set_transceiver:
- otg_set_transceiver(NULL);
+ usb_set_transceiver(NULL);
err_free_irq:
free_irq(mvotg->irq, mvotg);
err_disable_clk:
@@ -888,6 +901,7 @@ err_put_clk:
clk_put(mvotg->clk[clk_i]);
platform_set_drvdata(pdev, NULL);
+ kfree(otg);
kfree(mvotg);
return retval;
@@ -898,10 +912,10 @@ static int mv_otg_suspend(struct platform_device *pdev, pm_message_t state)
{
struct mv_otg *mvotg = platform_get_drvdata(pdev);
- if (mvotg->otg.state != OTG_STATE_B_IDLE) {
+ if (mvotg->phy.state != OTG_STATE_B_IDLE) {
dev_info(&pdev->dev,
"OTG state is not B_IDLE, it is %d!\n",
- mvotg->otg.state);
+ mvotg->phy.state);
return -EAGAIN;
}
diff --git a/drivers/usb/otg/mv_otg.h b/drivers/usb/otg/mv_otg.h
index be6ca1437645..8a9e351b36ba 100644
--- a/drivers/usb/otg/mv_otg.h
+++ b/drivers/usb/otg/mv_otg.h
@@ -136,7 +136,7 @@ struct mv_otg_regs {
};
struct mv_otg {
- struct otg_transceiver otg;
+ struct usb_phy phy;
struct mv_otg_ctrl otg_ctrl;
/* base address */
diff --git a/drivers/usb/otg/nop-usb-xceiv.c b/drivers/usb/otg/nop-usb-xceiv.c
index c1e360046435..58b26df6afd1 100644
--- a/drivers/usb/otg/nop-usb-xceiv.c
+++ b/drivers/usb/otg/nop-usb-xceiv.c
@@ -33,7 +33,7 @@
#include <linux/slab.h>
struct nop_usb_xceiv {
- struct otg_transceiver otg;
+ struct usb_phy phy;
struct device *dev;
};
@@ -58,51 +58,37 @@ void usb_nop_xceiv_unregister(void)
}
EXPORT_SYMBOL(usb_nop_xceiv_unregister);
-static inline struct nop_usb_xceiv *xceiv_to_nop(struct otg_transceiver *x)
-{
- return container_of(x, struct nop_usb_xceiv, otg);
-}
-
-static int nop_set_suspend(struct otg_transceiver *x, int suspend)
+static int nop_set_suspend(struct usb_phy *x, int suspend)
{
return 0;
}
-static int nop_set_peripheral(struct otg_transceiver *x,
- struct usb_gadget *gadget)
+static int nop_set_peripheral(struct usb_otg *otg, struct usb_gadget *gadget)
{
- struct nop_usb_xceiv *nop;
-
- if (!x)
+ if (!otg)
return -ENODEV;
- nop = xceiv_to_nop(x);
-
if (!gadget) {
- nop->otg.gadget = NULL;
+ otg->gadget = NULL;
return -ENODEV;
}
- nop->otg.gadget = gadget;
- nop->otg.state = OTG_STATE_B_IDLE;
+ otg->gadget = gadget;
+ otg->phy->state = OTG_STATE_B_IDLE;
return 0;
}
-static int nop_set_host(struct otg_transceiver *x, struct usb_bus *host)
+static int nop_set_host(struct usb_otg *otg, struct usb_bus *host)
{
- struct nop_usb_xceiv *nop;
-
- if (!x)
+ if (!otg)
return -ENODEV;
- nop = xceiv_to_nop(x);
-
if (!host) {
- nop->otg.host = NULL;
+ otg->host = NULL;
return -ENODEV;
}
- nop->otg.host = host;
+ otg->host = host;
return 0;
}
@@ -115,15 +101,23 @@ static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev)
if (!nop)
return -ENOMEM;
+ nop->phy.otg = kzalloc(sizeof *nop->phy.otg, GFP_KERNEL);
+ if (!nop->phy.otg) {
+ kfree(nop);
+ return -ENOMEM;
+ }
+
nop->dev = &pdev->dev;
- nop->otg.dev = nop->dev;
- nop->otg.label = "nop-xceiv";
- nop->otg.state = OTG_STATE_UNDEFINED;
- nop->otg.set_host = nop_set_host;
- nop->otg.set_peripheral = nop_set_peripheral;
- nop->otg.set_suspend = nop_set_suspend;
-
- err = otg_set_transceiver(&nop->otg);
+ nop->phy.dev = nop->dev;
+ nop->phy.label = "nop-xceiv";
+ nop->phy.set_suspend = nop_set_suspend;
+ nop->phy.state = OTG_STATE_UNDEFINED;
+
+ nop->phy.otg->phy = &nop->phy;
+ nop->phy.otg->set_host = nop_set_host;
+ nop->phy.otg->set_peripheral = nop_set_peripheral;
+
+ err = usb_set_transceiver(&nop->phy);
if (err) {
dev_err(&pdev->dev, "can't register transceiver, err: %d\n",
err);
@@ -132,10 +126,11 @@ static int __devinit nop_usb_xceiv_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, nop);
- ATOMIC_INIT_NOTIFIER_HEAD(&nop->otg.notifier);
+ ATOMIC_INIT_NOTIFIER_HEAD(&nop->phy.notifier);
return 0;
exit:
+ kfree(nop->phy.otg);
kfree(nop);
return err;
}
@@ -144,9 +139,10 @@ static int __devexit nop_usb_xceiv_remove(struct platform_device *pdev)
{
struct nop_usb_xceiv *nop = platform_get_drvdata(pdev);
- otg_set_transceiver(NULL);
+ usb_set_transceiver(NULL);
platform_set_drvdata(pdev, NULL);
+ kfree(nop->phy.otg);
kfree(nop);
return 0;
diff --git a/drivers/usb/otg/otg.c b/drivers/usb/otg/otg.c
index 307c27bc51eb..801e597a1541 100644
--- a/drivers/usb/otg/otg.c
+++ b/drivers/usb/otg/otg.c
@@ -15,56 +15,56 @@
#include <linux/usb/otg.h>
-static struct otg_transceiver *xceiv;
+static struct usb_phy *phy;
/**
- * otg_get_transceiver - find the (single) OTG transceiver
+ * usb_get_transceiver - find the (single) USB transceiver
*
* Returns the transceiver driver, after getting a refcount to it; or
* null if there is no such transceiver. The caller is responsible for
- * calling otg_put_transceiver() to release that count.
+ * calling usb_put_transceiver() to release that count.
*
* For use by USB host and peripheral drivers.
*/
-struct otg_transceiver *otg_get_transceiver(void)
+struct usb_phy *usb_get_transceiver(void)
{
- if (xceiv)
- get_device(xceiv->dev);
- return xceiv;
+ if (phy)
+ get_device(phy->dev);
+ return phy;
}
-EXPORT_SYMBOL(otg_get_transceiver);
+EXPORT_SYMBOL(usb_get_transceiver);
/**
- * otg_put_transceiver - release the (single) OTG transceiver
- * @x: the transceiver returned by otg_get_transceiver()
+ * usb_put_transceiver - release the (single) USB transceiver
+ * @x: the transceiver returned by usb_get_transceiver()
*
- * Releases a refcount the caller received from otg_get_transceiver().
+ * Releases a refcount the caller received from usb_get_transceiver().
*
* For use by USB host and peripheral drivers.
*/
-void otg_put_transceiver(struct otg_transceiver *x)
+void usb_put_transceiver(struct usb_phy *x)
{
if (x)
put_device(x->dev);
}
-EXPORT_SYMBOL(otg_put_transceiver);
+EXPORT_SYMBOL(usb_put_transceiver);
/**
- * otg_set_transceiver - declare the (single) OTG transceiver
- * @x: the USB OTG transceiver to be used; or NULL
+ * usb_set_transceiver - declare the (single) USB transceiver
+ * @x: the USB transceiver to be used; or NULL
*
* This call is exclusively for use by transceiver drivers, which
* coordinate the activities of drivers for host and peripheral
* controllers, and in some cases for VBUS current regulation.
*/
-int otg_set_transceiver(struct otg_transceiver *x)
+int usb_set_transceiver(struct usb_phy *x)
{
- if (xceiv && x)
+ if (phy && x)
return -EBUSY;
- xceiv = x;
+ phy = x;
return 0;
}
-EXPORT_SYMBOL(otg_set_transceiver);
+EXPORT_SYMBOL(usb_set_transceiver);
const char *otg_state_string(enum usb_otg_state state)
{
diff --git a/drivers/usb/otg/otg_fsm.c b/drivers/usb/otg/otg_fsm.c
index 09117387d2a4..ade131a8ae5e 100644
--- a/drivers/usb/otg/otg_fsm.c
+++ b/drivers/usb/otg/otg_fsm.c
@@ -117,10 +117,10 @@ void otg_leave_state(struct otg_fsm *fsm, enum usb_otg_state old_state)
int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
{
state_changed = 1;
- if (fsm->transceiver->state == new_state)
+ if (fsm->otg->phy->state == new_state)
return 0;
VDBG("Set state: %s\n", otg_state_string(new_state));
- otg_leave_state(fsm, fsm->transceiver->state);
+ otg_leave_state(fsm, fsm->otg->phy->state);
switch (new_state) {
case OTG_STATE_B_IDLE:
otg_drv_vbus(fsm, 0);
@@ -155,8 +155,8 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
otg_loc_conn(fsm, 0);
otg_loc_sof(fsm, 1);
otg_set_protocol(fsm, PROTO_HOST);
- usb_bus_start_enum(fsm->transceiver->host,
- fsm->transceiver->host->otg_port);
+ usb_bus_start_enum(fsm->otg->host,
+ fsm->otg->host->otg_port);
break;
case OTG_STATE_A_IDLE:
otg_drv_vbus(fsm, 0);
@@ -221,7 +221,7 @@ int otg_set_state(struct otg_fsm *fsm, enum usb_otg_state new_state)
break;
}
- fsm->transceiver->state = new_state;
+ fsm->otg->phy->state = new_state;
return 0;
}
@@ -233,7 +233,7 @@ int otg_statemachine(struct otg_fsm *fsm)
spin_lock_irqsave(&fsm->lock, flags);
- state = fsm->transceiver->state;
+ state = fsm->otg->phy->state;
state_changed = 0;
/* State machine state change judgement */
@@ -248,7 +248,7 @@ int otg_statemachine(struct otg_fsm *fsm)
case OTG_STATE_B_IDLE:
if (!fsm->id)
otg_set_state(fsm, OTG_STATE_A_IDLE);
- else if (fsm->b_sess_vld && fsm->transceiver->gadget)
+ else if (fsm->b_sess_vld && fsm->otg->gadget)
otg_set_state(fsm, OTG_STATE_B_PERIPHERAL);
else if (fsm->b_bus_req && fsm->b_sess_end && fsm->b_se0_srp)
otg_set_state(fsm, OTG_STATE_B_SRP_INIT);
@@ -260,7 +260,7 @@ int otg_statemachine(struct otg_fsm *fsm)
case OTG_STATE_B_PERIPHERAL:
if (!fsm->id || !fsm->b_sess_vld)
otg_set_state(fsm, OTG_STATE_B_IDLE);
- else if (fsm->b_bus_req && fsm->transceiver->
+ else if (fsm->b_bus_req && fsm->otg->
gadget->b_hnp_enable && fsm->a_bus_suspend)
otg_set_state(fsm, OTG_STATE_B_WAIT_ACON);
break;
@@ -302,7 +302,7 @@ int otg_statemachine(struct otg_fsm *fsm)
break;
case OTG_STATE_A_HOST:
if ((!fsm->a_bus_req || fsm->a_suspend_req) &&
- fsm->transceiver->host->b_hnp_enable)
+ fsm->otg->host->b_hnp_enable)
otg_set_state(fsm, OTG_STATE_A_SUSPEND);
else if (fsm->id || !fsm->b_conn || fsm->a_bus_drop)
otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
@@ -310,9 +310,9 @@ int otg_statemachine(struct otg_fsm *fsm)
otg_set_state(fsm, OTG_STATE_A_VBUS_ERR);
break;
case OTG_STATE_A_SUSPEND:
- if (!fsm->b_conn && fsm->transceiver->host->b_hnp_enable)
+ if (!fsm->b_conn && fsm->otg->host->b_hnp_enable)
otg_set_state(fsm, OTG_STATE_A_PERIPHERAL);
- else if (!fsm->b_conn && !fsm->transceiver->host->b_hnp_enable)
+ else if (!fsm->b_conn && !fsm->otg->host->b_hnp_enable)
otg_set_state(fsm, OTG_STATE_A_WAIT_BCON);
else if (fsm->a_bus_req || fsm->b_bus_resume)
otg_set_state(fsm, OTG_STATE_A_HOST);
diff --git a/drivers/usb/otg/otg_fsm.h b/drivers/usb/otg/otg_fsm.h
index 0cecf1d593a0..c30a2e1d9e46 100644
--- a/drivers/usb/otg/otg_fsm.h
+++ b/drivers/usb/otg/otg_fsm.h
@@ -82,7 +82,7 @@ struct otg_fsm {
int loc_sof;
struct otg_fsm_ops *ops;
- struct otg_transceiver *transceiver;
+ struct usb_otg *otg;
/* Current usb protocol used: 0:undefine; 1:host; 2:client */
int protocol;
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c
index 14f66c358629..c4a86da858e2 100644
--- a/drivers/usb/otg/twl4030-usb.c
+++ b/drivers/usb/otg/twl4030-usb.c
@@ -144,7 +144,7 @@
#define GPIO_USB_4PIN_ULPI_2430C (3 << 0)
struct twl4030_usb {
- struct otg_transceiver otg;
+ struct usb_phy phy;
struct device *dev;
/* TWL4030 internal USB regulator supplies */
@@ -166,7 +166,7 @@ struct twl4030_usb {
};
/* internal define on top of container_of */
-#define xceiv_to_twl(x) container_of((x), struct twl4030_usb, otg)
+#define phy_to_twl(x) container_of((x), struct twl4030_usb, phy)
/*-------------------------------------------------------------------------*/
@@ -246,10 +246,11 @@ twl4030_usb_clear_bits(struct twl4030_usb *twl, u8 reg, u8 bits)
/*-------------------------------------------------------------------------*/
-static enum usb_xceiv_events twl4030_usb_linkstat(struct twl4030_usb *twl)
+static enum usb_phy_events twl4030_usb_linkstat(struct twl4030_usb *twl)
{
int status;
int linkstat = USB_EVENT_NONE;
+ struct usb_otg *otg = twl->phy.otg;
twl->vbus_supplied = false;
@@ -281,7 +282,7 @@ static enum usb_xceiv_events twl4030_usb_linkstat(struct twl4030_usb *twl)
dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n",
status, status, linkstat);
- twl->otg.last_event = linkstat;
+ twl->phy.last_event = linkstat;
/* REVISIT this assumes host and peripheral controllers
* are registered, and that both are active...
@@ -290,11 +291,11 @@ static enum usb_xceiv_events twl4030_usb_linkstat(struct twl4030_usb *twl)
spin_lock_irq(&twl->lock);
twl->linkstat = linkstat;
if (linkstat == USB_EVENT_ID) {
- twl->otg.default_a = true;
- twl->otg.state = OTG_STATE_A_IDLE;
+ otg->default_a = true;
+ twl->phy.state = OTG_STATE_A_IDLE;
} else {
- twl->otg.default_a = false;
- twl->otg.state = OTG_STATE_B_IDLE;
+ otg->default_a = false;
+ twl->phy.state = OTG_STATE_B_IDLE;
}
spin_unlock_irq(&twl->lock);
@@ -520,8 +521,8 @@ static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
else
twl4030_phy_resume(twl);
- atomic_notifier_call_chain(&twl->otg.notifier, status,
- twl->otg.gadget);
+ atomic_notifier_call_chain(&twl->phy.notifier, status,
+ twl->phy.otg->gadget);
}
sysfs_notify(&twl->dev->kobj, NULL, "vbus");
@@ -542,15 +543,15 @@ static void twl4030_usb_phy_init(struct twl4030_usb *twl)
twl->asleep = 0;
}
- atomic_notifier_call_chain(&twl->otg.notifier, status,
- twl->otg.gadget);
+ atomic_notifier_call_chain(&twl->phy.notifier, status,
+ twl->phy.otg->gadget);
}
sysfs_notify(&twl->dev->kobj, NULL, "vbus");
}
-static int twl4030_set_suspend(struct otg_transceiver *x, int suspend)
+static int twl4030_set_suspend(struct usb_phy *x, int suspend)
{
- struct twl4030_usb *twl = xceiv_to_twl(x);
+ struct twl4030_usb *twl = phy_to_twl(x);
if (suspend)
twl4030_phy_suspend(twl, 1);
@@ -560,33 +561,27 @@ static int twl4030_set_suspend(struct otg_transceiver *x, int suspend)
return 0;
}
-static int twl4030_set_peripheral(struct otg_transceiver *x,
- struct usb_gadget *gadget)
+static int twl4030_set_peripheral(struct usb_otg *otg,
+ struct usb_gadget *gadget)
{
- struct twl4030_usb *twl;
-
- if (!x)
+ if (!otg)
return -ENODEV;
- twl = xceiv_to_twl(x);
- twl->otg.gadget = gadget;
+ otg->gadget = gadget;
if (!gadget)
- twl->otg.state = OTG_STATE_UNDEFINED;
+ otg->phy->state = OTG_STATE_UNDEFINED;
return 0;
}
-static int twl4030_set_host(struct otg_transceiver *x, struct usb_bus *host)
+static int twl4030_set_host(struct usb_otg *otg, struct usb_bus *host)
{
- struct twl4030_usb *twl;
-
- if (!x)
+ if (!otg)
return -ENODEV;
- twl = xceiv_to_twl(x);
- twl->otg.host = host;
+ otg->host = host;
if (!host)
- twl->otg.state = OTG_STATE_UNDEFINED;
+ otg->phy->state = OTG_STATE_UNDEFINED;
return 0;
}
@@ -596,6 +591,7 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev)
struct twl4030_usb_data *pdata = pdev->dev.platform_data;
struct twl4030_usb *twl;
int status, err;
+ struct usb_otg *otg;
if (!pdata) {
dev_dbg(&pdev->dev, "platform_data not available\n");
@@ -606,16 +602,26 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev)
if (!twl)
return -ENOMEM;
+ otg = kzalloc(sizeof *otg, GFP_KERNEL);
+ if (!otg) {
+ kfree(twl);
+ return -ENOMEM;
+ }
+
twl->dev = &pdev->dev;
twl->irq = platform_get_irq(pdev, 0);
- twl->otg.dev = twl->dev;
- twl->otg.label = "twl4030";
- twl->otg.set_host = twl4030_set_host;
- twl->otg.set_peripheral = twl4030_set_peripheral;
- twl->otg.set_suspend = twl4030_set_suspend;
twl->usb_mode = pdata->usb_mode;
twl->vbus_supplied = false;
- twl->asleep = 1;
+ twl->asleep = 1;
+
+ twl->phy.dev = twl->dev;
+ twl->phy.label = "twl4030";
+ twl->phy.otg = otg;
+ twl->phy.set_suspend = twl4030_set_suspend;
+
+ otg->phy = &twl->phy;
+ otg->set_host = twl4030_set_host;
+ otg->set_peripheral = twl4030_set_peripheral;
/* init spinlock for workqueue */
spin_lock_init(&twl->lock);
@@ -623,16 +629,17 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev)
err = twl4030_usb_ldo_init(twl);
if (err) {
dev_err(&pdev->dev, "ldo init failed\n");
+ kfree(otg);
kfree(twl);
return err;
}
- otg_set_transceiver(&twl->otg);
+ usb_set_transceiver(&twl->phy);
platform_set_drvdata(pdev, twl);
if (device_create_file(&pdev->dev, &dev_attr_vbus))
dev_warn(&pdev->dev, "could not create sysfs file\n");
- ATOMIC_INIT_NOTIFIER_HEAD(&twl->otg.notifier);
+ ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier);
/* Our job is to use irqs and status from the power module
* to keep the transceiver disabled when nothing's connected.
@@ -649,6 +656,7 @@ static int __devinit twl4030_usb_probe(struct platform_device *pdev)
if (status < 0) {
dev_dbg(&pdev->dev, "can't get IRQ %d, err %d\n",
twl->irq, status);
+ kfree(otg);
kfree(twl);
return status;
}
@@ -693,6 +701,7 @@ static int __exit twl4030_usb_remove(struct platform_device *pdev)
regulator_put(twl->usb1v8);
regulator_put(twl->usb3v1);
+ kfree(twl->phy.otg);
kfree(twl);
return 0;
diff --git a/drivers/usb/otg/twl6030-usb.c b/drivers/usb/otg/twl6030-usb.c
index ed2b26cfe814..e3fa387ca81e 100644
--- a/drivers/usb/otg/twl6030-usb.c
+++ b/drivers/usb/otg/twl6030-usb.c
@@ -87,7 +87,7 @@
#define VBUS_DET BIT(2)
struct twl6030_usb {
- struct otg_transceiver otg;
+ struct usb_phy phy;
struct device *dev;
/* for vbus reporting with irqs disabled */
@@ -107,7 +107,7 @@ struct twl6030_usb {
unsigned long features;
};
-#define xceiv_to_twl(x) container_of((x), struct twl6030_usb, otg)
+#define phy_to_twl(x) container_of((x), struct twl6030_usb, phy)
/*-------------------------------------------------------------------------*/
@@ -137,13 +137,13 @@ static inline u8 twl6030_readb(struct twl6030_usb *twl, u8 module, u8 address)
return ret;
}
-static int twl6030_phy_init(struct otg_transceiver *x)
+static int twl6030_phy_init(struct usb_phy *x)
{
struct twl6030_usb *twl;
struct device *dev;
struct twl4030_usb_data *pdata;
- twl = xceiv_to_twl(x);
+ twl = phy_to_twl(x);
dev = twl->dev;
pdata = dev->platform_data;
@@ -155,21 +155,21 @@ static int twl6030_phy_init(struct otg_transceiver *x)
return 0;
}
-static void twl6030_phy_shutdown(struct otg_transceiver *x)
+static void twl6030_phy_shutdown(struct usb_phy *x)
{
struct twl6030_usb *twl;
struct device *dev;
struct twl4030_usb_data *pdata;
- twl = xceiv_to_twl(x);
+ twl = phy_to_twl(x);
dev = twl->dev;
pdata = dev->platform_data;
pdata->phy_power(twl->dev, 0, 0);
}
-static int twl6030_phy_suspend(struct otg_transceiver *x, int suspend)
+static int twl6030_phy_suspend(struct usb_phy *x, int suspend)
{
- struct twl6030_usb *twl = xceiv_to_twl(x);
+ struct twl6030_usb *twl = phy_to_twl(x);
struct device *dev = twl->dev;
struct twl4030_usb_data *pdata = dev->platform_data;
@@ -178,9 +178,9 @@ static int twl6030_phy_suspend(struct otg_transceiver *x, int suspend)
return 0;
}
-static int twl6030_start_srp(struct otg_transceiver *x)
+static int twl6030_start_srp(struct usb_otg *otg)
{
- struct twl6030_usb *twl = xceiv_to_twl(x);
+ struct twl6030_usb *twl = phy_to_twl(otg->phy);
twl6030_writeb(twl, TWL_MODULE_USB, 0x24, USB_VBUS_CTRL_SET);
twl6030_writeb(twl, TWL_MODULE_USB, 0x84, USB_VBUS_CTRL_SET);
@@ -256,6 +256,7 @@ static DEVICE_ATTR(vbus, 0444, twl6030_usb_vbus_show, NULL);
static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
{
struct twl6030_usb *twl = _twl;
+ struct usb_otg *otg = twl->phy.otg;
int status;
u8 vbus_state, hw_state;
@@ -268,18 +269,18 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
regulator_enable(twl->usb3v3);
twl->asleep = 1;
status = USB_EVENT_VBUS;
- twl->otg.default_a = false;
- twl->otg.state = OTG_STATE_B_IDLE;
+ otg->default_a = false;
+ twl->phy.state = OTG_STATE_B_IDLE;
twl->linkstat = status;
- twl->otg.last_event = status;
- atomic_notifier_call_chain(&twl->otg.notifier,
- status, twl->otg.gadget);
+ twl->phy.last_event = status;
+ atomic_notifier_call_chain(&twl->phy.notifier,
+ status, otg->gadget);
} else {
status = USB_EVENT_NONE;
twl->linkstat = status;
- twl->otg.last_event = status;
- atomic_notifier_call_chain(&twl->otg.notifier,
- status, twl->otg.gadget);
+ twl->phy.last_event = status;
+ atomic_notifier_call_chain(&twl->phy.notifier,
+ status, otg->gadget);
if (twl->asleep) {
regulator_disable(twl->usb3v3);
twl->asleep = 0;
@@ -294,6 +295,7 @@ static irqreturn_t twl6030_usb_irq(int irq, void *_twl)
static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
{
struct twl6030_usb *twl = _twl;
+ struct usb_otg *otg = twl->phy.otg;
int status = USB_EVENT_NONE;
u8 hw_state;
@@ -307,12 +309,12 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET,
0x10);
status = USB_EVENT_ID;
- twl->otg.default_a = true;
- twl->otg.state = OTG_STATE_A_IDLE;
+ otg->default_a = true;
+ twl->phy.state = OTG_STATE_A_IDLE;
twl->linkstat = status;
- twl->otg.last_event = status;
- atomic_notifier_call_chain(&twl->otg.notifier, status,
- twl->otg.gadget);
+ twl->phy.last_event = status;
+ atomic_notifier_call_chain(&twl->phy.notifier, status,
+ otg->gadget);
} else {
twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_CLR,
0x10);
@@ -324,25 +326,22 @@ static irqreturn_t twl6030_usbotg_irq(int irq, void *_twl)
return IRQ_HANDLED;
}
-static int twl6030_set_peripheral(struct otg_transceiver *x,
+static int twl6030_set_peripheral(struct usb_otg *otg,
struct usb_gadget *gadget)
{
- struct twl6030_usb *twl;
-
- if (!x)
+ if (!otg)
return -ENODEV;
- twl = xceiv_to_twl(x);
- twl->otg.gadget = gadget;
+ otg->gadget = gadget;
if (!gadget)
- twl->otg.state = OTG_STATE_UNDEFINED;
+ otg->phy->state = OTG_STATE_UNDEFINED;
return 0;
}
-static int twl6030_enable_irq(struct otg_transceiver *x)
+static int twl6030_enable_irq(struct usb_phy *x)
{
- struct twl6030_usb *twl = xceiv_to_twl(x);
+ struct twl6030_usb *twl = phy_to_twl(x);
twl6030_writeb(twl, TWL_MODULE_USB, USB_ID_INT_EN_HI_SET, 0x1);
twl6030_interrupt_unmask(0x05, REG_INT_MSK_LINE_C);
@@ -376,9 +375,9 @@ static void otg_set_vbus_work(struct work_struct *data)
CHARGERUSB_CTRL1);
}
-static int twl6030_set_vbus(struct otg_transceiver *x, bool enabled)
+static int twl6030_set_vbus(struct usb_otg *otg, bool enabled)
{
- struct twl6030_usb *twl = xceiv_to_twl(x);
+ struct twl6030_usb *twl = phy_to_twl(otg->phy);
twl->vbus_enable = enabled;
schedule_work(&twl->set_vbus_work);
@@ -386,17 +385,14 @@ static int twl6030_set_vbus(struct otg_transceiver *x, bool enabled)
return 0;
}
-static int twl6030_set_host(struct otg_transceiver *x, struct usb_bus *host)
+static int twl6030_set_host(struct usb_otg *otg, struct usb_bus *host)
{
- struct twl6030_usb *twl;
-
- if (!x)
+ if (!otg)
return -ENODEV;
- twl = xceiv_to_twl(x);
- twl->otg.host = host;
+ otg->host = host;
if (!host)
- twl->otg.state = OTG_STATE_UNDEFINED;
+ otg->phy->state = OTG_STATE_UNDEFINED;
return 0;
}
@@ -405,6 +401,7 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev)
struct twl6030_usb *twl;
int status, err;
struct twl4030_usb_data *pdata;
+ struct usb_otg *otg;
struct device *dev = &pdev->dev;
pdata = dev->platform_data;
@@ -412,19 +409,29 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev)
if (!twl)
return -ENOMEM;
+ otg = kzalloc(sizeof *otg, GFP_KERNEL);
+ if (!otg) {
+ kfree(twl);
+ return -ENOMEM;
+ }
+
twl->dev = &pdev->dev;
twl->irq1 = platform_get_irq(pdev, 0);
twl->irq2 = platform_get_irq(pdev, 1);
twl->features = pdata->features;
- twl->otg.dev = twl->dev;
- twl->otg.label = "twl6030";
- twl->otg.set_host = twl6030_set_host;
- twl->otg.set_peripheral = twl6030_set_peripheral;
- twl->otg.set_vbus = twl6030_set_vbus;
- twl->otg.init = twl6030_phy_init;
- twl->otg.shutdown = twl6030_phy_shutdown;
- twl->otg.set_suspend = twl6030_phy_suspend;
- twl->otg.start_srp = twl6030_start_srp;
+
+ twl->phy.dev = twl->dev;
+ twl->phy.label = "twl6030";
+ twl->phy.otg = otg;
+ twl->phy.init = twl6030_phy_init;
+ twl->phy.shutdown = twl6030_phy_shutdown;
+ twl->phy.set_suspend = twl6030_phy_suspend;
+
+ otg->phy = &twl->phy;
+ otg->set_host = twl6030_set_host;
+ otg->set_peripheral = twl6030_set_peripheral;
+ otg->set_vbus = twl6030_set_vbus;
+ otg->start_srp = twl6030_start_srp;
/* init spinlock for workqueue */
spin_lock_init(&twl->lock);
@@ -432,16 +439,17 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev)
err = twl6030_usb_ldo_init(twl);
if (err) {
dev_err(&pdev->dev, "ldo init failed\n");
+ kfree(otg);
kfree(twl);
return err;
}
- otg_set_transceiver(&twl->otg);
+ usb_set_transceiver(&twl->phy);
platform_set_drvdata(pdev, twl);
if (device_create_file(&pdev->dev, &dev_attr_vbus))
dev_warn(&pdev->dev, "could not create sysfs file\n");
- ATOMIC_INIT_NOTIFIER_HEAD(&twl->otg.notifier);
+ ATOMIC_INIT_NOTIFIER_HEAD(&twl->phy.notifier);
INIT_WORK(&twl->set_vbus_work, otg_set_vbus_work);
@@ -453,6 +461,7 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "can't get IRQ %d, err %d\n",
twl->irq1, status);
device_remove_file(twl->dev, &dev_attr_vbus);
+ kfree(otg);
kfree(twl);
return status;
}
@@ -465,14 +474,15 @@ static int __devinit twl6030_usb_probe(struct platform_device *pdev)
twl->irq2, status);
free_irq(twl->irq1, twl);
device_remove_file(twl->dev, &dev_attr_vbus);
+ kfree(otg);
kfree(twl);
return status;
}
twl->asleep = 0;
pdata->phy_init(dev);
- twl6030_phy_suspend(&twl->otg, 0);
- twl6030_enable_irq(&twl->otg);
+ twl6030_phy_suspend(&twl->phy, 0);
+ twl6030_enable_irq(&twl->phy);
dev_info(&pdev->dev, "Initialized TWL6030 USB module\n");
return 0;
@@ -496,6 +506,7 @@ static int __exit twl6030_usb_remove(struct platform_device *pdev)
pdata->phy_exit(twl->dev);
device_remove_file(twl->dev, &dev_attr_vbus);
cancel_work_sync(&twl->set_vbus_work);
+ kfree(twl->phy.otg);
kfree(twl);
return 0;
diff --git a/drivers/usb/otg/ulpi.c b/drivers/usb/otg/ulpi.c
index 0b0466728fdc..217339dd7a90 100644
--- a/drivers/usb/otg/ulpi.c
+++ b/drivers/usb/otg/ulpi.c
@@ -49,31 +49,31 @@ static struct ulpi_info ulpi_ids[] = {
ULPI_INFO(ULPI_ID(0x0424, 0x0006), "SMSC USB331x"),
};
-static int ulpi_set_otg_flags(struct otg_transceiver *otg)
+static int ulpi_set_otg_flags(struct usb_phy *phy)
{
unsigned int flags = ULPI_OTG_CTRL_DP_PULLDOWN |
ULPI_OTG_CTRL_DM_PULLDOWN;
- if (otg->flags & ULPI_OTG_ID_PULLUP)
+ if (phy->flags & ULPI_OTG_ID_PULLUP)
flags |= ULPI_OTG_CTRL_ID_PULLUP;
/*
* ULPI Specification rev.1.1 default
* for Dp/DmPulldown is enabled.
*/
- if (otg->flags & ULPI_OTG_DP_PULLDOWN_DIS)
+ if (phy->flags & ULPI_OTG_DP_PULLDOWN_DIS)
flags &= ~ULPI_OTG_CTRL_DP_PULLDOWN;
- if (otg->flags & ULPI_OTG_DM_PULLDOWN_DIS)
+ if (phy->flags & ULPI_OTG_DM_PULLDOWN_DIS)
flags &= ~ULPI_OTG_CTRL_DM_PULLDOWN;
- if (otg->flags & ULPI_OTG_EXTVBUSIND)
+ if (phy->flags & ULPI_OTG_EXTVBUSIND)
flags |= ULPI_OTG_CTRL_EXTVBUSIND;
- return otg_io_write(otg, flags, ULPI_OTG_CTRL);
+ return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL);
}
-static int ulpi_set_fc_flags(struct otg_transceiver *otg)
+static int ulpi_set_fc_flags(struct usb_phy *phy)
{
unsigned int flags = 0;
@@ -81,27 +81,27 @@ static int ulpi_set_fc_flags(struct otg_transceiver *otg)
* ULPI Specification rev.1.1 default
* for XcvrSelect is Full Speed.
*/
- if (otg->flags & ULPI_FC_HS)
+ if (phy->flags & ULPI_FC_HS)
flags |= ULPI_FUNC_CTRL_HIGH_SPEED;
- else if (otg->flags & ULPI_FC_LS)
+ else if (phy->flags & ULPI_FC_LS)
flags |= ULPI_FUNC_CTRL_LOW_SPEED;
- else if (otg->flags & ULPI_FC_FS4LS)
+ else if (phy->flags & ULPI_FC_FS4LS)
flags |= ULPI_FUNC_CTRL_FS4LS;
else
flags |= ULPI_FUNC_CTRL_FULL_SPEED;
- if (otg->flags & ULPI_FC_TERMSEL)
+ if (phy->flags & ULPI_FC_TERMSEL)
flags |= ULPI_FUNC_CTRL_TERMSELECT;
/*
* ULPI Specification rev.1.1 default
* for OpMode is Normal Operation.
*/
- if (otg->flags & ULPI_FC_OP_NODRV)
+ if (phy->flags & ULPI_FC_OP_NODRV)
flags |= ULPI_FUNC_CTRL_OPMODE_NONDRIVING;
- else if (otg->flags & ULPI_FC_OP_DIS_NRZI)
+ else if (phy->flags & ULPI_FC_OP_DIS_NRZI)
flags |= ULPI_FUNC_CTRL_OPMODE_DISABLE_NRZI;
- else if (otg->flags & ULPI_FC_OP_NSYNC_NEOP)
+ else if (phy->flags & ULPI_FC_OP_NSYNC_NEOP)
flags |= ULPI_FUNC_CTRL_OPMODE_NOSYNC_NOEOP;
else
flags |= ULPI_FUNC_CTRL_OPMODE_NORMAL;
@@ -112,54 +112,54 @@ static int ulpi_set_fc_flags(struct otg_transceiver *otg)
*/
flags |= ULPI_FUNC_CTRL_SUSPENDM;
- return otg_io_write(otg, flags, ULPI_FUNC_CTRL);
+ return usb_phy_io_write(phy, flags, ULPI_FUNC_CTRL);
}
-static int ulpi_set_ic_flags(struct otg_transceiver *otg)
+static int ulpi_set_ic_flags(struct usb_phy *phy)
{
unsigned int flags = 0;
- if (otg->flags & ULPI_IC_AUTORESUME)
+ if (phy->flags & ULPI_IC_AUTORESUME)
flags |= ULPI_IFC_CTRL_AUTORESUME;
- if (otg->flags & ULPI_IC_EXTVBUS_INDINV)
+ if (phy->flags & ULPI_IC_EXTVBUS_INDINV)
flags |= ULPI_IFC_CTRL_EXTERNAL_VBUS;
- if (otg->flags & ULPI_IC_IND_PASSTHRU)
+ if (phy->flags & ULPI_IC_IND_PASSTHRU)
flags |= ULPI_IFC_CTRL_PASSTHRU;
- if (otg->flags & ULPI_IC_PROTECT_DIS)
+ if (phy->flags & ULPI_IC_PROTECT_DIS)
flags |= ULPI_IFC_CTRL_PROTECT_IFC_DISABLE;
- return otg_io_write(otg, flags, ULPI_IFC_CTRL);
+ return usb_phy_io_write(phy, flags, ULPI_IFC_CTRL);
}
-static int ulpi_set_flags(struct otg_transceiver *otg)
+static int ulpi_set_flags(struct usb_phy *phy)
{
int ret;
- ret = ulpi_set_otg_flags(otg);
+ ret = ulpi_set_otg_flags(phy);
if (ret)
return ret;
- ret = ulpi_set_ic_flags(otg);
+ ret = ulpi_set_ic_flags(phy);
if (ret)
return ret;
- return ulpi_set_fc_flags(otg);
+ return ulpi_set_fc_flags(phy);
}
-static int ulpi_check_integrity(struct otg_transceiver *otg)
+static int ulpi_check_integrity(struct usb_phy *phy)
{
int ret, i;
unsigned int val = 0x55;
for (i = 0; i < 2; i++) {
- ret = otg_io_write(otg, val, ULPI_SCRATCH);
+ ret = usb_phy_io_write(phy, val, ULPI_SCRATCH);
if (ret < 0)
return ret;
- ret = otg_io_read(otg, ULPI_SCRATCH);
+ ret = usb_phy_io_read(phy, ULPI_SCRATCH);
if (ret < 0)
return ret;
@@ -175,13 +175,13 @@ static int ulpi_check_integrity(struct otg_transceiver *otg)
return 0;
}
-static int ulpi_init(struct otg_transceiver *otg)
+static int ulpi_init(struct usb_phy *phy)
{
int i, vid, pid, ret;
u32 ulpi_id = 0;
for (i = 0; i < 4; i++) {
- ret = otg_io_read(otg, ULPI_PRODUCT_ID_HIGH - i);
+ ret = usb_phy_io_read(phy, ULPI_PRODUCT_ID_HIGH - i);
if (ret < 0)
return ret;
ulpi_id = (ulpi_id << 8) | ret;
@@ -199,16 +199,17 @@ static int ulpi_init(struct otg_transceiver *otg)
}
}
- ret = ulpi_check_integrity(otg);
+ ret = ulpi_check_integrity(phy);
if (ret)
return ret;
- return ulpi_set_flags(otg);
+ return ulpi_set_flags(phy);
}
-static int ulpi_set_host(struct otg_transceiver *otg, struct usb_bus *host)
+static int ulpi_set_host(struct usb_otg *otg, struct usb_bus *host)
{
- unsigned int flags = otg_io_read(otg, ULPI_IFC_CTRL);
+ struct usb_phy *phy = otg->phy;
+ unsigned int flags = usb_phy_io_read(phy, ULPI_IFC_CTRL);
if (!host) {
otg->host = NULL;
@@ -221,51 +222,62 @@ static int ulpi_set_host(struct otg_transceiver *otg, struct usb_bus *host)
ULPI_IFC_CTRL_3_PIN_SERIAL_MODE |
ULPI_IFC_CTRL_CARKITMODE);
- if (otg->flags & ULPI_IC_6PIN_SERIAL)
+ if (phy->flags & ULPI_IC_6PIN_SERIAL)
flags |= ULPI_IFC_CTRL_6_PIN_SERIAL_MODE;
- else if (otg->flags & ULPI_IC_3PIN_SERIAL)
+ else if (phy->flags & ULPI_IC_3PIN_SERIAL)
flags |= ULPI_IFC_CTRL_3_PIN_SERIAL_MODE;
- else if (otg->flags & ULPI_IC_CARKIT)
+ else if (phy->flags & ULPI_IC_CARKIT)
flags |= ULPI_IFC_CTRL_CARKITMODE;
- return otg_io_write(otg, flags, ULPI_IFC_CTRL);
+ return usb_phy_io_write(phy, flags, ULPI_IFC_CTRL);
}
-static int ulpi_set_vbus(struct otg_transceiver *otg, bool on)
+static int ulpi_set_vbus(struct usb_otg *otg, bool on)
{
- unsigned int flags = otg_io_read(otg, ULPI_OTG_CTRL);
+ struct usb_phy *phy = otg->phy;
+ unsigned int flags = usb_phy_io_read(phy, ULPI_OTG_CTRL);
flags &= ~(ULPI_OTG_CTRL_DRVVBUS | ULPI_OTG_CTRL_DRVVBUS_EXT);
if (on) {
- if (otg->flags & ULPI_OTG_DRVVBUS)
+ if (phy->flags & ULPI_OTG_DRVVBUS)
flags |= ULPI_OTG_CTRL_DRVVBUS;
- if (otg->flags & ULPI_OTG_DRVVBUS_EXT)
+ if (phy->flags & ULPI_OTG_DRVVBUS_EXT)
flags |= ULPI_OTG_CTRL_DRVVBUS_EXT;
}
- return otg_io_write(otg, flags, ULPI_OTG_CTRL);
+ return usb_phy_io_write(phy, flags, ULPI_OTG_CTRL);
}
-struct otg_transceiver *
-otg_ulpi_create(struct otg_io_access_ops *ops,
+struct usb_phy *
+otg_ulpi_create(struct usb_phy_io_ops *ops,
unsigned int flags)
{
- struct otg_transceiver *otg;
+ struct usb_phy *phy;
+ struct usb_otg *otg;
+
+ phy = kzalloc(sizeof(*phy), GFP_KERNEL);
+ if (!phy)
+ return NULL;
otg = kzalloc(sizeof(*otg), GFP_KERNEL);
- if (!otg)
+ if (!otg) {
+ kfree(phy);
return NULL;
+ }
+
+ phy->label = "ULPI";
+ phy->flags = flags;
+ phy->io_ops = ops;
+ phy->otg = otg;
+ phy->init = ulpi_init;
- otg->label = "ULPI";
- otg->flags = flags;
- otg->io_ops = ops;
- otg->init = ulpi_init;
+ otg->phy = phy;
otg->set_host = ulpi_set_host;
otg->set_vbus = ulpi_set_vbus;
- return otg;
+ return phy;
}
EXPORT_SYMBOL_GPL(otg_ulpi_create);
diff --git a/drivers/usb/otg/ulpi_viewport.c b/drivers/usb/otg/ulpi_viewport.c
index e9a37f90994f..c5ba7e5423fc 100644
--- a/drivers/usb/otg/ulpi_viewport.c
+++ b/drivers/usb/otg/ulpi_viewport.c
@@ -40,7 +40,7 @@ static int ulpi_viewport_wait(void __iomem *view, u32 mask)
return -ETIMEDOUT;
}
-static int ulpi_viewport_read(struct otg_transceiver *otg, u32 reg)
+static int ulpi_viewport_read(struct usb_phy *otg, u32 reg)
{
int ret;
void __iomem *view = otg->io_priv;
@@ -58,7 +58,7 @@ static int ulpi_viewport_read(struct otg_transceiver *otg, u32 reg)
return ULPI_VIEW_DATA_READ(readl(view));
}
-static int ulpi_viewport_write(struct otg_transceiver *otg, u32 val, u32 reg)
+static int ulpi_viewport_write(struct usb_phy *otg, u32 val, u32 reg)
{
int ret;
void __iomem *view = otg->io_priv;
@@ -74,7 +74,7 @@ static int ulpi_viewport_write(struct otg_transceiver *otg, u32 val, u32 reg)
return ulpi_viewport_wait(view, ULPI_VIEW_RUN);
}
-struct otg_io_access_ops ulpi_viewport_access_ops = {
+struct usb_phy_io_ops ulpi_viewport_access_ops = {
.read = ulpi_viewport_read,
.write = ulpi_viewport_write,
};
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index e9a5b1d2615e..a165490bae48 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -413,8 +413,7 @@ static int usbhs_probe(struct platform_device *pdev)
struct renesas_usbhs_platform_info *info = pdev->dev.platform_data;
struct renesas_usbhs_driver_callback *dfunc;
struct usbhs_priv *priv;
- struct resource *res;
- unsigned int irq;
+ struct resource *res, *irq_res;
int ret;
/* check platform information */
@@ -426,8 +425,8 @@ static int usbhs_probe(struct platform_device *pdev)
/* platform data */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- irq = platform_get_irq(pdev, 0);
- if (!res || (int)irq <= 0) {
+ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res || !irq_res) {
dev_err(&pdev->dev, "Not enough Renesas USB platform resources.\n");
return -ENODEV;
}
@@ -476,7 +475,9 @@ static int usbhs_probe(struct platform_device *pdev)
/*
* priv settings
*/
- priv->irq = irq;
+ priv->irq = irq_res->start;
+ if (irq_res->flags & IORESOURCE_IRQ_SHAREABLE)
+ priv->irqflags = IRQF_SHARED;
priv->pdev = pdev;
INIT_DELAYED_WORK(&priv->notify_hotplug_work, usbhsc_notify_hotplug);
spin_lock_init(usbhs_priv_to_lock(priv));
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h
index d79b3e27db95..3f3ccd358753 100644
--- a/drivers/usb/renesas_usbhs/common.h
+++ b/drivers/usb/renesas_usbhs/common.h
@@ -242,6 +242,7 @@ struct usbhs_priv {
void __iomem *base;
unsigned int irq;
+ unsigned long irqflags;
struct renesas_usbhs_platform_callback pfunc;
struct renesas_usbhs_driver_param dparam;
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index 72339bd6fcab..6ec7f838d7fa 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -23,6 +23,7 @@
#define usbhsf_get_cfifo(p) (&((p)->fifo_info.cfifo))
#define usbhsf_get_d0fifo(p) (&((p)->fifo_info.d0fifo))
#define usbhsf_get_d1fifo(p) (&((p)->fifo_info.d1fifo))
+#define usbhsf_is_cfifo(p, f) (usbhsf_get_cfifo(p) == f)
#define usbhsf_fifo_is_busy(f) ((f)->pipe) /* see usbhs_pipe_select_fifo */
@@ -75,8 +76,7 @@ void usbhs_pkt_push(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt,
pipe->handler = &usbhsf_null_handler;
}
- list_del_init(&pkt->node);
- list_add_tail(&pkt->node, &pipe->list);
+ list_move_tail(&pkt->node, &pipe->list);
/*
* each pkt must hold own handler.
@@ -106,7 +106,7 @@ static struct usbhs_pkt *__usbhsf_pkt_get(struct usbhs_pipe *pipe)
if (list_empty(&pipe->list))
return NULL;
- return list_entry(pipe->list.next, struct usbhs_pkt, node);
+ return list_first_entry(&pipe->list, struct usbhs_pkt, node);
}
struct usbhs_pkt *usbhs_pkt_pop(struct usbhs_pipe *pipe, struct usbhs_pkt *pkt)
@@ -305,7 +305,10 @@ static int usbhsf_fifo_select(struct usbhs_pipe *pipe,
}
/* "base" will be used below */
- usbhs_write(priv, fifo->sel, base | MBW_32);
+ if (usbhs_get_dparam(priv, has_sudmac) && !usbhsf_is_cfifo(priv, fifo))
+ usbhs_write(priv, fifo->sel, base);
+ else
+ usbhs_write(priv, fifo->sel, base | MBW_32);
/* check ISEL and CURPIPE value */
while (timeout--) {
@@ -762,9 +765,9 @@ static int __usbhsf_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
}
static void usbhsf_dma_complete(void *arg);
-static void usbhsf_dma_prepare_tasklet(unsigned long data)
+static void xfer_work(struct work_struct *work)
{
- struct usbhs_pkt *pkt = (struct usbhs_pkt *)data;
+ struct usbhs_pkt *pkt = container_of(work, struct usbhs_pkt, work);
struct usbhs_pipe *pipe = pkt->pipe;
struct usbhs_fifo *fifo = usbhs_pipe_to_fifo(pipe);
struct usbhs_priv *priv = usbhs_pipe_to_priv(pipe);
@@ -783,9 +786,8 @@ static void usbhsf_dma_prepare_tasklet(unsigned long data)
sg_dma_address(&sg) = pkt->dma + pkt->actual;
sg_dma_len(&sg) = pkt->trans;
- desc = chan->device->device_prep_slave_sg(chan, &sg, 1, dir,
- DMA_PREP_INTERRUPT |
- DMA_CTRL_ACK);
+ desc = dmaengine_prep_slave_sg(chan, &sg, 1, dir,
+ DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
if (!desc)
return;
@@ -844,11 +846,8 @@ static int usbhsf_dma_prepare_push(struct usbhs_pkt *pkt, int *is_done)
pkt->trans = len;
- tasklet_init(&fifo->tasklet,
- usbhsf_dma_prepare_tasklet,
- (unsigned long)pkt);
-
- tasklet_schedule(&fifo->tasklet);
+ INIT_WORK(&pkt->work, xfer_work);
+ schedule_work(&pkt->work);
return 0;
@@ -938,11 +937,8 @@ static int usbhsf_dma_try_pop(struct usbhs_pkt *pkt, int *is_done)
pkt->trans = len;
- tasklet_init(&fifo->tasklet,
- usbhsf_dma_prepare_tasklet,
- (unsigned long)pkt);
-
- tasklet_schedule(&fifo->tasklet);
+ INIT_WORK(&pkt->work, xfer_work);
+ schedule_work(&pkt->work);
return 0;
diff --git a/drivers/usb/renesas_usbhs/fifo.h b/drivers/usb/renesas_usbhs/fifo.h
index f68609c0f489..c31731a843d1 100644
--- a/drivers/usb/renesas_usbhs/fifo.h
+++ b/drivers/usb/renesas_usbhs/fifo.h
@@ -19,6 +19,7 @@
#include <linux/interrupt.h>
#include <linux/sh_dma.h>
+#include <linux/workqueue.h>
#include <asm/dma.h>
#include "pipe.h"
@@ -31,7 +32,6 @@ struct usbhs_fifo {
u32 ctr; /* xFIFOCTR */
struct usbhs_pipe *pipe;
- struct tasklet_struct tasklet;
struct dma_chan *tx_chan;
struct dma_chan *rx_chan;
@@ -53,6 +53,7 @@ struct usbhs_pkt {
struct usbhs_pkt_handle *handler;
void (*done)(struct usbhs_priv *priv,
struct usbhs_pkt *pkt);
+ struct work_struct work;
dma_addr_t dma;
void *buf;
int length;
diff --git a/drivers/usb/renesas_usbhs/mod.c b/drivers/usb/renesas_usbhs/mod.c
index 1b97fb12694b..0871e816df45 100644
--- a/drivers/usb/renesas_usbhs/mod.c
+++ b/drivers/usb/renesas_usbhs/mod.c
@@ -152,7 +152,7 @@ int usbhs_mod_probe(struct usbhs_priv *priv)
/* irq settings */
ret = request_irq(priv->irq, usbhs_interrupt,
- 0, dev_name(dev), priv);
+ priv->irqflags, dev_name(dev), priv);
if (ret) {
dev_err(dev, "irq request err\n");
goto mod_init_gadget_err;
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 7542aa94a462..00bd2a5e0362 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -165,69 +165,32 @@ static void usbhsg_queue_push(struct usbhsg_uep *uep,
/*
* dma map/unmap
*/
-static int usbhsg_dma_map(struct device *dev,
- struct usbhs_pkt *pkt,
- enum dma_data_direction dir)
-{
- struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt);
- struct usb_request *req = &ureq->req;
-
- if (pkt->dma != DMA_ADDR_INVALID) {
- dev_err(dev, "dma is already mapped\n");
- return -EIO;
- }
-
- if (req->dma == DMA_ADDR_INVALID) {
- pkt->dma = dma_map_single(dev, pkt->buf, pkt->length, dir);
- } else {
- dma_sync_single_for_device(dev, req->dma, req->length, dir);
- pkt->dma = req->dma;
- }
-
- if (dma_mapping_error(dev, pkt->dma)) {
- dev_err(dev, "dma mapping error %llx\n", (u64)pkt->dma);
- return -EIO;
- }
-
- return 0;
-}
-
-static int usbhsg_dma_unmap(struct device *dev,
- struct usbhs_pkt *pkt,
- enum dma_data_direction dir)
+static int usbhsg_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
{
struct usbhsg_request *ureq = usbhsg_pkt_to_ureq(pkt);
struct usb_request *req = &ureq->req;
-
- if (pkt->dma == DMA_ADDR_INVALID) {
- dev_err(dev, "dma is not mapped\n");
- return -EIO;
- }
-
- if (req->dma == DMA_ADDR_INVALID)
- dma_unmap_single(dev, pkt->dma, pkt->length, dir);
- else
- dma_sync_single_for_cpu(dev, req->dma, req->length, dir);
-
- pkt->dma = DMA_ADDR_INVALID;
-
- return 0;
-}
-
-static int usbhsg_dma_map_ctrl(struct usbhs_pkt *pkt, int map)
-{
struct usbhs_pipe *pipe = pkt->pipe;
struct usbhsg_uep *uep = usbhsg_pipe_to_uep(pipe);
struct usbhsg_gpriv *gpriv = usbhsg_uep_to_gpriv(uep);
- struct device *dev = usbhsg_gpriv_to_dev(gpriv);
enum dma_data_direction dir;
+ int ret = 0;
- dir = usbhs_pipe_is_dir_in(pipe) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ dir = usbhs_pipe_is_dir_host(pipe);
- if (map)
- return usbhsg_dma_map(dev, pkt, dir);
- else
- return usbhsg_dma_unmap(dev, pkt, dir);
+ if (map) {
+ /* it can not use scatter/gather */
+ WARN_ON(req->num_sgs);
+
+ ret = usb_gadget_map_request(&gpriv->gadget, req, dir);
+ if (ret < 0)
+ return ret;
+
+ pkt->dma = req->dma;
+ } else {
+ usb_gadget_unmap_request(&gpriv->gadget, req, dir);
+ }
+
+ return ret;
}
/*
@@ -657,8 +620,6 @@ static struct usb_request *usbhsg_ep_alloc_request(struct usb_ep *ep,
usbhs_pkt_init(usbhsg_ureq_to_pkt(ureq));
- ureq->req.dma = DMA_ADDR_INVALID;
-
return &ureq->req;
}
@@ -941,6 +902,11 @@ static int usbhsg_stop(struct usbhs_priv *priv)
return usbhsg_try_stop(priv, USBHSG_STATUS_STARTED);
}
+static void usbhs_mod_gadget_release(struct device *pdev)
+{
+ /* do nothing */
+}
+
int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
{
struct usbhsg_gpriv *gpriv;
@@ -989,6 +955,7 @@ int usbhs_mod_gadget_probe(struct usbhs_priv *priv)
*/
dev_set_name(&gpriv->gadget.dev, "gadget");
gpriv->gadget.dev.parent = dev;
+ gpriv->gadget.dev.release = usbhs_mod_gadget_release;
gpriv->gadget.name = "renesas_usbhs_udc";
gpriv->gadget.ops = &usbhsg_gadget_ops;
gpriv->gadget.max_speed = USB_SPEED_HIGH;
diff --git a/drivers/usb/serial/Kconfig b/drivers/usb/serial/Kconfig
index 677f577c0243..7141d6599060 100644
--- a/drivers/usb/serial/Kconfig
+++ b/drivers/usb/serial/Kconfig
@@ -238,6 +238,15 @@ config USB_SERIAL_EDGEPORT_TI
To compile this driver as a module, choose M here: the
module will be called io_ti.
+config USB_SERIAL_F81232
+ tristate "USB Fintek F81232 Single Port Serial Driver"
+ help
+ Say Y here if you want to use the Fintek F81232 single
+ port usb to serial adapter.
+
+ To compile this driver as a module, choose M here: the
+ module will be called f81232.
+
config USB_SERIAL_GARMIN
tristate "USB Garmin GPS driver"
help
@@ -417,6 +426,14 @@ config USB_SERIAL_MCT_U232
To compile this driver as a module, choose M here: the
module will be called mct_u232.
+config USB_SERIAL_METRO
+ tristate "USB Metrologic Instruments USB-POS Barcode Scanner Driver"
+ ---help---
+ Say Y here if you want to use a USB POS Metrologic barcode scanner.
+
+ To compile this driver as a module, choose M here: the
+ module will be called metro-usb.
+
config USB_SERIAL_MOS7720
tristate "USB Moschip 7720 Serial Driver"
---help---
diff --git a/drivers/usb/serial/Makefile b/drivers/usb/serial/Makefile
index 9e536eefb32c..07f198ee0486 100644
--- a/drivers/usb/serial/Makefile
+++ b/drivers/usb/serial/Makefile
@@ -23,6 +23,7 @@ obj-$(CONFIG_USB_SERIAL_DIGI_ACCELEPORT) += digi_acceleport.o
obj-$(CONFIG_USB_SERIAL_EDGEPORT) += io_edgeport.o
obj-$(CONFIG_USB_SERIAL_EDGEPORT_TI) += io_ti.o
obj-$(CONFIG_USB_SERIAL_EMPEG) += empeg.o
+obj-$(CONFIG_USB_SERIAL_F81232) += f81232.o
obj-$(CONFIG_USB_SERIAL_FTDI_SIO) += ftdi_sio.o
obj-$(CONFIG_USB_SERIAL_FUNSOFT) += funsoft.o
obj-$(CONFIG_USB_SERIAL_GARMIN) += garmin_gps.o
@@ -36,6 +37,7 @@ obj-$(CONFIG_USB_SERIAL_KEYSPAN_PDA) += keyspan_pda.o
obj-$(CONFIG_USB_SERIAL_KLSI) += kl5kusb105.o
obj-$(CONFIG_USB_SERIAL_KOBIL_SCT) += kobil_sct.o
obj-$(CONFIG_USB_SERIAL_MCT_U232) += mct_u232.o
+obj-$(CONFIG_USB_SERIAL_METRO) += metro-usb.o
obj-$(CONFIG_USB_SERIAL_MOS7720) += mos7720.o
obj-$(CONFIG_USB_SERIAL_MOS7840) += mos7840.o
obj-$(CONFIG_USB_SERIAL_MOTOROLA) += moto_modem.o
diff --git a/drivers/usb/serial/aircable.c b/drivers/usb/serial/aircable.c
index 123bf9155339..eec4fb9a35c1 100644
--- a/drivers/usb/serial/aircable.c
+++ b/drivers/usb/serial/aircable.c
@@ -175,7 +175,6 @@ static struct usb_driver aircable_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
static struct usb_serial_driver aircable_device = {
@@ -183,7 +182,6 @@ static struct usb_serial_driver aircable_device = {
.owner = THIS_MODULE,
.name = "aircable",
},
- .usb_driver = &aircable_driver,
.id_table = id_table,
.num_ports = 1,
.bulk_out_size = HCI_COMPLETE_FRAME,
@@ -194,36 +192,16 @@ static struct usb_serial_driver aircable_device = {
.unthrottle = usb_serial_generic_unthrottle,
};
-static int __init aircable_init(void)
-{
- int retval;
- retval = usb_serial_register(&aircable_device);
- if (retval)
- goto failed_serial_register;
- retval = usb_register(&aircable_driver);
- if (retval)
- goto failed_usb_register;
- return 0;
-
-failed_usb_register:
- usb_serial_deregister(&aircable_device);
-failed_serial_register:
- return retval;
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &aircable_device, NULL
+};
-static void __exit aircable_exit(void)
-{
- usb_deregister(&aircable_driver);
- usb_serial_deregister(&aircable_device);
-}
+module_usb_serial_driver(aircable_driver, serial_drivers);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL");
-module_init(aircable_init);
-module_exit(aircable_exit);
-
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/usb/serial/ark3116.c b/drivers/usb/serial/ark3116.c
index 69328dcfd91a..f99f47100dd8 100644
--- a/drivers/usb/serial/ark3116.c
+++ b/drivers/usb/serial/ark3116.c
@@ -719,7 +719,6 @@ static struct usb_driver ark3116_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
static struct usb_serial_driver ark3116_device = {
@@ -728,7 +727,6 @@ static struct usb_serial_driver ark3116_device = {
.name = "ark3116",
},
.id_table = id_table,
- .usb_driver = &ark3116_driver,
.num_ports = 1,
.attach = ark3116_attach,
.release = ark3116_release,
@@ -745,32 +743,12 @@ static struct usb_serial_driver ark3116_device = {
.process_read_urb = ark3116_process_read_urb,
};
-static int __init ark3116_init(void)
-{
- int retval;
-
- retval = usb_serial_register(&ark3116_device);
- if (retval)
- return retval;
- retval = usb_register(&ark3116_driver);
- if (retval == 0) {
- printk(KERN_INFO "%s:"
- DRIVER_VERSION ":"
- DRIVER_DESC "\n",
- KBUILD_MODNAME);
- } else
- usb_serial_deregister(&ark3116_device);
- return retval;
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &ark3116_device, NULL
+};
-static void __exit ark3116_exit(void)
-{
- usb_deregister(&ark3116_driver);
- usb_serial_deregister(&ark3116_device);
-}
+module_usb_serial_driver(ark3116_driver, serial_drivers);
-module_init(ark3116_init);
-module_exit(ark3116_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/usb/serial/belkin_sa.c b/drivers/usb/serial/belkin_sa.c
index 29ffeb6279c7..a52e0d2cec31 100644
--- a/drivers/usb/serial/belkin_sa.c
+++ b/drivers/usb/serial/belkin_sa.c
@@ -78,7 +78,6 @@ static struct usb_driver belkin_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table_combined,
- .no_dynamic_id = 1,
};
/* All of the device info needed for the serial converters */
@@ -88,7 +87,6 @@ static struct usb_serial_driver belkin_device = {
.name = "belkin",
},
.description = "Belkin / Peracom / GoHubs USB Serial Adapter",
- .usb_driver = &belkin_driver,
.id_table = id_table_combined,
.num_ports = 1,
.open = belkin_sa_open,
@@ -103,6 +101,10 @@ static struct usb_serial_driver belkin_device = {
.release = belkin_sa_release,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &belkin_device, NULL
+};
+
struct belkin_sa_private {
spinlock_t lock;
unsigned long control_state;
@@ -522,34 +524,7 @@ exit:
return retval;
}
-
-static int __init belkin_sa_init(void)
-{
- int retval;
- retval = usb_serial_register(&belkin_device);
- if (retval)
- goto failed_usb_serial_register;
- retval = usb_register(&belkin_driver);
- if (retval)
- goto failed_usb_register;
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return 0;
-failed_usb_register:
- usb_serial_deregister(&belkin_device);
-failed_usb_serial_register:
- return retval;
-}
-
-static void __exit belkin_sa_exit (void)
-{
- usb_deregister(&belkin_driver);
- usb_serial_deregister(&belkin_device);
-}
-
-
-module_init(belkin_sa_init);
-module_exit(belkin_sa_exit);
+module_usb_serial_driver(belkin_driver, serial_drivers);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/bus.c b/drivers/usb/serial/bus.c
index 7f547dc3a590..ed8adb052ca7 100644
--- a/drivers/usb/serial/bus.c
+++ b/drivers/usb/serial/bus.c
@@ -60,8 +60,6 @@ static int usb_serial_device_probe(struct device *dev)
retval = -ENODEV;
goto exit;
}
- if (port->dev_state != PORT_REGISTERING)
- goto exit;
driver = port->serial->type;
if (driver->port_probe) {
@@ -98,9 +96,6 @@ static int usb_serial_device_remove(struct device *dev)
if (!port)
return -ENODEV;
- if (port->dev_state != PORT_UNREGISTERING)
- return retval;
-
device_remove_file(&port->dev, &dev_attr_port_number);
driver = port->serial->type;
diff --git a/drivers/usb/serial/ch341.c b/drivers/usb/serial/ch341.c
index 5e53cc59e652..aaab32db31d0 100644
--- a/drivers/usb/serial/ch341.c
+++ b/drivers/usb/serial/ch341.c
@@ -625,7 +625,6 @@ static struct usb_driver ch341_driver = {
.resume = usb_serial_resume,
.reset_resume = ch341_reset_resume,
.id_table = id_table,
- .no_dynamic_id = 1,
.supports_autosuspend = 1,
};
@@ -635,7 +634,6 @@ static struct usb_serial_driver ch341_device = {
.name = "ch341-uart",
},
.id_table = id_table,
- .usb_driver = &ch341_driver,
.num_ports = 1,
.open = ch341_open,
.dtr_rts = ch341_dtr_rts,
@@ -650,30 +648,13 @@ static struct usb_serial_driver ch341_device = {
.attach = ch341_attach,
};
-static int __init ch341_init(void)
-{
- int retval;
-
- retval = usb_serial_register(&ch341_device);
- if (retval)
- return retval;
- retval = usb_register(&ch341_driver);
- if (retval)
- usb_serial_deregister(&ch341_device);
- return retval;
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &ch341_device, NULL
+};
-static void __exit ch341_exit(void)
-{
- usb_deregister(&ch341_driver);
- usb_serial_deregister(&ch341_device);
-}
+module_usb_serial_driver(ch341_driver, serial_drivers);
-module_init(ch341_init);
-module_exit(ch341_exit);
MODULE_LICENSE("GPL");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
-
-/* EOF ch341.c */
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index 08a5575724cd..ec30f95ef399 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -49,6 +49,7 @@ static int cp210x_tiocmset_port(struct usb_serial_port *port,
unsigned int, unsigned int);
static void cp210x_break_ctl(struct tty_struct *, int);
static int cp210x_startup(struct usb_serial *);
+static void cp210x_release(struct usb_serial *);
static void cp210x_dtr_rts(struct usb_serial_port *p, int on);
static bool debug;
@@ -121,6 +122,8 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x10C4, 0x8665) }, /* AC-Services OBD-IF */
{ USB_DEVICE(0x10C4, 0xEA60) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA61) }, /* Silicon Labs factory default */
+ { USB_DEVICE(0x10C4, 0xEA70) }, /* Silicon Labs factory default */
+ { USB_DEVICE(0x10C4, 0xEA80) }, /* Silicon Labs factory default */
{ USB_DEVICE(0x10C4, 0xEA71) }, /* Infinity GPS-MIC-1 Radio Monophone */
{ USB_DEVICE(0x10C4, 0xF001) }, /* Elan Digital Systems USBscope50 */
{ USB_DEVICE(0x10C4, 0xF002) }, /* Elan Digital Systems USBwave12 */
@@ -149,12 +152,15 @@ static const struct usb_device_id id_table[] = {
MODULE_DEVICE_TABLE(usb, id_table);
+struct cp210x_port_private {
+ __u8 bInterfaceNumber;
+};
+
static struct usb_driver cp210x_driver = {
.name = "cp210x",
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
static struct usb_serial_driver cp210x_device = {
@@ -162,7 +168,6 @@ static struct usb_serial_driver cp210x_device = {
.owner = THIS_MODULE,
.name = "cp210x",
},
- .usb_driver = &cp210x_driver,
.id_table = id_table,
.num_ports = 1,
.bulk_in_size = 256,
@@ -174,9 +179,14 @@ static struct usb_serial_driver cp210x_device = {
.tiocmget = cp210x_tiocmget,
.tiocmset = cp210x_tiocmset,
.attach = cp210x_startup,
+ .release = cp210x_release,
.dtr_rts = cp210x_dtr_rts
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &cp210x_device, NULL
+};
+
/* Config request types */
#define REQTYPE_HOST_TO_DEVICE 0x41
#define REQTYPE_DEVICE_TO_HOST 0xc1
@@ -261,6 +271,7 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request,
unsigned int *data, int size)
{
struct usb_serial *serial = port->serial;
+ struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
__le32 *buf;
int result, i, length;
@@ -276,7 +287,8 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request,
/* Issue the request, attempting to read 'size' bytes */
result = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
request, REQTYPE_DEVICE_TO_HOST, 0x0000,
- 0, buf, size, 300);
+ port_priv->bInterfaceNumber, buf, size,
+ USB_CTRL_GET_TIMEOUT);
/* Convert data into an array of integers */
for (i = 0; i < length; i++)
@@ -286,7 +298,7 @@ static int cp210x_get_config(struct usb_serial_port *port, u8 request,
if (result != size) {
dbg("%s - Unable to send config request, "
- "request=0x%x size=%d result=%d\n",
+ "request=0x%x size=%d result=%d",
__func__, request, size, result);
if (result > 0)
result = -EPROTO;
@@ -307,6 +319,7 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request,
unsigned int *data, int size)
{
struct usb_serial *serial = port->serial;
+ struct cp210x_port_private *port_priv = usb_get_serial_port_data(port);
__le32 *buf;
int result, i, length;
@@ -328,19 +341,21 @@ static int cp210x_set_config(struct usb_serial_port *port, u8 request,
result = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
request, REQTYPE_HOST_TO_DEVICE, 0x0000,
- 0, buf, size, 300);
+ port_priv->bInterfaceNumber, buf, size,
+ USB_CTRL_SET_TIMEOUT);
} else {
result = usb_control_msg(serial->dev,
usb_sndctrlpipe(serial->dev, 0),
request, REQTYPE_HOST_TO_DEVICE, data[0],
- 0, NULL, 0, 300);
+ port_priv->bInterfaceNumber, NULL, 0,
+ USB_CTRL_SET_TIMEOUT);
}
kfree(buf);
if ((size > 2 && result != size) || result < 0) {
dbg("%s - Unable to send request, "
- "request=0x%x size=%d result=%d\n",
+ "request=0x%x size=%d result=%d",
__func__, request, size, result);
if (result > 0)
result = -EPROTO;
@@ -683,13 +698,13 @@ static void cp210x_set_termios(struct tty_struct *tty,
default:
dbg("cp210x driver does not "
"support the number of bits requested,"
- " using 8 bit mode\n");
+ " using 8 bit mode");
bits |= BITS_DATA_8;
break;
}
if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
dbg("Number of data bits requested "
- "not supported by device\n");
+ "not supported by device");
}
if ((cflag & (PARENB|PARODD|CMSPAR)) !=
@@ -716,8 +731,7 @@ static void cp210x_set_termios(struct tty_struct *tty,
}
}
if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
- dbg("Parity mode not supported "
- "by device\n");
+ dbg("Parity mode not supported by device");
}
if ((cflag & CSTOPB) != (old_cflag & CSTOPB)) {
@@ -732,7 +746,7 @@ static void cp210x_set_termios(struct tty_struct *tty,
}
if (cp210x_set_config(port, CP210X_SET_LINE_CTL, &bits, 2))
dbg("Number of stop bits requested "
- "not supported by device\n");
+ "not supported by device");
}
if ((cflag & CRTSCTS) != (old_cflag & CRTSCTS)) {
@@ -844,40 +858,40 @@ static void cp210x_break_ctl (struct tty_struct *tty, int break_state)
static int cp210x_startup(struct usb_serial *serial)
{
+ struct cp210x_port_private *port_priv;
+ int i;
+
/* cp210x buffers behave strangely unless device is reset */
usb_reset_device(serial->dev);
- return 0;
-}
-static int __init cp210x_init(void)
-{
- int retval;
+ for (i = 0; i < serial->num_ports; i++) {
+ port_priv = kzalloc(sizeof(*port_priv), GFP_KERNEL);
+ if (!port_priv)
+ return -ENOMEM;
- retval = usb_serial_register(&cp210x_device);
- if (retval)
- return retval; /* Failed to register */
+ memset(port_priv, 0x00, sizeof(*port_priv));
+ port_priv->bInterfaceNumber =
+ serial->interface->cur_altsetting->desc.bInterfaceNumber;
- retval = usb_register(&cp210x_driver);
- if (retval) {
- /* Failed to register */
- usb_serial_deregister(&cp210x_device);
- return retval;
+ usb_set_serial_port_data(serial->port[i], port_priv);
}
- /* Success */
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
return 0;
}
-static void __exit cp210x_exit(void)
+static void cp210x_release(struct usb_serial *serial)
{
- usb_deregister(&cp210x_driver);
- usb_serial_deregister(&cp210x_device);
+ struct cp210x_port_private *port_priv;
+ int i;
+
+ for (i = 0; i < serial->num_ports; i++) {
+ port_priv = usb_get_serial_port_data(serial->port[i]);
+ kfree(port_priv);
+ usb_set_serial_port_data(serial->port[i], NULL);
+ }
}
-module_init(cp210x_init);
-module_exit(cp210x_exit);
+module_usb_serial_driver(cp210x_driver, serial_drivers);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/usb/serial/cyberjack.c b/drivers/usb/serial/cyberjack.c
index 6bc3802a581a..d39b9418f2fb 100644
--- a/drivers/usb/serial/cyberjack.c
+++ b/drivers/usb/serial/cyberjack.c
@@ -82,7 +82,6 @@ static struct usb_driver cyberjack_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
static struct usb_serial_driver cyberjack_device = {
@@ -91,7 +90,6 @@ static struct usb_serial_driver cyberjack_device = {
.name = "cyberjack",
},
.description = "Reiner SCT Cyberjack USB card reader",
- .usb_driver = &cyberjack_driver,
.id_table = id_table,
.num_ports = 1,
.attach = cyberjack_startup,
@@ -106,6 +104,10 @@ static struct usb_serial_driver cyberjack_device = {
.write_bulk_callback = cyberjack_write_bulk_callback,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &cyberjack_device, NULL
+};
+
struct cyberjack_private {
spinlock_t lock; /* Lock for SMP */
short rdtodo; /* Bytes still to read */
@@ -473,35 +475,7 @@ exit:
usb_serial_port_softint(port);
}
-static int __init cyberjack_init(void)
-{
- int retval;
- retval = usb_serial_register(&cyberjack_device);
- if (retval)
- goto failed_usb_serial_register;
- retval = usb_register(&cyberjack_driver);
- if (retval)
- goto failed_usb_register;
-
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION " "
- DRIVER_AUTHOR "\n");
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
-
- return 0;
-failed_usb_register:
- usb_serial_deregister(&cyberjack_device);
-failed_usb_serial_register:
- return retval;
-}
-
-static void __exit cyberjack_exit(void)
-{
- usb_deregister(&cyberjack_driver);
- usb_serial_deregister(&cyberjack_device);
-}
-
-module_init(cyberjack_init);
-module_exit(cyberjack_exit);
+module_usb_serial_driver(cyberjack_driver, serial_drivers);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/cypress_m8.c b/drivers/usb/serial/cypress_m8.c
index 3bdeafa29c24..afc886c75d2f 100644
--- a/drivers/usb/serial/cypress_m8.c
+++ b/drivers/usb/serial/cypress_m8.c
@@ -94,7 +94,6 @@ static struct usb_driver cypress_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table_combined,
- .no_dynamic_id = 1,
};
enum packet_format {
@@ -163,7 +162,6 @@ static struct usb_serial_driver cypress_earthmate_device = {
.name = "earthmate",
},
.description = "DeLorme Earthmate USB",
- .usb_driver = &cypress_driver,
.id_table = id_table_earthmate,
.num_ports = 1,
.attach = cypress_earthmate_startup,
@@ -190,7 +188,6 @@ static struct usb_serial_driver cypress_hidcom_device = {
.name = "cyphidcom",
},
.description = "HID->COM RS232 Adapter",
- .usb_driver = &cypress_driver,
.id_table = id_table_cyphidcomrs232,
.num_ports = 1,
.attach = cypress_hidcom_startup,
@@ -217,7 +214,6 @@ static struct usb_serial_driver cypress_ca42v2_device = {
.name = "nokiaca42v2",
},
.description = "Nokia CA-42 V2 Adapter",
- .usb_driver = &cypress_driver,
.id_table = id_table_nokiaca42v2,
.num_ports = 1,
.attach = cypress_ca42v2_startup,
@@ -238,6 +234,11 @@ static struct usb_serial_driver cypress_ca42v2_device = {
.write_int_callback = cypress_write_int_callback,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &cypress_earthmate_device, &cypress_hidcom_device,
+ &cypress_ca42v2_device, NULL
+};
+
/*****************************************************************************
* Cypress serial helper functions
*****************************************************************************/
@@ -800,7 +801,7 @@ send:
cypress_write_int_callback, port, priv->write_urb_interval);
result = usb_submit_urb(port->interrupt_out_urb, GFP_ATOMIC);
if (result) {
- dev_err(&port->dev,
+ dev_err_console(port,
"%s - failed submitting write urb, error %d\n",
__func__, result);
priv->write_urb_in_use = 0;
@@ -1345,58 +1346,7 @@ static void cypress_write_int_callback(struct urb *urb)
cypress_send(port);
}
-
-/*****************************************************************************
- * Module functions
- *****************************************************************************/
-
-static int __init cypress_init(void)
-{
- int retval;
-
- dbg("%s", __func__);
-
- retval = usb_serial_register(&cypress_earthmate_device);
- if (retval)
- goto failed_em_register;
- retval = usb_serial_register(&cypress_hidcom_device);
- if (retval)
- goto failed_hidcom_register;
- retval = usb_serial_register(&cypress_ca42v2_device);
- if (retval)
- goto failed_ca42v2_register;
- retval = usb_register(&cypress_driver);
- if (retval)
- goto failed_usb_register;
-
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return 0;
-
-failed_usb_register:
- usb_serial_deregister(&cypress_ca42v2_device);
-failed_ca42v2_register:
- usb_serial_deregister(&cypress_hidcom_device);
-failed_hidcom_register:
- usb_serial_deregister(&cypress_earthmate_device);
-failed_em_register:
- return retval;
-}
-
-
-static void __exit cypress_exit(void)
-{
- dbg("%s", __func__);
-
- usb_deregister(&cypress_driver);
- usb_serial_deregister(&cypress_earthmate_device);
- usb_serial_deregister(&cypress_hidcom_device);
- usb_serial_deregister(&cypress_ca42v2_device);
-}
-
-
-module_init(cypress_init);
-module_exit(cypress_exit);
+module_usb_serial_driver(cypress_driver, serial_drivers);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/digi_acceleport.c b/drivers/usb/serial/digi_acceleport.c
index b23bebd721a1..999f91bf70de 100644
--- a/drivers/usb/serial/digi_acceleport.c
+++ b/drivers/usb/serial/digi_acceleport.c
@@ -276,7 +276,6 @@ static struct usb_driver digi_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table_combined,
- .no_dynamic_id = 1,
};
@@ -288,7 +287,6 @@ static struct usb_serial_driver digi_acceleport_2_device = {
.name = "digi_2",
},
.description = "Digi 2 port USB adapter",
- .usb_driver = &digi_driver,
.id_table = id_table_2,
.num_ports = 3,
.open = digi_open,
@@ -316,7 +314,6 @@ static struct usb_serial_driver digi_acceleport_4_device = {
.name = "digi_4",
},
.description = "Digi 4 port USB adapter",
- .usb_driver = &digi_driver,
.id_table = id_table_4,
.num_ports = 4,
.open = digi_open,
@@ -337,6 +334,9 @@ static struct usb_serial_driver digi_acceleport_4_device = {
.release = digi_release,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &digi_acceleport_2_device, &digi_acceleport_4_device, NULL
+};
/* Functions */
@@ -995,7 +995,7 @@ static int digi_write(struct tty_struct *tty, struct usb_serial_port *port,
/* return length of new data written, or error */
spin_unlock_irqrestore(&priv->dp_port_lock, flags);
if (ret < 0)
- dev_err(&port->dev,
+ dev_err_console(port,
"%s: usb_submit_urb failed, ret=%d, port=%d\n",
__func__, ret, priv->dp_port_num);
dbg("digi_write: returning %d", ret);
@@ -1065,7 +1065,7 @@ static void digi_write_bulk_callback(struct urb *urb)
spin_unlock(&priv->dp_port_lock);
if (ret && ret != -EPERM)
- dev_err(&port->dev,
+ dev_err_console(port,
"%s: usb_submit_urb failed, ret=%d, port=%d\n",
__func__, ret, priv->dp_port_num);
}
@@ -1580,40 +1580,7 @@ static int digi_read_oob_callback(struct urb *urb)
}
-static int __init digi_init(void)
-{
- int retval;
- retval = usb_serial_register(&digi_acceleport_2_device);
- if (retval)
- goto failed_acceleport_2_device;
- retval = usb_serial_register(&digi_acceleport_4_device);
- if (retval)
- goto failed_acceleport_4_device;
- retval = usb_register(&digi_driver);
- if (retval)
- goto failed_usb_register;
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return 0;
-failed_usb_register:
- usb_serial_deregister(&digi_acceleport_4_device);
-failed_acceleport_4_device:
- usb_serial_deregister(&digi_acceleport_2_device);
-failed_acceleport_2_device:
- return retval;
-}
-
-static void __exit digi_exit (void)
-{
- usb_deregister(&digi_driver);
- usb_serial_deregister(&digi_acceleport_2_device);
- usb_serial_deregister(&digi_acceleport_4_device);
-}
-
-
-module_init(digi_init);
-module_exit(digi_exit);
-
+module_usb_serial_driver(digi_driver, serial_drivers);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/empeg.c b/drivers/usb/serial/empeg.c
index aced6817bf95..5b99fc09e327 100644
--- a/drivers/usb/serial/empeg.c
+++ b/drivers/usb/serial/empeg.c
@@ -56,7 +56,6 @@ static struct usb_driver empeg_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
static struct usb_serial_driver empeg_device = {
@@ -65,7 +64,6 @@ static struct usb_serial_driver empeg_device = {
.name = "empeg",
},
.id_table = id_table,
- .usb_driver = &empeg_driver,
.num_ports = 1,
.bulk_out_size = 256,
.throttle = usb_serial_generic_throttle,
@@ -74,6 +72,10 @@ static struct usb_serial_driver empeg_device = {
.init_termios = empeg_init_termios,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &empeg_device, NULL
+};
+
static int empeg_startup(struct usb_serial *serial)
{
int r;
@@ -136,33 +138,7 @@ static void empeg_init_termios(struct tty_struct *tty)
tty_encode_baud_rate(tty, 115200, 115200);
}
-static int __init empeg_init(void)
-{
- int retval;
-
- retval = usb_serial_register(&empeg_device);
- if (retval)
- return retval;
- retval = usb_register(&empeg_driver);
- if (retval) {
- usb_serial_deregister(&empeg_device);
- return retval;
- }
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
-
- return 0;
-}
-
-static void __exit empeg_exit(void)
-{
- usb_deregister(&empeg_driver);
- usb_serial_deregister(&empeg_device);
-}
-
-
-module_init(empeg_init);
-module_exit(empeg_exit);
+module_usb_serial_driver(empeg_driver, serial_drivers);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/f81232.c b/drivers/usb/serial/f81232.c
new file mode 100644
index 000000000000..88c0b1963920
--- /dev/null
+++ b/drivers/usb/serial/f81232.c
@@ -0,0 +1,405 @@
+/*
+ * Fintek F81232 USB to serial adaptor driver
+ *
+ * Copyright (C) 2012 Greg Kroah-Hartman (gregkh@linuxfoundation.org)
+ * Copyright (C) 2012 Linux Foundation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/serial.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/uaccess.h>
+#include <linux/usb.h>
+#include <linux/usb/serial.h>
+
+static bool debug;
+
+static const struct usb_device_id id_table[] = {
+ { USB_DEVICE(0x1934, 0x0706) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+#define CONTROL_DTR 0x01
+#define CONTROL_RTS 0x02
+
+#define UART_STATE 0x08
+#define UART_STATE_TRANSIENT_MASK 0x74
+#define UART_DCD 0x01
+#define UART_DSR 0x02
+#define UART_BREAK_ERROR 0x04
+#define UART_RING 0x08
+#define UART_FRAME_ERROR 0x10
+#define UART_PARITY_ERROR 0x20
+#define UART_OVERRUN_ERROR 0x40
+#define UART_CTS 0x80
+
+struct f81232_private {
+ spinlock_t lock;
+ wait_queue_head_t delta_msr_wait;
+ u8 line_control;
+ u8 line_status;
+};
+
+static void f81232_update_line_status(struct usb_serial_port *port,
+ unsigned char *data,
+ unsigned int actual_length)
+{
+}
+
+static void f81232_read_int_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = urb->context;
+ unsigned char *data = urb->transfer_buffer;
+ unsigned int actual_length = urb->actual_length;
+ int status = urb->status;
+ int retval;
+
+ dbg("%s (%d)", __func__, port->number);
+
+ switch (status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* this urb is terminated, clean up */
+ dbg("%s - urb shutting down with status: %d", __func__,
+ status);
+ return;
+ default:
+ dbg("%s - nonzero urb status received: %d", __func__,
+ status);
+ goto exit;
+ }
+
+ usb_serial_debug_data(debug, &port->dev, __func__,
+ urb->actual_length, urb->transfer_buffer);
+
+ f81232_update_line_status(port, data, actual_length);
+
+exit:
+ retval = usb_submit_urb(urb, GFP_ATOMIC);
+ if (retval)
+ dev_err(&urb->dev->dev,
+ "%s - usb_submit_urb failed with result %d\n",
+ __func__, retval);
+}
+
+static void f81232_process_read_urb(struct urb *urb)
+{
+ struct usb_serial_port *port = urb->context;
+ struct f81232_private *priv = usb_get_serial_port_data(port);
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+ char tty_flag = TTY_NORMAL;
+ unsigned long flags;
+ u8 line_status;
+ int i;
+
+ /* update line status */
+ spin_lock_irqsave(&priv->lock, flags);
+ line_status = priv->line_status;
+ priv->line_status &= ~UART_STATE_TRANSIENT_MASK;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ wake_up_interruptible(&priv->delta_msr_wait);
+
+ if (!urb->actual_length)
+ return;
+
+ tty = tty_port_tty_get(&port->port);
+ if (!tty)
+ return;
+
+ /* break takes precedence over parity, */
+ /* which takes precedence over framing errors */
+ if (line_status & UART_BREAK_ERROR)
+ tty_flag = TTY_BREAK;
+ else if (line_status & UART_PARITY_ERROR)
+ tty_flag = TTY_PARITY;
+ else if (line_status & UART_FRAME_ERROR)
+ tty_flag = TTY_FRAME;
+ dbg("%s - tty_flag = %d", __func__, tty_flag);
+
+ /* overrun is special, not associated with a char */
+ if (line_status & UART_OVERRUN_ERROR)
+ tty_insert_flip_char(tty, 0, TTY_OVERRUN);
+
+ if (port->port.console && port->sysrq) {
+ for (i = 0; i < urb->actual_length; ++i)
+ if (!usb_serial_handle_sysrq_char(port, data[i]))
+ tty_insert_flip_char(tty, data[i], tty_flag);
+ } else {
+ tty_insert_flip_string_fixed_flag(tty, data, tty_flag,
+ urb->actual_length);
+ }
+
+ tty_flip_buffer_push(tty);
+ tty_kref_put(tty);
+}
+
+static int set_control_lines(struct usb_device *dev, u8 value)
+{
+ /* FIXME - Stubbed out for now */
+ return 0;
+}
+
+static void f81232_break_ctl(struct tty_struct *tty, int break_state)
+{
+ /* FIXME - Stubbed out for now */
+
+ /*
+ * break_state = -1 to turn on break, and 0 to turn off break
+ * see drivers/char/tty_io.c to see it used.
+ * last_set_data_urb_value NEVER has the break bit set in it.
+ */
+}
+
+static void f81232_set_termios(struct tty_struct *tty,
+ struct usb_serial_port *port, struct ktermios *old_termios)
+{
+ /* FIXME - Stubbed out for now */
+
+ /* Don't change anything if nothing has changed */
+ if (!tty_termios_hw_change(tty->termios, old_termios))
+ return;
+
+ /* Do the real work here... */
+}
+
+static int f81232_tiocmget(struct tty_struct *tty)
+{
+ /* FIXME - Stubbed out for now */
+ return 0;
+}
+
+static int f81232_tiocmset(struct tty_struct *tty,
+ unsigned int set, unsigned int clear)
+{
+ /* FIXME - Stubbed out for now */
+ return 0;
+}
+
+static int f81232_open(struct tty_struct *tty, struct usb_serial_port *port)
+{
+ struct ktermios tmp_termios;
+ int result;
+
+ /* Setup termios */
+ if (tty)
+ f81232_set_termios(tty, port, &tmp_termios);
+
+ 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;
+ }
+
+ 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;
+}
+
+static void f81232_close(struct usb_serial_port *port)
+{
+ usb_serial_generic_close(port);
+ usb_kill_urb(port->interrupt_in_urb);
+}
+
+static void f81232_dtr_rts(struct usb_serial_port *port, int on)
+{
+ struct f81232_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ u8 control;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ /* Change DTR and RTS */
+ if (on)
+ priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
+ else
+ priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
+ control = priv->line_control;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ set_control_lines(port->serial->dev, control);
+}
+
+static int f81232_carrier_raised(struct usb_serial_port *port)
+{
+ struct f81232_private *priv = usb_get_serial_port_data(port);
+ if (priv->line_status & UART_DCD)
+ return 1;
+ return 0;
+}
+
+static int wait_modem_info(struct usb_serial_port *port, unsigned int arg)
+{
+ struct f81232_private *priv = usb_get_serial_port_data(port);
+ unsigned long flags;
+ unsigned int prevstatus;
+ unsigned int status;
+ unsigned int changed;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ prevstatus = priv->line_status;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ while (1) {
+ interruptible_sleep_on(&priv->delta_msr_wait);
+ /* see if a signal did it */
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ status = priv->line_status;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ changed = prevstatus ^ status;
+
+ if (((arg & TIOCM_RNG) && (changed & UART_RING)) ||
+ ((arg & TIOCM_DSR) && (changed & UART_DSR)) ||
+ ((arg & TIOCM_CD) && (changed & UART_DCD)) ||
+ ((arg & TIOCM_CTS) && (changed & UART_CTS))) {
+ return 0;
+ }
+ prevstatus = status;
+ }
+ /* NOTREACHED */
+ return 0;
+}
+
+static int f81232_ioctl(struct tty_struct *tty,
+ unsigned int cmd, unsigned long arg)
+{
+ struct serial_struct ser;
+ struct usb_serial_port *port = tty->driver_data;
+ dbg("%s (%d) cmd = 0x%04x", __func__, port->number, cmd);
+
+ switch (cmd) {
+ case TIOCGSERIAL:
+ memset(&ser, 0, sizeof ser);
+ ser.type = PORT_16654;
+ ser.line = port->serial->minor;
+ ser.port = port->number;
+ ser.baud_base = 460800;
+
+ if (copy_to_user((void __user *)arg, &ser, sizeof ser))
+ return -EFAULT;
+
+ return 0;
+
+ case TIOCMIWAIT:
+ dbg("%s (%d) TIOCMIWAIT", __func__, port->number);
+ return wait_modem_info(port, arg);
+ default:
+ dbg("%s not supported = 0x%04x", __func__, cmd);
+ break;
+ }
+ return -ENOIOCTLCMD;
+}
+
+static int f81232_startup(struct usb_serial *serial)
+{
+ struct f81232_private *priv;
+ int i;
+
+ for (i = 0; i < serial->num_ports; ++i) {
+ priv = kzalloc(sizeof(struct f81232_private), GFP_KERNEL);
+ if (!priv)
+ goto cleanup;
+ spin_lock_init(&priv->lock);
+ init_waitqueue_head(&priv->delta_msr_wait);
+ usb_set_serial_port_data(serial->port[i], priv);
+ }
+ return 0;
+
+cleanup:
+ for (--i; i >= 0; --i) {
+ priv = usb_get_serial_port_data(serial->port[i]);
+ kfree(priv);
+ usb_set_serial_port_data(serial->port[i], NULL);
+ }
+ return -ENOMEM;
+}
+
+static void f81232_release(struct usb_serial *serial)
+{
+ int i;
+ struct f81232_private *priv;
+
+ for (i = 0; i < serial->num_ports; ++i) {
+ priv = usb_get_serial_port_data(serial->port[i]);
+ kfree(priv);
+ }
+}
+
+static struct usb_driver f81232_driver = {
+ .name = "f81232",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table,
+ .suspend = usb_serial_suspend,
+ .resume = usb_serial_resume,
+ .no_dynamic_id = 1,
+ .supports_autosuspend = 1,
+};
+
+static struct usb_serial_driver f81232_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "f81232",
+ },
+ .id_table = id_table,
+ .usb_driver = &f81232_driver,
+ .num_ports = 1,
+ .bulk_in_size = 256,
+ .bulk_out_size = 256,
+ .open = f81232_open,
+ .close = f81232_close,
+ .dtr_rts = f81232_dtr_rts,
+ .carrier_raised = f81232_carrier_raised,
+ .ioctl = f81232_ioctl,
+ .break_ctl = f81232_break_ctl,
+ .set_termios = f81232_set_termios,
+ .tiocmget = f81232_tiocmget,
+ .tiocmset = f81232_tiocmset,
+ .process_read_urb = f81232_process_read_urb,
+ .read_int_callback = f81232_read_int_callback,
+ .attach = f81232_startup,
+ .release = f81232_release,
+};
+
+static struct usb_serial_driver * const serial_drivers[] = {
+ &f81232_device,
+ NULL,
+};
+
+module_usb_serial_driver(f81232_driver, serial_drivers);
+
+MODULE_DESCRIPTION("Fintek F81232 USB to serial adaptor driver");
+MODULE_AUTHOR("Greg Kroah-Hartman <gregkh@linuxfoundation.org");
+MODULE_LICENSE("GPL v2");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+
diff --git a/drivers/usb/serial/ftdi_sio.c b/drivers/usb/serial/ftdi_sio.c
index f770415305f8..02e7f2d32d52 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -75,7 +75,8 @@ struct ftdi_private {
unsigned long last_dtr_rts; /* saved modem control outputs */
struct async_icount icount;
wait_queue_head_t delta_msr_wait; /* Used for TIOCMIWAIT */
- char prev_status, diff_status; /* Used for TIOCMIWAIT */
+ char prev_status; /* Used for TIOCMIWAIT */
+ bool dev_gone; /* Used to abort TIOCMIWAIT */
char transmit_empty; /* If transmitter is empty or not */
struct usb_serial_port *port;
__u16 interface; /* FT2232C, FT2232H or FT4232H port interface
@@ -188,6 +189,7 @@ static struct usb_device_id id_table_combined [] = {
.driver_info = (kernel_ulong_t)&ftdi_8u2232c_quirk },
{ USB_DEVICE(FTDI_VID, FTDI_4232H_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_232H_PID) },
+ { USB_DEVICE(FTDI_VID, FTDI_FTX_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_MICRO_CHAMELEON_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_RELAIS_PID) },
{ USB_DEVICE(FTDI_VID, FTDI_OPENDCC_PID) },
@@ -536,6 +538,10 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_6_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_7_PID) },
{ USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803_8_PID) },
+ { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_1_PID) },
+ { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_2_PID) },
+ { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_3_PID) },
+ { USB_DEVICE(SEALEVEL_VID, SEALEVEL_2803R_4_PID) },
{ USB_DEVICE(IDTECH_VID, IDTECH_IDT1221U_PID) },
{ USB_DEVICE(OCT_VID, OCT_US101_PID) },
{ USB_DEVICE(OCT_VID, OCT_DK201_PID) },
@@ -797,7 +803,7 @@ static struct usb_device_id id_table_combined [] = {
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
{ USB_DEVICE(ADI_VID, ADI_GNICEPLUS_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
- { USB_DEVICE(HORNBY_VID, HORNBY_ELITE_PID) },
+ { USB_DEVICE(MICROCHIP_VID, MICROCHIP_USB_BOARD_PID) },
{ USB_DEVICE(JETI_VID, JETI_SPC1201_PID) },
{ USB_DEVICE(MARVELL_VID, MARVELL_SHEEVAPLUG_PID),
.driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
@@ -846,6 +852,9 @@ static struct usb_device_id id_table_combined [] = {
{ USB_DEVICE(ST_VID, ST_STMCLT1030_PID),
.driver_info = (kernel_ulong_t)&ftdi_stmclite_quirk },
{ USB_DEVICE(FTDI_VID, FTDI_RF_R106) },
+ { USB_DEVICE(FTDI_VID, FTDI_DISTORTEC_JTAG_LOCK_PICK_PID),
+ .driver_info = (kernel_ulong_t)&ftdi_jtag_quirk },
+ { USB_DEVICE(FTDI_VID, FTDI_LUMEL_PD12_PID) },
{ }, /* Optional parameter entry */
{ } /* Terminating entry */
};
@@ -857,7 +866,6 @@ static struct usb_driver ftdi_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table_combined,
- .no_dynamic_id = 1,
};
static const char *ftdi_chip_name[] = {
@@ -868,7 +876,8 @@ static const char *ftdi_chip_name[] = {
[FT232RL] = "FT232RL",
[FT2232H] = "FT2232H",
[FT4232H] = "FT4232H",
- [FT232H] = "FT232H"
+ [FT232H] = "FT232H",
+ [FTX] = "FT-X"
};
@@ -915,7 +924,6 @@ static struct usb_serial_driver ftdi_sio_device = {
.name = "ftdi_sio",
},
.description = "FTDI USB Serial Device",
- .usb_driver = &ftdi_driver,
.id_table = id_table_combined,
.num_ports = 1,
.bulk_in_size = 512,
@@ -938,6 +946,10 @@ static struct usb_serial_driver ftdi_sio_device = {
.break_ctl = ftdi_break_ctl,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &ftdi_sio_device, NULL
+};
+
#define WDR_TIMEOUT 5000 /* default urb timeout */
#define WDR_SHORT_TIMEOUT 1000 /* shorter urb timeout */
@@ -1169,7 +1181,8 @@ static __u32 get_ftdi_divisor(struct tty_struct *tty,
break;
case FT232BM: /* FT232BM chip */
case FT2232C: /* FT2232C chip */
- case FT232RL:
+ case FT232RL: /* FT232RL chip */
+ case FTX: /* FT-X series */
if (baud <= 3000000) {
__u16 product_id = le16_to_cpu(
port->serial->dev->descriptor.idProduct);
@@ -1458,10 +1471,14 @@ static void ftdi_determine_type(struct usb_serial_port *port)
} else if (version < 0x900) {
/* Assume it's an FT232RL */
priv->chip_type = FT232RL;
- } else {
+ } else if (version < 0x1000) {
/* Assume it's an FT232H */
priv->chip_type = FT232H;
+ } else {
+ /* Assume it's an FT-X series device */
+ priv->chip_type = FTX;
}
+
dev_info(&udev->dev, "Detected %s\n", ftdi_chip_name[priv->chip_type]);
}
@@ -1589,7 +1606,8 @@ static int create_sysfs_attrs(struct usb_serial_port *port)
priv->chip_type == FT232RL ||
priv->chip_type == FT2232H ||
priv->chip_type == FT4232H ||
- priv->chip_type == FT232H)) {
+ priv->chip_type == FT232H ||
+ priv->chip_type == FTX)) {
retval = device_create_file(&port->dev,
&dev_attr_latency_timer);
}
@@ -1611,7 +1629,8 @@ static void remove_sysfs_attrs(struct usb_serial_port *port)
priv->chip_type == FT232RL ||
priv->chip_type == FT2232H ||
priv->chip_type == FT4232H ||
- priv->chip_type == FT232H) {
+ priv->chip_type == FT232H ||
+ priv->chip_type == FTX) {
device_remove_file(&port->dev, &dev_attr_latency_timer);
}
}
@@ -1663,6 +1682,7 @@ static int ftdi_sio_port_probe(struct usb_serial_port *port)
init_waitqueue_head(&priv->delta_msr_wait);
priv->flags = ASYNC_LOW_LATENCY;
+ priv->dev_gone = false;
if (quirk && quirk->port_probe)
quirk->port_probe(priv);
@@ -1706,7 +1726,8 @@ static void ftdi_HE_TIRA1_setup(struct ftdi_private *priv)
/*
* Module parameter to control latency timer for NDI FTDI-based USB devices.
- * If this value is not set in modprobe.conf.local its value will be set to 1ms.
+ * If this value is not set in /etc/modprobe.d/ its value will be set
+ * to 1ms.
*/
static int ndi_latency_timer = 1;
@@ -1763,7 +1784,8 @@ static int ftdi_8u2232c_probe(struct usb_serial *serial)
dbg("%s", __func__);
- if (strcmp(udev->manufacturer, "CALAO Systems") == 0)
+ if ((udev->manufacturer && !strcmp(udev->manufacturer, "CALAO Systems")) ||
+ (udev->product && !strcmp(udev->product, "BeagleBone/XDS100")))
return ftdi_jtag_probe(serial);
return 0;
@@ -1819,6 +1841,9 @@ static int ftdi_sio_port_remove(struct usb_serial_port *port)
dbg("%s", __func__);
+ priv->dev_gone = true;
+ wake_up_interruptible_all(&priv->delta_msr_wait);
+
remove_sysfs_attrs(port);
kref_put(&priv->kref, ftdi_sio_priv_release);
@@ -1962,17 +1987,19 @@ static int ftdi_process_packet(struct tty_struct *tty,
N.B. packet may be processed more than once, but differences
are only processed once. */
status = packet[0] & FTDI_STATUS_B0_MASK;
- if (status & FTDI_RS0_CTS)
- priv->icount.cts++;
- if (status & FTDI_RS0_DSR)
- priv->icount.dsr++;
- if (status & FTDI_RS0_RI)
- priv->icount.rng++;
- if (status & FTDI_RS0_RLSD)
- priv->icount.dcd++;
if (status != priv->prev_status) {
- priv->diff_status |= status ^ priv->prev_status;
- wake_up_interruptible(&priv->delta_msr_wait);
+ char diff_status = status ^ priv->prev_status;
+
+ if (diff_status & FTDI_RS0_CTS)
+ priv->icount.cts++;
+ if (diff_status & FTDI_RS0_DSR)
+ priv->icount.dsr++;
+ if (diff_status & FTDI_RS0_RI)
+ priv->icount.rng++;
+ if (diff_status & FTDI_RS0_RLSD)
+ priv->icount.dcd++;
+
+ wake_up_interruptible_all(&priv->delta_msr_wait);
priv->prev_status = status;
}
@@ -2288,6 +2315,7 @@ static int ftdi_tiocmget(struct tty_struct *tty)
case FT2232H:
case FT4232H:
case FT232H:
+ case FTX:
len = 2;
break;
default:
@@ -2374,15 +2402,12 @@ static int ftdi_ioctl(struct tty_struct *tty,
*/
case TIOCMIWAIT:
cprev = priv->icount;
- while (1) {
+ while (!priv->dev_gone) {
interruptible_sleep_on(&priv->delta_msr_wait);
/* see if a signal did it */
if (signal_pending(current))
return -ERESTARTSYS;
cnow = priv->icount;
- if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr &&
- cnow.dcd == cprev.dcd && cnow.cts == cprev.cts)
- return -EIO; /* no change => error */
if (((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) ||
((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) ||
((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) ||
@@ -2391,7 +2416,7 @@ static int ftdi_ioctl(struct tty_struct *tty,
}
cprev = cnow;
}
- /* not reached */
+ return -EIO;
break;
case TIOCSERGETLSR:
return get_lsr_info(port, (struct serial_struct __user *)arg);
@@ -2420,19 +2445,10 @@ static int __init ftdi_init(void)
id_table_combined[i].idVendor = vendor;
id_table_combined[i].idProduct = product;
}
- retval = usb_serial_register(&ftdi_sio_device);
- if (retval)
- goto failed_sio_register;
- retval = usb_register(&ftdi_driver);
- if (retval)
- goto failed_usb_register;
-
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return 0;
-failed_usb_register:
- usb_serial_deregister(&ftdi_sio_device);
-failed_sio_register:
+ retval = usb_serial_register_drivers(&ftdi_driver, serial_drivers);
+ if (retval == 0)
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return retval;
}
@@ -2440,8 +2456,7 @@ static void __exit ftdi_exit(void)
{
dbg("%s", __func__);
- usb_deregister(&ftdi_driver);
- usb_serial_deregister(&ftdi_sio_device);
+ usb_serial_deregister_drivers(&ftdi_driver, serial_drivers);
}
diff --git a/drivers/usb/serial/ftdi_sio.h b/drivers/usb/serial/ftdi_sio.h
index 19584faa86f9..ed58c6fa8dbe 100644
--- a/drivers/usb/serial/ftdi_sio.h
+++ b/drivers/usb/serial/ftdi_sio.h
@@ -157,7 +157,8 @@ enum ftdi_chip_type {
FT232RL = 5,
FT2232H = 6,
FT4232H = 7,
- FT232H = 8
+ FT232H = 8,
+ FTX = 9,
};
enum ftdi_sio_baudrate {
diff --git a/drivers/usb/serial/ftdi_sio_ids.h b/drivers/usb/serial/ftdi_sio_ids.h
index 6f6058f0db1b..0838baf892f3 100644
--- a/drivers/usb/serial/ftdi_sio_ids.h
+++ b/drivers/usb/serial/ftdi_sio_ids.h
@@ -23,12 +23,15 @@
#define FTDI_8U2232C_PID 0x6010 /* Dual channel device */
#define FTDI_4232H_PID 0x6011 /* Quad channel hi-speed device */
#define FTDI_232H_PID 0x6014 /* Single channel hi-speed device */
+#define FTDI_FTX_PID 0x6015 /* FT-X series (FT201X, FT230X, FT231X, etc) */
#define FTDI_SIO_PID 0x8372 /* Product Id SIO application of 8U100AX */
#define FTDI_232RL_PID 0xFBFA /* Product ID for FT232RL */
/*** third-party PIDs (using FTDI_VID) ***/
+#define FTDI_LUMEL_PD12_PID 0x6002
+
/*
* Marvell OpenRD Base, Client
* http://www.open-rd.org
@@ -97,6 +100,8 @@
#define FTDI_TACTRIX_OPENPORT_13S_PID 0xCC49 /* OpenPort 1.3 Subaru */
#define FTDI_TACTRIX_OPENPORT_13U_PID 0xCC4A /* OpenPort 1.3 Universal */
+#define FTDI_DISTORTEC_JTAG_LOCK_PICK_PID 0xCFF8
+
/* SCS HF Radio Modems PID's (http://www.scs-ptc.com) */
/* the VID is the standard ftdi vid (FTDI_VID) */
#define FTDI_SCS_DEVICE_0_PID 0xD010 /* SCS PTC-IIusb */
@@ -532,10 +537,14 @@
#define ADI_GNICEPLUS_PID 0xF001
/*
- * Hornby Elite
+ * Microchip Technology, Inc.
+ *
+ * MICROCHIP_VID (0x04D8) and MICROCHIP_USB_BOARD_PID (0x000A) are also used by:
+ * Hornby Elite - Digital Command Control Console
+ * http://www.hornby.com/hornby-dcc/controllers/
*/
-#define HORNBY_VID 0x04D8
-#define HORNBY_ELITE_PID 0x000A
+#define MICROCHIP_VID 0x04D8
+#define MICROCHIP_USB_BOARD_PID 0x000A /* CDC RS-232 Emulation Demo */
/*
* RATOC REX-USB60F
@@ -680,6 +689,10 @@
#define SEALEVEL_2803_6_PID 0X2863 /* SeaLINK+8 (2803) Port 6 */
#define SEALEVEL_2803_7_PID 0X2873 /* SeaLINK+8 (2803) Port 7 */
#define SEALEVEL_2803_8_PID 0X2883 /* SeaLINK+8 (2803) Port 8 */
+#define SEALEVEL_2803R_1_PID 0Xa02a /* SeaLINK+8 (2803-ROHS) Port 1+2 */
+#define SEALEVEL_2803R_2_PID 0Xa02b /* SeaLINK+8 (2803-ROHS) Port 3+4 */
+#define SEALEVEL_2803R_3_PID 0Xa02c /* SeaLINK+8 (2803-ROHS) Port 5+6 */
+#define SEALEVEL_2803R_4_PID 0Xa02d /* SeaLINK+8 (2803-ROHS) Port 7+8 */
/*
* JETI SPECTROMETER SPECBOS 1201
diff --git a/drivers/usb/serial/funsoft.c b/drivers/usb/serial/funsoft.c
index 5d4b099dcf8b..4577b3607922 100644
--- a/drivers/usb/serial/funsoft.c
+++ b/drivers/usb/serial/funsoft.c
@@ -29,7 +29,6 @@ static struct usb_driver funsoft_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
static struct usb_serial_driver funsoft_device = {
@@ -38,31 +37,15 @@ static struct usb_serial_driver funsoft_device = {
.name = "funsoft",
},
.id_table = id_table,
- .usb_driver = &funsoft_driver,
.num_ports = 1,
};
-static int __init funsoft_init(void)
-{
- int retval;
-
- retval = usb_serial_register(&funsoft_device);
- if (retval)
- return retval;
- retval = usb_register(&funsoft_driver);
- if (retval)
- usb_serial_deregister(&funsoft_device);
- return retval;
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &funsoft_device, NULL
+};
-static void __exit funsoft_exit(void)
-{
- usb_deregister(&funsoft_driver);
- usb_serial_deregister(&funsoft_device);
-}
+module_usb_serial_driver(funsoft_driver, serial_drivers);
-module_init(funsoft_init);
-module_exit(funsoft_exit);
MODULE_LICENSE("GPL");
module_param(debug, bool, S_IRUGO | S_IWUSR);
diff --git a/drivers/usb/serial/garmin_gps.c b/drivers/usb/serial/garmin_gps.c
index 21343378c322..e8eb6347bf3a 100644
--- a/drivers/usb/serial/garmin_gps.c
+++ b/drivers/usb/serial/garmin_gps.c
@@ -224,7 +224,6 @@ static struct usb_driver garmin_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
@@ -1497,7 +1496,6 @@ static struct usb_serial_driver garmin_device = {
.name = "garmin_gps",
},
.description = "Garmin GPS usb/tty",
- .usb_driver = &garmin_driver,
.id_table = id_table,
.num_ports = 1,
.open = garmin_open,
@@ -1514,40 +1512,11 @@ static struct usb_serial_driver garmin_device = {
.read_int_callback = garmin_read_int_callback,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &garmin_device, NULL
+};
-
-static int __init garmin_init(void)
-{
- int retval;
-
- retval = usb_serial_register(&garmin_device);
- if (retval)
- goto failed_garmin_register;
- retval = usb_register(&garmin_driver);
- if (retval)
- goto failed_usb_register;
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
-
- return 0;
-failed_usb_register:
- usb_serial_deregister(&garmin_device);
-failed_garmin_register:
- return retval;
-}
-
-
-static void __exit garmin_exit(void)
-{
- usb_deregister(&garmin_driver);
- usb_serial_deregister(&garmin_device);
-}
-
-
-
-
-module_init(garmin_init);
-module_exit(garmin_exit);
+module_usb_serial_driver(garmin_driver, serial_drivers);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
@@ -1557,4 +1526,3 @@ module_param(debug, bool, S_IWUSR | S_IRUGO);
MODULE_PARM_DESC(debug, "Debug enabled or not");
module_param(initial_mode, int, S_IRUGO);
MODULE_PARM_DESC(initial_mode, "Initial mode");
-
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index f7403576f99f..664deb63807c 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -54,7 +54,6 @@ static struct usb_driver generic_driver = {
.probe = generic_probe,
.disconnect = usb_serial_disconnect,
.id_table = generic_serial_ids,
- .no_dynamic_id = 1,
};
/* All of the device info needed for the Generic Serial Converter */
@@ -64,7 +63,6 @@ struct usb_serial_driver usb_serial_generic_device = {
.name = "generic",
},
.id_table = generic_device_ids,
- .usb_driver = &generic_driver,
.num_ports = 1,
.disconnect = usb_serial_generic_disconnect,
.release = usb_serial_generic_release,
@@ -73,6 +71,10 @@ struct usb_serial_driver usb_serial_generic_device = {
.resume = usb_serial_generic_resume,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &usb_serial_generic_device, NULL
+};
+
static int generic_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
@@ -97,13 +99,7 @@ int usb_serial_generic_register(int _debug)
USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_PRODUCT;
/* register our generic driver with ourselves */
- retval = usb_serial_register(&usb_serial_generic_device);
- if (retval)
- goto exit;
- retval = usb_register(&generic_driver);
- if (retval)
- usb_serial_deregister(&usb_serial_generic_device);
-exit:
+ retval = usb_serial_register_drivers(&generic_driver, serial_drivers);
#endif
return retval;
}
@@ -112,8 +108,7 @@ void usb_serial_generic_deregister(void)
{
#ifdef CONFIG_USB_SERIAL_GENERIC
/* remove our generic driver */
- usb_deregister(&generic_driver);
- usb_serial_deregister(&usb_serial_generic_device);
+ usb_serial_deregister_drivers(&generic_driver, serial_drivers);
#endif
}
@@ -217,7 +212,7 @@ retry:
clear_bit(i, &port->write_urbs_free);
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result) {
- dev_err(&port->dev, "%s - error submitting urb: %d\n",
+ dev_err_console(port, "%s - error submitting urb: %d\n",
__func__, result);
set_bit(i, &port->write_urbs_free);
spin_lock_irqsave(&port->lock, flags);
diff --git a/drivers/usb/serial/hp4x.c b/drivers/usb/serial/hp4x.c
index 809379159b0e..2563e788c9b3 100644
--- a/drivers/usb/serial/hp4x.c
+++ b/drivers/usb/serial/hp4x.c
@@ -41,7 +41,6 @@ static struct usb_driver hp49gp_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
static struct usb_serial_driver hp49gp_device = {
@@ -50,36 +49,14 @@ static struct usb_serial_driver hp49gp_device = {
.name = "hp4X",
},
.id_table = id_table,
- .usb_driver = &hp49gp_driver,
.num_ports = 1,
};
-static int __init hp49gp_init(void)
-{
- int retval;
- retval = usb_serial_register(&hp49gp_device);
- if (retval)
- goto failed_usb_serial_register;
- retval = usb_register(&hp49gp_driver);
- if (retval)
- goto failed_usb_register;
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return 0;
-failed_usb_register:
- usb_serial_deregister(&hp49gp_device);
-failed_usb_serial_register:
- return retval;
-}
-
-static void __exit hp49gp_exit(void)
-{
- usb_deregister(&hp49gp_driver);
- usb_serial_deregister(&hp49gp_device);
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &hp49gp_device, NULL
+};
-module_init(hp49gp_init);
-module_exit(hp49gp_exit);
+module_usb_serial_driver(hp49gp_driver, serial_drivers);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/usb/serial/io_edgeport.c b/drivers/usb/serial/io_edgeport.c
index 0497575e4799..323e87235711 100644
--- a/drivers/usb/serial/io_edgeport.c
+++ b/drivers/usb/serial/io_edgeport.c
@@ -193,7 +193,8 @@ static const struct divisor_table_entry divisor_table[] = {
/* local variables */
static bool debug;
-static atomic_t CmdUrbs; /* Number of outstanding Command Write Urbs */
+/* Number of outstanding Command Write Urbs */
+static atomic_t CmdUrbs = ATOMIC_INIT(0);
/* local function prototypes */
@@ -1286,7 +1287,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial,
count = fifo->count;
buffer = kmalloc(count+2, GFP_ATOMIC);
if (buffer == NULL) {
- dev_err(&edge_port->port->dev,
+ dev_err_console(edge_port->port,
"%s - no more kernel memory...\n", __func__);
edge_port->write_in_progress = false;
goto exit_send;
@@ -1331,7 +1332,7 @@ static void send_more_port_data(struct edgeport_serial *edge_serial,
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
/* something went wrong */
- dev_err(&edge_port->port->dev,
+ dev_err_console(edge_port->port,
"%s - usb_submit_urb(write bulk) failed, status = %d, data lost\n",
__func__, status);
edge_port->write_in_progress = false;
@@ -3180,65 +3181,8 @@ static void edge_release(struct usb_serial *serial)
kfree(edge_serial);
}
+module_usb_serial_driver(io_driver, serial_drivers);
-/****************************************************************************
- * edgeport_init
- * This is called by the module subsystem, or on startup to initialize us
- ****************************************************************************/
-static int __init edgeport_init(void)
-{
- int retval;
-
- retval = usb_serial_register(&edgeport_2port_device);
- if (retval)
- goto failed_2port_device_register;
- retval = usb_serial_register(&edgeport_4port_device);
- if (retval)
- goto failed_4port_device_register;
- retval = usb_serial_register(&edgeport_8port_device);
- if (retval)
- goto failed_8port_device_register;
- retval = usb_serial_register(&epic_device);
- if (retval)
- goto failed_epic_device_register;
- retval = usb_register(&io_driver);
- if (retval)
- goto failed_usb_register;
- atomic_set(&CmdUrbs, 0);
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return 0;
-
-failed_usb_register:
- usb_serial_deregister(&epic_device);
-failed_epic_device_register:
- usb_serial_deregister(&edgeport_8port_device);
-failed_8port_device_register:
- usb_serial_deregister(&edgeport_4port_device);
-failed_4port_device_register:
- usb_serial_deregister(&edgeport_2port_device);
-failed_2port_device_register:
- return retval;
-}
-
-
-/****************************************************************************
- * edgeport_exit
- * Called when the driver is about to be unloaded.
- ****************************************************************************/
-static void __exit edgeport_exit (void)
-{
- usb_deregister(&io_driver);
- usb_serial_deregister(&edgeport_2port_device);
- usb_serial_deregister(&edgeport_4port_device);
- usb_serial_deregister(&edgeport_8port_device);
- usb_serial_deregister(&epic_device);
-}
-
-module_init(edgeport_init);
-module_exit(edgeport_exit);
-
-/* Module information */
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/io_tables.h b/drivers/usb/serial/io_tables.h
index 178b22eb32b1..d0e7c9affb6f 100644
--- a/drivers/usb/serial/io_tables.h
+++ b/drivers/usb/serial/io_tables.h
@@ -100,7 +100,6 @@ static struct usb_driver io_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table_combined,
- .no_dynamic_id = 1,
};
static struct usb_serial_driver edgeport_2port_device = {
@@ -109,7 +108,6 @@ static struct usb_serial_driver edgeport_2port_device = {
.name = "edgeport_2",
},
.description = "Edgeport 2 port adapter",
- .usb_driver = &io_driver,
.id_table = edgeport_2port_id_table,
.num_ports = 2,
.open = edge_open,
@@ -139,7 +137,6 @@ static struct usb_serial_driver edgeport_4port_device = {
.name = "edgeport_4",
},
.description = "Edgeport 4 port adapter",
- .usb_driver = &io_driver,
.id_table = edgeport_4port_id_table,
.num_ports = 4,
.open = edge_open,
@@ -169,7 +166,6 @@ static struct usb_serial_driver edgeport_8port_device = {
.name = "edgeport_8",
},
.description = "Edgeport 8 port adapter",
- .usb_driver = &io_driver,
.id_table = edgeport_8port_id_table,
.num_ports = 8,
.open = edge_open,
@@ -199,7 +195,6 @@ static struct usb_serial_driver epic_device = {
.name = "epic",
},
.description = "EPiC device",
- .usb_driver = &io_driver,
.id_table = Epic_port_id_table,
.num_ports = 1,
.open = edge_open,
@@ -223,5 +218,10 @@ static struct usb_serial_driver epic_device = {
.write_bulk_callback = edge_bulk_out_data_callback,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &edgeport_2port_device, &edgeport_4port_device,
+ &edgeport_8port_device, &epic_device, NULL
+};
+
#endif
diff --git a/drivers/usb/serial/io_ti.c b/drivers/usb/serial/io_ti.c
index 5818bfc3261e..40a95a7fe383 100644
--- a/drivers/usb/serial/io_ti.c
+++ b/drivers/usb/serial/io_ti.c
@@ -202,7 +202,6 @@ static struct usb_driver io_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table_combined,
- .no_dynamic_id = 1,
};
@@ -1817,7 +1816,7 @@ static void edge_bulk_out_callback(struct urb *urb)
__func__, status);
return;
default:
- dev_err(&urb->dev->dev, "%s - nonzero write bulk status "
+ dev_err_console(port, "%s - nonzero write bulk status "
"received: %d\n", __func__, status);
}
@@ -2111,7 +2110,7 @@ static void edge_send(struct tty_struct *tty)
/* send the data out the bulk port */
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
- dev_err(&port->dev,
+ dev_err_console(port,
"%s - failed submitting write urb, error %d\n",
__func__, result);
edge_port->ep_write_urb_in_use = 0;
@@ -2725,7 +2724,6 @@ static struct usb_serial_driver edgeport_1port_device = {
.name = "edgeport_ti_1",
},
.description = "Edgeport TI 1 port adapter",
- .usb_driver = &io_driver,
.id_table = edgeport_1port_id_table,
.num_ports = 1,
.open = edge_open,
@@ -2757,7 +2755,6 @@ static struct usb_serial_driver edgeport_2port_device = {
.name = "edgeport_ti_2",
},
.description = "Edgeport TI 2 port adapter",
- .usb_driver = &io_driver,
.id_table = edgeport_2port_id_table,
.num_ports = 2,
.open = edge_open,
@@ -2782,41 +2779,12 @@ static struct usb_serial_driver edgeport_2port_device = {
.write_bulk_callback = edge_bulk_out_callback,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &edgeport_1port_device, &edgeport_2port_device, NULL
+};
-static int __init edgeport_init(void)
-{
- int retval;
- retval = usb_serial_register(&edgeport_1port_device);
- if (retval)
- goto failed_1port_device_register;
- retval = usb_serial_register(&edgeport_2port_device);
- if (retval)
- goto failed_2port_device_register;
- retval = usb_register(&io_driver);
- if (retval)
- goto failed_usb_register;
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return 0;
-failed_usb_register:
- usb_serial_deregister(&edgeport_2port_device);
-failed_2port_device_register:
- usb_serial_deregister(&edgeport_1port_device);
-failed_1port_device_register:
- return retval;
-}
-
-static void __exit edgeport_exit(void)
-{
- usb_deregister(&io_driver);
- usb_serial_deregister(&edgeport_1port_device);
- usb_serial_deregister(&edgeport_2port_device);
-}
-
-module_init(edgeport_init);
-module_exit(edgeport_exit);
+module_usb_serial_driver(io_driver, serial_drivers);
-/* Module information */
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/ipaq.c b/drivers/usb/serial/ipaq.c
index 06053a920dd8..10c02b8b5664 100644
--- a/drivers/usb/serial/ipaq.c
+++ b/drivers/usb/serial/ipaq.c
@@ -510,7 +510,6 @@ static struct usb_driver ipaq_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = ipaq_id_table,
- .no_dynamic_id = 1,
};
@@ -521,7 +520,6 @@ static struct usb_serial_driver ipaq_device = {
.name = "ipaq",
},
.description = "PocketPC PDA",
- .usb_driver = &ipaq_driver,
.id_table = ipaq_id_table,
.bulk_in_size = 256,
.bulk_out_size = 256,
@@ -530,6 +528,10 @@ static struct usb_serial_driver ipaq_device = {
.calc_num_ports = ipaq_calc_num_ports,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &ipaq_device, NULL
+};
+
static int ipaq_open(struct tty_struct *tty,
struct usb_serial_port *port)
{
@@ -624,30 +626,22 @@ static int ipaq_startup(struct usb_serial *serial)
static int __init ipaq_init(void)
{
int retval;
- retval = usb_serial_register(&ipaq_device);
- if (retval)
- goto failed_usb_serial_register;
+
if (vendor) {
ipaq_id_table[0].idVendor = vendor;
ipaq_id_table[0].idProduct = product;
}
- retval = usb_register(&ipaq_driver);
- if (retval)
- goto failed_usb_register;
-
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return 0;
-failed_usb_register:
- usb_serial_deregister(&ipaq_device);
-failed_usb_serial_register:
+
+ retval = usb_serial_register_drivers(&ipaq_driver, serial_drivers);
+ if (retval == 0)
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return retval;
}
static void __exit ipaq_exit(void)
{
- usb_deregister(&ipaq_driver);
- usb_serial_deregister(&ipaq_device);
+ usb_serial_deregister_drivers(&ipaq_driver, serial_drivers);
}
diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index 6f9356f3f99e..76a06406e26a 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -144,7 +144,6 @@ static struct usb_driver usb_ipw_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = usb_ipw_ids,
- .no_dynamic_id = 1,
};
static bool debug;
@@ -318,7 +317,6 @@ static struct usb_serial_driver ipw_device = {
.name = "ipw",
},
.description = "IPWireless converter",
- .usb_driver = &usb_ipw_driver,
.id_table = usb_ipw_ids,
.num_ports = 1,
.disconnect = usb_wwan_disconnect,
@@ -331,33 +329,11 @@ static struct usb_serial_driver ipw_device = {
.write = usb_wwan_write,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &ipw_device, NULL
+};
-
-static int __init usb_ipw_init(void)
-{
- int retval;
-
- retval = usb_serial_register(&ipw_device);
- if (retval)
- return retval;
- retval = usb_register(&usb_ipw_driver);
- if (retval) {
- usb_serial_deregister(&ipw_device);
- return retval;
- }
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return 0;
-}
-
-static void __exit usb_ipw_exit(void)
-{
- usb_deregister(&usb_ipw_driver);
- usb_serial_deregister(&ipw_device);
-}
-
-module_init(usb_ipw_init);
-module_exit(usb_ipw_exit);
+module_usb_serial_driver(usb_ipw_driver, serial_drivers);
/* Module information */
MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/usb/serial/ir-usb.c b/drivers/usb/serial/ir-usb.c
index 84a396e83671..84965cd65c76 100644
--- a/drivers/usb/serial/ir-usb.c
+++ b/drivers/usb/serial/ir-usb.c
@@ -82,7 +82,6 @@ static struct usb_driver ir_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = ir_id_table,
- .no_dynamic_id = 1,
};
static struct usb_serial_driver ir_device = {
@@ -91,7 +90,6 @@ static struct usb_serial_driver ir_device = {
.name = "ir-usb",
},
.description = "IR Dongle",
- .usb_driver = &ir_driver,
.id_table = ir_id_table,
.num_ports = 1,
.set_termios = ir_set_termios,
@@ -101,6 +99,10 @@ static struct usb_serial_driver ir_device = {
.process_read_urb = ir_process_read_urb,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &ir_device, NULL
+};
+
static inline void irda_usb_dump_class_desc(struct usb_irda_cs_descriptor *desc)
{
dbg("bLength=%x", desc->bLength);
@@ -445,30 +447,16 @@ static int __init ir_init(void)
ir_device.bulk_out_size = buffer_size;
}
- retval = usb_serial_register(&ir_device);
- if (retval)
- goto failed_usb_serial_register;
-
- retval = usb_register(&ir_driver);
- if (retval)
- goto failed_usb_register;
-
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
-
- return 0;
-
-failed_usb_register:
- usb_serial_deregister(&ir_device);
-
-failed_usb_serial_register:
+ retval = usb_serial_register_drivers(&ir_driver, serial_drivers);
+ if (retval == 0)
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
+ DRIVER_DESC "\n");
return retval;
}
static void __exit ir_exit(void)
{
- usb_deregister(&ir_driver);
- usb_serial_deregister(&ir_device);
+ usb_serial_deregister_drivers(&ir_driver, serial_drivers);
}
diff --git a/drivers/usb/serial/iuu_phoenix.c b/drivers/usb/serial/iuu_phoenix.c
index 3077a4436976..f2192d527db0 100644
--- a/drivers/usb/serial/iuu_phoenix.c
+++ b/drivers/usb/serial/iuu_phoenix.c
@@ -56,7 +56,6 @@ static struct usb_driver iuu_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
/* turbo parameter */
@@ -1274,7 +1273,6 @@ static struct usb_serial_driver iuu_device = {
.name = "iuu_phoenix",
},
.id_table = id_table,
- .usb_driver = &iuu_driver,
.num_ports = 1,
.bulk_in_size = 512,
.bulk_out_size = 512,
@@ -1292,32 +1290,11 @@ static struct usb_serial_driver iuu_device = {
.release = iuu_release,
};
-static int __init iuu_init(void)
-{
- int retval;
- retval = usb_serial_register(&iuu_device);
- if (retval)
- goto failed_usb_serial_register;
- retval = usb_register(&iuu_driver);
- if (retval)
- goto failed_usb_register;
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return 0;
-failed_usb_register:
- usb_serial_deregister(&iuu_device);
-failed_usb_serial_register:
- return retval;
-}
-
-static void __exit iuu_exit(void)
-{
- usb_deregister(&iuu_driver);
- usb_serial_deregister(&iuu_device);
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &iuu_device, NULL
+};
-module_init(iuu_init);
-module_exit(iuu_exit);
+module_usb_serial_driver(iuu_driver, serial_drivers);
MODULE_AUTHOR("Alain Degreffe eczema@ecze.com");
diff --git a/drivers/usb/serial/keyspan.c b/drivers/usb/serial/keyspan.c
index 4cc36c761801..a39ddd1b0dca 100644
--- a/drivers/usb/serial/keyspan.c
+++ b/drivers/usb/serial/keyspan.c
@@ -130,53 +130,7 @@ struct keyspan_port_private {
#include "keyspan_usa67msg.h"
-/* Functions used by new usb-serial code. */
-static int __init keyspan_init(void)
-{
- int retval;
- retval = usb_serial_register(&keyspan_pre_device);
- if (retval)
- goto failed_pre_device_register;
- retval = usb_serial_register(&keyspan_1port_device);
- if (retval)
- goto failed_1port_device_register;
- retval = usb_serial_register(&keyspan_2port_device);
- if (retval)
- goto failed_2port_device_register;
- retval = usb_serial_register(&keyspan_4port_device);
- if (retval)
- goto failed_4port_device_register;
- retval = usb_register(&keyspan_driver);
- if (retval)
- goto failed_usb_register;
-
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
-
- return 0;
-failed_usb_register:
- usb_serial_deregister(&keyspan_4port_device);
-failed_4port_device_register:
- usb_serial_deregister(&keyspan_2port_device);
-failed_2port_device_register:
- usb_serial_deregister(&keyspan_1port_device);
-failed_1port_device_register:
- usb_serial_deregister(&keyspan_pre_device);
-failed_pre_device_register:
- return retval;
-}
-
-static void __exit keyspan_exit(void)
-{
- usb_deregister(&keyspan_driver);
- usb_serial_deregister(&keyspan_pre_device);
- usb_serial_deregister(&keyspan_1port_device);
- usb_serial_deregister(&keyspan_2port_device);
- usb_serial_deregister(&keyspan_4port_device);
-}
-
-module_init(keyspan_init);
-module_exit(keyspan_exit);
+module_usb_serial_driver(keyspan_driver, serial_drivers);
static void keyspan_break_ctl(struct tty_struct *tty, int break_state)
{
diff --git a/drivers/usb/serial/keyspan.h b/drivers/usb/serial/keyspan.h
index 13fa1d1cc900..622853c9e384 100644
--- a/drivers/usb/serial/keyspan.h
+++ b/drivers/usb/serial/keyspan.h
@@ -492,7 +492,6 @@ static struct usb_driver keyspan_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = keyspan_ids_combined,
- .no_dynamic_id = 1,
};
/* usb_device_id table for the pre-firmware download keyspan devices */
@@ -545,7 +544,6 @@ static struct usb_serial_driver keyspan_pre_device = {
.name = "keyspan_no_firm",
},
.description = "Keyspan - (without firmware)",
- .usb_driver = &keyspan_driver,
.id_table = keyspan_pre_ids,
.num_ports = 1,
.attach = keyspan_fake_startup,
@@ -557,7 +555,6 @@ static struct usb_serial_driver keyspan_1port_device = {
.name = "keyspan_1",
},
.description = "Keyspan 1 port adapter",
- .usb_driver = &keyspan_driver,
.id_table = keyspan_1port_ids,
.num_ports = 1,
.open = keyspan_open,
@@ -580,7 +577,6 @@ static struct usb_serial_driver keyspan_2port_device = {
.name = "keyspan_2",
},
.description = "Keyspan 2 port adapter",
- .usb_driver = &keyspan_driver,
.id_table = keyspan_2port_ids,
.num_ports = 2,
.open = keyspan_open,
@@ -603,7 +599,6 @@ static struct usb_serial_driver keyspan_4port_device = {
.name = "keyspan_4",
},
.description = "Keyspan 4 port adapter",
- .usb_driver = &keyspan_driver,
.id_table = keyspan_4port_ids,
.num_ports = 4,
.open = keyspan_open,
@@ -620,4 +615,9 @@ static struct usb_serial_driver keyspan_4port_device = {
.release = keyspan_release,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &keyspan_pre_device, &keyspan_1port_device,
+ &keyspan_2port_device, &keyspan_4port_device, NULL
+};
+
#endif
diff --git a/drivers/usb/serial/keyspan_pda.c b/drivers/usb/serial/keyspan_pda.c
index 7c62a7048302..693bcdfcb3d5 100644
--- a/drivers/usb/serial/keyspan_pda.c
+++ b/drivers/usb/serial/keyspan_pda.c
@@ -91,7 +91,6 @@ static struct usb_driver keyspan_pda_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table_combined,
- .no_dynamic_id = 1,
};
static const struct usb_device_id id_table_std[] = {
@@ -779,7 +778,6 @@ static struct usb_serial_driver keyspan_pda_fake_device = {
.name = "keyspan_pda_pre",
},
.description = "Keyspan PDA - (prerenumeration)",
- .usb_driver = &keyspan_pda_driver,
.id_table = id_table_fake,
.num_ports = 1,
.attach = keyspan_pda_fake_startup,
@@ -793,7 +791,6 @@ static struct usb_serial_driver xircom_pgs_fake_device = {
.name = "xircom_no_firm",
},
.description = "Xircom / Entregra PGS - (prerenumeration)",
- .usb_driver = &keyspan_pda_driver,
.id_table = id_table_fake_xircom,
.num_ports = 1,
.attach = keyspan_pda_fake_startup,
@@ -806,7 +803,6 @@ static struct usb_serial_driver keyspan_pda_device = {
.name = "keyspan_pda",
},
.description = "Keyspan PDA",
- .usb_driver = &keyspan_pda_driver,
.id_table = id_table_std,
.num_ports = 1,
.dtr_rts = keyspan_pda_dtr_rts,
@@ -827,61 +823,18 @@ static struct usb_serial_driver keyspan_pda_device = {
.release = keyspan_pda_release,
};
-
-static int __init keyspan_pda_init(void)
-{
- int retval;
- retval = usb_serial_register(&keyspan_pda_device);
- if (retval)
- goto failed_pda_register;
+static struct usb_serial_driver * const serial_drivers[] = {
+ &keyspan_pda_device,
#ifdef KEYSPAN
- retval = usb_serial_register(&keyspan_pda_fake_device);
- if (retval)
- goto failed_pda_fake_register;
+ &keyspan_pda_fake_device,
#endif
#ifdef XIRCOM
- retval = usb_serial_register(&xircom_pgs_fake_device);
- if (retval)
- goto failed_xircom_register;
-#endif
- retval = usb_register(&keyspan_pda_driver);
- if (retval)
- goto failed_usb_register;
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return 0;
-failed_usb_register:
-#ifdef XIRCOM
- usb_serial_deregister(&xircom_pgs_fake_device);
-failed_xircom_register:
-#endif /* XIRCOM */
-#ifdef KEYSPAN
- usb_serial_deregister(&keyspan_pda_fake_device);
-#endif
-#ifdef KEYSPAN
-failed_pda_fake_register:
+ &xircom_pgs_fake_device,
#endif
- usb_serial_deregister(&keyspan_pda_device);
-failed_pda_register:
- return retval;
-}
-
-
-static void __exit keyspan_pda_exit(void)
-{
- usb_deregister(&keyspan_pda_driver);
- usb_serial_deregister(&keyspan_pda_device);
-#ifdef KEYSPAN
- usb_serial_deregister(&keyspan_pda_fake_device);
-#endif
-#ifdef XIRCOM
- usb_serial_deregister(&xircom_pgs_fake_device);
-#endif
-}
-
+ NULL
+};
-module_init(keyspan_pda_init);
-module_exit(keyspan_pda_exit);
+module_usb_serial_driver(keyspan_pda_driver, serial_drivers);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
@@ -889,4 +842,3 @@ MODULE_LICENSE("GPL");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
-
diff --git a/drivers/usb/serial/kl5kusb105.c b/drivers/usb/serial/kl5kusb105.c
index fc064e1442ca..10f05407e535 100644
--- a/drivers/usb/serial/kl5kusb105.c
+++ b/drivers/usb/serial/kl5kusb105.c
@@ -91,7 +91,6 @@ static struct usb_driver kl5kusb105d_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
static struct usb_serial_driver kl5kusb105d_device = {
@@ -100,7 +99,6 @@ static struct usb_serial_driver kl5kusb105d_device = {
.name = "kl5kusb105d",
},
.description = "KL5KUSB105D / PalmConnect",
- .usb_driver = &kl5kusb105d_driver,
.id_table = id_table,
.num_ports = 1,
.bulk_out_size = 64,
@@ -118,6 +116,10 @@ static struct usb_serial_driver kl5kusb105d_device = {
.prepare_write_buffer = klsi_105_prepare_write_buffer,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &kl5kusb105d_device, NULL
+};
+
struct klsi_105_port_settings {
__u8 pktlen; /* always 5, it seems */
__u8 baudrate;
@@ -690,40 +692,11 @@ static int klsi_105_tiocmset(struct tty_struct *tty,
return retval;
}
-
-static int __init klsi_105_init(void)
-{
- int retval;
- retval = usb_serial_register(&kl5kusb105d_device);
- if (retval)
- goto failed_usb_serial_register;
- retval = usb_register(&kl5kusb105d_driver);
- if (retval)
- goto failed_usb_register;
-
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return 0;
-failed_usb_register:
- usb_serial_deregister(&kl5kusb105d_device);
-failed_usb_serial_register:
- return retval;
-}
-
-static void __exit klsi_105_exit(void)
-{
- usb_deregister(&kl5kusb105d_driver);
- usb_serial_deregister(&kl5kusb105d_device);
-}
-
-
-module_init(klsi_105_init);
-module_exit(klsi_105_exit);
+module_usb_serial_driver(kl5kusb105d_driver, serial_drivers);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
-
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "enable extensive debugging messages");
diff --git a/drivers/usb/serial/kobil_sct.c b/drivers/usb/serial/kobil_sct.c
index a92a3efb507b..4a9a75eb9b95 100644
--- a/drivers/usb/serial/kobil_sct.c
+++ b/drivers/usb/serial/kobil_sct.c
@@ -90,7 +90,6 @@ static struct usb_driver kobil_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
@@ -100,7 +99,6 @@ static struct usb_serial_driver kobil_device = {
.name = "kobil",
},
.description = "KOBIL USB smart card terminal",
- .usb_driver = &kobil_driver,
.id_table = id_table,
.num_ports = 1,
.attach = kobil_startup,
@@ -117,6 +115,9 @@ static struct usb_serial_driver kobil_device = {
.read_int_callback = kobil_read_int_callback,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &kobil_device, NULL
+};
struct kobil_private {
int write_int_endpoint_address;
@@ -682,35 +683,7 @@ static int kobil_ioctl(struct tty_struct *tty,
}
}
-static int __init kobil_init(void)
-{
- int retval;
- retval = usb_serial_register(&kobil_device);
- if (retval)
- goto failed_usb_serial_register;
- retval = usb_register(&kobil_driver);
- if (retval)
- goto failed_usb_register;
-
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
-
- return 0;
-failed_usb_register:
- usb_serial_deregister(&kobil_device);
-failed_usb_serial_register:
- return retval;
-}
-
-
-static void __exit kobil_exit(void)
-{
- usb_deregister(&kobil_driver);
- usb_serial_deregister(&kobil_device);
-}
-
-module_init(kobil_init);
-module_exit(kobil_exit);
+module_usb_serial_driver(kobil_driver, serial_drivers);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/mct_u232.c b/drivers/usb/serial/mct_u232.c
index 27fa9c8a77b0..6edd26130e25 100644
--- a/drivers/usb/serial/mct_u232.c
+++ b/drivers/usb/serial/mct_u232.c
@@ -88,7 +88,6 @@ static struct usb_driver mct_u232_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table_combined,
- .no_dynamic_id = 1,
};
static struct usb_serial_driver mct_u232_device = {
@@ -97,7 +96,6 @@ static struct usb_serial_driver mct_u232_device = {
.name = "mct_u232",
},
.description = "MCT U232",
- .usb_driver = &mct_u232_driver,
.id_table = id_table_combined,
.num_ports = 1,
.open = mct_u232_open,
@@ -116,6 +114,10 @@ static struct usb_serial_driver mct_u232_device = {
.get_icount = mct_u232_get_icount,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &mct_u232_device, NULL
+};
+
struct mct_u232_private {
spinlock_t lock;
unsigned int control_state; /* Modem Line Setting (TIOCM) */
@@ -904,33 +906,7 @@ static int mct_u232_get_icount(struct tty_struct *tty,
return 0;
}
-static int __init mct_u232_init(void)
-{
- int retval;
- retval = usb_serial_register(&mct_u232_device);
- if (retval)
- goto failed_usb_serial_register;
- retval = usb_register(&mct_u232_driver);
- if (retval)
- goto failed_usb_register;
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return 0;
-failed_usb_register:
- usb_serial_deregister(&mct_u232_device);
-failed_usb_serial_register:
- return retval;
-}
-
-
-static void __exit mct_u232_exit(void)
-{
- usb_deregister(&mct_u232_driver);
- usb_serial_deregister(&mct_u232_device);
-}
-
-module_init(mct_u232_init);
-module_exit(mct_u232_exit);
+module_usb_serial_driver(mct_u232_driver, serial_drivers);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/metro-usb.c b/drivers/usb/serial/metro-usb.c
new file mode 100644
index 000000000000..08d16e8c002d
--- /dev/null
+++ b/drivers/usb/serial/metro-usb.c
@@ -0,0 +1,402 @@
+/*
+ Some of this code is credited to Linux USB open source files that are
+ distributed with Linux.
+
+ Copyright: 2007 Metrologic Instruments. All rights reserved.
+ Copyright: 2011 Azimut Ltd. <http://azimutrzn.ru/>
+*/
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/tty_driver.h>
+#include <linux/tty_flip.h>
+#include <linux/moduleparam.h>
+#include <linux/spinlock.h>
+#include <linux/errno.h>
+#include <linux/uaccess.h>
+#include <linux/usb/serial.h>
+
+/* Version Information */
+#define DRIVER_VERSION "v1.2.0.0"
+#define DRIVER_DESC "Metrologic Instruments Inc. - USB-POS driver"
+
+/* Product information. */
+#define FOCUS_VENDOR_ID 0x0C2E
+#define FOCUS_PRODUCT_ID_BI 0x0720
+#define FOCUS_PRODUCT_ID_UNI 0x0700
+
+#define METROUSB_SET_REQUEST_TYPE 0x40
+#define METROUSB_SET_MODEM_CTRL_REQUEST 10
+#define METROUSB_SET_BREAK_REQUEST 0x40
+#define METROUSB_MCR_NONE 0x08 /* Deactivate DTR and RTS. */
+#define METROUSB_MCR_RTS 0x0a /* Activate RTS. */
+#define METROUSB_MCR_DTR 0x09 /* Activate DTR. */
+#define WDR_TIMEOUT 5000 /* default urb timeout. */
+
+/* Private data structure. */
+struct metrousb_private {
+ spinlock_t lock;
+ int throttled;
+ unsigned long control_state;
+};
+
+/* Device table list. */
+static struct usb_device_id id_table[] = {
+ { USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_BI) },
+ { USB_DEVICE(FOCUS_VENDOR_ID, FOCUS_PRODUCT_ID_UNI) },
+ { }, /* Terminating entry. */
+};
+MODULE_DEVICE_TABLE(usb, id_table);
+
+/* Input parameter constants. */
+static bool debug;
+
+static void metrousb_read_int_callback(struct urb *urb)
+{
+ struct usb_serial_port *port = urb->context;
+ struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
+ struct tty_struct *tty;
+ unsigned char *data = urb->transfer_buffer;
+ int throttled = 0;
+ int result = 0;
+ unsigned long flags = 0;
+
+ dev_dbg(&port->dev, "%s\n", __func__);
+
+ switch (urb->status) {
+ case 0:
+ /* Success status, read from the port. */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /* urb has been terminated. */
+ dev_dbg(&port->dev,
+ "%s - urb shutting down, error code=%d\n",
+ __func__, result);
+ return;
+ default:
+ dev_dbg(&port->dev,
+ "%s - non-zero urb received, error code=%d\n",
+ __func__, result);
+ goto exit;
+ }
+
+
+ /* Set the data read from the usb port into the serial port buffer. */
+ tty = tty_port_tty_get(&port->port);
+ if (!tty) {
+ dev_dbg(&port->dev, "%s - bad tty pointer - exiting\n",
+ __func__);
+ return;
+ }
+
+ if (tty && urb->actual_length) {
+ /* Loop through the data copying each byte to the tty layer. */
+ tty_insert_flip_string(tty, data, urb->actual_length);
+
+ /* Force the data to the tty layer. */
+ tty_flip_buffer_push(tty);
+ }
+ tty_kref_put(tty);
+
+ /* Set any port variables. */
+ spin_lock_irqsave(&metro_priv->lock, flags);
+ throttled = metro_priv->throttled;
+ spin_unlock_irqrestore(&metro_priv->lock, flags);
+
+ /* Continue trying to read if set. */
+ if (!throttled) {
+ usb_fill_int_urb(port->interrupt_in_urb, port->serial->dev,
+ usb_rcvintpipe(port->serial->dev, port->interrupt_in_endpointAddress),
+ port->interrupt_in_urb->transfer_buffer,
+ port->interrupt_in_urb->transfer_buffer_length,
+ metrousb_read_int_callback, port, 1);
+
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
+
+ if (result)
+ dev_dbg(&port->dev,
+ "%s - failed submitting interrupt in urb, error code=%d\n",
+ __func__, result);
+ }
+ return;
+
+exit:
+ /* Try to resubmit the urb. */
+ result = usb_submit_urb(urb, GFP_ATOMIC);
+ if (result)
+ dev_dbg(&port->dev,
+ "%s - failed submitting interrupt in urb, error code=%d\n",
+ __func__, result);
+}
+
+static void metrousb_cleanup(struct usb_serial_port *port)
+{
+ dev_dbg(&port->dev, "%s\n", __func__);
+
+ if (port->serial->dev) {
+ /* Shutdown any interrupt in urbs. */
+ if (port->interrupt_in_urb) {
+ usb_unlink_urb(port->interrupt_in_urb);
+ usb_kill_urb(port->interrupt_in_urb);
+ }
+ }
+}
+
+static int metrousb_open(struct tty_struct *tty, struct usb_serial_port *port)
+{
+ struct usb_serial *serial = port->serial;
+ struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
+ unsigned long flags = 0;
+ int result = 0;
+
+ dev_dbg(&port->dev, "%s\n", __func__);
+
+ /* Make sure the urb is initialized. */
+ if (!port->interrupt_in_urb) {
+ dev_dbg(&port->dev, "%s - interrupt urb not initialized\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ /* Set the private data information for the port. */
+ spin_lock_irqsave(&metro_priv->lock, flags);
+ metro_priv->control_state = 0;
+ metro_priv->throttled = 0;
+ spin_unlock_irqrestore(&metro_priv->lock, flags);
+
+ /*
+ * Force low_latency on so that our tty_push actually forces the data
+ * through, otherwise it is scheduled, and with high data rates (like
+ * with OHCI) data can get lost.
+ */
+ if (tty)
+ tty->low_latency = 1;
+
+ /* Clear the urb pipe. */
+ usb_clear_halt(serial->dev, port->interrupt_in_urb->pipe);
+
+ /* Start reading from the device */
+ usb_fill_int_urb(port->interrupt_in_urb, serial->dev,
+ usb_rcvintpipe(serial->dev, port->interrupt_in_endpointAddress),
+ port->interrupt_in_urb->transfer_buffer,
+ port->interrupt_in_urb->transfer_buffer_length,
+ metrousb_read_int_callback, port, 1);
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_KERNEL);
+
+ if (result) {
+ dev_dbg(&port->dev,
+ "%s - failed submitting interrupt in urb, error code=%d\n",
+ __func__, result);
+ goto exit;
+ }
+
+ dev_dbg(&port->dev, "%s - port open\n", __func__);
+exit:
+ return result;
+}
+
+static int metrousb_set_modem_ctrl(struct usb_serial *serial, unsigned int control_state)
+{
+ int retval = 0;
+ unsigned char mcr = METROUSB_MCR_NONE;
+
+ dev_dbg(&serial->dev->dev, "%s - control state = %d\n",
+ __func__, control_state);
+
+ /* Set the modem control value. */
+ if (control_state & TIOCM_DTR)
+ mcr |= METROUSB_MCR_DTR;
+ if (control_state & TIOCM_RTS)
+ mcr |= METROUSB_MCR_RTS;
+
+ /* Send the command to the usb port. */
+ retval = usb_control_msg(serial->dev, usb_sndctrlpipe(serial->dev, 0),
+ METROUSB_SET_REQUEST_TYPE, METROUSB_SET_MODEM_CTRL_REQUEST,
+ control_state, 0, NULL, 0, WDR_TIMEOUT);
+ if (retval < 0)
+ dev_dbg(&serial->dev->dev,
+ "%s - set modem ctrl=0x%x failed, error code=%d\n",
+ __func__, mcr, retval);
+
+ return retval;
+}
+
+static void metrousb_shutdown(struct usb_serial *serial)
+{
+ int i = 0;
+
+ dev_dbg(&serial->dev->dev, "%s\n", __func__);
+
+ /* Stop reading and writing on all ports. */
+ for (i = 0; i < serial->num_ports; ++i) {
+ /* Close any open urbs. */
+ metrousb_cleanup(serial->port[i]);
+
+ /* Free memory. */
+ kfree(usb_get_serial_port_data(serial->port[i]));
+ usb_set_serial_port_data(serial->port[i], NULL);
+
+ dev_dbg(&serial->dev->dev, "%s - freed port number=%d\n",
+ __func__, serial->port[i]->number);
+ }
+}
+
+static int metrousb_startup(struct usb_serial *serial)
+{
+ struct metrousb_private *metro_priv;
+ struct usb_serial_port *port;
+ int i = 0;
+
+ dev_dbg(&serial->dev->dev, "%s\n", __func__);
+
+ /* Loop through the serial ports setting up the private structures.
+ * Currently we only use one port. */
+ for (i = 0; i < serial->num_ports; ++i) {
+ port = serial->port[i];
+
+ /* Declare memory. */
+ metro_priv = kzalloc(sizeof(struct metrousb_private), GFP_KERNEL);
+ if (!metro_priv)
+ return -ENOMEM;
+
+ /* Initialize memory. */
+ spin_lock_init(&metro_priv->lock);
+ usb_set_serial_port_data(port, metro_priv);
+
+ dev_dbg(&serial->dev->dev, "%s - port number=%d\n ",
+ __func__, port->number);
+ }
+
+ return 0;
+}
+
+static void metrousb_throttle(struct tty_struct *tty)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
+ unsigned long flags = 0;
+
+ dev_dbg(tty->dev, "%s\n", __func__);
+
+ /* Set the private information for the port to stop reading data. */
+ spin_lock_irqsave(&metro_priv->lock, flags);
+ metro_priv->throttled = 1;
+ spin_unlock_irqrestore(&metro_priv->lock, flags);
+}
+
+static int metrousb_tiocmget(struct tty_struct *tty)
+{
+ unsigned long control_state = 0;
+ struct usb_serial_port *port = tty->driver_data;
+ struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
+ unsigned long flags = 0;
+
+ dev_dbg(tty->dev, "%s\n", __func__);
+
+ spin_lock_irqsave(&metro_priv->lock, flags);
+ control_state = metro_priv->control_state;
+ spin_unlock_irqrestore(&metro_priv->lock, flags);
+
+ return control_state;
+}
+
+static int metrousb_tiocmset(struct tty_struct *tty,
+ unsigned int set, unsigned int clear)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct usb_serial *serial = port->serial;
+ struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
+ unsigned long flags = 0;
+ unsigned long control_state = 0;
+
+ dev_dbg(tty->dev, "%s - set=%d, clear=%d\n", __func__, set, clear);
+
+ spin_lock_irqsave(&metro_priv->lock, flags);
+ control_state = metro_priv->control_state;
+
+ /* Set the RTS and DTR values. */
+ if (set & TIOCM_RTS)
+ control_state |= TIOCM_RTS;
+ if (set & TIOCM_DTR)
+ control_state |= TIOCM_DTR;
+ if (clear & TIOCM_RTS)
+ control_state &= ~TIOCM_RTS;
+ if (clear & TIOCM_DTR)
+ control_state &= ~TIOCM_DTR;
+
+ metro_priv->control_state = control_state;
+ spin_unlock_irqrestore(&metro_priv->lock, flags);
+ return metrousb_set_modem_ctrl(serial, control_state);
+}
+
+static void metrousb_unthrottle(struct tty_struct *tty)
+{
+ struct usb_serial_port *port = tty->driver_data;
+ struct metrousb_private *metro_priv = usb_get_serial_port_data(port);
+ unsigned long flags = 0;
+ int result = 0;
+
+ dev_dbg(tty->dev, "%s\n", __func__);
+
+ /* Set the private information for the port to resume reading data. */
+ spin_lock_irqsave(&metro_priv->lock, flags);
+ metro_priv->throttled = 0;
+ spin_unlock_irqrestore(&metro_priv->lock, flags);
+
+ /* Submit the urb to read from the port. */
+ port->interrupt_in_urb->dev = port->serial->dev;
+ result = usb_submit_urb(port->interrupt_in_urb, GFP_ATOMIC);
+ if (result)
+ dev_dbg(tty->dev,
+ "failed submitting interrupt in urb error code=%d\n",
+ result);
+}
+
+static struct usb_driver metrousb_driver = {
+ .name = "metro-usb",
+ .probe = usb_serial_probe,
+ .disconnect = usb_serial_disconnect,
+ .id_table = id_table
+};
+
+static struct usb_serial_driver metrousb_device = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "metro-usb",
+ },
+ .description = "Metrologic USB to serial converter.",
+ .id_table = id_table,
+ .num_ports = 1,
+ .open = metrousb_open,
+ .close = metrousb_cleanup,
+ .read_int_callback = metrousb_read_int_callback,
+ .attach = metrousb_startup,
+ .release = metrousb_shutdown,
+ .throttle = metrousb_throttle,
+ .unthrottle = metrousb_unthrottle,
+ .tiocmget = metrousb_tiocmget,
+ .tiocmset = metrousb_tiocmset,
+};
+
+static struct usb_serial_driver * const serial_drivers[] = {
+ &metrousb_device,
+ NULL,
+};
+
+module_usb_serial_driver(metrousb_driver, serial_drivers);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Philip Nicastro");
+MODULE_AUTHOR("Aleksey Babahin <tamerlan311@gmail.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+
+/* Module input parameters */
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Print debug info (bool 1=on, 0=off)");
diff --git a/drivers/usb/serial/mos7720.c b/drivers/usb/serial/mos7720.c
index 4554ee49e635..bdce82034122 100644
--- a/drivers/usb/serial/mos7720.c
+++ b/drivers/usb/serial/mos7720.c
@@ -1294,7 +1294,7 @@ static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port,
urb->transfer_buffer = kmalloc(URB_TRANSFER_BUFFER_SIZE,
GFP_KERNEL);
if (urb->transfer_buffer == NULL) {
- dev_err(&port->dev, "%s no more kernel memory...\n",
+ dev_err_console(port, "%s no more kernel memory...\n",
__func__);
goto exit;
}
@@ -1315,7 +1315,7 @@ static int mos7720_write(struct tty_struct *tty, struct usb_serial_port *port,
/* send it down the pipe */
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
- dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed "
+ dev_err_console(port, "%s - usb_submit_urb(write bulk) failed "
"with status = %d\n", __func__, status);
bytes_sent = status;
goto exit;
@@ -2169,7 +2169,6 @@ static struct usb_driver usb_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = moschip_port_id_table,
- .no_dynamic_id = 1,
};
static struct usb_serial_driver moschip7720_2port_driver = {
@@ -2178,7 +2177,6 @@ static struct usb_serial_driver moschip7720_2port_driver = {
.name = "moschip7720",
},
.description = "Moschip 2 port adapter",
- .usb_driver = &usb_driver,
.id_table = moschip_port_id_table,
.calc_num_ports = mos77xx_calc_num_ports,
.open = mos7720_open,
@@ -2201,44 +2199,12 @@ static struct usb_serial_driver moschip7720_2port_driver = {
.read_int_callback = NULL /* dynamically assigned in probe() */
};
-static int __init moschip7720_init(void)
-{
- int retval;
-
- dbg("%s: Entering ..........", __func__);
-
- /* Register with the usb serial */
- retval = usb_serial_register(&moschip7720_2port_driver);
- if (retval)
- goto failed_port_device_register;
-
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
-
- /* Register with the usb */
- retval = usb_register(&usb_driver);
- if (retval)
- goto failed_usb_register;
-
- return 0;
-
-failed_usb_register:
- usb_serial_deregister(&moschip7720_2port_driver);
-
-failed_port_device_register:
- return retval;
-}
-
-static void __exit moschip7720_exit(void)
-{
- usb_deregister(&usb_driver);
- usb_serial_deregister(&moschip7720_2port_driver);
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &moschip7720_2port_driver, NULL
+};
-module_init(moschip7720_init);
-module_exit(moschip7720_exit);
+module_usb_serial_driver(usb_driver, serial_drivers);
-/* Module information */
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 03b5e249e95e..c526550694a0 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -174,6 +174,7 @@
#define CLK_MULTI_REGISTER ((__u16)(0x02))
#define CLK_START_VALUE_REGISTER ((__u16)(0x03))
+#define GPIO_REGISTER ((__u16)(0x07))
#define SERIAL_LCR_DLAB ((__u16)(0x0080))
@@ -1101,14 +1102,25 @@ static int mos7840_open(struct tty_struct *tty, struct usb_serial_port *port)
mos7840_port->read_urb = port->read_urb;
/* set up our bulk in urb */
-
- usb_fill_bulk_urb(mos7840_port->read_urb,
- serial->dev,
- usb_rcvbulkpipe(serial->dev,
- port->bulk_in_endpointAddress),
- port->bulk_in_buffer,
- mos7840_port->read_urb->transfer_buffer_length,
- mos7840_bulk_in_callback, mos7840_port);
+ if ((serial->num_ports == 2)
+ && ((((__u16)port->number -
+ (__u16)(port->serial->minor)) % 2) != 0)) {
+ usb_fill_bulk_urb(mos7840_port->read_urb,
+ serial->dev,
+ usb_rcvbulkpipe(serial->dev,
+ (port->bulk_in_endpointAddress) + 2),
+ port->bulk_in_buffer,
+ mos7840_port->read_urb->transfer_buffer_length,
+ mos7840_bulk_in_callback, mos7840_port);
+ } else {
+ usb_fill_bulk_urb(mos7840_port->read_urb,
+ serial->dev,
+ usb_rcvbulkpipe(serial->dev,
+ port->bulk_in_endpointAddress),
+ port->bulk_in_buffer,
+ mos7840_port->read_urb->transfer_buffer_length,
+ mos7840_bulk_in_callback, mos7840_port);
+ }
dbg("mos7840_open: bulkin endpoint is %d",
port->bulk_in_endpointAddress);
@@ -1509,7 +1521,7 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
kmalloc(URB_TRANSFER_BUFFER_SIZE, GFP_KERNEL);
if (urb->transfer_buffer == NULL) {
- dev_err(&port->dev, "%s no more kernel memory...\n",
+ dev_err_console(port, "%s no more kernel memory...\n",
__func__);
goto exit;
}
@@ -1519,13 +1531,25 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
memcpy(urb->transfer_buffer, current_position, transfer_size);
/* fill urb with data and submit */
- usb_fill_bulk_urb(urb,
- serial->dev,
- usb_sndbulkpipe(serial->dev,
- port->bulk_out_endpointAddress),
- urb->transfer_buffer,
- transfer_size,
- mos7840_bulk_out_data_callback, mos7840_port);
+ if ((serial->num_ports == 2)
+ && ((((__u16)port->number -
+ (__u16)(port->serial->minor)) % 2) != 0)) {
+ usb_fill_bulk_urb(urb,
+ serial->dev,
+ usb_sndbulkpipe(serial->dev,
+ (port->bulk_out_endpointAddress) + 2),
+ urb->transfer_buffer,
+ transfer_size,
+ mos7840_bulk_out_data_callback, mos7840_port);
+ } else {
+ usb_fill_bulk_urb(urb,
+ serial->dev,
+ usb_sndbulkpipe(serial->dev,
+ port->bulk_out_endpointAddress),
+ urb->transfer_buffer,
+ transfer_size,
+ mos7840_bulk_out_data_callback, mos7840_port);
+ }
data1 = urb->transfer_buffer;
dbg("bulkout endpoint is %d", port->bulk_out_endpointAddress);
@@ -1535,7 +1559,7 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
if (status) {
mos7840_port->busy[i] = 0;
- dev_err(&port->dev, "%s - usb_submit_urb(write bulk) failed "
+ dev_err_console(port, "%s - usb_submit_urb(write bulk) failed "
"with status = %d\n", __func__, status);
bytes_sent = status;
goto exit;
@@ -1838,7 +1862,7 @@ static int mos7840_send_cmd_write_baud_rate(struct moschip_port *mos7840_port,
} else {
#ifdef HW_flow_control
- / *setting h/w flow control bit to 0 */
+ /* setting h/w flow control bit to 0 */
Data = 0xb;
mos7840_port->shadowMCR = Data;
status = mos7840_set_uart_reg(port, MODEM_CONTROL_REGISTER,
@@ -2305,19 +2329,26 @@ static int mos7840_ioctl(struct tty_struct *tty,
static int mos7840_calc_num_ports(struct usb_serial *serial)
{
- int mos7840_num_ports = 0;
-
- dbg("numberofendpoints: cur %d, alt %d",
- (int)serial->interface->cur_altsetting->desc.bNumEndpoints,
- (int)serial->interface->altsetting->desc.bNumEndpoints);
- if (serial->interface->cur_altsetting->desc.bNumEndpoints == 5) {
- mos7840_num_ports = serial->num_ports = 2;
- } else if (serial->interface->cur_altsetting->desc.bNumEndpoints == 9) {
+ __u16 Data = 0x00;
+ int ret = 0;
+ int mos7840_num_ports;
+
+ ret = usb_control_msg(serial->dev, usb_rcvctrlpipe(serial->dev, 0),
+ MCS_RDREQ, MCS_RD_RTYPE, 0, GPIO_REGISTER, &Data,
+ VENDOR_READ_LENGTH, MOS_WDR_TIMEOUT);
+
+ if ((Data & 0x01) == 0) {
+ mos7840_num_ports = 2;
+ serial->num_bulk_in = 2;
+ serial->num_bulk_out = 2;
+ serial->num_ports = 2;
+ } else {
+ mos7840_num_ports = 4;
serial->num_bulk_in = 4;
serial->num_bulk_out = 4;
- mos7840_num_ports = serial->num_ports = 4;
+ serial->num_ports = 4;
}
- dbg ("mos7840_num_ports = %d", mos7840_num_ports);
+
return mos7840_num_ports;
}
@@ -2638,7 +2669,6 @@ static struct usb_driver io_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = moschip_id_table_combined,
- .no_dynamic_id = 1,
};
static struct usb_serial_driver moschip7840_4port_device = {
@@ -2647,7 +2677,6 @@ static struct usb_serial_driver moschip7840_4port_device = {
.name = "mos7840",
},
.description = DRIVER_DESC,
- .usb_driver = &io_driver,
.id_table = moschip_port_id_table,
.num_ports = 4,
.open = mos7840_open,
@@ -2674,57 +2703,12 @@ static struct usb_serial_driver moschip7840_4port_device = {
.read_int_callback = mos7840_interrupt_callback,
};
-/****************************************************************************
- * moschip7840_init
- * This is called by the module subsystem, or on startup to initialize us
- ****************************************************************************/
-static int __init moschip7840_init(void)
-{
- int retval;
-
- dbg("%s", " mos7840_init :entering..........");
-
- /* Register with the usb serial */
- retval = usb_serial_register(&moschip7840_4port_device);
-
- if (retval)
- goto failed_port_device_register;
-
- dbg("%s", "Entering...");
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
-
- /* Register with the usb */
- retval = usb_register(&io_driver);
- if (retval == 0) {
- dbg("%s", "Leaving...");
- return 0;
- }
- usb_serial_deregister(&moschip7840_4port_device);
-failed_port_device_register:
- return retval;
-}
-
-/****************************************************************************
- * moschip7840_exit
- * Called when the driver is about to be unloaded.
- ****************************************************************************/
-static void __exit moschip7840_exit(void)
-{
-
- dbg("%s", " mos7840_exit :entering..........");
-
- usb_deregister(&io_driver);
-
- usb_serial_deregister(&moschip7840_4port_device);
-
- dbg("%s", "Entering...");
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &moschip7840_4port_device, NULL
+};
-module_init(moschip7840_init);
-module_exit(moschip7840_exit);
+module_usb_serial_driver(io_driver, serial_drivers);
-/* Module information */
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/moto_modem.c b/drivers/usb/serial/moto_modem.c
index e2bfecc46402..3ab6214b4bbf 100644
--- a/drivers/usb/serial/moto_modem.c
+++ b/drivers/usb/serial/moto_modem.c
@@ -36,7 +36,6 @@ static struct usb_driver moto_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
static struct usb_serial_driver moto_device = {
@@ -45,29 +44,12 @@ static struct usb_serial_driver moto_device = {
.name = "moto-modem",
},
.id_table = id_table,
- .usb_driver = &moto_driver,
.num_ports = 1,
};
-static int __init moto_init(void)
-{
- int retval;
-
- retval = usb_serial_register(&moto_device);
- if (retval)
- return retval;
- retval = usb_register(&moto_driver);
- if (retval)
- usb_serial_deregister(&moto_device);
- return retval;
-}
-
-static void __exit moto_exit(void)
-{
- usb_deregister(&moto_driver);
- usb_serial_deregister(&moto_device);
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &moto_device, NULL
+};
-module_init(moto_init);
-module_exit(moto_exit);
+module_usb_serial_driver(moto_driver, serial_drivers);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/navman.c b/drivers/usb/serial/navman.c
index b28f1db0195f..29ab6eb5b536 100644
--- a/drivers/usb/serial/navman.c
+++ b/drivers/usb/serial/navman.c
@@ -35,7 +35,6 @@ static struct usb_driver navman_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
static void navman_read_int_callback(struct urb *urb)
@@ -122,7 +121,6 @@ static struct usb_serial_driver navman_device = {
.name = "navman",
},
.id_table = id_table,
- .usb_driver = &navman_driver,
.num_ports = 1,
.open = navman_open,
.close = navman_close,
@@ -130,27 +128,12 @@ static struct usb_serial_driver navman_device = {
.read_int_callback = navman_read_int_callback,
};
-static int __init navman_init(void)
-{
- int retval;
-
- retval = usb_serial_register(&navman_device);
- if (retval)
- return retval;
- retval = usb_register(&navman_driver);
- if (retval)
- usb_serial_deregister(&navman_device);
- return retval;
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &navman_device, NULL
+};
-static void __exit navman_exit(void)
-{
- usb_deregister(&navman_driver);
- usb_serial_deregister(&navman_device);
-}
+module_usb_serial_driver(navman_driver, serial_drivers);
-module_init(navman_init);
-module_exit(navman_exit);
MODULE_LICENSE("GPL");
module_param(debug, bool, S_IRUGO | S_IWUSR);
diff --git a/drivers/usb/serial/omninet.c b/drivers/usb/serial/omninet.c
index 8b8d58a2ac12..88dc785bb298 100644
--- a/drivers/usb/serial/omninet.c
+++ b/drivers/usb/serial/omninet.c
@@ -62,7 +62,6 @@ static struct usb_driver omninet_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
@@ -72,7 +71,6 @@ static struct usb_serial_driver zyxel_omninet_device = {
.name = "omninet",
},
.description = "ZyXEL - omni.net lcd plus usb",
- .usb_driver = &omninet_driver,
.id_table = id_table,
.num_ports = 1,
.attach = omninet_attach,
@@ -86,6 +84,10 @@ static struct usb_serial_driver zyxel_omninet_device = {
.release = omninet_release,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &zyxel_omninet_device, NULL
+};
+
/* The protocol.
*
@@ -254,7 +256,7 @@ static int omninet_write(struct tty_struct *tty, struct usb_serial_port *port,
result = usb_submit_urb(wport->write_urb, GFP_ATOMIC);
if (result) {
set_bit(0, &wport->write_urbs_free);
- dev_err(&port->dev,
+ dev_err_console(port,
"%s - failed submitting write urb, error %d\n",
__func__, result);
} else
@@ -319,35 +321,7 @@ static void omninet_release(struct usb_serial *serial)
kfree(usb_get_serial_port_data(port));
}
-
-static int __init omninet_init(void)
-{
- int retval;
- retval = usb_serial_register(&zyxel_omninet_device);
- if (retval)
- goto failed_usb_serial_register;
- retval = usb_register(&omninet_driver);
- if (retval)
- goto failed_usb_register;
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return 0;
-failed_usb_register:
- usb_serial_deregister(&zyxel_omninet_device);
-failed_usb_serial_register:
- return retval;
-}
-
-
-static void __exit omninet_exit(void)
-{
- usb_deregister(&omninet_driver);
- usb_serial_deregister(&zyxel_omninet_device);
-}
-
-
-module_init(omninet_init);
-module_exit(omninet_exit);
+module_usb_serial_driver(omninet_driver, serial_drivers);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/opticon.c b/drivers/usb/serial/opticon.c
index 262ded9e076b..82cc9d202b83 100644
--- a/drivers/usb/serial/opticon.c
+++ b/drivers/usb/serial/opticon.c
@@ -604,7 +604,6 @@ static struct usb_driver opticon_driver = {
.suspend = opticon_suspend,
.resume = opticon_resume,
.id_table = id_table,
- .no_dynamic_id = 1,
};
static struct usb_serial_driver opticon_device = {
@@ -613,7 +612,6 @@ static struct usb_serial_driver opticon_device = {
.name = "opticon",
},
.id_table = id_table,
- .usb_driver = &opticon_driver,
.num_ports = 1,
.attach = opticon_startup,
.open = opticon_open,
@@ -629,27 +627,12 @@ static struct usb_serial_driver opticon_device = {
.tiocmset = opticon_tiocmset,
};
-static int __init opticon_init(void)
-{
- int retval;
-
- retval = usb_serial_register(&opticon_device);
- if (retval)
- return retval;
- retval = usb_register(&opticon_driver);
- if (retval)
- usb_serial_deregister(&opticon_device);
- return retval;
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &opticon_device, NULL
+};
-static void __exit opticon_exit(void)
-{
- usb_deregister(&opticon_driver);
- usb_serial_deregister(&opticon_device);
-}
+module_usb_serial_driver(opticon_driver, serial_drivers);
-module_init(opticon_init);
-module_exit(opticon_exit);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index b54afceb9611..f4465ccddc35 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -307,6 +307,9 @@ static void option_instat_callback(struct urb *urb);
#define TELIT_VENDOR_ID 0x1bc7
#define TELIT_PRODUCT_UC864E 0x1003
#define TELIT_PRODUCT_UC864G 0x1004
+#define TELIT_PRODUCT_CC864_DUAL 0x1005
+#define TELIT_PRODUCT_CC864_SINGLE 0x1006
+#define TELIT_PRODUCT_DE910_DUAL 0x1010
/* ZTE PRODUCTS */
#define ZTE_VENDOR_ID 0x19d2
@@ -484,6 +487,9 @@ static void option_instat_callback(struct urb *urb);
#define LG_VENDOR_ID 0x1004
#define LG_PRODUCT_L02C 0x618f
+/* MediaTek products */
+#define MEDIATEK_VENDOR_ID 0x0e8d
+
/* some devices interfaces need special handling due to a number of reasons */
enum option_blacklist_reason {
OPTION_BLACKLIST_NONE = 0,
@@ -702,6 +708,7 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_EMBEDDED_FULLSPEED) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_EMBEDDED_FULLSPEED) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_EVDO_HIGHSPEED) },
+ { USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED3) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED4) },
{ USB_DEVICE(NOVATELWIRELESS_VENDOR_ID, NOVATELWIRELESS_PRODUCT_HSPA_HIGHSPEED5) },
@@ -768,6 +775,9 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE(CMOTECH_VENDOR_ID, CMOTECH_PRODUCT_6008) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864E) },
{ USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_UC864G) },
+ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_DUAL) },
+ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_CC864_SINGLE) },
+ { USB_DEVICE(TELIT_VENDOR_ID, TELIT_PRODUCT_DE910_DUAL) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, ZTE_PRODUCT_MF622, 0xff, 0xff, 0xff) }, /* ZTE WCDMA products */
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0002, 0xff, 0xff, 0xff),
.driver_info = (kernel_ulong_t)&net_intf1_blacklist },
@@ -892,8 +902,12 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0162, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0164, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0165, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff) },
- { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff) },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x0167, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1008, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
+ { USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1010, 0xff, 0xff, 0xff),
+ .driver_info = (kernel_ulong_t)&net_intf4_blacklist },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1012, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1057, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZTE_VENDOR_ID, 0x1058, 0xff, 0xff, 0xff) },
@@ -1198,6 +1212,10 @@ static const struct usb_device_id option_ids[] = {
{ USB_DEVICE_AND_INTERFACE_INFO(VIETTEL_VENDOR_ID, VIETTEL_PRODUCT_VT1000, 0xff, 0xff, 0xff) },
{ USB_DEVICE_AND_INTERFACE_INFO(ZD_VENDOR_ID, ZD_PRODUCT_7000, 0xff, 0xff, 0xff) },
{ USB_DEVICE(LG_VENDOR_ID, LG_PRODUCT_L02C) }, /* docomo L-02C modem */
+ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x00, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a1, 0xff, 0x02, 0x01) },
+ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x00, 0x00) },
+ { USB_DEVICE_AND_INTERFACE_INFO(MEDIATEK_VENDOR_ID, 0x00a2, 0xff, 0x02, 0x01) }, /* MediaTek MT6276M modem & app port */
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, option_ids);
@@ -1212,7 +1230,6 @@ static struct usb_driver option_driver = {
.supports_autosuspend = 1,
#endif
.id_table = option_ids,
- .no_dynamic_id = 1,
};
/* The card has three separate interfaces, which the serial driver
@@ -1225,7 +1242,6 @@ static struct usb_serial_driver option_1port_device = {
.name = "option1",
},
.description = "GSM modem (1-port)",
- .usb_driver = &option_driver,
.id_table = option_ids,
.num_ports = 1,
.probe = option_probe,
@@ -1249,6 +1265,10 @@ static struct usb_serial_driver option_1port_device = {
#endif
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &option_1port_device, NULL
+};
+
static bool debug;
/* per port private data */
@@ -1280,36 +1300,7 @@ struct option_port_private {
unsigned long tx_start_time[N_OUT_URB];
};
-/* Functions used by new usb-serial code. */
-static int __init option_init(void)
-{
- int retval;
- retval = usb_serial_register(&option_1port_device);
- if (retval)
- goto failed_1port_device_register;
- retval = usb_register(&option_driver);
- if (retval)
- goto failed_driver_register;
-
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
-
- return 0;
-
-failed_driver_register:
- usb_serial_deregister(&option_1port_device);
-failed_1port_device_register:
- return retval;
-}
-
-static void __exit option_exit(void)
-{
- usb_deregister(&option_driver);
- usb_serial_deregister(&option_1port_device);
-}
-
-module_init(option_init);
-module_exit(option_exit);
+module_usb_serial_driver(option_driver, serial_drivers);
static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason,
const struct option_blacklist_info *blacklist)
@@ -1360,6 +1351,7 @@ static int option_probe(struct usb_serial *serial,
serial->interface->cur_altsetting->desc.bInterfaceNumber,
OPTION_BLACKLIST_RESERVED_IF,
(const struct option_blacklist_info *) id->driver_info))
+ return -ENODEV;
/* Don't bind network interface on Samsung GT-B3730, it is handled by a separate module */
if (serial->dev->descriptor.idVendor == SAMSUNG_VENDOR_ID &&
diff --git a/drivers/usb/serial/oti6858.c b/drivers/usb/serial/oti6858.c
index e287fd32682c..5fdc33c6a3c0 100644
--- a/drivers/usb/serial/oti6858.c
+++ b/drivers/usb/serial/oti6858.c
@@ -71,7 +71,6 @@ static struct usb_driver oti6858_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
static bool debug;
@@ -157,7 +156,6 @@ static struct usb_serial_driver oti6858_device = {
.name = "oti6858",
},
.id_table = id_table,
- .usb_driver = &oti6858_driver,
.num_ports = 1,
.open = oti6858_open,
.close = oti6858_close,
@@ -176,6 +174,10 @@ static struct usb_serial_driver oti6858_device = {
.release = oti6858_release,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &oti6858_device, NULL
+};
+
struct oti6858_private {
spinlock_t lock;
@@ -302,7 +304,7 @@ static void send_data(struct work_struct *work)
if (count != 0) {
allow = kmalloc(1, GFP_KERNEL);
if (!allow) {
- dev_err(&port->dev, "%s(): kmalloc failed\n",
+ dev_err_console(port, "%s(): kmalloc failed\n",
__func__);
return;
}
@@ -334,7 +336,7 @@ static void send_data(struct work_struct *work)
port->write_urb->transfer_buffer_length = count;
result = usb_submit_urb(port->write_urb, GFP_NOIO);
if (result != 0) {
- dev_err(&port->dev, "%s(): usb_submit_urb() failed"
+ dev_err_console(port, "%s(): usb_submit_urb() failed"
" with error %d\n", __func__, result);
priv->flags.write_urb_in_use = 0;
}
@@ -938,7 +940,7 @@ static void oti6858_write_bulk_callback(struct urb *urb)
port->write_urb->transfer_buffer_length = 1;
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
- dev_err(&port->dev, "%s(): usb_submit_urb() failed,"
+ dev_err_console(port, "%s(): usb_submit_urb() failed,"
" error %d\n", __func__, result);
} else {
return;
@@ -956,29 +958,7 @@ static void oti6858_write_bulk_callback(struct urb *urb)
}
}
-/* module description and (de)initialization */
-
-static int __init oti6858_init(void)
-{
- int retval;
-
- retval = usb_serial_register(&oti6858_device);
- if (retval == 0) {
- retval = usb_register(&oti6858_driver);
- if (retval)
- usb_serial_deregister(&oti6858_device);
- }
- return retval;
-}
-
-static void __exit oti6858_exit(void)
-{
- usb_deregister(&oti6858_driver);
- usb_serial_deregister(&oti6858_device);
-}
-
-module_init(oti6858_init);
-module_exit(oti6858_exit);
+module_usb_serial_driver(oti6858_driver, serial_drivers);
MODULE_DESCRIPTION(OTI6858_DESCRIPTION);
MODULE_AUTHOR(OTI6858_AUTHOR);
diff --git a/drivers/usb/serial/pl2303.c b/drivers/usb/serial/pl2303.c
index 3d8cda57ce7a..a1a9062954c4 100644
--- a/drivers/usb/serial/pl2303.c
+++ b/drivers/usb/serial/pl2303.c
@@ -104,7 +104,6 @@ static struct usb_driver pl2303_driver = {
.id_table = id_table,
.suspend = usb_serial_suspend,
.resume = usb_serial_resume,
- .no_dynamic_id = 1,
.supports_autosuspend = 1,
};
@@ -421,7 +420,7 @@ static void pl2303_set_termios(struct tty_struct *tty,
control = priv->line_control;
if ((cflag & CBAUD) == B0)
priv->line_control &= ~(CONTROL_DTR | CONTROL_RTS);
- else
+ else if ((old_termios->c_cflag & CBAUD) == B0)
priv->line_control |= (CONTROL_DTR | CONTROL_RTS);
if (control != priv->line_control) {
control = priv->line_control;
@@ -834,7 +833,6 @@ static struct usb_serial_driver pl2303_device = {
.name = "pl2303",
},
.id_table = id_table,
- .usb_driver = &pl2303_driver,
.num_ports = 1,
.bulk_in_size = 256,
.bulk_out_size = 256,
@@ -853,32 +851,11 @@ static struct usb_serial_driver pl2303_device = {
.release = pl2303_release,
};
-static int __init pl2303_init(void)
-{
- int retval;
-
- retval = usb_serial_register(&pl2303_device);
- if (retval)
- goto failed_usb_serial_register;
- retval = usb_register(&pl2303_driver);
- if (retval)
- goto failed_usb_register;
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
- return 0;
-failed_usb_register:
- usb_serial_deregister(&pl2303_device);
-failed_usb_serial_register:
- return retval;
-}
-
-static void __exit pl2303_exit(void)
-{
- usb_deregister(&pl2303_driver);
- usb_serial_deregister(&pl2303_device);
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &pl2303_device, NULL
+};
-module_init(pl2303_init);
-module_exit(pl2303_exit);
+module_usb_serial_driver(pl2303_driver, serial_drivers);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/qcaux.c b/drivers/usb/serial/qcaux.c
index a34819884c1a..966245680f55 100644
--- a/drivers/usb/serial/qcaux.c
+++ b/drivers/usb/serial/qcaux.c
@@ -82,7 +82,6 @@ static struct usb_driver qcaux_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
static struct usb_serial_driver qcaux_device = {
@@ -91,29 +90,12 @@ static struct usb_serial_driver qcaux_device = {
.name = "qcaux",
},
.id_table = id_table,
- .usb_driver = &qcaux_driver,
.num_ports = 1,
};
-static int __init qcaux_init(void)
-{
- int retval;
-
- retval = usb_serial_register(&qcaux_device);
- if (retval)
- return retval;
- retval = usb_register(&qcaux_driver);
- if (retval)
- usb_serial_deregister(&qcaux_device);
- return retval;
-}
-
-static void __exit qcaux_exit(void)
-{
- usb_deregister(&qcaux_driver);
- usb_serial_deregister(&qcaux_device);
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &qcaux_device, NULL
+};
-module_init(qcaux_init);
-module_exit(qcaux_exit);
+module_usb_serial_driver(qcaux_driver, serial_drivers);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/qcserial.c b/drivers/usb/serial/qcserial.c
index f98800f2324c..0206b10c9e6e 100644
--- a/drivers/usb/serial/qcserial.c
+++ b/drivers/usb/serial/qcserial.c
@@ -24,39 +24,44 @@
static bool debug;
+#define DEVICE_G1K(v, p) \
+ USB_DEVICE(v, p), .driver_info = 1
+
static const struct usb_device_id id_table[] = {
- {USB_DEVICE(0x05c6, 0x9211)}, /* Acer Gobi QDL device */
- {USB_DEVICE(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */
- {USB_DEVICE(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */
- {USB_DEVICE(0x03f0, 0x201d)}, /* HP un2400 Gobi QDL Device */
- {USB_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Mobile Broadband Module */
- {USB_DEVICE(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */
- {USB_DEVICE(0x04da, 0x250c)}, /* Panasonic Gobi QDL device */
- {USB_DEVICE(0x413c, 0x8172)}, /* Dell Gobi Modem device */
- {USB_DEVICE(0x413c, 0x8171)}, /* Dell Gobi QDL device */
- {USB_DEVICE(0x1410, 0xa001)}, /* Novatel Gobi Modem device */
- {USB_DEVICE(0x1410, 0xa008)}, /* Novatel Gobi QDL device */
- {USB_DEVICE(0x1410, 0xa010)}, /* Novatel Gobi QDL device */
- {USB_DEVICE(0x1410, 0xa011)}, /* Novatel Gobi QDL device */
- {USB_DEVICE(0x1410, 0xa012)}, /* Novatel Gobi QDL device */
- {USB_DEVICE(0x1410, 0xa013)}, /* Novatel Gobi QDL device */
- {USB_DEVICE(0x1410, 0xa014)}, /* Novatel Gobi QDL device */
- {USB_DEVICE(0x0b05, 0x1776)}, /* Asus Gobi Modem device */
- {USB_DEVICE(0x0b05, 0x1774)}, /* Asus Gobi QDL device */
- {USB_DEVICE(0x19d2, 0xfff3)}, /* ONDA Gobi Modem device */
- {USB_DEVICE(0x19d2, 0xfff2)}, /* ONDA Gobi QDL device */
- {USB_DEVICE(0x1557, 0x0a80)}, /* OQO Gobi QDL device */
- {USB_DEVICE(0x05c6, 0x9001)}, /* Generic Gobi Modem device */
- {USB_DEVICE(0x05c6, 0x9002)}, /* Generic Gobi Modem device */
- {USB_DEVICE(0x05c6, 0x9202)}, /* Generic Gobi Modem device */
- {USB_DEVICE(0x05c6, 0x9203)}, /* Generic Gobi Modem device */
- {USB_DEVICE(0x05c6, 0x9222)}, /* Generic Gobi Modem device */
- {USB_DEVICE(0x05c6, 0x9008)}, /* Generic Gobi QDL device */
- {USB_DEVICE(0x05c6, 0x9009)}, /* Generic Gobi Modem device */
- {USB_DEVICE(0x05c6, 0x9201)}, /* Generic Gobi QDL device */
- {USB_DEVICE(0x05c6, 0x9221)}, /* Generic Gobi QDL device */
- {USB_DEVICE(0x05c6, 0x9231)}, /* Generic Gobi QDL device */
- {USB_DEVICE(0x1f45, 0x0001)}, /* Unknown Gobi QDL device */
+ /* Gobi 1000 devices */
+ {DEVICE_G1K(0x05c6, 0x9211)}, /* Acer Gobi QDL device */
+ {DEVICE_G1K(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */
+ {DEVICE_G1K(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */
+ {DEVICE_G1K(0x03f0, 0x201d)}, /* HP un2400 Gobi QDL Device */
+ {DEVICE_G1K(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */
+ {DEVICE_G1K(0x04da, 0x250c)}, /* Panasonic Gobi QDL device */
+ {DEVICE_G1K(0x413c, 0x8172)}, /* Dell Gobi Modem device */
+ {DEVICE_G1K(0x413c, 0x8171)}, /* Dell Gobi QDL device */
+ {DEVICE_G1K(0x1410, 0xa001)}, /* Novatel Gobi Modem device */
+ {DEVICE_G1K(0x1410, 0xa008)}, /* Novatel Gobi QDL device */
+ {DEVICE_G1K(0x0b05, 0x1776)}, /* Asus Gobi Modem device */
+ {DEVICE_G1K(0x0b05, 0x1774)}, /* Asus Gobi QDL device */
+ {DEVICE_G1K(0x19d2, 0xfff3)}, /* ONDA Gobi Modem device */
+ {DEVICE_G1K(0x19d2, 0xfff2)}, /* ONDA Gobi QDL device */
+ {DEVICE_G1K(0x1557, 0x0a80)}, /* OQO Gobi QDL device */
+ {DEVICE_G1K(0x05c6, 0x9001)}, /* Generic Gobi Modem device */
+ {DEVICE_G1K(0x05c6, 0x9002)}, /* Generic Gobi Modem device */
+ {DEVICE_G1K(0x05c6, 0x9202)}, /* Generic Gobi Modem device */
+ {DEVICE_G1K(0x05c6, 0x9203)}, /* Generic Gobi Modem device */
+ {DEVICE_G1K(0x05c6, 0x9222)}, /* Generic Gobi Modem device */
+ {DEVICE_G1K(0x05c6, 0x9008)}, /* Generic Gobi QDL device */
+ {DEVICE_G1K(0x05c6, 0x9009)}, /* Generic Gobi Modem device */
+ {DEVICE_G1K(0x05c6, 0x9201)}, /* Generic Gobi QDL device */
+ {DEVICE_G1K(0x05c6, 0x9221)}, /* Generic Gobi QDL device */
+ {DEVICE_G1K(0x05c6, 0x9231)}, /* Generic Gobi QDL device */
+ {DEVICE_G1K(0x1f45, 0x0001)}, /* Unknown Gobi QDL device */
+
+ /* Gobi 2000 devices */
+ {USB_DEVICE(0x1410, 0xa010)}, /* Novatel Gobi 2000 QDL device */
+ {USB_DEVICE(0x1410, 0xa011)}, /* Novatel Gobi 2000 QDL device */
+ {USB_DEVICE(0x1410, 0xa012)}, /* Novatel Gobi 2000 QDL device */
+ {USB_DEVICE(0x1410, 0xa013)}, /* Novatel Gobi 2000 QDL device */
+ {USB_DEVICE(0x1410, 0xa014)}, /* Novatel Gobi 2000 QDL device */
{USB_DEVICE(0x413c, 0x8185)}, /* Dell Gobi 2000 QDL device (N0218, VU936) */
{USB_DEVICE(0x413c, 0x8186)}, /* Dell Gobi 2000 Modem device (N0218, VU936) */
{USB_DEVICE(0x05c6, 0x9208)}, /* Generic Gobi 2000 QDL device */
@@ -92,6 +97,8 @@ static const struct usb_device_id id_table[] = {
{USB_DEVICE(0x05c6, 0x9204)}, /* Gobi 2000 QDL device */
{USB_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */
+ /* Gobi 3000 devices */
+ {USB_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Gobi 3000 QDL */
{USB_DEVICE(0x05c6, 0x920c)}, /* Gobi 3000 QDL */
{USB_DEVICE(0x05c6, 0x920d)}, /* Gobi 3000 Composite */
{USB_DEVICE(0x1410, 0xa020)}, /* Novatel Gobi 3000 QDL */
@@ -122,8 +129,10 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
int retval = -ENODEV;
__u8 nintf;
__u8 ifnum;
+ bool is_gobi1k = id->driver_info ? true : false;
dbg("%s", __func__);
+ dbg("Is Gobi 1000 = %d", is_gobi1k);
nintf = serial->dev->actconfig->desc.bNumInterfaces;
dbg("Num Interfaces = %d", nintf);
@@ -169,15 +178,25 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
case 3:
case 4:
- /* Composite mode */
- /* ifnum == 0 is a broadband network adapter */
- if (ifnum == 1) {
- /*
- * Diagnostics Monitor (serial line 9600 8N1)
- * Qualcomm DM protocol
- * use "libqcdm" (ModemManager) for communication
- */
- dbg("Diagnostics Monitor found");
+ /* Composite mode; don't bind to the QMI/net interface as that
+ * gets handled by other drivers.
+ */
+
+ /* Gobi 1K USB layout:
+ * 0: serial port (doesn't respond)
+ * 1: serial port (doesn't respond)
+ * 2: AT-capable modem port
+ * 3: QMI/net
+ *
+ * Gobi 2K+ USB layout:
+ * 0: QMI/net
+ * 1: DM/DIAG (use libqcdm from ModemManager for communication)
+ * 2: AT-capable modem port
+ * 3: NMEA
+ */
+
+ if (ifnum == 1 && !is_gobi1k) {
+ dbg("Gobi 2K+ DM/DIAG interface found");
retval = usb_set_interface(serial->dev, ifnum, 0);
if (retval < 0) {
dev_err(&serial->dev->dev,
@@ -196,13 +215,13 @@ static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
retval = -ENODEV;
kfree(data);
}
- } else if (ifnum==3) {
+ } else if (ifnum==3 && !is_gobi1k) {
/*
* NMEA (serial line 9600 8N1)
* # echo "\$GPS_START" > /dev/ttyUSBx
* # echo "\$GPS_STOP" > /dev/ttyUSBx
*/
- dbg("NMEA GPS interface found");
+ dbg("Gobi 2K+ NMEA GPS interface found");
retval = usb_set_interface(serial->dev, ifnum, 0);
if (retval < 0) {
dev_err(&serial->dev->dev,
@@ -246,7 +265,6 @@ static struct usb_serial_driver qcdevice = {
},
.description = "Qualcomm USB modem",
.id_table = id_table,
- .usb_driver = &qcdriver,
.num_ports = 1,
.probe = qcprobe,
.open = usb_wwan_open,
@@ -263,31 +281,11 @@ static struct usb_serial_driver qcdevice = {
#endif
};
-static int __init qcinit(void)
-{
- int retval;
-
- retval = usb_serial_register(&qcdevice);
- if (retval)
- return retval;
-
- retval = usb_register(&qcdriver);
- if (retval) {
- usb_serial_deregister(&qcdevice);
- return retval;
- }
-
- return 0;
-}
-
-static void __exit qcexit(void)
-{
- usb_deregister(&qcdriver);
- usb_serial_deregister(&qcdevice);
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &qcdevice, NULL
+};
-module_init(qcinit);
-module_exit(qcexit);
+module_usb_serial_driver(qcdriver, serial_drivers);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/safe_serial.c b/drivers/usb/serial/safe_serial.c
index d074b3740dcb..ae4ee30c7411 100644
--- a/drivers/usb/serial/safe_serial.c
+++ b/drivers/usb/serial/safe_serial.c
@@ -156,7 +156,6 @@ static struct usb_driver safe_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
static const __u16 crc10_table[256] = {
@@ -309,16 +308,19 @@ static struct usb_serial_driver safe_device = {
.name = "safe_serial",
},
.id_table = id_table,
- .usb_driver = &safe_driver,
.num_ports = 1,
.process_read_urb = safe_process_read_urb,
.prepare_write_buffer = safe_prepare_write_buffer,
.attach = safe_startup,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &safe_device, NULL
+};
+
static int __init safe_init(void)
{
- int i, retval;
+ int i;
printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
DRIVER_DESC "\n");
@@ -337,24 +339,12 @@ static int __init safe_init(void)
}
}
- retval = usb_serial_register(&safe_device);
- if (retval)
- goto failed_usb_serial_register;
- retval = usb_register(&safe_driver);
- if (retval)
- goto failed_usb_register;
-
- return 0;
-failed_usb_register:
- usb_serial_deregister(&safe_device);
-failed_usb_serial_register:
- return retval;
+ return usb_serial_register_drivers(&safe_driver, serial_drivers);
}
static void __exit safe_exit(void)
{
- usb_deregister(&safe_driver);
- usb_serial_deregister(&safe_device);
+ usb_serial_deregister_drivers(&safe_driver, serial_drivers);
}
module_init(safe_init);
diff --git a/drivers/usb/serial/siemens_mpi.c b/drivers/usb/serial/siemens_mpi.c
index 74cd4ccdb3fc..46c0430fd38b 100644
--- a/drivers/usb/serial/siemens_mpi.c
+++ b/drivers/usb/serial/siemens_mpi.c
@@ -42,37 +42,15 @@ static struct usb_serial_driver siemens_usb_mpi_device = {
.name = "siemens_mpi",
},
.id_table = id_table,
- .usb_driver = &siemens_usb_mpi_driver,
.num_ports = 1,
};
-static int __init siemens_usb_mpi_init(void)
-{
- int retval;
-
- retval = usb_serial_register(&siemens_usb_mpi_device);
- if (retval)
- goto failed_usb_serial_register;
- retval = usb_register(&siemens_usb_mpi_driver);
- if (retval)
- goto failed_usb_register;
- printk(KERN_INFO DRIVER_DESC "\n");
- printk(KERN_INFO DRIVER_VERSION " " DRIVER_AUTHOR "\n");
- return retval;
-failed_usb_register:
- usb_serial_deregister(&siemens_usb_mpi_device);
-failed_usb_serial_register:
- return retval;
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &siemens_usb_mpi_device, NULL
+};
-static void __exit siemens_usb_mpi_exit(void)
-{
- usb_deregister(&siemens_usb_mpi_driver);
- usb_serial_deregister(&siemens_usb_mpi_device);
-}
+module_usb_serial_driver(siemens_usb_mpi_driver, serial_drivers);
-module_init(siemens_usb_mpi_init);
-module_exit(siemens_usb_mpi_exit);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/sierra.c b/drivers/usb/serial/sierra.c
index fdae0a4407cb..8c8bf806f6fa 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -221,7 +221,7 @@ static const struct sierra_iface_info typeB_interface_list = {
};
/* 'blacklist' of interfaces not served by this driver */
-static const u8 direct_ip_non_serial_ifaces[] = { 7, 8, 9, 10, 11 };
+static const u8 direct_ip_non_serial_ifaces[] = { 7, 8, 9, 10, 11, 19, 20 };
static const struct sierra_iface_info direct_ip_interface_blacklist = {
.infolen = ARRAY_SIZE(direct_ip_non_serial_ifaces),
.ifaceinfo = direct_ip_non_serial_ifaces,
@@ -298,6 +298,9 @@ static const struct usb_device_id id_table[] = {
/* Sierra Wireless HSPA Non-Composite Device */
{ USB_DEVICE_AND_INTERFACE_INFO(0x1199, 0x6892, 0xFF, 0xFF, 0xFF)},
{ USB_DEVICE(0x1199, 0x6893) }, /* Sierra Wireless Device */
+ { USB_DEVICE(0x1199, 0x68A2), /* Sierra Wireless MC77xx in QMI mode */
+ .driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
+ },
{ USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless Direct IP modems */
.driver_info = (kernel_ulong_t)&direct_ip_interface_blacklist
},
@@ -1084,7 +1087,6 @@ static struct usb_driver sierra_driver = {
.resume = usb_serial_resume,
.reset_resume = sierra_reset_resume,
.id_table = id_table,
- .no_dynamic_id = 1,
.supports_autosuspend = 1,
};
@@ -1095,7 +1097,6 @@ static struct usb_serial_driver sierra_device = {
},
.description = "Sierra USB modem",
.id_table = id_table,
- .usb_driver = &sierra_driver,
.calc_num_ports = sierra_calc_num_ports,
.probe = sierra_probe,
.open = sierra_open,
@@ -1113,38 +1114,11 @@ static struct usb_serial_driver sierra_device = {
.read_int_callback = sierra_instat_callback,
};
-/* Functions used by new usb-serial code. */
-static int __init sierra_init(void)
-{
- int retval;
- retval = usb_serial_register(&sierra_device);
- if (retval)
- goto failed_device_register;
-
-
- retval = usb_register(&sierra_driver);
- if (retval)
- goto failed_driver_register;
-
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
-
- return 0;
-
-failed_driver_register:
- usb_serial_deregister(&sierra_device);
-failed_device_register:
- return retval;
-}
-
-static void __exit sierra_exit(void)
-{
- usb_deregister(&sierra_driver);
- usb_serial_deregister(&sierra_device);
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &sierra_device, NULL
+};
-module_init(sierra_init);
-module_exit(sierra_exit);
+module_usb_serial_driver(sierra_driver, serial_drivers);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/spcp8x5.c b/drivers/usb/serial/spcp8x5.c
index d7f5eee18f00..f06c9a8f3d37 100644
--- a/drivers/usb/serial/spcp8x5.c
+++ b/drivers/usb/serial/spcp8x5.c
@@ -156,7 +156,6 @@ static struct usb_driver spcp8x5_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
@@ -649,7 +648,6 @@ static struct usb_serial_driver spcp8x5_device = {
.name = "SPCP8x5",
},
.id_table = id_table,
- .usb_driver = &spcp8x5_driver,
.num_ports = 1,
.open = spcp8x5_open,
.dtr_rts = spcp8x5_dtr_rts,
@@ -664,32 +662,11 @@ static struct usb_serial_driver spcp8x5_device = {
.process_read_urb = spcp8x5_process_read_urb,
};
-static int __init spcp8x5_init(void)
-{
- int retval;
- retval = usb_serial_register(&spcp8x5_device);
- if (retval)
- goto failed_usb_serial_register;
- retval = usb_register(&spcp8x5_driver);
- if (retval)
- goto failed_usb_register;
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return 0;
-failed_usb_register:
- usb_serial_deregister(&spcp8x5_device);
-failed_usb_serial_register:
- return retval;
-}
-
-static void __exit spcp8x5_exit(void)
-{
- usb_deregister(&spcp8x5_driver);
- usb_serial_deregister(&spcp8x5_device);
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &spcp8x5_device, NULL
+};
-module_init(spcp8x5_init);
-module_exit(spcp8x5_exit);
+module_usb_serial_driver(spcp8x5_driver, serial_drivers);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/usb/serial/ssu100.c b/drivers/usb/serial/ssu100.c
index 7697858d8858..3cdc8a52de44 100644
--- a/drivers/usb/serial/ssu100.c
+++ b/drivers/usb/serial/ssu100.c
@@ -70,7 +70,6 @@ static struct usb_driver ssu100_driver = {
.id_table = id_table,
.suspend = usb_serial_suspend,
.resume = usb_serial_resume,
- .no_dynamic_id = 1,
.supports_autosuspend = 1,
};
@@ -677,7 +676,6 @@ static struct usb_serial_driver ssu100_device = {
},
.description = DRIVER_DESC,
.id_table = id_table,
- .usb_driver = &ssu100_driver,
.num_ports = 1,
.open = ssu100_open,
.close = ssu100_close,
@@ -693,41 +691,11 @@ static struct usb_serial_driver ssu100_device = {
.disconnect = usb_serial_generic_disconnect,
};
-static int __init ssu100_init(void)
-{
- int retval;
-
- dbg("%s", __func__);
-
- /* register with usb-serial */
- retval = usb_serial_register(&ssu100_device);
-
- if (retval)
- goto failed_usb_sio_register;
-
- retval = usb_register(&ssu100_driver);
- if (retval)
- goto failed_usb_register;
-
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
-
- return 0;
-
-failed_usb_register:
- usb_serial_deregister(&ssu100_device);
-failed_usb_sio_register:
- return retval;
-}
-
-static void __exit ssu100_exit(void)
-{
- usb_deregister(&ssu100_driver);
- usb_serial_deregister(&ssu100_device);
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &ssu100_device, NULL
+};
-module_init(ssu100_init);
-module_exit(ssu100_exit);
+module_usb_serial_driver(ssu100_driver, serial_drivers);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/symbolserial.c b/drivers/usb/serial/symbolserial.c
index 50651cf4fc61..1a5be136e6cf 100644
--- a/drivers/usb/serial/symbolserial.c
+++ b/drivers/usb/serial/symbolserial.c
@@ -287,7 +287,6 @@ static struct usb_driver symbol_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
static struct usb_serial_driver symbol_device = {
@@ -296,7 +295,6 @@ static struct usb_serial_driver symbol_device = {
.name = "symbol",
},
.id_table = id_table,
- .usb_driver = &symbol_driver,
.num_ports = 1,
.attach = symbol_startup,
.open = symbol_open,
@@ -307,27 +305,12 @@ static struct usb_serial_driver symbol_device = {
.unthrottle = symbol_unthrottle,
};
-static int __init symbol_init(void)
-{
- int retval;
-
- retval = usb_serial_register(&symbol_device);
- if (retval)
- return retval;
- retval = usb_register(&symbol_driver);
- if (retval)
- usb_serial_deregister(&symbol_device);
- return retval;
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &symbol_device, NULL
+};
-static void __exit symbol_exit(void)
-{
- usb_deregister(&symbol_driver);
- usb_serial_deregister(&symbol_device);
-}
+module_usb_serial_driver(symbol_driver, serial_drivers);
-module_init(symbol_init);
-module_exit(symbol_exit);
MODULE_LICENSE("GPL");
module_param(debug, bool, S_IRUGO | S_IWUSR);
diff --git a/drivers/usb/serial/ti_usb_3410_5052.c b/drivers/usb/serial/ti_usb_3410_5052.c
index 75b838eff178..ab74123d658e 100644
--- a/drivers/usb/serial/ti_usb_3410_5052.c
+++ b/drivers/usb/serial/ti_usb_3410_5052.c
@@ -216,7 +216,6 @@ static struct usb_driver ti_usb_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = ti_id_table_combined,
- .no_dynamic_id = 1,
};
static struct usb_serial_driver ti_1port_device = {
@@ -225,7 +224,6 @@ static struct usb_serial_driver ti_1port_device = {
.name = "ti_usb_3410_5052_1",
},
.description = "TI USB 3410 1 port adapter",
- .usb_driver = &ti_usb_driver,
.id_table = ti_id_table_3410,
.num_ports = 1,
.attach = ti_startup,
@@ -254,7 +252,6 @@ static struct usb_serial_driver ti_2port_device = {
.name = "ti_usb_3410_5052_2",
},
.description = "TI USB 5052 2 port adapter",
- .usb_driver = &ti_usb_driver,
.id_table = ti_id_table_5052,
.num_ports = 2,
.attach = ti_startup,
@@ -277,6 +274,9 @@ static struct usb_serial_driver ti_2port_device = {
.write_bulk_callback = ti_bulk_out_callback,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &ti_1port_device, &ti_2port_device, NULL
+};
/* Module */
@@ -344,36 +344,17 @@ static int __init ti_init(void)
ti_id_table_combined[c].match_flags = USB_DEVICE_ID_MATCH_DEVICE;
}
- ret = usb_serial_register(&ti_1port_device);
- if (ret)
- goto failed_1port;
- ret = usb_serial_register(&ti_2port_device);
- if (ret)
- goto failed_2port;
-
- ret = usb_register(&ti_usb_driver);
- if (ret)
- goto failed_usb;
-
- printk(KERN_INFO KBUILD_MODNAME ": " TI_DRIVER_VERSION ":"
- TI_DRIVER_DESC "\n");
-
- return 0;
-
-failed_usb:
- usb_serial_deregister(&ti_2port_device);
-failed_2port:
- usb_serial_deregister(&ti_1port_device);
-failed_1port:
+ ret = usb_serial_register_drivers(&ti_usb_driver, serial_drivers);
+ if (ret == 0)
+ printk(KERN_INFO KBUILD_MODNAME ": " TI_DRIVER_VERSION ":"
+ TI_DRIVER_DESC "\n");
return ret;
}
static void __exit ti_exit(void)
{
- usb_deregister(&ti_usb_driver);
- usb_serial_deregister(&ti_1port_device);
- usb_serial_deregister(&ti_2port_device);
+ usb_serial_deregister_drivers(&ti_usb_driver, serial_drivers);
}
@@ -1250,7 +1231,6 @@ static void ti_bulk_out_callback(struct urb *urb)
{
struct ti_port *tport = urb->context;
struct usb_serial_port *port = tport->tp_port;
- struct device *dev = &urb->dev->dev;
int status = urb->status;
dbg("%s - port %d", __func__, port->number);
@@ -1268,7 +1248,7 @@ static void ti_bulk_out_callback(struct urb *urb)
wake_up_interruptible(&tport->tp_write_wait);
return;
default:
- dev_err(dev, "%s - nonzero urb status, %d\n",
+ dev_err_console(port, "%s - nonzero urb status, %d\n",
__func__, status);
tport->tp_tdev->td_urb_error = 1;
wake_up_interruptible(&tport->tp_write_wait);
@@ -1337,7 +1317,7 @@ static void ti_send(struct ti_port *tport)
result = usb_submit_urb(port->write_urb, GFP_ATOMIC);
if (result) {
- dev_err(&port->dev, "%s - submit write urb failed, %d\n",
+ dev_err_console(port, "%s - submit write urb failed, %d\n",
__func__, result);
tport->tp_write_urb_in_use = 0;
/* TODO: reschedule ti_send */
diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c
index 611b206591cb..97355a15bbea 100644
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -214,15 +214,14 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
if (!try_module_get(serial->type->driver.owner))
goto error_module_get;
- /* perform the standard setup */
- retval = tty_init_termios(tty);
- if (retval)
- goto error_init_termios;
-
retval = usb_autopm_get_interface(serial->interface);
if (retval)
goto error_get_interface;
+ retval = tty_standard_install(driver, tty);
+ if (retval)
+ goto error_init_termios;
+
mutex_unlock(&serial->disc_mutex);
/* allow the driver to update the settings */
@@ -231,14 +230,11 @@ static int serial_install(struct tty_driver *driver, struct tty_struct *tty)
tty->driver_data = port;
- /* Final install (we use the default method) */
- tty_driver_kref_get(driver);
- tty->count++;
- driver->ttys[idx] = tty;
return retval;
- error_get_interface:
error_init_termios:
+ usb_autopm_put_interface(serial->interface);
+ error_get_interface:
module_put(serial->type->driver.owner);
error_module_get:
error_no_port:
@@ -1063,6 +1059,12 @@ int usb_serial_probe(struct usb_interface *interface,
serial->attached = 1;
}
+ /* Avoid race with tty_open and serial_install by setting the
+ * disconnected flag and not clearing it until all ports have been
+ * registered.
+ */
+ serial->disconnected = 1;
+
if (get_free_serial(serial, num_ports, &minor) == NULL) {
dev_err(&interface->dev, "No more free serial devices\n");
goto probe_error;
@@ -1074,19 +1076,16 @@ int usb_serial_probe(struct usb_interface *interface,
port = serial->port[i];
dev_set_name(&port->dev, "ttyUSB%d", port->number);
dbg ("%s - registering %s", __func__, dev_name(&port->dev));
- port->dev_state = PORT_REGISTERING;
device_enable_async_suspend(&port->dev);
retval = device_add(&port->dev);
- if (retval) {
+ if (retval)
dev_err(&port->dev, "Error registering port device, "
"continuing\n");
- port->dev_state = PORT_UNREGISTERED;
- } else {
- port->dev_state = PORT_REGISTERED;
- }
}
+ serial->disconnected = 0;
+
usb_serial_console_init(debug, minor);
exit:
@@ -1128,22 +1127,8 @@ void usb_serial_disconnect(struct usb_interface *interface)
}
kill_traffic(port);
cancel_work_sync(&port->work);
- if (port->dev_state == PORT_REGISTERED) {
-
- /* Make sure the port is bound so that the
- * driver's port_remove method is called.
- */
- if (!port->dev.driver) {
- int rc;
-
- port->dev.driver =
- &serial->type->driver;
- rc = device_bind_driver(&port->dev);
- }
- port->dev_state = PORT_UNREGISTERING;
+ if (device_is_registered(&port->dev))
device_del(&port->dev);
- port->dev_state = PORT_UNREGISTERED;
- }
}
}
serial->type->disconnect(serial);
@@ -1239,7 +1224,6 @@ static int __init usb_serial_init(void)
goto exit_bus;
}
- usb_serial_tty_driver->owner = THIS_MODULE;
usb_serial_tty_driver->driver_name = "usbserial";
usb_serial_tty_driver->name = "ttyUSB";
usb_serial_tty_driver->major = SERIAL_TTY_MAJOR;
@@ -1338,7 +1322,7 @@ static void fixup_generic(struct usb_serial_driver *device)
set_to_generic_if_null(device, prepare_write_buffer);
}
-int usb_serial_register(struct usb_serial_driver *driver)
+static int usb_serial_register(struct usb_serial_driver *driver)
{
int retval;
@@ -1372,10 +1356,8 @@ int usb_serial_register(struct usb_serial_driver *driver)
mutex_unlock(&table_lock);
return retval;
}
-EXPORT_SYMBOL_GPL(usb_serial_register);
-
-void usb_serial_deregister(struct usb_serial_driver *device)
+static void usb_serial_deregister(struct usb_serial_driver *device)
{
printk(KERN_INFO "USB Serial deregistering driver %s\n",
device->description);
@@ -1384,7 +1366,76 @@ void usb_serial_deregister(struct usb_serial_driver *device)
usb_serial_bus_deregister(device);
mutex_unlock(&table_lock);
}
-EXPORT_SYMBOL_GPL(usb_serial_deregister);
+
+/**
+ * usb_serial_register_drivers - register drivers for a usb-serial module
+ * @udriver: usb_driver used for matching devices/interfaces
+ * @serial_drivers: NULL-terminated array of pointers to drivers to be registered
+ *
+ * Registers @udriver and all the drivers in the @serial_drivers array.
+ * Automatically fills in the .no_dynamic_id field in @udriver and
+ * the .usb_driver field in each serial driver.
+ */
+int usb_serial_register_drivers(struct usb_driver *udriver,
+ struct usb_serial_driver * const serial_drivers[])
+{
+ int rc;
+ const struct usb_device_id *saved_id_table;
+ struct usb_serial_driver * const *sd;
+
+ /*
+ * udriver must be registered before any of the serial drivers,
+ * because the store_new_id() routine for the serial drivers (in
+ * bus.c) probes udriver.
+ *
+ * Performance hack: We don't want udriver to be probed until
+ * the serial drivers are registered, because the probe would
+ * simply fail for lack of a matching serial driver.
+ * Therefore save off udriver's id_table until we are all set.
+ */
+ saved_id_table = udriver->id_table;
+ udriver->id_table = NULL;
+
+ udriver->no_dynamic_id = 1;
+ rc = usb_register(udriver);
+ if (rc)
+ return rc;
+
+ for (sd = serial_drivers; *sd; ++sd) {
+ (*sd)->usb_driver = udriver;
+ rc = usb_serial_register(*sd);
+ if (rc)
+ goto failed;
+ }
+
+ /* Now restore udriver's id_table and look for matches */
+ udriver->id_table = saved_id_table;
+ rc = driver_attach(&udriver->drvwrap.driver);
+ return 0;
+
+ failed:
+ while (sd-- > serial_drivers)
+ usb_serial_deregister(*sd);
+ usb_deregister(udriver);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(usb_serial_register_drivers);
+
+/**
+ * usb_serial_deregister_drivers - deregister drivers for a usb-serial module
+ * @udriver: usb_driver to unregister
+ * @serial_drivers: NULL-terminated array of pointers to drivers to be deregistered
+ *
+ * Deregisters @udriver and all the drivers in the @serial_drivers array.
+ */
+void usb_serial_deregister_drivers(struct usb_driver *udriver,
+ struct usb_serial_driver * const serial_drivers[])
+{
+ for (; *serial_drivers; ++serial_drivers)
+ usb_serial_deregister(*serial_drivers);
+ usb_deregister(udriver);
+}
+EXPORT_SYMBOL_GPL(usb_serial_deregister_drivers);
/* Module information */
MODULE_AUTHOR(DRIVER_AUTHOR);
diff --git a/drivers/usb/serial/usb_debug.c b/drivers/usb/serial/usb_debug.c
index 9b632e753210..e3e8995a4739 100644
--- a/drivers/usb/serial/usb_debug.c
+++ b/drivers/usb/serial/usb_debug.c
@@ -40,7 +40,6 @@ static struct usb_driver debug_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
/* This HW really does not support a serial break, so one will be
@@ -74,32 +73,15 @@ static struct usb_serial_driver debug_device = {
.name = "debug",
},
.id_table = id_table,
- .usb_driver = &debug_driver,
.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,
};
-static int __init debug_init(void)
-{
- int retval;
-
- retval = usb_serial_register(&debug_device);
- if (retval)
- return retval;
- retval = usb_register(&debug_driver);
- if (retval)
- usb_serial_deregister(&debug_device);
- return retval;
-}
-
-static void __exit debug_exit(void)
-{
- usb_deregister(&debug_driver);
- usb_serial_deregister(&debug_device);
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &debug_device, NULL
+};
-module_init(debug_init);
-module_exit(debug_exit);
+module_usb_serial_driver(debug_driver, serial_drivers);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/serial/visor.c b/drivers/usb/serial/visor.c
index 210e4b10dc11..71d696474f24 100644
--- a/drivers/usb/serial/visor.c
+++ b/drivers/usb/serial/visor.c
@@ -173,7 +173,6 @@ static struct usb_driver visor_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table_combined,
- .no_dynamic_id = 1,
};
/* All of the device info needed for the Handspring Visor,
@@ -184,7 +183,6 @@ static struct usb_serial_driver handspring_device = {
.name = "visor",
},
.description = "Handspring Visor / Palm OS",
- .usb_driver = &visor_driver,
.id_table = id_table,
.num_ports = 2,
.bulk_out_size = 256,
@@ -205,7 +203,6 @@ static struct usb_serial_driver clie_5_device = {
.name = "clie_5",
},
.description = "Sony Clie 5.0",
- .usb_driver = &visor_driver,
.id_table = clie_id_5_table,
.num_ports = 2,
.bulk_out_size = 256,
@@ -226,7 +223,6 @@ static struct usb_serial_driver clie_3_5_device = {
.name = "clie_3.5",
},
.description = "Sony Clie 3.5",
- .usb_driver = &visor_driver,
.id_table = clie_id_3_5_table,
.num_ports = 1,
.bulk_out_size = 256,
@@ -237,6 +233,10 @@ static struct usb_serial_driver clie_3_5_device = {
.attach = clie_3_5_startup,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &handspring_device, &clie_5_device, &clie_3_5_device, NULL
+};
+
/******************************************************************************
* Handspring Visor specific driver functions
******************************************************************************/
@@ -685,38 +685,17 @@ static int __init visor_init(void)
": Adding Palm OS protocol 4.x support for unknown device: 0x%x/0x%x\n",
vendor, product);
}
- retval = usb_serial_register(&handspring_device);
- if (retval)
- goto failed_handspring_register;
- retval = usb_serial_register(&clie_3_5_device);
- if (retval)
- goto failed_clie_3_5_register;
- retval = usb_serial_register(&clie_5_device);
- if (retval)
- goto failed_clie_5_register;
- retval = usb_register(&visor_driver);
- if (retval)
- goto failed_usb_register;
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
- return 0;
-failed_usb_register:
- usb_serial_deregister(&clie_5_device);
-failed_clie_5_register:
- usb_serial_deregister(&clie_3_5_device);
-failed_clie_3_5_register:
- usb_serial_deregister(&handspring_device);
-failed_handspring_register:
+ retval = usb_serial_register_drivers(&visor_driver, serial_drivers);
+ if (retval == 0)
+ printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_DESC "\n");
return retval;
}
static void __exit visor_exit (void)
{
- usb_deregister(&visor_driver);
- usb_serial_deregister(&handspring_device);
- usb_serial_deregister(&clie_3_5_device);
- usb_serial_deregister(&clie_5_device);
+ usb_serial_deregister_drivers(&visor_driver, serial_drivers);
}
diff --git a/drivers/usb/serial/vivopay-serial.c b/drivers/usb/serial/vivopay-serial.c
index f719d00972fc..078f338b5feb 100644
--- a/drivers/usb/serial/vivopay-serial.c
+++ b/drivers/usb/serial/vivopay-serial.c
@@ -30,7 +30,6 @@ static struct usb_driver vivopay_serial_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
static struct usb_serial_driver vivopay_serial_device = {
@@ -39,36 +38,14 @@ static struct usb_serial_driver vivopay_serial_device = {
.name = "vivopay-serial",
},
.id_table = id_table,
- .usb_driver = &vivopay_serial_driver,
.num_ports = 1,
};
-static int __init vivopay_serial_init(void)
-{
- int retval;
- retval = usb_serial_register(&vivopay_serial_device);
- if (retval)
- goto failed_usb_serial_register;
- retval = usb_register(&vivopay_serial_driver);
- if (retval)
- goto failed_usb_register;
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return 0;
-failed_usb_register:
- usb_serial_deregister(&vivopay_serial_device);
-failed_usb_serial_register:
- return retval;
-}
-
-static void __exit vivopay_serial_exit(void)
-{
- usb_deregister(&vivopay_serial_driver);
- usb_serial_deregister(&vivopay_serial_device);
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &vivopay_serial_device, NULL
+};
-module_init(vivopay_serial_init);
-module_exit(vivopay_serial_exit);
+module_usb_serial_driver(vivopay_serial_driver, serial_drivers);
MODULE_AUTHOR("Forest Bond <forest.bond@outpostembedded.com>");
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/whiteheat.c b/drivers/usb/serial/whiteheat.c
index 7e0acf5c8e38..407e23c87946 100644
--- a/drivers/usb/serial/whiteheat.c
+++ b/drivers/usb/serial/whiteheat.c
@@ -83,7 +83,6 @@ static struct usb_driver whiteheat_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table_combined,
- .no_dynamic_id = 1,
};
/* function prototypes for the Connect Tech WhiteHEAT prerenumeration device */
@@ -121,7 +120,6 @@ static struct usb_serial_driver whiteheat_fake_device = {
.name = "whiteheatnofirm",
},
.description = "Connect Tech - WhiteHEAT - (prerenumeration)",
- .usb_driver = &whiteheat_driver,
.id_table = id_table_prerenumeration,
.num_ports = 1,
.probe = whiteheat_firmware_download,
@@ -134,7 +132,6 @@ static struct usb_serial_driver whiteheat_device = {
.name = "whiteheat",
},
.description = "Connect Tech - WhiteHEAT",
- .usb_driver = &whiteheat_driver,
.id_table = id_table_std,
.num_ports = 4,
.attach = whiteheat_attach,
@@ -155,6 +152,9 @@ static struct usb_serial_driver whiteheat_device = {
.write_bulk_callback = whiteheat_write_callback,
};
+static struct usb_serial_driver * const serial_drivers[] = {
+ &whiteheat_fake_device, &whiteheat_device, NULL
+};
struct whiteheat_command_private {
struct mutex mutex;
@@ -740,7 +740,7 @@ static int whiteheat_write(struct tty_struct *tty,
urb->transfer_buffer_length = bytes;
result = usb_submit_urb(urb, GFP_ATOMIC);
if (result) {
- dev_err(&port->dev,
+ dev_err_console(port,
"%s - failed submitting write urb, error %d\n",
__func__, result);
sent = result;
@@ -1454,44 +1454,7 @@ out:
tty_kref_put(tty);
}
-
-/*****************************************************************************
- * Connect Tech's White Heat module functions
- *****************************************************************************/
-static int __init whiteheat_init(void)
-{
- int retval;
- retval = usb_serial_register(&whiteheat_fake_device);
- if (retval)
- goto failed_fake_register;
- retval = usb_serial_register(&whiteheat_device);
- if (retval)
- goto failed_device_register;
- retval = usb_register(&whiteheat_driver);
- if (retval)
- goto failed_usb_register;
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return 0;
-failed_usb_register:
- usb_serial_deregister(&whiteheat_device);
-failed_device_register:
- usb_serial_deregister(&whiteheat_fake_device);
-failed_fake_register:
- return retval;
-}
-
-
-static void __exit whiteheat_exit(void)
-{
- usb_deregister(&whiteheat_driver);
- usb_serial_deregister(&whiteheat_fake_device);
- usb_serial_deregister(&whiteheat_device);
-}
-
-
-module_init(whiteheat_init);
-module_exit(whiteheat_exit);
+module_usb_serial_driver(whiteheat_driver, serial_drivers);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/usb/serial/zio.c b/drivers/usb/serial/zio.c
index f57967278833..9d0bb3752cd4 100644
--- a/drivers/usb/serial/zio.c
+++ b/drivers/usb/serial/zio.c
@@ -27,7 +27,6 @@ static struct usb_driver zio_driver = {
.probe = usb_serial_probe,
.disconnect = usb_serial_disconnect,
.id_table = id_table,
- .no_dynamic_id = 1,
};
static struct usb_serial_driver zio_device = {
@@ -36,29 +35,12 @@ static struct usb_serial_driver zio_device = {
.name = "zio",
},
.id_table = id_table,
- .usb_driver = &zio_driver,
.num_ports = 1,
};
-static int __init zio_init(void)
-{
- int retval;
-
- retval = usb_serial_register(&zio_device);
- if (retval)
- return retval;
- retval = usb_register(&zio_driver);
- if (retval)
- usb_serial_deregister(&zio_device);
- return retval;
-}
-
-static void __exit zio_exit(void)
-{
- usb_deregister(&zio_driver);
- usb_serial_deregister(&zio_device);
-}
+static struct usb_serial_driver * const serial_drivers[] = {
+ &zio_device, NULL
+};
-module_init(zio_init);
-module_exit(zio_exit);
+module_usb_serial_driver(zio_driver, serial_drivers);
MODULE_LICENSE("GPL");
diff --git a/drivers/usb/storage/Kconfig b/drivers/usb/storage/Kconfig
index fe2d803a6347..7691c866637b 100644
--- a/drivers/usb/storage/Kconfig
+++ b/drivers/usb/storage/Kconfig
@@ -222,7 +222,7 @@ config USB_LIBUSUAL
for usb-storage and ub drivers, and allows to switch binding
of these devices without rebuilding modules.
- Typical syntax of /etc/modprobe.conf is:
+ Typical syntax of /etc/modprobe.d/*conf is:
options libusual bias="ub"
diff --git a/drivers/usb/storage/alauda.c b/drivers/usb/storage/alauda.c
index 51af2fee2efd..bab8c8fe8290 100644
--- a/drivers/usb/storage/alauda.c
+++ b/drivers/usb/storage/alauda.c
@@ -1276,6 +1276,7 @@ static struct usb_driver alauda_driver = {
.post_reset = usb_stor_post_reset,
.id_table = alauda_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(alauda_driver);
diff --git a/drivers/usb/storage/cypress_atacb.c b/drivers/usb/storage/cypress_atacb.c
index 387cbd47acc9..5fe451d16e68 100644
--- a/drivers/usb/storage/cypress_atacb.c
+++ b/drivers/usb/storage/cypress_atacb.c
@@ -272,6 +272,7 @@ static struct usb_driver cypress_driver = {
.post_reset = usb_stor_post_reset,
.id_table = cypress_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(cypress_driver);
diff --git a/drivers/usb/storage/datafab.c b/drivers/usb/storage/datafab.c
index 15d41f2b3d6f..35e9c51e6696 100644
--- a/drivers/usb/storage/datafab.c
+++ b/drivers/usb/storage/datafab.c
@@ -751,6 +751,7 @@ static struct usb_driver datafab_driver = {
.post_reset = usb_stor_post_reset,
.id_table = datafab_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(datafab_driver);
diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c
index a6ade4071a9a..e7e678109500 100644
--- a/drivers/usb/storage/ene_ub6250.c
+++ b/drivers/usb/storage/ene_ub6250.c
@@ -674,7 +674,7 @@ static int sd_scsi_read(struct us_data *us, struct scsi_cmnd *srb)
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = blenByte;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF1;
bcb->CDB[5] = (unsigned char)(bnByte);
bcb->CDB[4] = (unsigned char)(bnByte>>8);
@@ -858,7 +858,7 @@ static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr,
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x02; /* in init.c ENE_MSInit() is 0x01 */
@@ -877,7 +877,7 @@ static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr,
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x4;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x03;
@@ -1170,7 +1170,7 @@ static int ms_read_eraseblock(struct us_data *us, u32 PhyBlockAddr)
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF2;
bcb->CDB[1] = 0x06;
bcb->CDB[4] = (unsigned char)(bn);
@@ -1249,7 +1249,7 @@ static int ms_lib_overwrite_extra(struct us_data *us, u32 PhyBlockAddr,
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x4;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF2;
bcb->CDB[1] = 0x05;
bcb->CDB[5] = (unsigned char)(PageNum);
@@ -1331,7 +1331,7 @@ static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock,
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x4;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x03;
bcb->CDB[5] = (unsigned char)(PageNum);
@@ -1533,7 +1533,7 @@ static int ms_lib_read_extrablock(struct us_data *us, u32 PhyBlock,
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x4 * blen;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x03;
bcb->CDB[5] = (unsigned char)(PageNum);
@@ -1650,7 +1650,7 @@ static int ms_scsi_read(struct us_data *us, struct scsi_cmnd *srb)
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = blenByte;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x02;
bcb->CDB[5] = (unsigned char)(bn);
@@ -1694,7 +1694,7 @@ static int ms_scsi_read(struct us_data *us, struct scsi_cmnd *srb)
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200 * len;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x02;
bcb->CDB[5] = (unsigned char)(blkno);
@@ -1827,7 +1827,7 @@ static int ene_get_card_type(struct us_data *us, u16 index, void *buf)
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x01;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xED;
bcb->CDB[2] = (unsigned char)(index>>8);
bcb->CDB[3] = (unsigned char)index;
@@ -2083,7 +2083,7 @@ static int ene_ms_init(struct us_data *us)
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x01;
@@ -2134,7 +2134,7 @@ static int ene_sd_init(struct us_data *us)
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF2;
result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0);
@@ -2153,7 +2153,7 @@ static int ene_sd_init(struct us_data *us)
memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = 0x200;
- bcb->Flags = 0x80;
+ bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF1;
result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0);
@@ -2407,6 +2407,7 @@ static struct usb_driver ene_ub6250_driver = {
.post_reset = usb_stor_post_reset,
.id_table = ene_ub6250_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(ene_ub6250_driver);
diff --git a/drivers/usb/storage/freecom.c b/drivers/usb/storage/freecom.c
index fa1615748475..042cf9ef3153 100644
--- a/drivers/usb/storage/freecom.c
+++ b/drivers/usb/storage/freecom.c
@@ -553,6 +553,7 @@ static struct usb_driver freecom_driver = {
.post_reset = usb_stor_post_reset,
.id_table = freecom_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(freecom_driver);
diff --git a/drivers/usb/storage/isd200.c b/drivers/usb/storage/isd200.c
index bd5502700831..31fa24e7e68a 100644
--- a/drivers/usb/storage/isd200.c
+++ b/drivers/usb/storage/isd200.c
@@ -1566,6 +1566,7 @@ static struct usb_driver isd200_driver = {
.post_reset = usb_stor_post_reset,
.id_table = isd200_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(isd200_driver);
diff --git a/drivers/usb/storage/jumpshot.c b/drivers/usb/storage/jumpshot.c
index a19211b5c265..e3b97383186a 100644
--- a/drivers/usb/storage/jumpshot.c
+++ b/drivers/usb/storage/jumpshot.c
@@ -677,6 +677,7 @@ static struct usb_driver jumpshot_driver = {
.post_reset = usb_stor_post_reset,
.id_table = jumpshot_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(jumpshot_driver);
diff --git a/drivers/usb/storage/karma.c b/drivers/usb/storage/karma.c
index e720f8ebdf9f..a8708eae9788 100644
--- a/drivers/usb/storage/karma.c
+++ b/drivers/usb/storage/karma.c
@@ -230,6 +230,7 @@ static struct usb_driver karma_driver = {
.post_reset = usb_stor_post_reset,
.id_table = karma_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(karma_driver);
diff --git a/drivers/usb/storage/onetouch.c b/drivers/usb/storage/onetouch.c
index d75155c38200..886567a3806d 100644
--- a/drivers/usb/storage/onetouch.c
+++ b/drivers/usb/storage/onetouch.c
@@ -312,6 +312,7 @@ static struct usb_driver onetouch_driver = {
.post_reset = usb_stor_post_reset,
.id_table = onetouch_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(onetouch_driver);
diff --git a/drivers/usb/storage/realtek_cr.c b/drivers/usb/storage/realtek_cr.c
index d32f72061c09..63cf2822e299 100644
--- a/drivers/usb/storage/realtek_cr.c
+++ b/drivers/usb/storage/realtek_cr.c
@@ -219,7 +219,7 @@ static int rts51x_bulk_transport(struct us_data *us, u8 lun,
/* set up the command wrapper */
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = cpu_to_le32(buf_len);
- bcb->Flags = (dir == DMA_FROM_DEVICE) ? 1 << 7 : 0;
+ bcb->Flags = (dir == DMA_FROM_DEVICE) ? US_BULK_FLAG_IN : 0;
bcb->Tag = ++us->tag;
bcb->Lun = lun;
bcb->Length = cmd_len;
@@ -305,7 +305,7 @@ static int rts51x_bulk_transport_special(struct us_data *us, u8 lun,
/* set up the command wrapper */
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = cpu_to_le32(buf_len);
- bcb->Flags = (dir == DMA_FROM_DEVICE) ? 1 << 7 : 0;
+ bcb->Flags = (dir == DMA_FROM_DEVICE) ? US_BULK_FLAG_IN : 0;
bcb->Tag = ++us->tag;
bcb->Lun = lun;
bcb->Length = cmd_len;
@@ -507,9 +507,14 @@ static int __do_config_autodelink(struct us_data *us, u8 *data, u16 len)
{
int retval;
u8 cmnd[12] = {0};
+ u8 *buf;
US_DEBUGP("%s, addr = 0xfe47, len = %d\n", __FUNCTION__, len);
+ buf = kmemdup(data, len, GFP_NOIO);
+ if (!buf)
+ return USB_STOR_TRANSPORT_ERROR;
+
cmnd[0] = 0xF0;
cmnd[1] = 0x0E;
cmnd[2] = 0xfe;
@@ -517,7 +522,8 @@ static int __do_config_autodelink(struct us_data *us, u8 *data, u16 len)
cmnd[4] = (u8)(len >> 8);
cmnd[5] = (u8)len;
- retval = rts51x_bulk_transport_special(us, 0, cmnd, 12, data, len, DMA_TO_DEVICE, NULL);
+ retval = rts51x_bulk_transport_special(us, 0, cmnd, 12, buf, len, DMA_TO_DEVICE, NULL);
+ kfree(buf);
if (retval != USB_STOR_TRANSPORT_GOOD) {
return -EIO;
}
@@ -1100,6 +1106,7 @@ static struct usb_driver realtek_cr_driver = {
.id_table = realtek_cr_ids,
.soft_unbind = 1,
.supports_autosuspend = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(realtek_cr_driver);
diff --git a/drivers/usb/storage/scsiglue.c b/drivers/usb/storage/scsiglue.c
index 13b8bcdf3dba..a324a5d21e99 100644
--- a/drivers/usb/storage/scsiglue.c
+++ b/drivers/usb/storage/scsiglue.c
@@ -78,8 +78,6 @@ static const char* host_info(struct Scsi_Host *host)
static int slave_alloc (struct scsi_device *sdev)
{
- struct us_data *us = host_to_us(sdev->host);
-
/*
* Set the INQUIRY transfer length to 36. We don't use any of
* the extra data and many devices choke if asked for more or
@@ -104,18 +102,6 @@ static int slave_alloc (struct scsi_device *sdev)
*/
blk_queue_update_dma_alignment(sdev->request_queue, (512 - 1));
- /*
- * The UFI spec treates the Peripheral Qualifier bits in an
- * INQUIRY result as reserved and requires devices to set them
- * to 0. However the SCSI spec requires these bits to be set
- * to 3 to indicate when a LUN is not present.
- *
- * Let the scanning code know if this target merely sets
- * Peripheral Device Type to 0x1f to indicate no LUN.
- */
- if (us->subclass == USB_SC_UFI)
- sdev->sdev_target->pdt_1f_for_no_lun = 1;
-
return 0;
}
@@ -197,6 +183,9 @@ static int slave_configure(struct scsi_device *sdev)
* page x08, so we will skip it. */
sdev->skip_ms_page_8 = 1;
+ /* Some devices don't handle VPD pages correctly */
+ sdev->skip_vpd_pages = 1;
+
/* Some disks return the total number of blocks in response
* to READ CAPACITY rather than the highest block number.
* If this device makes that mistake, tell the sd driver. */
@@ -217,16 +206,6 @@ static int slave_configure(struct scsi_device *sdev)
if (sdev->scsi_level > SCSI_SPC_2)
us->fflags |= US_FL_SANE_SENSE;
- /* Some devices report a SCSI revision level above 2 but are
- * unable to handle the REPORT LUNS command (for which
- * support is mandatory at level 3). Since we already have
- * a Get-Max-LUN request, we won't lose much by setting the
- * revision level down to 2. The only devices that would be
- * affected are those with sparse LUNs. */
- if (sdev->scsi_level > SCSI_2)
- sdev->sdev_target->scsi_level =
- sdev->scsi_level = SCSI_2;
-
/* USB-IDE bridges tend to report SK = 0x04 (Non-recoverable
* Hardware Error) when any low-level error occurs,
* recoverable or not. Setting this flag tells the SCSI
@@ -283,6 +262,33 @@ static int slave_configure(struct scsi_device *sdev)
return 0;
}
+static int target_alloc(struct scsi_target *starget)
+{
+ struct us_data *us = host_to_us(dev_to_shost(starget->dev.parent));
+
+ /*
+ * Some USB drives don't support REPORT LUNS, even though they
+ * report a SCSI revision level above 2. Tell the SCSI layer
+ * not to issue that command; it will perform a normal sequential
+ * scan instead.
+ */
+ starget->no_report_luns = 1;
+
+ /*
+ * The UFI spec treats the Peripheral Qualifier bits in an
+ * INQUIRY result as reserved and requires devices to set them
+ * to 0. However the SCSI spec requires these bits to be set
+ * to 3 to indicate when a LUN is not present.
+ *
+ * Let the scanning code know if this target merely sets
+ * Peripheral Device Type to 0x1f to indicate no LUN.
+ */
+ if (us->subclass == USB_SC_UFI)
+ starget->pdt_1f_for_no_lun = 1;
+
+ return 0;
+}
+
/* queue a command */
/* This is always called with scsi_lock(host) held */
static int queuecommand_lck(struct scsi_cmnd *srb,
@@ -546,6 +552,7 @@ struct scsi_host_template usb_stor_host_template = {
.slave_alloc = slave_alloc,
.slave_configure = slave_configure,
+ .target_alloc = target_alloc,
/* lots of sg segments can be handled */
.sg_tablesize = SCSI_MAX_SG_CHAIN_SEGMENTS,
diff --git a/drivers/usb/storage/sddr09.c b/drivers/usb/storage/sddr09.c
index 425df7df2e56..3252a62b31bc 100644
--- a/drivers/usb/storage/sddr09.c
+++ b/drivers/usb/storage/sddr09.c
@@ -1787,6 +1787,7 @@ static struct usb_driver sddr09_driver = {
.post_reset = usb_stor_post_reset,
.id_table = sddr09_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(sddr09_driver);
diff --git a/drivers/usb/storage/sddr55.c b/drivers/usb/storage/sddr55.c
index e4ca5fcb7cc3..c144078065a7 100644
--- a/drivers/usb/storage/sddr55.c
+++ b/drivers/usb/storage/sddr55.c
@@ -1006,6 +1006,7 @@ static struct usb_driver sddr55_driver = {
.post_reset = usb_stor_post_reset,
.id_table = sddr55_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(sddr55_driver);
diff --git a/drivers/usb/storage/shuttle_usbat.c b/drivers/usb/storage/shuttle_usbat.c
index 1369d2590616..fa1ceebc465c 100644
--- a/drivers/usb/storage/shuttle_usbat.c
+++ b/drivers/usb/storage/shuttle_usbat.c
@@ -1863,6 +1863,7 @@ static struct usb_driver usbat_driver = {
.post_reset = usb_stor_post_reset,
.id_table = usbat_usb_ids,
.soft_unbind = 1,
+ .no_dynamic_id = 1,
};
module_usb_driver(usbat_driver);
diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c
index 0e5c91c6187f..c70109e5d60b 100644
--- a/drivers/usb/storage/transport.c
+++ b/drivers/usb/storage/transport.c
@@ -1071,7 +1071,8 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us)
/* set up the command wrapper */
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
bcb->DataTransferLength = cpu_to_le32(transfer_length);
- bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ? 1 << 7 : 0;
+ bcb->Flags = srb->sc_data_direction == DMA_FROM_DEVICE ?
+ US_BULK_FLAG_IN : 0;
bcb->Tag = ++us->tag;
bcb->Lun = srb->device->lun;
if (us->fflags & US_FL_SCM_MULT_TARG)
diff --git a/drivers/usb/storage/transport.h b/drivers/usb/storage/transport.h
index 242ff5e791a5..9369d752d419 100644
--- a/drivers/usb/storage/transport.h
+++ b/drivers/usb/storage/transport.h
@@ -42,45 +42,6 @@
#include <linux/blkdev.h>
/*
- * Bulk only data structures
- */
-
-/* command block wrapper */
-struct bulk_cb_wrap {
- __le32 Signature; /* contains 'USBC' */
- __u32 Tag; /* unique per command id */
- __le32 DataTransferLength; /* size of data */
- __u8 Flags; /* direction in bit 0 */
- __u8 Lun; /* LUN normally 0 */
- __u8 Length; /* of of the CDB */
- __u8 CDB[16]; /* max command */
-};
-
-#define US_BULK_CB_WRAP_LEN 31
-#define US_BULK_CB_SIGN 0x43425355 /*spells out USBC */
-#define US_BULK_FLAG_IN 1
-#define US_BULK_FLAG_OUT 0
-
-/* command status wrapper */
-struct bulk_cs_wrap {
- __le32 Signature; /* should = 'USBS' */
- __u32 Tag; /* same as original command */
- __le32 Residue; /* amount not transferred */
- __u8 Status; /* see below */
- __u8 Filler[18];
-};
-
-#define US_BULK_CS_WRAP_LEN 13
-#define US_BULK_CS_SIGN 0x53425355 /* spells out 'USBS' */
-#define US_BULK_STAT_OK 0
-#define US_BULK_STAT_FAIL 1
-#define US_BULK_STAT_PHASE 2
-
-/* bulk-only class specific requests */
-#define US_BULK_RESET_REQUEST 0xff
-#define US_BULK_GET_MAX_LUN 0xfe
-
-/*
* usb_stor_bulk_transfer_xxx() return codes, in order of severity
*/
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index a33ead5dce20..8ec8a6e66f50 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -13,7 +13,9 @@
#include <linux/types.h>
#include <linux/module.h>
#include <linux/usb.h>
+#include <linux/usb/hcd.h>
#include <linux/usb/storage.h>
+#include <linux/usb/uas.h>
#include <scsi/scsi.h>
#include <scsi/scsi_dbg.h>
@@ -22,49 +24,6 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_tcq.h>
-/* Common header for all IUs */
-struct iu {
- __u8 iu_id;
- __u8 rsvd1;
- __be16 tag;
-};
-
-enum {
- IU_ID_COMMAND = 0x01,
- IU_ID_STATUS = 0x03,
- IU_ID_RESPONSE = 0x04,
- IU_ID_TASK_MGMT = 0x05,
- IU_ID_READ_READY = 0x06,
- IU_ID_WRITE_READY = 0x07,
-};
-
-struct command_iu {
- __u8 iu_id;
- __u8 rsvd1;
- __be16 tag;
- __u8 prio_attr;
- __u8 rsvd5;
- __u8 len;
- __u8 rsvd7;
- struct scsi_lun lun;
- __u8 cdb[16]; /* XXX: Overflow-checking tools may misunderstand */
-};
-
-/*
- * Also used for the Read Ready and Write Ready IUs since they have the
- * same first four bytes
- */
-struct sense_iu {
- __u8 iu_id;
- __u8 rsvd1;
- __be16 tag;
- __be16 status_qual;
- __u8 status;
- __u8 rsvd7[7];
- __be16 len;
- __u8 sense[SCSI_SENSE_BUFFERSIZE];
-};
-
/*
* The r00-r01c specs define this version of the SENSE IU data structure.
* It's still in use by several different firmware releases.
@@ -79,18 +38,6 @@ struct sense_iu_old {
__u8 sense[SCSI_SENSE_BUFFERSIZE];
};
-enum {
- CMD_PIPE_ID = 1,
- STATUS_PIPE_ID = 2,
- DATA_IN_PIPE_ID = 3,
- DATA_OUT_PIPE_ID = 4,
-
- UAS_SIMPLE_TAG = 0,
- UAS_HEAD_TAG = 1,
- UAS_ORDERED_TAG = 2,
- UAS_ACA = 4,
-};
-
struct uas_dev_info {
struct usb_interface *intf;
struct usb_device *udev;
@@ -98,6 +45,8 @@ struct uas_dev_info {
unsigned cmd_pipe, status_pipe, data_in_pipe, data_out_pipe;
unsigned use_streams:1;
unsigned uas_sense_old:1;
+ struct scsi_cmnd *cmnd;
+ struct urb *status_urb; /* used only if stream support is available */
};
enum {
@@ -109,6 +58,9 @@ enum {
SUBMIT_DATA_OUT_URB = (1 << 5),
ALLOC_CMD_URB = (1 << 6),
SUBMIT_CMD_URB = (1 << 7),
+ COMPLETED_DATA_IN = (1 << 8),
+ COMPLETED_DATA_OUT = (1 << 9),
+ DATA_COMPLETES_CMD = (1 << 10),
};
/* Overrides scsi_pointer */
@@ -116,6 +68,7 @@ struct uas_cmd_info {
unsigned int state;
unsigned int stream;
struct urb *cmd_urb;
+ /* status_urb is used only if stream support isn't available */
struct urb *status_urb;
struct urb *data_in_urb;
struct urb *data_out_urb;
@@ -125,33 +78,43 @@ struct uas_cmd_info {
/* I hate forward declarations, but I actually have a loop */
static int uas_submit_urbs(struct scsi_cmnd *cmnd,
struct uas_dev_info *devinfo, gfp_t gfp);
+static void uas_do_work(struct work_struct *work);
+static DECLARE_WORK(uas_work, uas_do_work);
static DEFINE_SPINLOCK(uas_work_lock);
static LIST_HEAD(uas_work_list);
static void uas_do_work(struct work_struct *work)
{
struct uas_cmd_info *cmdinfo;
+ struct uas_cmd_info *temp;
struct list_head list;
+ int err;
spin_lock_irq(&uas_work_lock);
list_replace_init(&uas_work_list, &list);
spin_unlock_irq(&uas_work_lock);
- list_for_each_entry(cmdinfo, &list, list) {
+ list_for_each_entry_safe(cmdinfo, temp, &list, list) {
struct scsi_pointer *scp = (void *)cmdinfo;
struct scsi_cmnd *cmnd = container_of(scp,
struct scsi_cmnd, SCp);
- uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
+ err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_NOIO);
+ if (err) {
+ list_del(&cmdinfo->list);
+ spin_lock_irq(&uas_work_lock);
+ list_add_tail(&cmdinfo->list, &uas_work_list);
+ spin_unlock_irq(&uas_work_lock);
+ schedule_work(&uas_work);
+ }
}
}
-static DECLARE_WORK(uas_work, uas_do_work);
-
static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
{
struct sense_iu *sense_iu = urb->transfer_buffer;
struct scsi_device *sdev = cmnd->device;
+ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
if (urb->actual_length > 16) {
unsigned len = be16_to_cpup(&sense_iu->len);
@@ -169,16 +132,15 @@ static void uas_sense(struct urb *urb, struct scsi_cmnd *cmnd)
}
cmnd->result = sense_iu->status;
- if (sdev->current_cmnd)
- sdev->current_cmnd = NULL;
- cmnd->scsi_done(cmnd);
- usb_free_urb(urb);
+ if (!(cmdinfo->state & DATA_COMPLETES_CMD))
+ cmnd->scsi_done(cmnd);
}
static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
{
struct sense_iu_old *sense_iu = urb->transfer_buffer;
struct scsi_device *sdev = cmnd->device;
+ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
if (urb->actual_length > 8) {
unsigned len = be16_to_cpup(&sense_iu->len) - 2;
@@ -196,10 +158,8 @@ static void uas_sense_old(struct urb *urb, struct scsi_cmnd *cmnd)
}
cmnd->result = sense_iu->status;
- if (sdev->current_cmnd)
- sdev->current_cmnd = NULL;
- cmnd->scsi_done(cmnd);
- usb_free_urb(urb);
+ if (!(cmdinfo->state & DATA_COMPLETES_CMD))
+ cmnd->scsi_done(cmnd);
}
static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
@@ -208,7 +168,7 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
int err;
- cmdinfo->state = direction | SUBMIT_STATUS_URB;
+ cmdinfo->state = direction;
err = uas_submit_urbs(cmnd, cmnd->device->hostdata, GFP_ATOMIC);
if (err) {
spin_lock(&uas_work_lock);
@@ -221,27 +181,61 @@ static void uas_xfer_data(struct urb *urb, struct scsi_cmnd *cmnd,
static void uas_stat_cmplt(struct urb *urb)
{
struct iu *iu = urb->transfer_buffer;
- struct scsi_device *sdev = urb->context;
- struct uas_dev_info *devinfo = sdev->hostdata;
+ struct Scsi_Host *shost = urb->context;
+ struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
struct scsi_cmnd *cmnd;
+ struct uas_cmd_info *cmdinfo;
u16 tag;
+ int ret;
if (urb->status) {
dev_err(&urb->dev->dev, "URB BAD STATUS %d\n", urb->status);
- usb_free_urb(urb);
+ if (devinfo->use_streams)
+ usb_free_urb(urb);
return;
}
tag = be16_to_cpup(&iu->tag) - 1;
- if (sdev->current_cmnd)
- cmnd = sdev->current_cmnd;
+ if (tag == 0)
+ cmnd = devinfo->cmnd;
else
- cmnd = scsi_find_tag(sdev, tag);
- if (!cmnd)
+ cmnd = scsi_host_find_tag(shost, tag - 1);
+ if (!cmnd) {
+ if (devinfo->use_streams) {
+ usb_free_urb(urb);
+ return;
+ }
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret)
+ dev_err(&urb->dev->dev, "failed submit status urb\n");
return;
+ }
+ cmdinfo = (void *)&cmnd->SCp;
switch (iu->iu_id) {
case IU_ID_STATUS:
+ if (devinfo->cmnd == cmnd)
+ devinfo->cmnd = NULL;
+
+ if (!(cmdinfo->state & COMPLETED_DATA_IN) &&
+ cmdinfo->data_in_urb) {
+ if (devinfo->use_streams) {
+ cmdinfo->state |= DATA_COMPLETES_CMD;
+ usb_unlink_urb(cmdinfo->data_in_urb);
+ } else {
+ usb_free_urb(cmdinfo->data_in_urb);
+ }
+ }
+ if (!(cmdinfo->state & COMPLETED_DATA_OUT) &&
+ cmdinfo->data_out_urb) {
+ if (devinfo->use_streams) {
+ cmdinfo->state |= DATA_COMPLETES_CMD;
+ usb_unlink_urb(cmdinfo->data_in_urb);
+ } else {
+ usb_free_urb(cmdinfo->data_out_urb);
+ }
+ }
+
if (urb->actual_length < 16)
devinfo->uas_sense_old = 1;
if (devinfo->uas_sense_old)
@@ -259,29 +253,70 @@ static void uas_stat_cmplt(struct urb *urb)
scmd_printk(KERN_ERR, cmnd,
"Bogus IU (%d) received on status pipe\n", iu->iu_id);
}
+
+ if (devinfo->use_streams) {
+ usb_free_urb(urb);
+ return;
+ }
+
+ ret = usb_submit_urb(urb, GFP_ATOMIC);
+ if (ret)
+ dev_err(&urb->dev->dev, "failed submit status urb\n");
}
-static void uas_data_cmplt(struct urb *urb)
+static void uas_data_out_cmplt(struct urb *urb)
{
- struct scsi_data_buffer *sdb = urb->context;
+ struct scsi_cmnd *cmnd = urb->context;
+ struct scsi_data_buffer *sdb = scsi_out(cmnd);
+ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+
+ cmdinfo->state |= COMPLETED_DATA_OUT;
+
sdb->resid = sdb->length - urb->actual_length;
usb_free_urb(urb);
+
+ if (cmdinfo->state & DATA_COMPLETES_CMD)
+ cmnd->scsi_done(cmnd);
+}
+
+static void uas_data_in_cmplt(struct urb *urb)
+{
+ struct scsi_cmnd *cmnd = urb->context;
+ struct scsi_data_buffer *sdb = scsi_in(cmnd);
+ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
+
+ cmdinfo->state |= COMPLETED_DATA_IN;
+
+ sdb->resid = sdb->length - urb->actual_length;
+ usb_free_urb(urb);
+
+ if (cmdinfo->state & DATA_COMPLETES_CMD)
+ cmnd->scsi_done(cmnd);
}
static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
- unsigned int pipe, u16 stream_id,
- struct scsi_data_buffer *sdb,
- enum dma_data_direction dir)
+ unsigned int pipe, struct scsi_cmnd *cmnd,
+ enum dma_data_direction dir)
{
+ struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
struct usb_device *udev = devinfo->udev;
struct urb *urb = usb_alloc_urb(0, gfp);
+ struct scsi_data_buffer *sdb;
+ usb_complete_t complete_fn;
+ u16 stream_id = cmdinfo->stream;
if (!urb)
goto out;
- usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length, uas_data_cmplt,
- sdb);
- if (devinfo->use_streams)
- urb->stream_id = stream_id;
+ if (dir == DMA_FROM_DEVICE) {
+ sdb = scsi_in(cmnd);
+ complete_fn = uas_data_in_cmplt;
+ } else {
+ sdb = scsi_out(cmnd);
+ complete_fn = uas_data_out_cmplt;
+ }
+ usb_fill_bulk_urb(urb, udev, pipe, NULL, sdb->length,
+ complete_fn, cmnd);
+ urb->stream_id = stream_id;
urb->num_sgs = udev->bus->sg_tablesize ? sdb->table.nents : 0;
urb->sg = sdb->table.sgl;
out:
@@ -289,7 +324,7 @@ static struct urb *uas_alloc_data_urb(struct uas_dev_info *devinfo, gfp_t gfp,
}
static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
- struct scsi_cmnd *cmnd, u16 stream_id)
+ struct Scsi_Host *shost, u16 stream_id)
{
struct usb_device *udev = devinfo->udev;
struct urb *urb = usb_alloc_urb(0, gfp);
@@ -303,7 +338,7 @@ static struct urb *uas_alloc_sense_urb(struct uas_dev_info *devinfo, gfp_t gfp,
goto free;
usb_fill_bulk_urb(urb, udev, devinfo->status_pipe, iu, sizeof(*iu),
- uas_stat_cmplt, cmnd->device);
+ uas_stat_cmplt, shost);
urb->stream_id = stream_id;
urb->transfer_flags |= URB_FREE_BUFFER;
out:
@@ -334,7 +369,10 @@ static struct urb *uas_alloc_cmd_urb(struct uas_dev_info *devinfo, gfp_t gfp,
goto free;
iu->iu_id = IU_ID_COMMAND;
- iu->tag = cpu_to_be16(stream_id);
+ if (blk_rq_tagged(cmnd->request))
+ iu->tag = cpu_to_be16(cmnd->request->tag + 2);
+ else
+ iu->tag = cpu_to_be16(1);
iu->prio_attr = UAS_SIMPLE_TAG;
iu->len = len;
int_to_scsilun(sdev->lun, &iu->lun);
@@ -362,8 +400,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
struct uas_cmd_info *cmdinfo = (void *)&cmnd->SCp;
if (cmdinfo->state & ALLOC_STATUS_URB) {
- cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp, cmnd,
- cmdinfo->stream);
+ cmdinfo->status_urb = uas_alloc_sense_urb(devinfo, gfp,
+ cmnd->device->host, cmdinfo->stream);
if (!cmdinfo->status_urb)
return SCSI_MLQUEUE_DEVICE_BUSY;
cmdinfo->state &= ~ALLOC_STATUS_URB;
@@ -380,8 +418,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
if (cmdinfo->state & ALLOC_DATA_IN_URB) {
cmdinfo->data_in_urb = uas_alloc_data_urb(devinfo, gfp,
- devinfo->data_in_pipe, cmdinfo->stream,
- scsi_in(cmnd), DMA_FROM_DEVICE);
+ devinfo->data_in_pipe, cmnd,
+ DMA_FROM_DEVICE);
if (!cmdinfo->data_in_urb)
return SCSI_MLQUEUE_DEVICE_BUSY;
cmdinfo->state &= ~ALLOC_DATA_IN_URB;
@@ -398,8 +436,8 @@ static int uas_submit_urbs(struct scsi_cmnd *cmnd,
if (cmdinfo->state & ALLOC_DATA_OUT_URB) {
cmdinfo->data_out_urb = uas_alloc_data_urb(devinfo, gfp,
- devinfo->data_out_pipe, cmdinfo->stream,
- scsi_out(cmnd), DMA_TO_DEVICE);
+ devinfo->data_out_pipe, cmnd,
+ DMA_TO_DEVICE);
if (!cmdinfo->data_out_urb)
return SCSI_MLQUEUE_DEVICE_BUSY;
cmdinfo->state &= ~ALLOC_DATA_OUT_URB;
@@ -444,13 +482,13 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
BUILD_BUG_ON(sizeof(struct uas_cmd_info) > sizeof(struct scsi_pointer));
- if (!cmdinfo->status_urb && sdev->current_cmnd)
+ if (devinfo->cmnd)
return SCSI_MLQUEUE_DEVICE_BUSY;
if (blk_rq_tagged(cmnd->request)) {
- cmdinfo->stream = cmnd->request->tag + 1;
+ cmdinfo->stream = cmnd->request->tag + 2;
} else {
- sdev->current_cmnd = cmnd;
+ devinfo->cmnd = cmnd;
cmdinfo->stream = 1;
}
@@ -472,7 +510,8 @@ static int uas_queuecommand_lck(struct scsi_cmnd *cmnd,
}
if (!devinfo->use_streams) {
- cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB);
+ cmdinfo->state &= ~(SUBMIT_DATA_IN_URB | SUBMIT_DATA_OUT_URB |
+ ALLOC_STATUS_URB | SUBMIT_STATUS_URB);
cmdinfo->stream = 0;
}
@@ -551,7 +590,7 @@ static int uas_slave_configure(struct scsi_device *sdev)
{
struct uas_dev_info *devinfo = sdev->hostdata;
scsi_set_tag_type(sdev, MSG_ORDERED_TAG);
- scsi_activate_tcq(sdev, devinfo->qdepth - 1);
+ scsi_activate_tcq(sdev, devinfo->qdepth - 2);
return 0;
}
@@ -589,22 +628,34 @@ static int uas_is_interface(struct usb_host_interface *intf)
intf->desc.bInterfaceProtocol == USB_PR_UAS);
}
+static int uas_isnt_supported(struct usb_device *udev)
+{
+ struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+
+ dev_warn(&udev->dev, "The driver for the USB controller %s does not "
+ "support scatter-gather which is\n",
+ hcd->driver->description);
+ dev_warn(&udev->dev, "required by the UAS driver. Please try an"
+ "alternative USB controller if you wish to use UAS.\n");
+ return -ENODEV;
+}
+
static int uas_switch_interface(struct usb_device *udev,
struct usb_interface *intf)
{
int i;
-
- if (uas_is_interface(intf->cur_altsetting))
- return 0;
+ int sg_supported = udev->bus->sg_tablesize != 0;
for (i = 0; i < intf->num_altsetting; i++) {
struct usb_host_interface *alt = &intf->altsetting[i];
- if (alt == intf->cur_altsetting)
- continue;
- if (uas_is_interface(alt))
+
+ if (uas_is_interface(alt)) {
+ if (!sg_supported)
+ return uas_isnt_supported(udev);
return usb_set_interface(udev,
alt->desc.bInterfaceNumber,
alt->desc.bAlternateSetting);
+ }
}
return -ENODEV;
@@ -619,6 +670,7 @@ static void uas_configure_endpoints(struct uas_dev_info *devinfo)
unsigned i, n_endpoints = intf->cur_altsetting->desc.bNumEndpoints;
devinfo->uas_sense_old = 0;
+ devinfo->cmnd = NULL;
for (i = 0; i < n_endpoints; i++) {
unsigned char *extra = endpoint[i].extra;
@@ -670,6 +722,40 @@ static void uas_configure_endpoints(struct uas_dev_info *devinfo)
}
}
+static int uas_alloc_status_urb(struct uas_dev_info *devinfo,
+ struct Scsi_Host *shost)
+{
+ if (devinfo->use_streams) {
+ devinfo->status_urb = NULL;
+ return 0;
+ }
+
+ devinfo->status_urb = uas_alloc_sense_urb(devinfo, GFP_KERNEL,
+ shost, 0);
+ if (!devinfo->status_urb)
+ goto err_s_urb;
+
+ if (usb_submit_urb(devinfo->status_urb, GFP_KERNEL))
+ goto err_submit_urb;
+
+ return 0;
+err_submit_urb:
+ usb_free_urb(devinfo->status_urb);
+err_s_urb:
+ return -ENOMEM;
+}
+
+static void uas_free_streams(struct uas_dev_info *devinfo)
+{
+ struct usb_device *udev = devinfo->udev;
+ struct usb_host_endpoint *eps[3];
+
+ eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe);
+ eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);
+ eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
+ usb_free_streams(devinfo->intf, eps, 3, GFP_KERNEL);
+}
+
/*
* XXX: What I'd like to do here is register a SCSI host for each USB host in
* the system. Follow usb-storage's design of registering a SCSI host for
@@ -699,18 +785,33 @@ static int uas_probe(struct usb_interface *intf, const struct usb_device_id *id)
shost->max_id = 1;
shost->sg_tablesize = udev->bus->sg_tablesize;
- result = scsi_add_host(shost, &intf->dev);
+ devinfo->intf = intf;
+ devinfo->udev = udev;
+ uas_configure_endpoints(devinfo);
+
+ result = scsi_init_shared_tag_map(shost, devinfo->qdepth - 2);
if (result)
goto free;
+
+ result = scsi_add_host(shost, &intf->dev);
+ if (result)
+ goto deconfig_eps;
+
shost->hostdata[0] = (unsigned long)devinfo;
- devinfo->intf = intf;
- devinfo->udev = udev;
- uas_configure_endpoints(devinfo);
+ result = uas_alloc_status_urb(devinfo, shost);
+ if (result)
+ goto err_alloc_status;
scsi_scan_host(shost);
usb_set_intfdata(intf, shost);
return result;
+
+err_alloc_status:
+ scsi_remove_host(shost);
+ shost = NULL;
+deconfig_eps:
+ uas_free_streams(devinfo);
free:
kfree(devinfo);
if (shost)
@@ -732,18 +833,13 @@ static int uas_post_reset(struct usb_interface *intf)
static void uas_disconnect(struct usb_interface *intf)
{
- struct usb_device *udev = interface_to_usbdev(intf);
- struct usb_host_endpoint *eps[3];
struct Scsi_Host *shost = usb_get_intfdata(intf);
struct uas_dev_info *devinfo = (void *)shost->hostdata[0];
scsi_remove_host(shost);
-
- eps[0] = usb_pipe_endpoint(udev, devinfo->status_pipe);
- eps[1] = usb_pipe_endpoint(udev, devinfo->data_in_pipe);
- eps[2] = usb_pipe_endpoint(udev, devinfo->data_out_pipe);
- usb_free_streams(intf, eps, 3, GFP_KERNEL);
-
+ usb_kill_urb(devinfo->status_urb);
+ usb_free_urb(devinfo->status_urb);
+ uas_free_streams(devinfo);
kfree(devinfo);
}
diff --git a/drivers/usb/storage/usb.c b/drivers/usb/storage/usb.c
index db51ba16dc07..2653e73db623 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -125,10 +125,42 @@ static struct us_unusual_dev us_unusual_dev_list[] = {
{ } /* Terminating entry */
};
+static struct us_unusual_dev for_dynamic_ids =
+ USUAL_DEV(USB_SC_SCSI, USB_PR_BULK, 0);
+
#undef UNUSUAL_DEV
#undef COMPLIANT_DEV
#undef USUAL_DEV
+#ifdef CONFIG_LOCKDEP
+
+static struct lock_class_key us_interface_key[USB_MAXINTERFACES];
+
+static void us_set_lock_class(struct mutex *mutex,
+ struct usb_interface *intf)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ struct usb_host_config *config = udev->actconfig;
+ int i;
+
+ for (i = 0; i < config->desc.bNumInterfaces; i++) {
+ if (config->interface[i] == intf)
+ break;
+ }
+
+ BUG_ON(i == config->desc.bNumInterfaces);
+
+ lockdep_set_class(mutex, &us_interface_key[i]);
+}
+
+#else
+
+static void us_set_lock_class(struct mutex *mutex,
+ struct usb_interface *intf)
+{
+}
+
+#endif
#ifdef CONFIG_PM /* Minimal support for suspend and resume */
@@ -892,6 +924,7 @@ int usb_stor_probe1(struct us_data **pus,
*pus = us = host_to_us(host);
memset(us, 0, sizeof(struct us_data));
mutex_init(&(us->dev_mutex));
+ us_set_lock_class(&us->dev_mutex, intf);
init_completion(&us->cmnd_ready);
init_completion(&(us->notify));
init_waitqueue_head(&us->delay_wait);
@@ -999,8 +1032,10 @@ EXPORT_SYMBOL_GPL(usb_stor_disconnect);
static int storage_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
+ struct us_unusual_dev *unusual_dev;
struct us_data *us;
int result;
+ int size;
/*
* If libusual is configured, let it decide whether a standard
@@ -1019,8 +1054,19 @@ static int storage_probe(struct usb_interface *intf,
* table, so we use the index of the id entry to find the
* corresponding unusual_devs entry.
*/
- result = usb_stor_probe1(&us, intf, id,
- (id - usb_storage_usb_ids) + us_unusual_dev_list);
+
+ size = ARRAY_SIZE(us_unusual_dev_list);
+ if (id >= usb_storage_usb_ids && id < usb_storage_usb_ids + size) {
+ unusual_dev = (id - usb_storage_usb_ids) + us_unusual_dev_list;
+ } else {
+ unusual_dev = &for_dynamic_ids;
+
+ US_DEBUGP("%s %s 0x%04x 0x%04x\n", "Use Bulk-Only transport",
+ "with the Transparent SCSI protocol for dynamic id:",
+ id->idVendor, id->idProduct);
+ }
+
+ result = usb_stor_probe1(&us, intf, id, unusual_dev);
if (result)
return result;
@@ -1046,7 +1092,6 @@ static struct usb_driver usb_storage_driver = {
.id_table = usb_storage_usb_ids,
.supports_autosuspend = 1,
.soft_unbind = 1,
- .no_dynamic_id = 1,
};
static int __init usb_stor_init(void)