summaryrefslogtreecommitdiff
path: root/drivers/usb
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2012-04-14 13:18:27 +0200
committerIngo Molnar <mingo@kernel.org>2012-04-14 13:19:04 +0200
commit6ac1ef482d7ae0c690f1640bf6eb818ff9a2d91e (patch)
tree021cc9f6b477146fcebe6f3be4752abfa2ba18a9 /drivers/usb
parent682968e0c425c60f0dde37977e5beb2b12ddc4cc (diff)
parenta385ec4f11bdcf81af094c03e2444ee9b7fad2e5 (diff)
Merge branch 'perf/core' into perf/uprobes
Merge in latest upstream (and the latest perf development tree), to prepare for tooling changes, and also to pick up v3.4 MM changes that the uprobes code needs to take care of. Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/Kconfig47
-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.c186
-rw-r--r--drivers/usb/core/hcd-pci.c2
-rw-r--r--drivers/usb/core/hcd.c6
-rw-r--r--drivers/usb/core/hub.c212
-rw-r--r--drivers/usb/core/inode.c33
-rw-r--r--drivers/usb/core/sysfs.c23
-rw-r--r--drivers/usb/core/urb.c32
-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.c122
-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.c98
-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.c52
-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.c14
-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.c2
-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.c29
-rw-r--r--drivers/usb/gadget/fsl_usb2_udc.h2
-rw-r--r--drivers/usb/gadget/g_ffs.c2
-rw-r--r--drivers/usb/gadget/goku_udc.c20
-rw-r--r--drivers/usb/gadget/hid.c6
-rw-r--r--drivers/usb/gadget/inode.c15
-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-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.c52
-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.c58
-rw-r--r--drivers/usb/host/ehci-fsl.h3
-rw-r--r--drivers/usb/host/ehci-hcd.c21
-rw-r--r--drivers/usb/host/ehci-hub.c10
-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-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.c14
-rw-r--r--drivers/usb/host/ehci.h2
-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.c189
-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.c3
-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/xhci-hub.c41
-rw-r--r--drivers/usb/host/xhci-mem.c241
-rw-r--r--drivers/usb/host/xhci-plat.c205
-rw-r--r--drivers/usb/host/xhci-ring.c333
-rw-r--r--drivers/usb/host/xhci.c72
-rw-r--r--drivers/usb/host/xhci.h34
-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.c77
-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_virthub.c9
-rw-r--r--drivers/usb/musb/omap2430.c46
-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/ch341.c27
-rw-r--r--drivers/usb/serial/cp210x.c77
-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.c61
-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.c59
-rw-r--r--drivers/usb/serial/oti6858.c36
-rw-r--r--drivers/usb/serial/pl2303.c31
-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.c37
-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.c94
-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.c21
235 files changed, 8989 insertions, 5644 deletions
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index 75823a1abeb6..cbd8f5f80596 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -10,34 +10,13 @@ menuconfig USB_SUPPORT
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 +44,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 +55,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 +63,27 @@ config USB_ARCH_HAS_XHCI
boolean
default PCI
+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..f8e2d6d52e5c 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;
@@ -1302,35 +1301,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..9d7fc9a39933 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2352,7 +2352,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 +2508,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 +2573,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..28664eb7f555 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,
@@ -1656,7 +1680,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]);
}
@@ -1842,6 +1866,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 +1955,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 +2449,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 +2759,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 +2772,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__);
@@ -3424,6 +3516,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 +3568,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 +3647,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 +3690,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/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..7239a73c1b8c 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,10 +527,13 @@ 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
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..7bd815a507e8 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
@@ -215,10 +215,10 @@ static void dwc3_free_event_buffers(struct dwc3 *dwc)
/**
* dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
- * @dwc: Pointer to out controller context structure
+ * @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..25910e251c04 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,25 +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);
- break;
- default:
- return -EINVAL;
+ dwc->test_mode_nr = wIndex >> 8;
+ dwc->test_mode = true;
}
break;
@@ -396,7 +374,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 +448,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 +541,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,16 +555,16 @@ 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) {
-
transferred = min_t(u32, ur->length,
- ep0->endpoint.maxpacket - trb.length);
+ ep0->endpoint.maxpacket - length);
memcpy(ur->buf, dwc->ep0_bounce, transferred);
dwc->ep0_bounced = false;
} else {
- transferred = ur->length - trb.length;
+ transferred = ur->length - length;
ur->actual += transferred;
}
@@ -614,6 +596,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 +617,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 +673,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 +693,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 +724,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..0c935d7c65bd 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);
@@ -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..1cbba70836bc 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
@@ -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);
}
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..7b1cf18df5e3 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
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..5f94e79cd6b9 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);
@@ -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,13 +910,11 @@ 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;
}
@@ -1217,7 +1215,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;
}
@@ -1295,7 +1293,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,7 +1377,7 @@ 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;
@@ -1966,7 +1964,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 +2005,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 +2429,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..331cd6729d3c 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
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..8793f32bab11 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,18 @@ 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 +1605,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 +2058,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-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..56da49f31d6c 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
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..3e7345172e03 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,8 @@ 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;
portsc = ehci_readl(ehci, &ehci->regs->port_status[port_offset]);
portsc &= ~(PORT_PTS_MSK | PORT_PTS_PTW);
@@ -231,6 +233,8 @@ static void ehci_fsl_setup_phy(struct ehci_hcd *ehci,
portsc |= PORT_PTS_PTW;
/* fall through */
case FSL_USB2_PHY_UTMI:
+ /* enable UTMI PHY */
+ setbits32(non_ehci + FSL_SOC_USB_CTRL, CTRL_UTMI_PHY_EN);
portsc |= PORT_PTS_UTMI;
break;
case FSL_USB2_PHY_NONE:
@@ -239,7 +243,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 +256,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 +300,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 +317,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 +349,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 +482,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..057cdda7a489 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)
@@ -1351,21 +1350,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 +1365,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..256fbd42e48c 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);
@@ -727,7 +727,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
@@ -1076,7 +1076,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 +1086,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-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..3de48a2d7955 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;
@@ -733,9 +733,9 @@ static int tegra_ehci_probe(struct platform_device *pdev)
#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 +750,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 +808,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..8f9acbc96fde 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -176,7 +176,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..09f597ad6e00 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;
@@ -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)
{
- 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");
}
}
}
@@ -518,14 +626,14 @@ static int ohci_hcd_at91_drv_remove(struct platform_device *pdev)
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);
@@ -595,5 +703,6 @@ static struct platform_driver ohci_hcd_at91_driver = {
.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..11de5f1be981 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -893,4 +893,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/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..cae4c6f2845a 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;
@@ -2157,7 +2263,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 +2341,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 +2372,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,6 +2446,15 @@ 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:
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..6bd9d53062eb 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,7 +2413,7 @@ 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);
@@ -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;
@@ -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,6 +3512,8 @@ int xhci_queue_isoc_tx_prepare(struct xhci_hcd *xhci, gfp_t mem_flags,
urb->dev->speed == USB_SPEED_FULL)
urb->interval /= 8;
}
+ ep_ring->num_trbs_free_temp = ep_ring->num_trbs_free;
+
return xhci_queue_isoc_tx(xhci, GFP_ATOMIC, urb, slot_id, ep_index);
}
@@ -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..e1963d4a430f 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -224,13 +224,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 +341,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 +349,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) {
@@ -729,6 +729,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 +3615,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 +3659,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 +3705,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 +3784,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 +3807,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 +3968,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 +4064,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 +4088,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..91074fdab3eb 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1223,10 +1223,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 +1250,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 +1277,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 +1356,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 +1622,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 +1663,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/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..0f8b82918a40 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -131,9 +131,9 @@ 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;
@@ -165,10 +165,9 @@ static int musb_ulpi_read(struct otg_transceiver *otg, u32 offset)
return musb_readb(addr, MUSB_ULPI_REG_DATA);
}
-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;
@@ -200,7 +199,7 @@ static int musb_ulpi_write(struct otg_transceiver *otg,
#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 +413,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 +626,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 +643,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 +1017,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 +1035,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 +1044,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 +1053,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 +1063,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 +1073,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 +1104,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 +1140,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 +1211,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 +1306,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 +1353,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 +1589,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 +1777,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 +1853,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;
@@ -1961,11 +1961,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 +1984,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 +1999,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);
@@ -2073,7 +2073,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 +2102,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 +2112,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 +2362,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 +2379,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_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..2ae0bb309994 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");
@@ -290,7 +291,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;
@@ -325,7 +326,7 @@ 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");
@@ -349,7 +350,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 +369,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 +380,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 +389,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 +409,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;
@@ -471,7 +472,7 @@ 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);
@@ -494,7 +495,7 @@ static int omap2430_runtime_suspend(struct device *dev)
OTG_INTERFSEL);
omap2430_low_level_exit(musb);
- otg_set_suspend(musb->xceiv, 1);
+ usb_phy_set_suspend(musb->xceiv, 1);
return 0;
}
@@ -508,7 +509,7 @@ static int omap2430_runtime_resume(struct device *dev)
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 +525,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 +539,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/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..0310e2df59f5 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,7 @@ 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, 300);
/* Convert data into an array of integers */
for (i = 0; i < length; i++)
@@ -286,7 +297,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 +318,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 +340,19 @@ 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, 300);
} 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, 300);
}
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 +695,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 +728,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 +743,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 +855,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..ff8605b4b4be 100644
--- a/drivers/usb/serial/ftdi_sio.c
+++ b/drivers/usb/serial/ftdi_sio.c
@@ -188,6 +188,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 +537,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 +802,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 +851,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 +865,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 +875,8 @@ static const char *ftdi_chip_name[] = {
[FT232RL] = "FT232RL",
[FT2232H] = "FT2232H",
[FT4232H] = "FT4232H",
- [FT232H] = "FT232H"
+ [FT232H] = "FT232H",
+ [FTX] = "FT-X"
};
@@ -915,7 +923,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 +945,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 +1180,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 +1470,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 +1605,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 +1628,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);
}
}
@@ -1706,7 +1724,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 +1782,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;
@@ -2288,6 +2308,7 @@ static int ftdi_tiocmget(struct tty_struct *tty)
case FT2232H:
case FT4232H:
case FT232H:
+ case FTX:
len = 2;
break;
default:
@@ -2420,19 +2441,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 +2452,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..6e1622f2a297
--- /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 0x0720
+#define FOCUS_PRODUCT_ID_UNI 0x0710
+
+#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) },
+ { 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..836cfa9a515f 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,
@@ -768,6 +774,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 +901,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 +1211,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 +1229,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 +1241,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 +1264,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 +1299,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 +1350,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..ff4a174fa5de 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,
};
@@ -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..f14465a83dd1 100644
--- a/drivers/usb/serial/sierra.c
+++ b/drivers/usb/serial/sierra.c
@@ -1084,7 +1084,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 +1094,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 +1111,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..69230f01056a 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:
@@ -1239,7 +1235,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 +1333,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 +1367,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 +1377,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..c18538e4a6db 100644
--- a/drivers/usb/storage/usb.c
+++ b/drivers/usb/storage/usb.c
@@ -125,6 +125,9 @@ 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
@@ -999,8 +1002,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 +1024,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 +1062,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)