Browse Source

Merge branch 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb

* 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (260 commits)
  usb: renesas_usbhs: fixup inconsistent return from usbhs_pkt_push()
  usb/isp1760: Allow to optionally trigger low-level chip reset via GPIOLIB.
  USB: gadget: midi: memory leak in f_midi_bind_config()
  USB: gadget: midi: fix range check in f_midi_out_open()
  QE/FHCI: fixed the CONTROL bug
  usb: renesas_usbhs: tidyup for smatch warnings
  USB: Fix USB Kconfig dependency problem on 85xx/QoirQ platforms
  EHCI: workaround for MosChip controller bug
  usb: gadget: file_storage: fix race on unloading
  USB: ftdi_sio.c: Use ftdi async_icount structure for TIOCMIWAIT, as in other drivers
  USB: ftdi_sio.c:Fill MSR fields of the ftdi async_icount structure
  USB: ftdi_sio.c: Fill LSR fields of the ftdi async_icount structure
  USB: ftdi_sio.c:Fill TX field of the ftdi async_icount structure
  USB: ftdi_sio.c: Fill the RX field of the ftdi async_icount structure
  USB: ftdi_sio.c: Basic icount infrastructure for ftdi_sio
  usb/isp1760: Let OF bindings depend on general CONFIG_OF instead of PPC_OF .
  USB: ftdi_sio: Support TI/Luminary Micro Stellaris BD-ICDI Board
  USB: Fix runtime wakeup on OHCI
  xHCI/USB: Make xHCI driver have a BOS descriptor.
  usb: gadget: add new usb gadget for ACM and mass storage
  ...
Linus Torvalds 13 years ago
parent
commit
1be025d3cb
100 changed files with 8542 additions and 2594 deletions
  1. 46 0
      Documentation/ABI/testing/sysfs-bus-pci-drivers-ehci_hcd
  2. 15 0
      Documentation/ABI/testing/sysfs-bus-usb
  3. 45 0
      Documentation/usb/dwc3.txt
  4. 26 0
      Documentation/usb/power-management.txt
  5. 8 0
      MAINTAINERS
  6. 7 0
      arch/arm/mach-mmp/include/mach/pxa168.h
  7. 46 0
      arch/arm/mach-mmp/pxa168.c
  8. 5 6
      arch/arm/mach-omap2/Makefile
  9. 1 0
      arch/arm/mach-shmobile/board-mackerel.c
  10. 15 1
      drivers/usb/Kconfig
  11. 4 0
      drivers/usb/Makefile
  12. 6 3
      drivers/usb/class/cdc-acm.c
  13. 1 1
      drivers/usb/class/cdc-wdm.c
  14. 2 3
      drivers/usb/class/usbtmc.c
  15. 107 4
      drivers/usb/core/config.c
  16. 2 2
      drivers/usb/core/devices.c
  17. 35 22
      drivers/usb/core/devio.c
  18. 15 1
      drivers/usb/core/driver.c
  19. 1 1
      drivers/usb/core/endpoint.c
  20. 1 1
      drivers/usb/core/hcd-pci.c
  21. 24 3
      drivers/usb/core/hcd.c
  22. 183 128
      drivers/usb/core/hub.c
  23. 1 1
      drivers/usb/core/message.c
  24. 24 0
      drivers/usb/core/quirks.c
  25. 58 1
      drivers/usb/core/sysfs.c
  26. 1 1
      drivers/usb/core/urb.c
  27. 1 0
      drivers/usb/core/usb.c
  28. 7 0
      drivers/usb/core/usb.h
  29. 25 0
      drivers/usb/dwc3/Kconfig
  30. 36 0
      drivers/usb/dwc3/Makefile
  31. 484 0
      drivers/usb/dwc3/core.c
  32. 768 0
      drivers/usb/dwc3/core.h
  33. 50 0
      drivers/usb/dwc3/debug.h
  34. 441 0
      drivers/usb/dwc3/debugfs.c
  35. 401 0
      drivers/usb/dwc3/dwc3-omap.c
  36. 219 0
      drivers/usb/dwc3/dwc3-pci.c
  37. 804 0
      drivers/usb/dwc3/ep0.c
  38. 2104 0
      drivers/usb/dwc3/gadget.c
  39. 211 0
      drivers/usb/dwc3/gadget.h
  40. 54 0
      drivers/usb/dwc3/io.h
  41. 42 5
      drivers/usb/gadget/Kconfig
  42. 3 1
      drivers/usb/gadget/Makefile
  43. 256 0
      drivers/usb/gadget/acm_ms.c
  44. 3 17
      drivers/usb/gadget/amd5536udc.c
  45. 0 9
      drivers/usb/gadget/amd5536udc.h
  46. 11 21
      drivers/usb/gadget/at91_udc.c
  47. 0 10
      drivers/usb/gadget/at91_udc.h
  48. 6 7
      drivers/usb/gadget/atmel_usba_udc.c
  49. 0 9
      drivers/usb/gadget/cdc2.c
  50. 0 11
      drivers/usb/gadget/ci13xxx_msm.c
  51. 1 1
      drivers/usb/gadget/ci13xxx_udc.c
  52. 6 31
      drivers/usb/gadget/composite.c
  53. 0 9
      drivers/usb/gadget/config.c
  54. 0 1
      drivers/usb/gadget/dbgp.c
  55. 2 11
      drivers/usb/gadget/dummy_hcd.c
  56. 1 11
      drivers/usb/gadget/epautoconf.c
  57. 0 9
      drivers/usb/gadget/ether.c
  58. 8 7
      drivers/usb/gadget/f_audio.c
  59. 0 9
      drivers/usb/gadget/f_ecm.c
  60. 0 9
      drivers/usb/gadget/f_eem.c
  61. 0 9
      drivers/usb/gadget/f_fs.c
  62. 0 9
      drivers/usb/gadget/f_hid.c
  63. 0 9
      drivers/usb/gadget/f_loopback.c
  64. 111 85
      drivers/usb/gadget/f_mass_storage.c
  65. 998 0
      drivers/usb/gadget/f_midi.c
  66. 0 9
      drivers/usb/gadget/f_ncm.c
  67. 0 9
      drivers/usb/gadget/f_obex.c
  68. 0 10
      drivers/usb/gadget/f_phonet.c
  69. 0 9
      drivers/usb/gadget/f_rndis.c
  70. 0 9
      drivers/usb/gadget/f_sourcesink.c
  71. 0 9
      drivers/usb/gadget/f_subset.c
  72. 0 1
      drivers/usb/gadget/f_uvc.c
  73. 0 1
      drivers/usb/gadget/f_uvc.h
  74. 139 115
      drivers/usb/gadget/file_storage.c
  75. 1 1
      drivers/usb/gadget/fsl_qe_udc.c
  76. 20 35
      drivers/usb/gadget/fsl_udc_core.c
  77. 3 13
      drivers/usb/gadget/fusb300_udc.c
  78. 0 10
      drivers/usb/gadget/fusb300_udc.h
  79. 0 9
      drivers/usb/gadget/g_ffs.c
  80. 3 0
      drivers/usb/gadget/gadget_chips.h
  81. 88 1204
      drivers/usb/gadget/gmidi.c
  82. 0 9
      drivers/usb/gadget/hid.c
  83. 2 2
      drivers/usb/gadget/imx_udc.c
  84. 0 5
      drivers/usb/gadget/imx_udc.h
  85. 0 9
      drivers/usb/gadget/inode.c
  86. 46 101
      drivers/usb/gadget/langwell_udc.c
  87. 2 10
      drivers/usb/gadget/langwell_udc.h
  88. 3 13
      drivers/usb/gadget/m66592-udc.c
  89. 0 10
      drivers/usb/gadget/m66592-udc.h
  90. 1 10
      drivers/usb/gadget/mass_storage.c
  91. 0 9
      drivers/usb/gadget/multi.c
  92. 22 4
      drivers/usb/gadget/mv_udc.h
  93. 434 114
      drivers/usb/gadget/mv_udc_core.c
  94. 0 214
      drivers/usb/gadget/mv_udc_phy.c
  95. 0 9
      drivers/usb/gadget/ncm.c
  96. 0 6
      drivers/usb/gadget/ndis.h
  97. 22 56
      drivers/usb/gadget/net2272.c
  98. 20 67
      drivers/usb/gadget/net2280.c
  99. 0 9
      drivers/usb/gadget/net2280.h
  100. 4 14
      drivers/usb/gadget/omap_udc.c

+ 46 - 0
Documentation/ABI/testing/sysfs-bus-pci-drivers-ehci_hcd

@@ -0,0 +1,46 @@
+What:		/sys/bus/pci/drivers/ehci_hcd/.../companion
+		/sys/bus/usb/devices/usbN/../companion
+Date:		January 2007
+KernelVersion:	2.6.21
+Contact:	Alan Stern <stern@rowland.harvard.edu>
+Description:
+		PCI-based EHCI USB controllers (i.e., high-speed USB-2.0
+		controllers) are often implemented along with a set of
+		"companion" full/low-speed USB-1.1 controllers.  When a
+		high-speed device is plugged in, the connection is routed
+		to the EHCI controller; when a full- or low-speed device
+		is plugged in, the connection is routed to the companion
+		controller.
+
+		Sometimes you want to force a high-speed device to connect
+		at full speed, which can be accomplished by forcing the
+		connection to be routed to the companion controller.
+		That's what this file does.  Writing a port number to the
+		file causes connections on that port to be routed to the
+		companion controller, and writing the negative of a port
+		number returns the port to normal operation.
+
+		For example: To force the high-speed device attached to
+		port 4 on bus 2 to run at full speed:
+
+			echo 4 >/sys/bus/usb/devices/usb2/../companion
+
+		To return the port to high-speed operation:
+
+			echo -4 >/sys/bus/usb/devices/usb2/../companion
+
+		Reading the file gives the list of ports currently forced
+		to the companion controller.
+
+		Note: Some EHCI controllers do not have companions; they
+		may contain an internal "transaction translator" or they
+		may be attached directly to a "rate-matching hub".  This
+		mechanism will not work with such controllers.  Also, it
+		cannot be used to force a port on a high-speed hub to
+		connect at full speed.
+
+		Note: When this file was first added, it appeared in a
+		different sysfs directory.  The location given above is
+		correct for 2.6.35 (and probably several earlier kernel
+		versions as well).
+

+ 15 - 0
Documentation/ABI/testing/sysfs-bus-usb

@@ -142,3 +142,18 @@ Description:
 		such devices.
 Users:
 		usb_modeswitch
+
+What:		/sys/bus/usb/devices/.../power/usb2_hardware_lpm
+Date:		September 2011
+Contact:	Andiry Xu <andiry.xu@amd.com>
+Description:
+		If CONFIG_USB_SUSPEND is set and a USB 2.0 lpm-capable device
+		is plugged in to a xHCI host which support link PM, it will
+		perform a LPM test; if the test is passed and host supports
+		USB2 hardware LPM (xHCI 1.0 feature), USB2 hardware LPM will
+		be enabled for the device and the USB device directory will
+		contain a file named power/usb2_hardware_lpm.  The file holds
+		a string value (enable or disable) indicating whether or not
+		USB2 hardware LPM is enabled for the device. Developer can
+		write y/Y/1 or n/N/0 to the file to enable/disable the
+		feature.

+ 45 - 0
Documentation/usb/dwc3.txt

@@ -0,0 +1,45 @@
+
+ TODO
+~~~~~~
+Please pick something while reading :)
+
+- Convert interrupt handler to per-ep-thread-irq
+
+  As it turns out some DWC3-commands ~1ms to complete. Currently we spin
+  until the command completes which is bad.
+
+  Implementation idea:
+  - dwc core implements a demultiplexing irq chip for interrupts per
+    endpoint. The interrupt numbers are allocated during probe and belong
+    to the device. If MSI provides per-endpoint interrupt this dummy
+    interrupt chip can be replaced with "real" interrupts.
+  - interrupts are requested / allocated on usb_ep_enable() and removed on
+    usb_ep_disable(). Worst case are 32 interrupts, the lower limit is two
+    for ep0/1.
+  - dwc3_send_gadget_ep_cmd() will sleep in wait_for_completion_timeout()
+    until the command completes.
+  - the interrupt handler is split into the following pieces:
+    - primary handler of the device
+      goes through every event and calls generic_handle_irq() for event
+      it. On return from generic_handle_irq() in acknowledges the event
+      counter so interrupt goes away (eventually).
+
+    - threaded handler of the device
+      none
+
+    - primary handler of the EP-interrupt
+      reads the event and tries to process it. Everything that requries
+      sleeping is handed over to the Thread. The event is saved in an
+      per-endpoint data-structure.
+      We probably have to pay attention not to process events once we
+      handed something to thread so we don't process event X prio Y
+      where X > Y.
+
+    - threaded handler of the EP-interrupt
+      handles the remaining EP work which might sleep such as waiting
+      for command completion.
+
+  Latency:
+   There should be no increase in latency since the interrupt-thread has a
+   high priority and will be run before an average task in user land
+   (except the user changed priorities).

+ 26 - 0
Documentation/usb/power-management.txt

@@ -487,3 +487,29 @@ succeed, it may still remain active and thus cause the system to
 resume as soon as the system suspend is complete.  Or the remote
 wakeup may fail and get lost.  Which outcome occurs depends on timing
 and on the hardware and firmware design.
+
+
+	xHCI hardware link PM
+	---------------------
+
+xHCI host controller provides hardware link power management to usb2.0
+(xHCI 1.0 feature) and usb3.0 devices which support link PM. By
+enabling hardware LPM, the host can automatically put the device into
+lower power state(L1 for usb2.0 devices, or U1/U2 for usb3.0 devices),
+which state device can enter and resume very quickly.
+
+The user interface for controlling USB2 hardware LPM is located in the
+power/ subdirectory of each USB device's sysfs directory, that is, in
+/sys/bus/usb/devices/.../power/ where "..." is the device's ID. The
+relevant attribute files is usb2_hardware_lpm.
+
+	power/usb2_hardware_lpm
+
+		When a USB2 device which support LPM is plugged to a
+		xHCI host root hub which support software LPM, the
+		host will run a software LPM test for it; if the device
+		enters L1 state and resume successfully and the host
+		supports USB2 hardware LPM, this file will show up and
+		driver will enable hardware LPM	for the device. You
+		can write y/Y/1 or n/N/0 to the file to	enable/disable
+		USB2 hardware LPM manually. This is for	test purpose mainly.

+ 8 - 0
MAINTAINERS

@@ -2136,6 +2136,14 @@ M:	Matthew Garrett <mjg59@srcf.ucam.org>
 S:	Maintained
 F:	drivers/platform/x86/dell-wmi.c
 
+DESIGNWARE USB3 DRD IP DRIVER
+M:	Felipe Balbi <balbi@ti.com>
+L:	linux-usb@vger.kernel.org
+L:	linux-omap@vger.kernel.org
+T:	git git://git.kernel.org/pub/scm/linux/kernel/git/balbi/usb.git
+S:	Maintained
+F:	drivers/usb/dwc3/
+
 DEVICE NUMBER REGISTRY
 M:	Torben Mathiasen <device@lanana.org>
 W:	http://lanana.org/docs/device-list/index.html

+ 7 - 0
arch/arm/mach-mmp/include/mach/pxa168.h

@@ -35,6 +35,13 @@ extern struct pxa_device_desc pxa168_device_fb;
 extern struct pxa_device_desc pxa168_device_keypad;
 extern struct pxa_device_desc pxa168_device_eth;
 
+struct pxa168_usb_pdata {
+	/* If NULL, default phy init routine for PXA168 would be called */
+	int (*phy_init)(void __iomem *usb_phy_reg_base);
+};
+/* pdata can be NULL */
+int __init pxa168_add_usb_host(struct pxa168_usb_pdata *pdata);
+
 static inline int pxa168_add_uart(int id)
 {
 	struct pxa_device_desc *d = NULL;

+ 46 - 0
arch/arm/mach-mmp/pxa168.c

@@ -25,6 +25,9 @@
 #include <mach/dma.h>
 #include <mach/devices.h>
 #include <mach/mfp.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <mach/pxa168.h>
 
 #include "common.h"
 #include "clock.h"
@@ -83,6 +86,7 @@ static APBC_CLK(keypad, PXA168_KPC, 0, 32000);
 static APMU_CLK(nand, NAND, 0x19b, 156000000);
 static APMU_CLK(lcd, LCD, 0x7f, 312000000);
 static APMU_CLK(eth, ETH, 0x09, 0);
+static APMU_CLK(usb, USB, 0x12, 0);
 
 /* device and clock bindings */
 static struct clk_lookup pxa168_clkregs[] = {
@@ -104,6 +108,7 @@ static struct clk_lookup pxa168_clkregs[] = {
 	INIT_CLKREG(&clk_lcd, "pxa168-fb", NULL),
 	INIT_CLKREG(&clk_keypad, "pxa27x-keypad", NULL),
 	INIT_CLKREG(&clk_eth, "pxa168-eth", "MFUCLK"),
+	INIT_CLKREG(&clk_usb, "pxa168-ehci", "PXA168-USBCLK"),
 };
 
 static int __init pxa168_init(void)
@@ -169,3 +174,44 @@ PXA168_DEVICE(ssp5, "pxa168-ssp", 4, SSP5, 0xd4021000, 0x40, 60, 61);
 PXA168_DEVICE(fb, "pxa168-fb", -1, LCD, 0xd420b000, 0x1c8);
 PXA168_DEVICE(keypad, "pxa27x-keypad", -1, KEYPAD, 0xd4012000, 0x4c);
 PXA168_DEVICE(eth, "pxa168-eth", -1, MFU, 0xc0800000, 0x0fff);
+
+struct resource pxa168_usb_host_resources[] = {
+	/* USB Host conroller register base */
+	[0] = {
+		.start	= 0xd4209000,
+		.end	= 0xd4209000 + 0x200,
+		.flags	= IORESOURCE_MEM,
+		.name	= "pxa168-usb-host",
+	},
+	/* USB PHY register base */
+	[1] = {
+		.start	= 0xd4206000,
+		.end	= 0xd4206000 + 0xff,
+		.flags	= IORESOURCE_MEM,
+		.name	= "pxa168-usb-phy",
+	},
+	[2] = {
+		.start	= IRQ_PXA168_USB2,
+		.end	= IRQ_PXA168_USB2,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static u64 pxa168_usb_host_dmamask = DMA_BIT_MASK(32);
+struct platform_device pxa168_device_usb_host = {
+	.name = "pxa168-ehci",
+	.id   = -1,
+	.dev  = {
+		.dma_mask = &pxa168_usb_host_dmamask,
+		.coherent_dma_mask = DMA_BIT_MASK(32),
+	},
+
+	.num_resources = ARRAY_SIZE(pxa168_usb_host_resources),
+	.resource      = pxa168_usb_host_resources,
+};
+
+int __init pxa168_add_usb_host(struct pxa168_usb_pdata *pdata)
+{
+	pxa168_device_usb_host.dev.platform_data = pdata;
+	return platform_device_register(&pxa168_device_usb_host);
+}

+ 5 - 6
arch/arm/mach-omap2/Makefile

@@ -242,14 +242,11 @@ obj-$(CONFIG_MACH_IGEP0020)		+= board-igep0020.o \
 obj-$(CONFIG_MACH_OMAP3_TOUCHBOOK)	+= board-omap3touchbook.o \
 					   hsmmc.o
 obj-$(CONFIG_MACH_OMAP_4430SDP)		+= board-4430sdp.o \
-					   hsmmc.o \
-					   omap_phy_internal.o
+					   hsmmc.o
 obj-$(CONFIG_MACH_OMAP4_PANDA)		+= board-omap4panda.o \
-					   hsmmc.o \
-					   omap_phy_internal.o
+					   hsmmc.o
 
-obj-$(CONFIG_MACH_OMAP3517EVM)		+= board-am3517evm.o \
-					   omap_phy_internal.o \
+obj-$(CONFIG_MACH_OMAP3517EVM)		+= board-am3517evm.o
 
 obj-$(CONFIG_MACH_CRANEBOARD)		+= board-am3517crane.o
 
@@ -260,6 +257,8 @@ obj-$(CONFIG_MACH_TI8168EVM)		+= board-ti8168evm.o
 usbfs-$(CONFIG_ARCH_OMAP_OTG)		:= usb-fs.o
 obj-y					+= $(usbfs-m) $(usbfs-y)
 obj-y					+= usb-musb.o
+obj-y					+= omap_phy_internal.o
+
 obj-$(CONFIG_MACH_OMAP2_TUSB6010)	+= usb-tusb6010.o
 obj-y					+= usb-host.o
 

+ 1 - 0
arch/arm/mach-shmobile/board-mackerel.c

@@ -810,6 +810,7 @@ static struct usbhs_private usbhs1_private = {
 		},
 		.driver_param = {
 			.buswait_bwait	= 4,
+			.has_otg	= 1,
 			.pipe_type	= usbhs1_pipe_cfg,
 			.pipe_size	= ARRAY_SIZE(usbhs1_pipe_cfg),
 			.d0_tx_id	= SHDMA_SLAVE_USB1_TX,

+ 15 - 1
drivers/usb/Kconfig

@@ -12,6 +12,11 @@ menuconfig USB_SUPPORT
 
 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 ...
@@ -19,6 +24,7 @@ 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
@@ -54,7 +60,7 @@ config USB_ARCH_HAS_OHCI
 # some non-PCI hcds implement EHCI
 config USB_ARCH_HAS_EHCI
 	boolean
-	default y if PPC_83xx
+	default y if FSL_SOC
 	default y if PPC_MPC512x
 	default y if SOC_AU1200
 	default y if ARCH_IXP4XX
@@ -69,6 +75,12 @@ config USB_ARCH_HAS_EHCI
 	default y if ARCH_MSM
 	default y if MICROBLAZE
 	default y if SPARC_LEON
+	default y if ARCH_MMP
+	default PCI
+
+# some non-PCI HCDs implement xHCI
+config USB_ARCH_HAS_XHCI
+	boolean
 	default PCI
 
 # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
@@ -110,6 +122,8 @@ config USB
 
 source "drivers/usb/core/Kconfig"
 
+source "drivers/usb/dwc3/Kconfig"
+
 source "drivers/usb/mon/Kconfig"
 
 source "drivers/usb/wusbcore/Kconfig"

+ 4 - 0
drivers/usb/Makefile

@@ -6,6 +6,8 @@
 
 obj-$(CONFIG_USB)		+= core/
 
+obj-$(CONFIG_USB_DWC3)		+= dwc3/
+
 obj-$(CONFIG_USB_MON)		+= mon/
 
 obj-$(CONFIG_PCI)		+= host/
@@ -51,3 +53,5 @@ obj-$(CONFIG_USB_MUSB_HDRC)	+= musb/
 obj-$(CONFIG_USB_RENESAS_USBHS)	+= renesas_usbhs/
 obj-$(CONFIG_USB_OTG_UTILS)	+= otg/
 obj-$(CONFIG_USB_GADGET)	+= gadget/
+
+obj-$(CONFIG_USB_COMMON)	+= usb-common.o

+ 6 - 3
drivers/usb/class/cdc-acm.c

@@ -1058,11 +1058,11 @@ made_compressed_probe:
 		goto alloc_fail;
 	}
 
-	ctrlsize = le16_to_cpu(epctrl->wMaxPacketSize);
-	readsize = le16_to_cpu(epread->wMaxPacketSize) *
+	ctrlsize = usb_endpoint_maxp(epctrl);
+	readsize = usb_endpoint_maxp(epread) *
 				(quirks == SINGLE_RX_URB ? 1 : 2);
 	acm->combined_interfaces = combined_interfaces;
-	acm->writesize = le16_to_cpu(epwrite->wMaxPacketSize) * 20;
+	acm->writesize = usb_endpoint_maxp(epwrite) * 20;
 	acm->control = control_interface;
 	acm->data = data_interface;
 	acm->minor = minor;
@@ -1534,6 +1534,9 @@ static const struct usb_device_id acm_ids[] = {
 	{ NOKIA_PCSUITE_ACM_INFO(0x03cd), }, /* Nokia C7 */
 	{ SAMSUNG_PCSUITE_ACM_INFO(0x6651), }, /* Samsung GTi8510 (INNOV8) */
 
+	/* Support for Owen devices */
+	{ USB_DEVICE(0x03eb, 0x0030), }, /* Owen SI30 */
+
 	/* NOTE: non-Nokia COMM/ACM/0xff is likely MSFT RNDIS... NOT a modem! */
 
 	/* Support Lego NXT using pbLua firmware */

+ 1 - 1
drivers/usb/class/cdc-wdm.c

@@ -682,7 +682,7 @@ next_desc:
 	if (!ep || !usb_endpoint_is_int_in(ep))
 		goto err;
 
-	desc->wMaxPacketSize = le16_to_cpu(ep->wMaxPacketSize);
+	desc->wMaxPacketSize = usb_endpoint_maxp(ep);
 	desc->bMaxPacketSize0 = udev->descriptor.bMaxPacketSize0;
 
 	desc->orq = kmalloc(sizeof(struct usb_ctrlrequest), GFP_KERNEL);

+ 2 - 3
drivers/usb/class/usbtmc.c

@@ -186,8 +186,7 @@ static int usbtmc_ioctl_abort_bulk_in(struct usbtmc_device_data *data)
 	for (n = 0; n < current_setting->desc.bNumEndpoints; n++)
 		if (current_setting->endpoint[n].desc.bEndpointAddress ==
 			data->bulk_in)
-			max_size = le16_to_cpu(current_setting->endpoint[n].
-						desc.wMaxPacketSize);
+			max_size = usb_endpoint_maxp(&current_setting->endpoint[n].desc);
 
 	if (max_size == 0) {
 		dev_err(dev, "Couldn't get wMaxPacketSize\n");
@@ -636,7 +635,7 @@ static int usbtmc_ioctl_clear(struct usbtmc_device_data *data)
 	for (n = 0; n < current_setting->desc.bNumEndpoints; n++) {
 		desc = &current_setting->endpoint[n].desc;
 		if (desc->bEndpointAddress == data->bulk_in)
-			max_size = le16_to_cpu(desc->wMaxPacketSize);
+			max_size = usb_endpoint_maxp(desc);
 	}
 
 	if (max_size == 0) {

+ 107 - 4
drivers/usb/core/config.c

@@ -124,9 +124,9 @@ static void usb_parse_ss_endpoint_companion(struct device *ddev, int cfgno,
 
 	if (usb_endpoint_xfer_isoc(&ep->desc))
 		max_tx = (desc->bMaxBurst + 1) * (desc->bmAttributes + 1) *
-			le16_to_cpu(ep->desc.wMaxPacketSize);
+			usb_endpoint_maxp(&ep->desc);
 	else if (usb_endpoint_xfer_int(&ep->desc))
-		max_tx = le16_to_cpu(ep->desc.wMaxPacketSize) *
+		max_tx = usb_endpoint_maxp(&ep->desc) *
 			(desc->bMaxBurst + 1);
 	else
 		max_tx = 999999;
@@ -241,7 +241,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
 		    cfgno, inum, asnum, d->bEndpointAddress);
 		endpoint->desc.bmAttributes = USB_ENDPOINT_XFER_INT;
 		endpoint->desc.bInterval = 1;
-		if (le16_to_cpu(endpoint->desc.wMaxPacketSize) > 8)
+		if (usb_endpoint_maxp(&endpoint->desc) > 8)
 			endpoint->desc.wMaxPacketSize = cpu_to_le16(8);
 	}
 
@@ -254,7 +254,7 @@ static int usb_parse_endpoint(struct device *ddev, int cfgno, int inum,
 			&& usb_endpoint_xfer_bulk(d)) {
 		unsigned maxp;
 
-		maxp = le16_to_cpu(endpoint->desc.wMaxPacketSize) & 0x07ff;
+		maxp = usb_endpoint_maxp(&endpoint->desc) & 0x07ff;
 		if (maxp != 512)
 			dev_warn(ddev, "config %d interface %d altsetting %d "
 				"bulk endpoint 0x%X has invalid maxpacket %d\n",
@@ -755,3 +755,106 @@ err2:
 		dev_err(ddev, "out of memory\n");
 	return result;
 }
+
+void usb_release_bos_descriptor(struct usb_device *dev)
+{
+	if (dev->bos) {
+		kfree(dev->bos->desc);
+		kfree(dev->bos);
+		dev->bos = NULL;
+	}
+}
+
+/* Get BOS descriptor set */
+int usb_get_bos_descriptor(struct usb_device *dev)
+{
+	struct device *ddev = &dev->dev;
+	struct usb_bos_descriptor *bos;
+	struct usb_dev_cap_header *cap;
+	unsigned char *buffer;
+	int length, total_len, num, i;
+	int ret;
+
+	bos = kzalloc(sizeof(struct usb_bos_descriptor), GFP_KERNEL);
+	if (!bos)
+		return -ENOMEM;
+
+	/* Get BOS descriptor */
+	ret = usb_get_descriptor(dev, USB_DT_BOS, 0, bos, USB_DT_BOS_SIZE);
+	if (ret < USB_DT_BOS_SIZE) {
+		dev_err(ddev, "unable to get BOS descriptor\n");
+		if (ret >= 0)
+			ret = -ENOMSG;
+		kfree(bos);
+		return ret;
+	}
+
+	length = bos->bLength;
+	total_len = le16_to_cpu(bos->wTotalLength);
+	num = bos->bNumDeviceCaps;
+	kfree(bos);
+	if (total_len < length)
+		return -EINVAL;
+
+	dev->bos = kzalloc(sizeof(struct usb_host_bos), GFP_KERNEL);
+	if (!dev->bos)
+		return -ENOMEM;
+
+	/* Now let's get the whole BOS descriptor set */
+	buffer = kzalloc(total_len, GFP_KERNEL);
+	if (!buffer) {
+		ret = -ENOMEM;
+		goto err;
+	}
+	dev->bos->desc = (struct usb_bos_descriptor *)buffer;
+
+	ret = usb_get_descriptor(dev, USB_DT_BOS, 0, buffer, total_len);
+	if (ret < total_len) {
+		dev_err(ddev, "unable to get BOS descriptor set\n");
+		if (ret >= 0)
+			ret = -ENOMSG;
+		goto err;
+	}
+	total_len -= length;
+
+	for (i = 0; i < num; i++) {
+		buffer += length;
+		cap = (struct usb_dev_cap_header *)buffer;
+		length = cap->bLength;
+
+		if (total_len < length)
+			break;
+		total_len -= length;
+
+		if (cap->bDescriptorType != USB_DT_DEVICE_CAPABILITY) {
+			dev_warn(ddev, "descriptor type invalid, skip\n");
+			continue;
+		}
+
+		switch (cap->bDevCapabilityType) {
+		case USB_CAP_TYPE_WIRELESS_USB:
+			/* Wireless USB cap descriptor is handled by wusb */
+			break;
+		case USB_CAP_TYPE_EXT:
+			dev->bos->ext_cap =
+				(struct usb_ext_cap_descriptor *)buffer;
+			break;
+		case USB_SS_CAP_TYPE:
+			dev->bos->ss_cap =
+				(struct usb_ss_cap_descriptor *)buffer;
+			break;
+		case CONTAINER_ID_TYPE:
+			dev->bos->ss_id =
+				(struct usb_ss_container_id_descriptor *)buffer;
+			break;
+		default:
+			break;
+		}
+	}
+
+	return 0;
+
+err:
+	usb_release_bos_descriptor(dev);
+	return ret;
+}

+ 2 - 2
drivers/usb/core/devices.c

@@ -190,7 +190,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
 	dir = usb_endpoint_dir_in(desc) ? 'I' : 'O';
 
 	if (speed == USB_SPEED_HIGH) {
-		switch (le16_to_cpu(desc->wMaxPacketSize) & (0x03 << 11)) {
+		switch (usb_endpoint_maxp(desc) & (0x03 << 11)) {
 		case 1 << 11:
 			bandwidth = 2; break;
 		case 2 << 11:
@@ -240,7 +240,7 @@ static char *usb_dump_endpoint_descriptor(int speed, char *start, char *end,
 
 	start += sprintf(start, format_endpt, desc->bEndpointAddress, dir,
 			 desc->bmAttributes, type,
-			 (le16_to_cpu(desc->wMaxPacketSize) & 0x07ff) *
+			 (usb_endpoint_maxp(desc) & 0x07ff) *
 			 bandwidth,
 			 interval, unit);
 	return start;

+ 35 - 22
drivers/usb/core/devio.c

@@ -46,6 +46,7 @@
 #include <linux/cdev.h>
 #include <linux/notifier.h>
 #include <linux/security.h>
+#include <linux/user_namespace.h>
 #include <asm/uaccess.h>
 #include <asm/byteorder.h>
 #include <linux/moduleparam.h>
@@ -68,7 +69,7 @@ struct dev_state {
 	wait_queue_head_t wait;     /* wake up if a request completed */
 	unsigned int discsignr;
 	struct pid *disc_pid;
-	uid_t disc_uid, disc_euid;
+	const struct cred *cred;
 	void __user *disccontext;
 	unsigned long ifclaimed;
 	u32 secid;
@@ -79,7 +80,7 @@ struct async {
 	struct list_head asynclist;
 	struct dev_state *ps;
 	struct pid *pid;
-	uid_t uid, euid;
+	const struct cred *cred;
 	unsigned int signr;
 	unsigned int ifnum;
 	void __user *userbuffer;
@@ -248,6 +249,7 @@ static struct async *alloc_async(unsigned int numisoframes)
 static void free_async(struct async *as)
 {
 	put_pid(as->pid);
+	put_cred(as->cred);
 	kfree(as->urb->transfer_buffer);
 	kfree(as->urb->setup_packet);
 	usb_free_urb(as->urb);
@@ -393,9 +395,8 @@ static void async_completed(struct urb *urb)
 	struct dev_state *ps = as->ps;
 	struct siginfo sinfo;
 	struct pid *pid = NULL;
-	uid_t uid = 0;
-	uid_t euid = 0;
 	u32 secid = 0;
+	const struct cred *cred = NULL;
 	int signr;
 
 	spin_lock(&ps->lock);
@@ -407,9 +408,8 @@ static void async_completed(struct urb *urb)
 		sinfo.si_errno = as->status;
 		sinfo.si_code = SI_ASYNCIO;
 		sinfo.si_addr = as->userurb;
-		pid = as->pid;
-		uid = as->uid;
-		euid = as->euid;
+		pid = get_pid(as->pid);
+		cred = get_cred(as->cred);
 		secid = as->secid;
 	}
 	snoop(&urb->dev->dev, "urb complete\n");
@@ -422,9 +422,11 @@ static void async_completed(struct urb *urb)
 		cancel_bulk_urbs(ps, as->bulk_addr);
 	spin_unlock(&ps->lock);
 
-	if (signr)
-		kill_pid_info_as_uid(sinfo.si_signo, &sinfo, pid, uid,
-				      euid, secid);
+	if (signr) {
+		kill_pid_info_as_cred(sinfo.si_signo, &sinfo, pid, cred, secid);
+		put_pid(pid);
+		put_cred(cred);
+	}
 
 	wake_up(&ps->wait);
 }
@@ -607,9 +609,10 @@ static int findintfep(struct usb_device *dev, unsigned int ep)
 }
 
 static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
-			   unsigned int index)
+			   unsigned int request, unsigned int index)
 {
 	int ret = 0;
+	struct usb_host_interface *alt_setting;
 
 	if (ps->dev->state != USB_STATE_UNAUTHENTICATED
 	 && ps->dev->state != USB_STATE_ADDRESS
@@ -618,6 +621,19 @@ static int check_ctrlrecip(struct dev_state *ps, unsigned int requesttype,
 	if (USB_TYPE_VENDOR == (USB_TYPE_MASK & requesttype))
 		return 0;
 
+	/*
+	 * check for the special corner case 'get_device_id' in the printer
+	 * class specification, where wIndex is (interface << 8 | altsetting)
+	 * instead of just interface
+	 */
+	if (requesttype == 0xa1 && request == 0) {
+		alt_setting = usb_find_alt_setting(ps->dev->actconfig,
+						   index >> 8, index & 0xff);
+		if (alt_setting
+		 && alt_setting->desc.bInterfaceClass == USB_CLASS_PRINTER)
+			index >>= 8;
+	}
+
 	index &= 0xff;
 	switch (requesttype & USB_RECIP_MASK) {
 	case USB_RECIP_ENDPOINT:
@@ -656,7 +672,6 @@ static int usbdev_open(struct inode *inode, struct file *file)
 {
 	struct usb_device *dev = NULL;
 	struct dev_state *ps;
-	const struct cred *cred = current_cred();
 	int ret;
 
 	ret = -ENOMEM;
@@ -706,8 +721,7 @@ static int usbdev_open(struct inode *inode, struct file *file)
 	init_waitqueue_head(&ps->wait);
 	ps->discsignr = 0;
 	ps->disc_pid = get_pid(task_pid(current));
-	ps->disc_uid = cred->uid;
-	ps->disc_euid = cred->euid;
+	ps->cred = get_current_cred();
 	ps->disccontext = NULL;
 	ps->ifclaimed = 0;
 	security_task_getsecid(current, &ps->secid);
@@ -749,6 +763,7 @@ static int usbdev_release(struct inode *inode, struct file *file)
 	usb_unlock_device(dev);
 	usb_put_dev(dev);
 	put_pid(ps->disc_pid);
+	put_cred(ps->cred);
 
 	as = async_getcompleted(ps);
 	while (as) {
@@ -770,7 +785,8 @@ static int proc_control(struct dev_state *ps, void __user *arg)
 
 	if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
 		return -EFAULT;
-	ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.wIndex);
+	ret = check_ctrlrecip(ps, ctrl.bRequestType, ctrl.bRequest,
+			      ctrl.wIndex);
 	if (ret)
 		return ret;
 	wLength = ctrl.wLength;		/* To suppress 64k PAGE_SIZE warning */
@@ -1048,7 +1064,6 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 	struct usb_host_endpoint *ep;
 	struct async *as;
 	struct usb_ctrlrequest *dr = NULL;
-	const struct cred *cred = current_cred();
 	unsigned int u, totlen, isofrmlen;
 	int ret, ifnum = -1;
 	int is_in;
@@ -1100,7 +1115,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 			kfree(dr);
 			return -EINVAL;
 		}
-		ret = check_ctrlrecip(ps, dr->bRequestType,
+		ret = check_ctrlrecip(ps, dr->bRequestType, dr->bRequest,
 				      le16_to_cpup(&dr->wIndex));
 		if (ret) {
 			kfree(dr);
@@ -1262,8 +1277,7 @@ static int proc_do_submiturb(struct dev_state *ps, struct usbdevfs_urb *uurb,
 	as->signr = uurb->signr;
 	as->ifnum = ifnum;
 	as->pid = get_pid(task_pid(current));
-	as->uid = cred->uid;
-	as->euid = cred->euid;
+	as->cred = get_current_cred();
 	security_task_getsecid(current, &as->secid);
 	if (!is_in && uurb->buffer_length > 0) {
 		if (copy_from_user(as->urb->transfer_buffer, uurb->buffer,
@@ -1981,9 +1995,8 @@ static void usbdev_remove(struct usb_device *udev)
 			sinfo.si_errno = EPIPE;
 			sinfo.si_code = SI_ASYNCIO;
 			sinfo.si_addr = ps->disccontext;
-			kill_pid_info_as_uid(ps->discsignr, &sinfo,
-					ps->disc_pid, ps->disc_uid,
-					ps->disc_euid, ps->secid);
+			kill_pid_info_as_cred(ps->discsignr, &sinfo,
+					ps->disc_pid, ps->cred, ps->secid);
 		}
 	}
 }

+ 15 - 1
drivers/usb/core/driver.c

@@ -1583,7 +1583,7 @@ int usb_autopm_get_interface_async(struct usb_interface *intf)
 	dev_vdbg(&intf->dev, "%s: cnt %d -> %d\n",
 			__func__, atomic_read(&intf->dev.power.usage_count),
 			status);
-	if (status > 0)
+	if (status > 0 || status == -EINPROGRESS)
 		status = 0;
 	return status;
 }
@@ -1700,6 +1700,20 @@ int usb_runtime_idle(struct device *dev)
 	return 0;
 }
 
+int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
+{
+	struct usb_hcd *hcd = bus_to_hcd(udev->bus);
+	int ret = -EPERM;
+
+	if (hcd->driver->set_usb2_hw_lpm) {
+		ret = hcd->driver->set_usb2_hw_lpm(hcd, udev, enable);
+		if (!ret)
+			udev->usb2_hw_lpm_enabled = enable;
+	}
+
+	return ret;
+}
+
 #endif /* CONFIG_USB_SUSPEND */
 
 struct bus_type usb_bus_type = {

+ 1 - 1
drivers/usb/core/endpoint.c

@@ -56,7 +56,7 @@ static ssize_t show_ep_wMaxPacketSize(struct device *dev,
 {
 	struct ep_device *ep = to_ep_device(dev);
 	return sprintf(buf, "%04x\n",
-			le16_to_cpu(ep->desc->wMaxPacketSize) & 0x07ff);
+		        usb_endpoint_maxp(ep->desc) & 0x07ff);
 }
 static DEVICE_ATTR(wMaxPacketSize, S_IRUGO, show_ep_wMaxPacketSize, NULL);
 

+ 1 - 1
drivers/usb/core/hcd-pci.c

@@ -242,7 +242,7 @@ int usb_hcd_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
 
 	pci_set_master(dev);
 
-	retval = usb_add_hcd(hcd, dev->irq, IRQF_DISABLED | IRQF_SHARED);
+	retval = usb_add_hcd(hcd, dev->irq, IRQF_SHARED);
 	if (retval != 0)
 		goto unmap_registers;
 	set_hs_companion(dev, hcd);

+ 24 - 3
drivers/usb/core/hcd.c

@@ -442,7 +442,11 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
 	struct usb_ctrlrequest *cmd;
  	u16		typeReq, wValue, wIndex, wLength;
 	u8		*ubuf = urb->transfer_buffer;
-	u8		tbuf [sizeof (struct usb_hub_descriptor)]
+	/*
+	 * tbuf should be as big as the BOS descriptor and
+	 * the USB hub descriptor.
+	 */
+	u8		tbuf[USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE]
 		__attribute__((aligned(4)));
 	const u8	*bufp = tbuf;
 	unsigned	len = 0;
@@ -562,6 +566,8 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
 			else /* unsupported IDs --> "protocol stall" */
 				goto error;
 			break;
+		case USB_DT_BOS << 8:
+			goto nongeneric;
 		default:
 			goto error;
 		}
@@ -596,6 +602,7 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
 	/* CLASS REQUESTS (and errors) */
 
 	default:
+nongeneric:
 		/* non-generic request */
 		switch (typeReq) {
 		case GetHubStatus:
@@ -605,6 +612,9 @@ static int rh_call_control (struct usb_hcd *hcd, struct urb *urb)
 		case GetHubDescriptor:
 			len = sizeof (struct usb_hub_descriptor);
 			break;
+		case DeviceRequest | USB_REQ_GET_DESCRIPTOR:
+			/* len is returned by hub_control */
+			break;
 		}
 		status = hcd->driver->hub_control (hcd,
 			typeReq, wValue, wIndex,
@@ -615,7 +625,7 @@ error:
 		status = -EPIPE;
 	}
 
-	if (status) {
+	if (status < 0) {
 		len = 0;
 		if (status != -EPIPE) {
 			dev_dbg (hcd->self.controller,
@@ -624,6 +634,10 @@ error:
 				typeReq, wValue, wIndex,
 				wLength, status);
 		}
+	} else if (status > 0) {
+		/* hub_control may return the length of data copied. */
+		len = status;
+		status = 0;
 	}
 	if (len) {
 		if (urb->transfer_buffer_length < len)
@@ -2429,7 +2443,7 @@ int usb_add_hcd(struct usb_hcd *hcd,
 	 * but drivers can override it in reset() if needed, along with
 	 * recording the overall controller's system wakeup capability.
 	 */
-	device_init_wakeup(&rhdev->dev, 1);
+	device_set_wakeup_capable(&rhdev->dev, 1);
 
 	/* HCD_FLAG_RH_RUNNING doesn't matter until the root hub is
 	 * registered.  But since the controller can die at any time,
@@ -2478,6 +2492,13 @@ int usb_add_hcd(struct usb_hcd *hcd,
 	}
 	if (hcd->uses_new_polling && HCD_POLL_RH(hcd))
 		usb_hcd_poll_rh_status(hcd);
+
+	/*
+	 * Host controllers don't generate their own wakeup requests;
+	 * they only forward requests from the root hub.  Therefore
+	 * controllers should always be enabled for remote wakeup.
+	 */
+	device_wakeup_enable(hcd->self.controller);
 	return retval;
 
 error_create_attr_group:

+ 183 - 128
drivers/usb/core/hub.c

@@ -1636,11 +1636,6 @@ void usb_disconnect(struct usb_device **pdev)
 	int			i;
 	struct usb_hcd		*hcd = bus_to_hcd(udev->bus);
 
-	if (!udev) {
-		pr_debug ("%s nodev\n", __func__);
-		return;
-	}
-
 	/* mark the device as inactive, so any further urb submissions for
 	 * this device (and any of its children) will fail immediately.
 	 * this quiesces everything except pending urbs.
@@ -2030,11 +2025,23 @@ static unsigned hub_is_wusb(struct usb_hub *hub)
 
 #define HUB_ROOT_RESET_TIME	50	/* times are in msec */
 #define HUB_SHORT_RESET_TIME	10
+#define HUB_BH_RESET_TIME	50
 #define HUB_LONG_RESET_TIME	200
 #define HUB_RESET_TIMEOUT	500
 
+static int hub_port_reset(struct usb_hub *hub, int port1,
+			struct usb_device *udev, unsigned int delay, bool warm);
+
+/* Is a USB 3.0 port in the Inactive state? */
+static bool hub_port_inactive(struct usb_hub *hub, u16 portstatus)
+{
+	return hub_is_superspeed(hub->hdev) &&
+		(portstatus & USB_PORT_STAT_LINK_STATE) ==
+		USB_SS_PORT_LS_SS_INACTIVE;
+}
+
 static int hub_port_wait_reset(struct usb_hub *hub, int port1,
-				struct usb_device *udev, unsigned int delay)
+			struct usb_device *udev, unsigned int delay, bool warm)
 {
 	int delay_time, ret;
 	u16 portstatus;
@@ -2051,28 +2058,71 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
 		if (ret < 0)
 			return ret;
 
-		/* Device went away? */
-		if (!(portstatus & USB_PORT_STAT_CONNECTION))
-			return -ENOTCONN;
-
-		/* bomb out completely if the connection bounced */
-		if ((portchange & USB_PORT_STAT_C_CONNECTION))
-			return -ENOTCONN;
-
-		/* if we`ve finished resetting, then break out of the loop */
-		if (!(portstatus & USB_PORT_STAT_RESET) &&
-		    (portstatus & USB_PORT_STAT_ENABLE)) {
-			if (hub_is_wusb(hub))
-				udev->speed = USB_SPEED_WIRELESS;
-			else if (hub_is_superspeed(hub->hdev))
-				udev->speed = USB_SPEED_SUPER;
-			else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
-				udev->speed = USB_SPEED_HIGH;
-			else if (portstatus & USB_PORT_STAT_LOW_SPEED)
-				udev->speed = USB_SPEED_LOW;
-			else
-				udev->speed = USB_SPEED_FULL;
-			return 0;
+		/*
+		 * Some buggy devices require a warm reset to be issued even
+		 * when the port appears not to be connected.
+		 */
+		if (!warm) {
+			/*
+			 * Some buggy devices can cause an NEC host controller
+			 * to transition to the "Error" state after a hot port
+			 * reset.  This will show up as the port state in
+			 * "Inactive", and the port may also report a
+			 * disconnect.  Forcing a warm port reset seems to make
+			 * the device work.
+			 *
+			 * See https://bugzilla.kernel.org/show_bug.cgi?id=41752
+			 */
+			if (hub_port_inactive(hub, portstatus)) {
+				int ret;
+
+				if ((portchange & USB_PORT_STAT_C_CONNECTION))
+					clear_port_feature(hub->hdev, port1,
+							USB_PORT_FEAT_C_CONNECTION);
+				if (portchange & USB_PORT_STAT_C_LINK_STATE)
+					clear_port_feature(hub->hdev, port1,
+							USB_PORT_FEAT_C_PORT_LINK_STATE);
+				if (portchange & USB_PORT_STAT_C_RESET)
+					clear_port_feature(hub->hdev, port1,
+							USB_PORT_FEAT_C_RESET);
+				dev_dbg(hub->intfdev, "hot reset failed, warm reset port %d\n",
+						port1);
+				ret = hub_port_reset(hub, port1,
+						udev, HUB_BH_RESET_TIME,
+						true);
+				if ((portchange & USB_PORT_STAT_C_CONNECTION))
+					clear_port_feature(hub->hdev, port1,
+							USB_PORT_FEAT_C_CONNECTION);
+				return ret;
+			}
+			/* Device went away? */
+			if (!(portstatus & USB_PORT_STAT_CONNECTION))
+				return -ENOTCONN;
+
+			/* bomb out completely if the connection bounced */
+			if ((portchange & USB_PORT_STAT_C_CONNECTION))
+				return -ENOTCONN;
+
+			/* if we`ve finished resetting, then break out of
+			 * the loop
+			 */
+			if (!(portstatus & USB_PORT_STAT_RESET) &&
+			    (portstatus & USB_PORT_STAT_ENABLE)) {
+				if (hub_is_wusb(hub))
+					udev->speed = USB_SPEED_WIRELESS;
+				else if (hub_is_superspeed(hub->hdev))
+					udev->speed = USB_SPEED_SUPER;
+				else if (portstatus & USB_PORT_STAT_HIGH_SPEED)
+					udev->speed = USB_SPEED_HIGH;
+				else if (portstatus & USB_PORT_STAT_LOW_SPEED)
+					udev->speed = USB_SPEED_LOW;
+				else
+					udev->speed = USB_SPEED_FULL;
+				return 0;
+			}
+		} else {
+			if (portchange & USB_PORT_STAT_C_BH_RESET)
+				return 0;
 		}
 
 		/* switch to the long delay after two short delay failures */
@@ -2080,35 +2130,84 @@ static int hub_port_wait_reset(struct usb_hub *hub, int port1,
 			delay = HUB_LONG_RESET_TIME;
 
 		dev_dbg (hub->intfdev,
-			"port %d not reset yet, waiting %dms\n",
-			port1, delay);
+			"port %d not %sreset yet, waiting %dms\n",
+			port1, warm ? "warm " : "", delay);
 	}
 
 	return -EBUSY;
 }
 
+static void hub_port_finish_reset(struct usb_hub *hub, int port1,
+			struct usb_device *udev, int *status, bool warm)
+{
+	switch (*status) {
+	case 0:
+		if (!warm) {
+			struct usb_hcd *hcd;
+			/* TRSTRCY = 10 ms; plus some extra */
+			msleep(10 + 40);
+			update_devnum(udev, 0);
+			hcd = bus_to_hcd(udev->bus);
+			if (hcd->driver->reset_device) {
+				*status = hcd->driver->reset_device(hcd, udev);
+				if (*status < 0) {
+					dev_err(&udev->dev, "Cannot reset "
+							"HCD device state\n");
+					break;
+				}
+			}
+		}
+		/* FALL THROUGH */
+	case -ENOTCONN:
+	case -ENODEV:
+		clear_port_feature(hub->hdev,
+				port1, USB_PORT_FEAT_C_RESET);
+		/* FIXME need disconnect() for NOTATTACHED device */
+		if (warm) {
+			clear_port_feature(hub->hdev, port1,
+					USB_PORT_FEAT_C_BH_PORT_RESET);
+			clear_port_feature(hub->hdev, port1,
+					USB_PORT_FEAT_C_PORT_LINK_STATE);
+		} else {
+			usb_set_device_state(udev, *status
+					? USB_STATE_NOTATTACHED
+					: USB_STATE_DEFAULT);
+		}
+		break;
+	}
+}
+
+/* Handle port reset and port warm(BH) reset (for USB3 protocol ports) */
 static int hub_port_reset(struct usb_hub *hub, int port1,
-				struct usb_device *udev, unsigned int delay)
+			struct usb_device *udev, unsigned int delay, bool warm)
 {
 	int i, status;
-	struct usb_hcd *hcd;
 
-	hcd = bus_to_hcd(udev->bus);
-	/* Block EHCI CF initialization during the port reset.
-	 * Some companion controllers don't like it when they mix.
-	 */
-	down_read(&ehci_cf_port_reset_rwsem);
+	if (!warm) {
+		/* Block EHCI CF initialization during the port reset.
+		 * Some companion controllers don't like it when they mix.
+		 */
+		down_read(&ehci_cf_port_reset_rwsem);
+	} else {
+		if (!hub_is_superspeed(hub->hdev)) {
+			dev_err(hub->intfdev, "only USB3 hub support "
+						"warm reset\n");
+			return -EINVAL;
+		}
+	}
 
 	/* Reset the port */
 	for (i = 0; i < PORT_RESET_TRIES; i++) {
-		status = set_port_feature(hub->hdev,
-				port1, USB_PORT_FEAT_RESET);
-		if (status)
+		status = set_port_feature(hub->hdev, port1, (warm ?
+					USB_PORT_FEAT_BH_PORT_RESET :
+					USB_PORT_FEAT_RESET));
+		if (status) {
 			dev_err(hub->intfdev,
-					"cannot reset port %d (err = %d)\n",
-					port1, status);
-		else {
-			status = hub_port_wait_reset(hub, port1, udev, delay);
+					"cannot %sreset port %d (err = %d)\n",
+					warm ? "warm " : "", port1, status);
+		} else {
+			status = hub_port_wait_reset(hub, port1, udev, delay,
+								warm);
 			if (status && status != -ENOTCONN)
 				dev_dbg(hub->intfdev,
 						"port_wait_reset: err = %d\n",
@@ -2116,34 +2215,14 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 		}
 
 		/* return on disconnect or reset */
-		switch (status) {
-		case 0:
-			/* TRSTRCY = 10 ms; plus some extra */
-			msleep(10 + 40);
-			update_devnum(udev, 0);
-			if (hcd->driver->reset_device) {
-				status = hcd->driver->reset_device(hcd, udev);
-				if (status < 0) {
-					dev_err(&udev->dev, "Cannot reset "
-							"HCD device state\n");
-					break;
-				}
-			}
-			/* FALL THROUGH */
-		case -ENOTCONN:
-		case -ENODEV:
-			clear_port_feature(hub->hdev,
-				port1, USB_PORT_FEAT_C_RESET);
-			/* FIXME need disconnect() for NOTATTACHED device */
-			usb_set_device_state(udev, status
-					? USB_STATE_NOTATTACHED
-					: USB_STATE_DEFAULT);
+		if (status == 0 || status == -ENOTCONN || status == -ENODEV) {
+			hub_port_finish_reset(hub, port1, udev, &status, warm);
 			goto done;
 		}
 
 		dev_dbg (hub->intfdev,
-			"port %d not enabled, trying reset again...\n",
-			port1);
+			"port %d not enabled, trying %sreset again...\n",
+			port1, warm ? "warm " : "");
 		delay = HUB_LONG_RESET_TIME;
 	}
 
@@ -2151,45 +2230,11 @@ static int hub_port_reset(struct usb_hub *hub, int port1,
 		"Cannot enable port %i.  Maybe the USB cable is bad?\n",
 		port1);
 
- done:
-	up_read(&ehci_cf_port_reset_rwsem);
-	return status;
-}
-
-/* Warm reset a USB3 protocol port */
-static int hub_port_warm_reset(struct usb_hub *hub, int port)
-{
-	int ret;
-	u16 portstatus, portchange;
-
-	if (!hub_is_superspeed(hub->hdev)) {
-		dev_err(hub->intfdev, "only USB3 hub support warm reset\n");
-		return -EINVAL;
-	}
-
-	/* Warm reset the port */
-	ret = set_port_feature(hub->hdev,
-				port, USB_PORT_FEAT_BH_PORT_RESET);
-	if (ret) {
-		dev_err(hub->intfdev, "cannot warm reset port %d\n", port);
-		return ret;
-	}
-
-	msleep(20);
-	ret = hub_port_status(hub, port, &portstatus, &portchange);
-
-	if (portchange & USB_PORT_STAT_C_RESET)
-		clear_port_feature(hub->hdev, port, USB_PORT_FEAT_C_RESET);
-
-	if (portchange & USB_PORT_STAT_C_BH_RESET)
-		clear_port_feature(hub->hdev, port,
-					USB_PORT_FEAT_C_BH_PORT_RESET);
-
-	if (portchange & USB_PORT_STAT_C_LINK_STATE)
-		clear_port_feature(hub->hdev, port,
-					USB_PORT_FEAT_C_PORT_LINK_STATE);
+done:
+	if (!warm)
+		up_read(&ehci_cf_port_reset_rwsem);
 
-	return ret;
+	return status;
 }
 
 /* Check if a port is power on */
@@ -2347,6 +2392,10 @@ int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
 		}
 	}
 
+	/* disable USB2 hardware LPM */
+	if (udev->usb2_hw_lpm_enabled == 1)
+		usb_set_usb2_hardware_lpm(udev, 0);
+
 	/* see 7.1.7.6 */
 	if (hub_is_superspeed(hub->hdev))
 		status = set_port_feature(hub->hdev,
@@ -2558,7 +2607,12 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
 	if (status < 0) {
 		dev_dbg(&udev->dev, "can't resume, status %d\n", status);
 		hub_port_logical_disconnect(hub, port1);
+	} else  {
+		/* Try to enable USB2 hardware LPM */
+		if (udev->usb2_hw_lpm_capable == 1)
+			usb_set_usb2_hardware_lpm(udev, 1);
 	}
+
 	return status;
 }
 
@@ -2798,7 +2852,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 	int			i, j, retval;
 	unsigned		delay = HUB_SHORT_RESET_TIME;
 	enum usb_device_speed	oldspeed = udev->speed;
-	char 			*speed, *type;
+	const char		*speed;
 	int			devnum = udev->devnum;
 
 	/* root hub ports have a slightly longer reset period
@@ -2819,7 +2873,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 
 	/* Reset the device; full speed may morph to high speed */
 	/* FIXME a USB 2.0 device may morph into SuperSpeed on reset. */
-	retval = hub_port_reset(hub, port1, udev, delay);
+	retval = hub_port_reset(hub, port1, udev, delay, false);
 	if (retval < 0)		/* error or disconnect */
 		goto fail;
 	/* success, speed is known */
@@ -2858,25 +2912,16 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 	default:
 		goto fail;
 	}
- 
-	type = "";
-	switch (udev->speed) {
-	case USB_SPEED_LOW:	speed = "low";	break;
-	case USB_SPEED_FULL:	speed = "full";	break;
-	case USB_SPEED_HIGH:	speed = "high";	break;
-	case USB_SPEED_SUPER:
-				speed = "super";
-				break;
-	case USB_SPEED_WIRELESS:
-				speed = "variable";
-				type = "Wireless ";
-				break;
-	default: 		speed = "?";	break;
-	}
+
+	if (udev->speed == USB_SPEED_WIRELESS)
+		speed = "variable speed Wireless";
+	else
+		speed = usb_speed_string(udev->speed);
+
 	if (udev->speed != USB_SPEED_SUPER)
 		dev_info(&udev->dev,
-				"%s %s speed %sUSB device number %d using %s\n",
-				(udev->config) ? "reset" : "new", speed, type,
+				"%s %s USB device number %d using %s\n",
+				(udev->config) ? "reset" : "new", speed,
 				devnum, udev->bus->controller->driver->name);
 
 	/* Set up TT records, if needed  */
@@ -2949,7 +2994,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 					buf->bMaxPacketSize0;
 			kfree(buf);
 
-			retval = hub_port_reset(hub, port1, udev, delay);
+			retval = hub_port_reset(hub, port1, udev, delay, false);
 			if (retval < 0)		/* error or disconnect */
 				goto fail;
 			if (oldspeed != udev->speed) {
@@ -3023,7 +3068,7 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 		i = 512;
 	else
 		i = udev->descriptor.bMaxPacketSize0;
-	if (le16_to_cpu(udev->ep0.desc.wMaxPacketSize) != i) {
+	if (usb_endpoint_maxp(&udev->ep0.desc) != i) {
 		if (udev->speed == USB_SPEED_LOW ||
 				!(i == 8 || i == 16 || i == 32 || i == 64)) {
 			dev_err(&udev->dev, "Invalid ep0 maxpacket: %d\n", i);
@@ -3047,6 +3092,15 @@ hub_port_init (struct usb_hub *hub, struct usb_device *udev, int port1,
 		goto fail;
 	}
 
+	if (udev->wusb == 0 && le16_to_cpu(udev->descriptor.bcdUSB) >= 0x0201) {
+		retval = usb_get_bos_descriptor(udev);
+		if (!retval) {
+			if (udev->bos->ext_cap && (USB_LPM_SUPPORT &
+				le32_to_cpu(udev->bos->ext_cap->bmAttributes)))
+					udev->lpm_capable = 1;
+		}
+	}
+
 	retval = 0;
 	/* notify HCD that we have a device connected and addressed */
 	if (hcd->driver->update_device)
@@ -3570,7 +3624,8 @@ static void hub_events(void)
 				(portstatus & USB_PORT_STAT_LINK_STATE)
 					== USB_SS_PORT_LS_SS_INACTIVE) {
 				dev_dbg(hub_dev, "warm reset port %d\n", i);
-				hub_port_warm_reset(hub, i);
+				hub_port_reset(hub, i, NULL,
+						HUB_BH_RESET_TIME, true);
 			}
 
 			if (connect_change)

+ 1 - 1
drivers/usb/core/message.c

@@ -435,7 +435,7 @@ int usb_sg_init(struct usb_sg_request *io, struct usb_device *dev,
 
 			len = sg->length;
 			if (length) {
-				len = min_t(unsigned, len, length);
+				len = min_t(size_t, len, length);
 				length -= len;
 				if (length == 0)
 					io->entries = i + 1;

+ 24 - 0
drivers/usb/core/quirks.c

@@ -38,6 +38,27 @@ static const struct usb_device_id usb_quirk_list[] = {
 	/* Creative SB Audigy 2 NX */
 	{ USB_DEVICE(0x041e, 0x3020), .driver_info = USB_QUIRK_RESET_RESUME },
 
+	/* Logitech Webcam C200 */
+	{ USB_DEVICE(0x046d, 0x0802), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Webcam C250 */
+	{ USB_DEVICE(0x046d, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Webcam C300 */
+	{ USB_DEVICE(0x046d, 0x0805), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Webcam B/C500 */
+	{ USB_DEVICE(0x046d, 0x0807), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Webcam Pro 9000 */
+	{ USB_DEVICE(0x046d, 0x0809), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Webcam C310 */
+	{ USB_DEVICE(0x046d, 0x081b), .driver_info = USB_QUIRK_RESET_RESUME },
+
+	/* Logitech Webcam C270 */
+	{ USB_DEVICE(0x046d, 0x0825), .driver_info = USB_QUIRK_RESET_RESUME },
+
 	/* Logitech Harmony 700-series */
 	{ USB_DEVICE(0x046d, 0xc122), .driver_info = USB_QUIRK_DELAY_INIT },
 
@@ -69,6 +90,9 @@ static const struct usb_device_id usb_quirk_list[] = {
 	{ USB_DEVICE(0x06a3, 0x0006), .driver_info =
 			USB_QUIRK_CONFIG_INTF_STRINGS },
 
+	/* Guillemot Webcam Hercules Dualpix Exchange*/
+	{ USB_DEVICE(0x06f8, 0x0804), .driver_info = USB_QUIRK_RESET_RESUME },
+
 	/* M-Systems Flash Disk Pioneers */
 	{ USB_DEVICE(0x08ec, 0x1000), .driver_info = USB_QUIRK_RESET_RESUME },
 

+ 58 - 1
drivers/usb/core/sysfs.c

@@ -412,6 +412,56 @@ set_level(struct device *dev, struct device_attribute *attr,
 
 static DEVICE_ATTR(level, S_IRUGO | S_IWUSR, show_level, set_level);
 
+static ssize_t
+show_usb2_hardware_lpm(struct device *dev, struct device_attribute *attr,
+				char *buf)
+{
+	struct usb_device *udev = to_usb_device(dev);
+	const char *p;
+
+	if (udev->usb2_hw_lpm_enabled == 1)
+		p = "enabled";
+	else
+		p = "disabled";
+
+	return sprintf(buf, "%s\n", p);
+}
+
+static ssize_t
+set_usb2_hardware_lpm(struct device *dev, struct device_attribute *attr,
+		const char *buf, size_t count)
+{
+	struct usb_device *udev = to_usb_device(dev);
+	bool value;
+	int ret;
+
+	usb_lock_device(udev);
+
+	ret = strtobool(buf, &value);
+
+	if (!ret)
+		ret = usb_set_usb2_hardware_lpm(udev, value);
+
+	usb_unlock_device(udev);
+
+	if (!ret)
+		return count;
+
+	return ret;
+}
+
+static DEVICE_ATTR(usb2_hardware_lpm, S_IRUGO | S_IWUSR, show_usb2_hardware_lpm,
+			set_usb2_hardware_lpm);
+
+static struct attribute *usb2_hardware_lpm_attr[] = {
+	&dev_attr_usb2_hardware_lpm.attr,
+	NULL,
+};
+static struct attribute_group usb2_hardware_lpm_attr_group = {
+	.name	= power_group_name,
+	.attrs	= usb2_hardware_lpm_attr,
+};
+
 static struct attribute *power_attrs[] = {
 	&dev_attr_autosuspend.attr,
 	&dev_attr_level.attr,
@@ -428,13 +478,20 @@ static int add_power_attributes(struct device *dev)
 {
 	int rc = 0;
 
-	if (is_usb_device(dev))
+	if (is_usb_device(dev)) {
+		struct usb_device *udev = to_usb_device(dev);
 		rc = sysfs_merge_group(&dev->kobj, &power_attr_group);
+		if (udev->usb2_hw_lpm_capable == 1)
+			rc = sysfs_merge_group(&dev->kobj,
+					&usb2_hardware_lpm_attr_group);
+	}
+
 	return rc;
 }
 
 static void remove_power_attributes(struct device *dev)
 {
+	sysfs_unmerge_group(&dev->kobj, &usb2_hardware_lpm_attr_group);
 	sysfs_unmerge_group(&dev->kobj, &power_attr_group);
 }
 

+ 1 - 1
drivers/usb/core/urb.c

@@ -350,7 +350,7 @@ int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
 			dev->state < USB_STATE_CONFIGURED)
 		return -ENODEV;
 
-	max = le16_to_cpu(ep->desc.wMaxPacketSize);
+	max = usb_endpoint_maxp(&ep->desc);
 	if (max <= 0) {
 		dev_dbg(&dev->dev,
 			"bogus endpoint ep%d%s in %s (bad maxpacket %d)\n",

+ 1 - 0
drivers/usb/core/usb.c

@@ -225,6 +225,7 @@ static void usb_release_dev(struct device *dev)
 	hcd = bus_to_hcd(udev->bus);
 
 	usb_destroy_configuration(udev);
+	usb_release_bos_descriptor(udev);
 	usb_put_hcd(hcd);
 	kfree(udev->product);
 	kfree(udev->manufacturer);

+ 7 - 0
drivers/usb/core/usb.h

@@ -28,6 +28,8 @@ extern int usb_remove_device(struct usb_device *udev);
 
 extern int usb_get_device_descriptor(struct usb_device *dev,
 		unsigned int size);
+extern int usb_get_bos_descriptor(struct usb_device *dev);
+extern void usb_release_bos_descriptor(struct usb_device *dev);
 extern char *usb_cache_string(struct usb_device *udev, int index);
 extern int usb_set_configuration(struct usb_device *dev, int configuration);
 extern int usb_choose_configuration(struct usb_device *udev);
@@ -80,6 +82,7 @@ extern int usb_remote_wakeup(struct usb_device *dev);
 extern int usb_runtime_suspend(struct device *dev);
 extern int usb_runtime_resume(struct device *dev);
 extern int usb_runtime_idle(struct device *dev);
+extern int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable);
 
 #else
 
@@ -94,6 +97,10 @@ static inline int usb_remote_wakeup(struct usb_device *udev)
 	return 0;
 }
 
+static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
+{
+	return 0;
+}
 #endif
 
 extern struct bus_type usb_bus_type;

+ 25 - 0
drivers/usb/dwc3/Kconfig

@@ -0,0 +1,25 @@
+config USB_DWC3
+	tristate "DesignWare USB3 DRD Core Support"
+	depends on (USB || USB_GADGET)
+	select USB_OTG_UTILS
+	help
+	  Say Y or M here if your system has a Dual Role SuperSpeed
+	  USB controller based on the DesignWare USB3 IP Core.
+
+	  If you choose to build this driver is a dynamically linked
+	  module, the module will be called dwc3.ko.
+
+if USB_DWC3
+
+config USB_DWC3_DEBUG
+	bool "Enable Debugging Messages"
+	help
+	  Say Y here to enable debugging messages on DWC3 Driver.
+
+config USB_DWC3_VERBOSE
+	bool "Enable Verbose Debugging Messages"
+	depends on USB_DWC3_DEBUG
+	help
+	  Say Y here to enable verbose debugging messages on DWC3 Driver.
+
+endif

+ 36 - 0
drivers/usb/dwc3/Makefile

@@ -0,0 +1,36 @@
+ccflags-$(CONFIG_USB_DWC3_DEBUG)	:= -DDEBUG
+ccflags-$(CONFIG_USB_DWC3_VERBOSE)	+= -DVERBOSE_DEBUG
+
+obj-$(CONFIG_USB_DWC3)			+= dwc3.o
+
+dwc3-y					:= core.o
+
+ifneq ($(CONFIG_USB_GADGET_DWC3),)
+	dwc3-y				+= gadget.o ep0.o
+endif
+
+ifneq ($(CONFIG_DEBUG_FS),)
+	dwc3-y				+= debugfs.o
+endif
+
+##
+# Platform-specific glue layers go here
+#
+# NOTICE: Make sure your glue layer doesn't depend on anything
+# which is arch-specific and that it compiles on all situations.
+#
+# We want to keep this requirement in order to be able to compile
+# the entire driver (with all its glue layers) on several architectures
+# and make sure it compiles fine. This will also help with allmodconfig
+# and allyesconfig builds.
+#
+# The only exception is the PCI glue layer, but that's only because
+# PCI doesn't provide nops if CONFIG_PCI isn't enabled.
+##
+
+obj-$(CONFIG_USB_DWC3)		+= dwc3-omap.o
+
+ifneq ($(CONFIG_PCI),)
+	obj-$(CONFIG_USB_DWC3)		+= dwc3-pci.o
+endif
+

+ 484 - 0
drivers/usb/dwc3/core.c

@@ -0,0 +1,484 @@
+/**
+ * core.c - DesignWare USB3 DRD Controller Core file
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/module.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+#include "debug.h"
+
+/**
+ * dwc3_core_soft_reset - Issues core soft reset and PHY reset
+ * @dwc: pointer to our context structure
+ */
+static void dwc3_core_soft_reset(struct dwc3 *dwc)
+{
+	u32		reg;
+
+	/* Before Resetting PHY, put Core in Reset */
+	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+	reg |= DWC3_GCTL_CORESOFTRESET;
+	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+	/* Assert USB3 PHY reset */
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+	reg |= DWC3_GUSB3PIPECTL_PHYSOFTRST;
+	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+
+	/* Assert USB2 PHY reset */
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+	reg |= DWC3_GUSB2PHYCFG_PHYSOFTRST;
+	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+	mdelay(100);
+
+	/* Clear USB3 PHY reset */
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+	reg &= ~DWC3_GUSB3PIPECTL_PHYSOFTRST;
+	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+
+	/* Clear USB2 PHY reset */
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+	reg &= ~DWC3_GUSB2PHYCFG_PHYSOFTRST;
+	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+
+	/* After PHYs are stable we can take Core out of reset state */
+	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+	reg &= ~DWC3_GCTL_CORESOFTRESET;
+	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+}
+
+/**
+ * dwc3_free_one_event_buffer - Frees one event buffer
+ * @dwc: Pointer to our controller context structure
+ * @evt: Pointer to event buffer to be freed
+ */
+static void dwc3_free_one_event_buffer(struct dwc3 *dwc,
+		struct dwc3_event_buffer *evt)
+{
+	dma_free_coherent(dwc->dev, evt->length, evt->buf, evt->dma);
+	kfree(evt);
+}
+
+/**
+ * dwc3_alloc_one_event_buffer - Allocated 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
+ * otherwise ERR_PTR(errno).
+ */
+static struct dwc3_event_buffer *__devinit
+dwc3_alloc_one_event_buffer(struct dwc3 *dwc, unsigned length)
+{
+	struct dwc3_event_buffer	*evt;
+
+	evt = kzalloc(sizeof(*evt), GFP_KERNEL);
+	if (!evt)
+		return ERR_PTR(-ENOMEM);
+
+	evt->dwc	= dwc;
+	evt->length	= length;
+	evt->buf	= dma_alloc_coherent(dwc->dev, length,
+			&evt->dma, GFP_KERNEL);
+	if (!evt->buf) {
+		kfree(evt);
+		return ERR_PTR(-ENOMEM);
+	}
+
+	return evt;
+}
+
+/**
+ * dwc3_free_event_buffers - frees all allocated event buffers
+ * @dwc: Pointer to our controller context structure
+ */
+static void dwc3_free_event_buffers(struct dwc3 *dwc)
+{
+	struct dwc3_event_buffer	*evt;
+	int i;
+
+	for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) {
+		evt = dwc->ev_buffs[i];
+		if (evt) {
+			dwc3_free_one_event_buffer(dwc, evt);
+			dwc->ev_buffs[i] = NULL;
+		}
+	}
+}
+
+/**
+ * dwc3_alloc_event_buffers - Allocates @num event buffers of size @length
+ * @dwc: Pointer to out controller context structure
+ * @num: number of event buffers to allocate
+ * @length: size of event buffer
+ *
+ * Returns 0 on success otherwise negative errno. In error the case, dwc
+ * may contain some buffers allocated but not all which were requested.
+ */
+static int __devinit dwc3_alloc_event_buffers(struct dwc3 *dwc, unsigned num,
+		unsigned length)
+{
+	int			i;
+
+	for (i = 0; i < num; i++) {
+		struct dwc3_event_buffer	*evt;
+
+		evt = dwc3_alloc_one_event_buffer(dwc, length);
+		if (IS_ERR(evt)) {
+			dev_err(dwc->dev, "can't allocate event buffer\n");
+			return PTR_ERR(evt);
+		}
+		dwc->ev_buffs[i] = evt;
+	}
+
+	return 0;
+}
+
+/**
+ * dwc3_event_buffers_setup - setup our allocated event buffers
+ * @dwc: Pointer to out controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int __devinit dwc3_event_buffers_setup(struct dwc3 *dwc)
+{
+	struct dwc3_event_buffer	*evt;
+	int				n;
+
+	for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) {
+		evt = dwc->ev_buffs[n];
+		dev_dbg(dwc->dev, "Event buf %p dma %08llx length %d\n",
+				evt->buf, (unsigned long long) evt->dma,
+				evt->length);
+
+		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n),
+				lower_32_bits(evt->dma));
+		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n),
+				upper_32_bits(evt->dma));
+		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n),
+				evt->length & 0xffff);
+		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
+	}
+
+	return 0;
+}
+
+static void dwc3_event_buffers_cleanup(struct dwc3 *dwc)
+{
+	struct dwc3_event_buffer	*evt;
+	int				n;
+
+	for (n = 0; n < DWC3_EVENT_BUFFERS_NUM; n++) {
+		evt = dwc->ev_buffs[n];
+		dwc3_writel(dwc->regs, DWC3_GEVNTADRLO(n), 0);
+		dwc3_writel(dwc->regs, DWC3_GEVNTADRHI(n), 0);
+		dwc3_writel(dwc->regs, DWC3_GEVNTSIZ(n), 0);
+		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(n), 0);
+	}
+}
+
+static void __devinit dwc3_cache_hwparams(struct dwc3 *dwc)
+{
+	struct dwc3_hwparams	*parms = &dwc->hwparams;
+
+	parms->hwparams0 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS0);
+	parms->hwparams1 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS1);
+	parms->hwparams2 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS2);
+	parms->hwparams3 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS3);
+	parms->hwparams4 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS4);
+	parms->hwparams5 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS5);
+	parms->hwparams6 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS6);
+	parms->hwparams7 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS7);
+	parms->hwparams8 = dwc3_readl(dwc->regs, DWC3_GHWPARAMS8);
+}
+
+/**
+ * dwc3_core_init - Low-level initialization of DWC3 Core
+ * @dwc: Pointer to our controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+static int __devinit dwc3_core_init(struct dwc3 *dwc)
+{
+	unsigned long		timeout;
+	u32			reg;
+	int			ret;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GSNPSID);
+	/* This should read as U3 followed by revision number */
+	if ((reg & DWC3_GSNPSID_MASK) != 0x55330000) {
+		dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n");
+		ret = -ENODEV;
+		goto err0;
+	}
+	dwc->revision = reg & DWC3_GSNPSREV_MASK;
+
+	dwc3_core_soft_reset(dwc);
+
+	/* issue device SoftReset too */
+	timeout = jiffies + msecs_to_jiffies(500);
+	dwc3_writel(dwc->regs, DWC3_DCTL, DWC3_DCTL_CSFTRST);
+	do {
+		reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+		if (!(reg & DWC3_DCTL_CSFTRST))
+			break;
+
+		if (time_after(jiffies, timeout)) {
+			dev_err(dwc->dev, "Reset Timed Out\n");
+			ret = -ETIMEDOUT;
+			goto err0;
+		}
+
+		cpu_relax();
+	} while (true);
+
+	ret = dwc3_alloc_event_buffers(dwc, DWC3_EVENT_BUFFERS_NUM,
+			DWC3_EVENT_BUFFERS_SIZE);
+	if (ret) {
+		dev_err(dwc->dev, "failed to allocate event buffers\n");
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	ret = dwc3_event_buffers_setup(dwc);
+	if (ret) {
+		dev_err(dwc->dev, "failed to setup event buffers\n");
+		goto err1;
+	}
+
+	dwc3_cache_hwparams(dwc);
+
+	return 0;
+
+err1:
+	dwc3_free_event_buffers(dwc);
+
+err0:
+	return ret;
+}
+
+static void dwc3_core_exit(struct dwc3 *dwc)
+{
+	dwc3_event_buffers_cleanup(dwc);
+	dwc3_free_event_buffers(dwc);
+}
+
+#define DWC3_ALIGN_MASK		(16 - 1)
+
+static int __devinit dwc3_probe(struct platform_device *pdev)
+{
+	const struct platform_device_id *id = platform_get_device_id(pdev);
+	struct resource		*res;
+	struct dwc3		*dwc;
+	void __iomem		*regs;
+	unsigned int		features = id->driver_data;
+	int			ret = -ENOMEM;
+	int			irq;
+	void			*mem;
+
+	mem = kzalloc(sizeof(*dwc) + DWC3_ALIGN_MASK, GFP_KERNEL);
+	if (!mem) {
+		dev_err(&pdev->dev, "not enough memory\n");
+		goto err0;
+	}
+	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;
+	}
+
+	res = request_mem_region(res->start, resource_size(res),
+			dev_name(&pdev->dev));
+	if (!res) {
+		dev_err(&pdev->dev, "can't request mem region\n");
+		goto err1;
+	}
+
+	regs = ioremap(res->start, resource_size(res));
+	if (!regs) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		goto err2;
+	}
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0) {
+		dev_err(&pdev->dev, "missing IRQ\n");
+		goto err3;
+	}
+
+	spin_lock_init(&dwc->lock);
+	platform_set_drvdata(pdev, dwc);
+
+	dwc->regs	= regs;
+	dwc->regs_size	= resource_size(res);
+	dwc->dev	= &pdev->dev;
+	dwc->irq	= irq;
+
+	pm_runtime_enable(&pdev->dev);
+	pm_runtime_get_sync(&pdev->dev);
+	pm_runtime_forbid(&pdev->dev);
+
+	ret = dwc3_core_init(dwc);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to initialize core\n");
+		goto err3;
+	}
+
+	if (features & DWC3_HAS_PERIPHERAL) {
+		ret = dwc3_gadget_init(dwc);
+		if (ret) {
+			dev_err(&pdev->dev, "failed to initialized gadget\n");
+			goto err4;
+		}
+	}
+
+	ret = dwc3_debugfs_init(dwc);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to initialize debugfs\n");
+		goto err5;
+	}
+
+	pm_runtime_allow(&pdev->dev);
+
+	return 0;
+
+err5:
+	if (features & DWC3_HAS_PERIPHERAL)
+		dwc3_gadget_exit(dwc);
+
+err4:
+	dwc3_core_exit(dwc);
+
+err3:
+	iounmap(regs);
+
+err2:
+	release_mem_region(res->start, resource_size(res));
+
+err1:
+	kfree(dwc->mem);
+
+err0:
+	return ret;
+}
+
+static int __devexit dwc3_remove(struct platform_device *pdev)
+{
+	const struct platform_device_id *id = platform_get_device_id(pdev);
+	struct dwc3	*dwc = platform_get_drvdata(pdev);
+	struct resource	*res;
+	unsigned int	features = id->driver_data;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+	pm_runtime_put(&pdev->dev);
+	pm_runtime_disable(&pdev->dev);
+
+	dwc3_debugfs_exit(dwc);
+
+	if (features & DWC3_HAS_PERIPHERAL)
+		dwc3_gadget_exit(dwc);
+
+	dwc3_core_exit(dwc);
+	release_mem_region(res->start, resource_size(res));
+	iounmap(dwc->regs);
+	kfree(dwc->mem);
+
+	return 0;
+}
+
+static const struct platform_device_id dwc3_id_table[] __devinitconst = {
+	{
+		.name	= "dwc3-omap",
+		.driver_data = (DWC3_HAS_PERIPHERAL
+			| DWC3_HAS_XHCI
+			| DWC3_HAS_OTG),
+	},
+	{
+		.name	= "dwc3-pci",
+		.driver_data = DWC3_HAS_PERIPHERAL,
+	},
+	{  },	/* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(platform, dwc3_id_table);
+
+static struct platform_driver dwc3_driver = {
+	.probe		= dwc3_probe,
+	.remove		= __devexit_p(dwc3_remove),
+	.driver		= {
+		.name	= "dwc3",
+	},
+	.id_table	= dwc3_id_table,
+};
+
+MODULE_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);

+ 768 - 0
drivers/usb/dwc3/core.h

@@ -0,0 +1,768 @@
+/**
+ * core.h - DesignWare USB3 DRD Core Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DRIVERS_USB_DWC3_CORE_H
+#define __DRIVERS_USB_DWC3_CORE_H
+
+#include <linux/device.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/debugfs.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/* Global constants */
+#define DWC3_ENDPOINTS_NUM	32
+
+#define DWC3_EVENT_BUFFERS_NUM	2
+#define DWC3_EVENT_BUFFERS_SIZE	PAGE_SIZE
+#define DWC3_EVENT_TYPE_MASK	0xfe
+
+#define DWC3_EVENT_TYPE_DEV	0
+#define DWC3_EVENT_TYPE_CARKIT	3
+#define DWC3_EVENT_TYPE_I2C	4
+
+#define DWC3_DEVICE_EVENT_DISCONNECT		0
+#define DWC3_DEVICE_EVENT_RESET			1
+#define DWC3_DEVICE_EVENT_CONNECT_DONE		2
+#define DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE	3
+#define DWC3_DEVICE_EVENT_WAKEUP		4
+#define DWC3_DEVICE_EVENT_EOPF			6
+#define DWC3_DEVICE_EVENT_SOF			7
+#define DWC3_DEVICE_EVENT_ERRATIC_ERROR		9
+#define DWC3_DEVICE_EVENT_CMD_CMPL		10
+#define DWC3_DEVICE_EVENT_OVERFLOW		11
+
+#define DWC3_GEVNTCOUNT_MASK	0xfffc
+#define DWC3_GSNPSID_MASK	0xffff0000
+#define DWC3_GSNPSREV_MASK	0xffff
+
+/* Global Registers */
+#define DWC3_GSBUSCFG0		0xc100
+#define DWC3_GSBUSCFG1		0xc104
+#define DWC3_GTXTHRCFG		0xc108
+#define DWC3_GRXTHRCFG		0xc10c
+#define DWC3_GCTL		0xc110
+#define DWC3_GEVTEN		0xc114
+#define DWC3_GSTS		0xc118
+#define DWC3_GSNPSID		0xc120
+#define DWC3_GGPIO		0xc124
+#define DWC3_GUID		0xc128
+#define DWC3_GUCTL		0xc12c
+#define DWC3_GBUSERRADDR0	0xc130
+#define DWC3_GBUSERRADDR1	0xc134
+#define DWC3_GPRTBIMAP0		0xc138
+#define DWC3_GPRTBIMAP1		0xc13c
+#define DWC3_GHWPARAMS0		0xc140
+#define DWC3_GHWPARAMS1		0xc144
+#define DWC3_GHWPARAMS2		0xc148
+#define DWC3_GHWPARAMS3		0xc14c
+#define DWC3_GHWPARAMS4		0xc150
+#define DWC3_GHWPARAMS5		0xc154
+#define DWC3_GHWPARAMS6		0xc158
+#define DWC3_GHWPARAMS7		0xc15c
+#define DWC3_GDBGFIFOSPACE	0xc160
+#define DWC3_GDBGLTSSM		0xc164
+#define DWC3_GPRTBIMAP_HS0	0xc180
+#define DWC3_GPRTBIMAP_HS1	0xc184
+#define DWC3_GPRTBIMAP_FS0	0xc188
+#define DWC3_GPRTBIMAP_FS1	0xc18c
+
+#define DWC3_GUSB2PHYCFG(n)	(0xc200 + (n * 0x04))
+#define DWC3_GUSB2I2CCTL(n)	(0xc240 + (n * 0x04))
+
+#define DWC3_GUSB2PHYACC(n)	(0xc280 + (n * 0x04))
+
+#define DWC3_GUSB3PIPECTL(n)	(0xc2c0 + (n * 0x04))
+
+#define DWC3_GTXFIFOSIZ(n)	(0xc300 + (n * 0x04))
+#define DWC3_GRXFIFOSIZ(n)	(0xc380 + (n * 0x04))
+
+#define DWC3_GEVNTADRLO(n)	(0xc400 + (n * 0x10))
+#define DWC3_GEVNTADRHI(n)	(0xc404 + (n * 0x10))
+#define DWC3_GEVNTSIZ(n)	(0xc408 + (n * 0x10))
+#define DWC3_GEVNTCOUNT(n)	(0xc40c + (n * 0x10))
+
+#define DWC3_GHWPARAMS8		0xc600
+
+/* Device Registers */
+#define DWC3_DCFG		0xc700
+#define DWC3_DCTL		0xc704
+#define DWC3_DEVTEN		0xc708
+#define DWC3_DSTS		0xc70c
+#define DWC3_DGCMDPAR		0xc710
+#define DWC3_DGCMD		0xc714
+#define DWC3_DALEPENA		0xc720
+#define DWC3_DEPCMDPAR2(n)	(0xc800 + (n * 0x10))
+#define DWC3_DEPCMDPAR1(n)	(0xc804 + (n * 0x10))
+#define DWC3_DEPCMDPAR0(n)	(0xc808 + (n * 0x10))
+#define DWC3_DEPCMD(n)		(0xc80c + (n * 0x10))
+
+/* OTG Registers */
+#define DWC3_OCFG		0xcc00
+#define DWC3_OCTL		0xcc04
+#define DWC3_OEVTEN		0xcc08
+#define DWC3_OSTS		0xcc0C
+
+/* Bit fields */
+
+/* Global Configuration Register */
+#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_CLK_BUS	(0)
+#define DWC3_GCTL_CLK_PIPE	(1)
+#define DWC3_GCTL_CLK_PIPEHALF	(2)
+#define DWC3_GCTL_CLK_MASK	(3)
+
+#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_DISSCRAMBLE	(1 << 3)
+#define DWC3_GCTL_DSBLCLKGTNG	(1 << 0)
+
+/* Global USB2 PHY Configuration Register */
+#define DWC3_GUSB2PHYCFG_PHYSOFTRST (1 << 31)
+#define DWC3_GUSB2PHYCFG_SUSPHY	(1 << 6)
+
+/* Global USB3 PIPE Control Register */
+#define DWC3_GUSB3PIPECTL_PHYSOFTRST (1 << 31)
+#define DWC3_GUSB3PIPECTL_SUSPHY (1 << 17)
+
+/* Global HWPARAMS1 Register */
+#define DWC3_GHWPARAMS1_EN_PWROPT(n)	((n & (3 << 24)) >> 24)
+#define DWC3_GHWPARAMS1_EN_PWROPT_NO	0
+#define DWC3_GHWPARAMS1_EN_PWROPT_CLK	1
+
+/* Device Configuration Register */
+#define DWC3_DCFG_DEVADDR(addr)	((addr) << 3)
+#define DWC3_DCFG_DEVADDR_MASK	DWC3_DCFG_DEVADDR(0x7f)
+
+#define DWC3_DCFG_SPEED_MASK	(7 << 0)
+#define DWC3_DCFG_SUPERSPEED	(4 << 0)
+#define DWC3_DCFG_HIGHSPEED	(0 << 0)
+#define DWC3_DCFG_FULLSPEED2	(1 << 0)
+#define DWC3_DCFG_LOWSPEED	(2 << 0)
+#define DWC3_DCFG_FULLSPEED1	(3 << 0)
+
+/* Device Control Register */
+#define DWC3_DCTL_RUN_STOP	(1 << 31)
+#define DWC3_DCTL_CSFTRST	(1 << 30)
+#define DWC3_DCTL_LSFTRST	(1 << 29)
+
+#define DWC3_DCTL_HIRD_THRES_MASK	(0x1f << 24)
+#define DWC3_DCTL_HIRD_THRES(n)	(((n) & DWC3_DCTL_HIRD_THRES_MASK) >> 24)
+
+#define DWC3_DCTL_APPL1RES	(1 << 23)
+
+#define DWC3_DCTL_INITU2ENA	(1 << 12)
+#define DWC3_DCTL_ACCEPTU2ENA	(1 << 11)
+#define DWC3_DCTL_INITU1ENA	(1 << 10)
+#define DWC3_DCTL_ACCEPTU1ENA	(1 << 9)
+#define DWC3_DCTL_TSTCTRL_MASK	(0xf << 1)
+
+#define DWC3_DCTL_ULSTCHNGREQ_MASK	(0x0f << 5)
+#define DWC3_DCTL_ULSTCHNGREQ(n) (((n) << 5) & DWC3_DCTL_ULSTCHNGREQ_MASK)
+
+#define DWC3_DCTL_ULSTCHNG_NO_ACTION	(DWC3_DCTL_ULSTCHNGREQ(0))
+#define DWC3_DCTL_ULSTCHNG_SS_DISABLED	(DWC3_DCTL_ULSTCHNGREQ(4))
+#define DWC3_DCTL_ULSTCHNG_RX_DETECT	(DWC3_DCTL_ULSTCHNGREQ(5))
+#define DWC3_DCTL_ULSTCHNG_SS_INACTIVE	(DWC3_DCTL_ULSTCHNGREQ(6))
+#define DWC3_DCTL_ULSTCHNG_RECOVERY	(DWC3_DCTL_ULSTCHNGREQ(8))
+#define DWC3_DCTL_ULSTCHNG_COMPLIANCE	(DWC3_DCTL_ULSTCHNGREQ(10))
+#define DWC3_DCTL_ULSTCHNG_LOOPBACK	(DWC3_DCTL_ULSTCHNGREQ(11))
+
+/* Device Event Enable Register */
+#define DWC3_DEVTEN_VNDRDEVTSTRCVEDEN	(1 << 12)
+#define DWC3_DEVTEN_EVNTOVERFLOWEN	(1 << 11)
+#define DWC3_DEVTEN_CMDCMPLTEN		(1 << 10)
+#define DWC3_DEVTEN_ERRTICERREN		(1 << 9)
+#define DWC3_DEVTEN_SOFEN		(1 << 7)
+#define DWC3_DEVTEN_EOPFEN		(1 << 6)
+#define DWC3_DEVTEN_WKUPEVTEN		(1 << 4)
+#define DWC3_DEVTEN_ULSTCNGEN		(1 << 3)
+#define DWC3_DEVTEN_CONNECTDONEEN	(1 << 2)
+#define DWC3_DEVTEN_USBRSTEN		(1 << 1)
+#define DWC3_DEVTEN_DISCONNEVTEN	(1 << 0)
+
+/* Device Status Register */
+#define DWC3_DSTS_PWRUPREQ		(1 << 24)
+#define DWC3_DSTS_COREIDLE		(1 << 23)
+#define DWC3_DSTS_DEVCTRLHLT		(1 << 22)
+
+#define DWC3_DSTS_USBLNKST_MASK		(0x0f << 18)
+#define DWC3_DSTS_USBLNKST(n)		(((n) & DWC3_DSTS_USBLNKST_MASK) >> 18)
+
+#define DWC3_DSTS_RXFIFOEMPTY		(1 << 17)
+
+#define DWC3_DSTS_SOFFN_MASK		(0x3ff << 3)
+#define DWC3_DSTS_SOFFN(n)		(((n) & DWC3_DSTS_SOFFN_MASK) >> 3)
+
+#define DWC3_DSTS_CONNECTSPD		(7 << 0)
+
+#define DWC3_DSTS_SUPERSPEED		(4 << 0)
+#define DWC3_DSTS_HIGHSPEED		(0 << 0)
+#define DWC3_DSTS_FULLSPEED2		(1 << 0)
+#define DWC3_DSTS_LOWSPEED		(2 << 0)
+#define DWC3_DSTS_FULLSPEED1		(3 << 0)
+
+/* Device Generic Command Register */
+#define DWC3_DGCMD_SET_LMP		0x01
+#define DWC3_DGCMD_SET_PERIODIC_PAR	0x02
+#define DWC3_DGCMD_XMIT_FUNCTION	0x03
+#define DWC3_DGCMD_SELECTED_FIFO_FLUSH	0x09
+#define DWC3_DGCMD_ALL_FIFO_FLUSH	0x0a
+#define DWC3_DGCMD_SET_ENDPOINT_NRDY	0x0c
+#define DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK	0x10
+
+/* 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_STATUS_MASK		(0x0f << 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)
+
+#define DWC3_DEPCMD_DEPSTARTCFG		(0x09 << 0)
+#define DWC3_DEPCMD_ENDTRANSFER		(0x08 << 0)
+#define DWC3_DEPCMD_UPDATETRANSFER	(0x07 << 0)
+#define DWC3_DEPCMD_STARTTRANSFER	(0x06 << 0)
+#define DWC3_DEPCMD_CLEARSTALL		(0x05 << 0)
+#define DWC3_DEPCMD_SETSTALL		(0x04 << 0)
+#define DWC3_DEPCMD_GETSEQNUMBER	(0x03 << 0)
+#define DWC3_DEPCMD_SETTRANSFRESOURCE	(0x02 << 0)
+#define DWC3_DEPCMD_SETEPCONFIG		(0x01 << 0)
+
+/* The EP number goes 0..31 so ep0 is always out and ep1 is always in */
+#define DWC3_DALEPENA_EP(n)		(1 << n)
+
+#define DWC3_DEPCMD_TYPE_CONTROL	0
+#define DWC3_DEPCMD_TYPE_ISOC		1
+#define DWC3_DEPCMD_TYPE_BULK		2
+#define DWC3_DEPCMD_TYPE_INTR		3
+
+/* Structures */
+
+struct dwc3_trb_hw;
+
+/**
+ * struct dwc3_event_buffer - Software event buffer representation
+ * @list: a list of event buffers
+ * @buf: _THE_ buffer
+ * @length: size of this buffer
+ * @dma: dma_addr_t
+ * @dwc: pointer to DWC controller
+ */
+struct dwc3_event_buffer {
+	void			*buf;
+	unsigned		length;
+	unsigned int		lpos;
+
+	dma_addr_t		dma;
+
+	struct dwc3		*dwc;
+};
+
+#define DWC3_EP_FLAG_STALLED	(1 << 0)
+#define DWC3_EP_FLAG_WEDGED	(1 << 1)
+
+#define DWC3_EP_DIRECTION_TX	true
+#define DWC3_EP_DIRECTION_RX	false
+
+#define DWC3_TRB_NUM		32
+#define DWC3_TRB_MASK		(DWC3_TRB_NUM - 1)
+
+/**
+ * struct dwc3_ep - device side endpoint representation
+ * @endpoint: usb endpoint
+ * @request_list: list of requests for this endpoint
+ * @req_queued: list of requests on this ep which have TRBs setup
+ * @trb_pool: array of transaction buffers
+ * @trb_pool_dma: dma address of @trb_pool
+ * @free_slot: next slot which is going to be used
+ * @busy_slot: first slot which is owned by HW
+ * @desc: usb_endpoint_descriptor pointer
+ * @dwc: pointer to DWC controller
+ * @flags: endpoint flags (wedged, stalled, ...)
+ * @current_trb: index of current used trb
+ * @number: endpoint number (1 - 15)
+ * @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
+ * @res_trans_idx: Resource transfer index
+ * @interval: the intervall on which the ISOC transfer is started
+ * @name: a human readable name e.g. ep1out-bulk
+ * @direction: true for TX, false for RX
+ * @stream_capable: true when streams are enabled
+ */
+struct dwc3_ep {
+	struct usb_ep		endpoint;
+	struct list_head	request_list;
+	struct list_head	req_queued;
+
+	struct dwc3_trb_hw	*trb_pool;
+	dma_addr_t		trb_pool_dma;
+	u32			free_slot;
+	u32			busy_slot;
+	const struct usb_endpoint_descriptor *desc;
+	struct dwc3		*dwc;
+
+	unsigned		flags;
+#define DWC3_EP_ENABLED		(1 << 0)
+#define DWC3_EP_STALL		(1 << 1)
+#define DWC3_EP_WEDGE		(1 << 2)
+#define DWC3_EP_BUSY		(1 << 4)
+#define DWC3_EP_PENDING_REQUEST	(1 << 5)
+
+	/* This last one is specific to EP0 */
+#define DWC3_EP0_DIR_IN		(1 << 31)
+
+	unsigned		current_trb;
+
+	u8			number;
+	u8			type;
+	u8			res_trans_idx;
+	u32			interval;
+
+	char			name[20];
+
+	unsigned		direction:1;
+	unsigned		stream_capable:1;
+};
+
+enum dwc3_phy {
+	DWC3_PHY_UNKNOWN = 0,
+	DWC3_PHY_USB3,
+	DWC3_PHY_USB2,
+};
+
+enum dwc3_ep0_next {
+	DWC3_EP0_UNKNOWN = 0,
+	DWC3_EP0_COMPLETE,
+	DWC3_EP0_NRDY_SETUP,
+	DWC3_EP0_NRDY_DATA,
+	DWC3_EP0_NRDY_STATUS,
+};
+
+enum dwc3_ep0_state {
+	EP0_UNCONNECTED		= 0,
+	EP0_SETUP_PHASE,
+	EP0_DATA_PHASE,
+	EP0_STATUS_PHASE,
+};
+
+enum dwc3_link_state {
+	/* In SuperSpeed */
+	DWC3_LINK_STATE_U0		= 0x00, /* in HS, means ON */
+	DWC3_LINK_STATE_U1		= 0x01,
+	DWC3_LINK_STATE_U2		= 0x02, /* in HS, means SLEEP */
+	DWC3_LINK_STATE_U3		= 0x03, /* in HS, means SUSPEND */
+	DWC3_LINK_STATE_SS_DIS		= 0x04,
+	DWC3_LINK_STATE_RX_DET		= 0x05, /* in HS, means Early Suspend */
+	DWC3_LINK_STATE_SS_INACT	= 0x06,
+	DWC3_LINK_STATE_POLL		= 0x07,
+	DWC3_LINK_STATE_RECOV		= 0x08,
+	DWC3_LINK_STATE_HRESET		= 0x09,
+	DWC3_LINK_STATE_CMPLY		= 0x0a,
+	DWC3_LINK_STATE_LPBK		= 0x0b,
+	DWC3_LINK_STATE_MASK		= 0x0f,
+};
+
+enum dwc3_device_state {
+	DWC3_DEFAULT_STATE,
+	DWC3_ADDRESS_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;
+
+/**
+ * struct dwc3_trb_hw - 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;
+} __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
+ * @hwparams1 - GHWPARAMS1
+ * @hwparams2 - GHWPARAMS2
+ * @hwparams3 - GHWPARAMS3
+ * @hwparams4 - GHWPARAMS4
+ * @hwparams5 - GHWPARAMS5
+ * @hwparams6 - GHWPARAMS6
+ * @hwparams7 - GHWPARAMS7
+ * @hwparams8 - GHWPARAMS8
+ */
+struct dwc3_hwparams {
+	u32	hwparams0;
+	u32	hwparams1;
+	u32	hwparams2;
+	u32	hwparams3;
+	u32	hwparams4;
+	u32	hwparams5;
+	u32	hwparams6;
+	u32	hwparams7;
+	u32	hwparams8;
+};
+
+/**
+ * struct dwc3 - representation of our controller
+ * @ctrl_req: usb control request which is used for ep0
+ * @ep0_trb: trb which is used for the ctrl_req
+ * @ep0_bounce: bounce buffer for ep0
+ * @setup_buf: used while precessing STD USB requests
+ * @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
+ * @event_buffer_list: a list of event buffers
+ * @gadget: device side representation of the peripheral controller
+ * @gadget_driver: pointer to the gadget driver
+ * @regs: base address for our registers
+ * @regs_size: address space size
+ * @irq: IRQ number
+ * @revision: revision register contents
+ * @is_selfpowered: true when we are selfpowered
+ * @three_stage_setup: set if we perform a three phase setup
+ * @ep0_status_pending: ep0 status response without a req is pending
+ * @ep0_bounced: true when we used bounce buffer
+ * @ep0_expect_in: true when we expect a DATA IN transfer
+ * @start_config_issued: true when StartConfig command has been issued
+ * @ep0_next_event: hold the next expected event
+ * @ep0state: state of endpoint zero
+ * @link_state: link state
+ * @speed: device speed (super, high, full, low)
+ * @mem: points to start of memory which is used for this struct.
+ * @hwparams: copy of hwparams registers
+ * @root: debugfs root folder pointer
+ */
+struct dwc3 {
+	struct usb_ctrlrequest	*ctrl_req;
+	struct dwc3_trb_hw	*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 usb_request	ep0_usb_req;
+	/* device lock */
+	spinlock_t		lock;
+	struct device		*dev;
+
+	struct dwc3_event_buffer *ev_buffs[DWC3_EVENT_BUFFERS_NUM];
+	struct dwc3_ep		*eps[DWC3_ENDPOINTS_NUM];
+
+	struct usb_gadget	gadget;
+	struct usb_gadget_driver *gadget_driver;
+
+	void __iomem		*regs;
+	size_t			regs_size;
+
+	int			irq;
+
+	u32			revision;
+
+#define DWC3_REVISION_173A	0x5533173a
+#define DWC3_REVISION_175A	0x5533175a
+#define DWC3_REVISION_180A	0x5533180a
+#define DWC3_REVISION_183A	0x5533183a
+#define DWC3_REVISION_185A	0x5533185a
+#define DWC3_REVISION_188A	0x5533188a
+#define DWC3_REVISION_190A	0x5533190a
+
+	unsigned		is_selfpowered:1;
+	unsigned		three_stage_setup:1;
+	unsigned		ep0_status_pending:1;
+	unsigned		ep0_bounced:1;
+	unsigned		ep0_expect_in:1;
+	unsigned		start_config_issued:1;
+
+	enum dwc3_ep0_next	ep0_next_event;
+	enum dwc3_ep0_state	ep0state;
+	enum dwc3_link_state	link_state;
+	enum dwc3_device_state	dev_state;
+
+	u8			speed;
+	void			*mem;
+
+	struct dwc3_hwparams	hwparams;
+	struct dentry		*root;
+};
+
+/* -------------------------------------------------------------------------- */
+
+#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 {
+	u32	is_devspec:1;
+	u32	type:6;
+	u32	reserved8_31:25;
+} __packed;
+
+#define DWC3_DEPEVT_XFERCOMPLETE	0x01
+#define DWC3_DEPEVT_XFERINPROGRESS	0x02
+#define DWC3_DEPEVT_XFERNOTREADY	0x03
+#define DWC3_DEPEVT_RXTXFIFOEVT		0x04
+#define DWC3_DEPEVT_STREAMEVT		0x06
+#define DWC3_DEPEVT_EPCMDCMPLT		0x07
+
+/**
+ * struct dwc3_event_depvt - Device Endpoint Events
+ * @one_bit: indicates this is an endpoint event (not used)
+ * @endpoint_number: number of the endpoint
+ * @endpoint_event: The event we have:
+ *	0x00	- Reserved
+ *	0x01	- XferComplete
+ *	0x02	- XferInProgress
+ *	0x03	- XferNotReady
+ *	0x04	- RxTxFifoEvt (IN->Underrun, OUT->Overrun)
+ *	0x05	- Reserved
+ *	0x06	- StreamEvt
+ *	0x07	- EPCmdCmplt
+ * @reserved11_10: Reserved, don't use.
+ * @status: Indicates the status of the event. Refer to databook for
+ *	more information.
+ * @parameters: Parameters of the current event. Refer to databook for
+ *	more information.
+ */
+struct dwc3_event_depevt {
+	u32	one_bit:1;
+	u32	endpoint_number:5;
+	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)
+#define DEPEVT_STATUS_LST	(1 << 3)
+
+/* Stream event only */
+#define DEPEVT_STREAMEVT_FOUND		1
+#define DEPEVT_STREAMEVT_NOTFOUND	2
+
+/* Control-only Status */
+#define DEPEVT_STATUS_CONTROL_SETUP	0
+#define DEPEVT_STATUS_CONTROL_DATA	1
+#define DEPEVT_STATUS_CONTROL_STATUS	2
+
+	u32	parameters:16;
+} __packed;
+
+/**
+ * struct dwc3_event_devt - Device Events
+ * @one_bit: indicates this is a non-endpoint event (not used)
+ * @device_event: indicates it's a device event. Should read as 0x00
+ * @type: indicates the type of device event.
+ *	0	- DisconnEvt
+ *	1	- USBRst
+ *	2	- ConnectDone
+ *	3	- ULStChng
+ *	4	- WkUpEvt
+ *	5	- Reserved
+ *	6	- EOPF
+ *	7	- SOF
+ *	8	- Reserved
+ *	9	- ErrticErr
+ *	10	- CmdCmplt
+ *	11	- EvntOverflow
+ *	12	- VndrDevTstRcved
+ * @reserved15_12: Reserved, not used
+ * @event_info: Information about this event
+ * @reserved31_24: Reserved, not used
+ */
+struct dwc3_event_devt {
+	u32	one_bit:1;
+	u32	device_event:7;
+	u32	type:4;
+	u32	reserved15_12:4;
+	u32	event_info:8;
+	u32	reserved31_24:8;
+} __packed;
+
+/**
+ * struct dwc3_event_gevt - Other Core Events
+ * @one_bit: indicates this is a non-endpoint event (not used)
+ * @device_event: indicates it's (0x03) Carkit or (0x04) I2C event.
+ * @phy_port_number: self-explanatory
+ * @reserved31_12: Reserved, not used.
+ */
+struct dwc3_event_gevt {
+	u32	one_bit:1;
+	u32	device_event:7;
+	u32	phy_port_number:4;
+	u32	reserved31_12:20;
+} __packed;
+
+/**
+ * union dwc3_event - representation of Event Buffer contents
+ * @raw: raw 32-bit event
+ * @type: the type of the event
+ * @depevt: Device Endpoint Event
+ * @devt: Device Event
+ * @gevt: Global Event
+ */
+union dwc3_event {
+	u32				raw;
+	struct dwc3_event_type		type;
+	struct dwc3_event_depevt	depevt;
+	struct dwc3_event_devt		devt;
+	struct dwc3_event_gevt		gevt;
+};
+
+/*
+ * DWC3 Features to be used as Driver Data
+ */
+
+#define DWC3_HAS_PERIPHERAL		BIT(0)
+#define DWC3_HAS_XHCI			BIT(1)
+#define DWC3_HAS_OTG			BIT(3)
+
+#endif /* __DRIVERS_USB_DWC3_CORE_H */

+ 50 - 0
drivers/usb/dwc3/debug.h

@@ -0,0 +1,50 @@
+/**
+ * debug.h - DesignWare USB3 DRD Controller Debug Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "core.h"
+
+#ifdef CONFIG_DEBUG_FS
+extern int dwc3_debugfs_init(struct dwc3 *);
+extern void dwc3_debugfs_exit(struct dwc3 *);
+#else
+static inline int dwc3_debugfs_init(struct dwc3 *d)
+{  return 0;  }
+static inline void dwc3_debugfs_exit(struct dwc3 *d)
+{  }
+#endif
+

+ 441 - 0
drivers/usb/dwc3/debugfs.c

@@ -0,0 +1,441 @@
+/**
+ * debugfs.c - DesignWare USB3 DRD Controller DebugFS file
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/ptrace.h>
+#include <linux/types.h>
+#include <linux/spinlock.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <linux/delay.h>
+
+#include <asm/uaccess.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+struct dwc3_register {
+	const char	*name;
+	u32		offset;
+};
+
+#define dump_register(nm)				\
+{							\
+	.name	= __stringify(nm),			\
+	.offset	= DWC3_ ##nm,				\
+}
+
+static const struct dwc3_register dwc3_regs[] = {
+	dump_register(GSBUSCFG0),
+	dump_register(GSBUSCFG1),
+	dump_register(GTXTHRCFG),
+	dump_register(GRXTHRCFG),
+	dump_register(GCTL),
+	dump_register(GEVTEN),
+	dump_register(GSTS),
+	dump_register(GSNPSID),
+	dump_register(GGPIO),
+	dump_register(GUID),
+	dump_register(GUCTL),
+	dump_register(GBUSERRADDR0),
+	dump_register(GBUSERRADDR1),
+	dump_register(GPRTBIMAP0),
+	dump_register(GPRTBIMAP1),
+	dump_register(GHWPARAMS0),
+	dump_register(GHWPARAMS1),
+	dump_register(GHWPARAMS2),
+	dump_register(GHWPARAMS3),
+	dump_register(GHWPARAMS4),
+	dump_register(GHWPARAMS5),
+	dump_register(GHWPARAMS6),
+	dump_register(GHWPARAMS7),
+	dump_register(GDBGFIFOSPACE),
+	dump_register(GDBGLTSSM),
+	dump_register(GPRTBIMAP_HS0),
+	dump_register(GPRTBIMAP_HS1),
+	dump_register(GPRTBIMAP_FS0),
+	dump_register(GPRTBIMAP_FS1),
+
+	dump_register(GUSB2PHYCFG(0)),
+	dump_register(GUSB2PHYCFG(1)),
+	dump_register(GUSB2PHYCFG(2)),
+	dump_register(GUSB2PHYCFG(3)),
+	dump_register(GUSB2PHYCFG(4)),
+	dump_register(GUSB2PHYCFG(5)),
+	dump_register(GUSB2PHYCFG(6)),
+	dump_register(GUSB2PHYCFG(7)),
+	dump_register(GUSB2PHYCFG(8)),
+	dump_register(GUSB2PHYCFG(9)),
+	dump_register(GUSB2PHYCFG(10)),
+	dump_register(GUSB2PHYCFG(11)),
+	dump_register(GUSB2PHYCFG(12)),
+	dump_register(GUSB2PHYCFG(13)),
+	dump_register(GUSB2PHYCFG(14)),
+	dump_register(GUSB2PHYCFG(15)),
+
+	dump_register(GUSB2I2CCTL(0)),
+	dump_register(GUSB2I2CCTL(1)),
+	dump_register(GUSB2I2CCTL(2)),
+	dump_register(GUSB2I2CCTL(3)),
+	dump_register(GUSB2I2CCTL(4)),
+	dump_register(GUSB2I2CCTL(5)),
+	dump_register(GUSB2I2CCTL(6)),
+	dump_register(GUSB2I2CCTL(7)),
+	dump_register(GUSB2I2CCTL(8)),
+	dump_register(GUSB2I2CCTL(9)),
+	dump_register(GUSB2I2CCTL(10)),
+	dump_register(GUSB2I2CCTL(11)),
+	dump_register(GUSB2I2CCTL(12)),
+	dump_register(GUSB2I2CCTL(13)),
+	dump_register(GUSB2I2CCTL(14)),
+	dump_register(GUSB2I2CCTL(15)),
+
+	dump_register(GUSB2PHYACC(0)),
+	dump_register(GUSB2PHYACC(1)),
+	dump_register(GUSB2PHYACC(2)),
+	dump_register(GUSB2PHYACC(3)),
+	dump_register(GUSB2PHYACC(4)),
+	dump_register(GUSB2PHYACC(5)),
+	dump_register(GUSB2PHYACC(6)),
+	dump_register(GUSB2PHYACC(7)),
+	dump_register(GUSB2PHYACC(8)),
+	dump_register(GUSB2PHYACC(9)),
+	dump_register(GUSB2PHYACC(10)),
+	dump_register(GUSB2PHYACC(11)),
+	dump_register(GUSB2PHYACC(12)),
+	dump_register(GUSB2PHYACC(13)),
+	dump_register(GUSB2PHYACC(14)),
+	dump_register(GUSB2PHYACC(15)),
+
+	dump_register(GUSB3PIPECTL(0)),
+	dump_register(GUSB3PIPECTL(1)),
+	dump_register(GUSB3PIPECTL(2)),
+	dump_register(GUSB3PIPECTL(3)),
+	dump_register(GUSB3PIPECTL(4)),
+	dump_register(GUSB3PIPECTL(5)),
+	dump_register(GUSB3PIPECTL(6)),
+	dump_register(GUSB3PIPECTL(7)),
+	dump_register(GUSB3PIPECTL(8)),
+	dump_register(GUSB3PIPECTL(9)),
+	dump_register(GUSB3PIPECTL(10)),
+	dump_register(GUSB3PIPECTL(11)),
+	dump_register(GUSB3PIPECTL(12)),
+	dump_register(GUSB3PIPECTL(13)),
+	dump_register(GUSB3PIPECTL(14)),
+	dump_register(GUSB3PIPECTL(15)),
+
+	dump_register(GTXFIFOSIZ(0)),
+	dump_register(GTXFIFOSIZ(1)),
+	dump_register(GTXFIFOSIZ(2)),
+	dump_register(GTXFIFOSIZ(3)),
+	dump_register(GTXFIFOSIZ(4)),
+	dump_register(GTXFIFOSIZ(5)),
+	dump_register(GTXFIFOSIZ(6)),
+	dump_register(GTXFIFOSIZ(7)),
+	dump_register(GTXFIFOSIZ(8)),
+	dump_register(GTXFIFOSIZ(9)),
+	dump_register(GTXFIFOSIZ(10)),
+	dump_register(GTXFIFOSIZ(11)),
+	dump_register(GTXFIFOSIZ(12)),
+	dump_register(GTXFIFOSIZ(13)),
+	dump_register(GTXFIFOSIZ(14)),
+	dump_register(GTXFIFOSIZ(15)),
+	dump_register(GTXFIFOSIZ(16)),
+	dump_register(GTXFIFOSIZ(17)),
+	dump_register(GTXFIFOSIZ(18)),
+	dump_register(GTXFIFOSIZ(19)),
+	dump_register(GTXFIFOSIZ(20)),
+	dump_register(GTXFIFOSIZ(21)),
+	dump_register(GTXFIFOSIZ(22)),
+	dump_register(GTXFIFOSIZ(23)),
+	dump_register(GTXFIFOSIZ(24)),
+	dump_register(GTXFIFOSIZ(25)),
+	dump_register(GTXFIFOSIZ(26)),
+	dump_register(GTXFIFOSIZ(27)),
+	dump_register(GTXFIFOSIZ(28)),
+	dump_register(GTXFIFOSIZ(29)),
+	dump_register(GTXFIFOSIZ(30)),
+	dump_register(GTXFIFOSIZ(31)),
+
+	dump_register(GRXFIFOSIZ(0)),
+	dump_register(GRXFIFOSIZ(1)),
+	dump_register(GRXFIFOSIZ(2)),
+	dump_register(GRXFIFOSIZ(3)),
+	dump_register(GRXFIFOSIZ(4)),
+	dump_register(GRXFIFOSIZ(5)),
+	dump_register(GRXFIFOSIZ(6)),
+	dump_register(GRXFIFOSIZ(7)),
+	dump_register(GRXFIFOSIZ(8)),
+	dump_register(GRXFIFOSIZ(9)),
+	dump_register(GRXFIFOSIZ(10)),
+	dump_register(GRXFIFOSIZ(11)),
+	dump_register(GRXFIFOSIZ(12)),
+	dump_register(GRXFIFOSIZ(13)),
+	dump_register(GRXFIFOSIZ(14)),
+	dump_register(GRXFIFOSIZ(15)),
+	dump_register(GRXFIFOSIZ(16)),
+	dump_register(GRXFIFOSIZ(17)),
+	dump_register(GRXFIFOSIZ(18)),
+	dump_register(GRXFIFOSIZ(19)),
+	dump_register(GRXFIFOSIZ(20)),
+	dump_register(GRXFIFOSIZ(21)),
+	dump_register(GRXFIFOSIZ(22)),
+	dump_register(GRXFIFOSIZ(23)),
+	dump_register(GRXFIFOSIZ(24)),
+	dump_register(GRXFIFOSIZ(25)),
+	dump_register(GRXFIFOSIZ(26)),
+	dump_register(GRXFIFOSIZ(27)),
+	dump_register(GRXFIFOSIZ(28)),
+	dump_register(GRXFIFOSIZ(29)),
+	dump_register(GRXFIFOSIZ(30)),
+	dump_register(GRXFIFOSIZ(31)),
+
+	dump_register(GEVNTADRLO(0)),
+	dump_register(GEVNTADRHI(0)),
+	dump_register(GEVNTSIZ(0)),
+	dump_register(GEVNTCOUNT(0)),
+
+	dump_register(GHWPARAMS8),
+	dump_register(DCFG),
+	dump_register(DCTL),
+	dump_register(DEVTEN),
+	dump_register(DSTS),
+	dump_register(DGCMDPAR),
+	dump_register(DGCMD),
+	dump_register(DALEPENA),
+
+	dump_register(DEPCMDPAR2(0)),
+	dump_register(DEPCMDPAR2(1)),
+	dump_register(DEPCMDPAR2(2)),
+	dump_register(DEPCMDPAR2(3)),
+	dump_register(DEPCMDPAR2(4)),
+	dump_register(DEPCMDPAR2(5)),
+	dump_register(DEPCMDPAR2(6)),
+	dump_register(DEPCMDPAR2(7)),
+	dump_register(DEPCMDPAR2(8)),
+	dump_register(DEPCMDPAR2(9)),
+	dump_register(DEPCMDPAR2(10)),
+	dump_register(DEPCMDPAR2(11)),
+	dump_register(DEPCMDPAR2(12)),
+	dump_register(DEPCMDPAR2(13)),
+	dump_register(DEPCMDPAR2(14)),
+	dump_register(DEPCMDPAR2(15)),
+	dump_register(DEPCMDPAR2(16)),
+	dump_register(DEPCMDPAR2(17)),
+	dump_register(DEPCMDPAR2(18)),
+	dump_register(DEPCMDPAR2(19)),
+	dump_register(DEPCMDPAR2(20)),
+	dump_register(DEPCMDPAR2(21)),
+	dump_register(DEPCMDPAR2(22)),
+	dump_register(DEPCMDPAR2(23)),
+	dump_register(DEPCMDPAR2(24)),
+	dump_register(DEPCMDPAR2(25)),
+	dump_register(DEPCMDPAR2(26)),
+	dump_register(DEPCMDPAR2(27)),
+	dump_register(DEPCMDPAR2(28)),
+	dump_register(DEPCMDPAR2(29)),
+	dump_register(DEPCMDPAR2(30)),
+	dump_register(DEPCMDPAR2(31)),
+
+	dump_register(DEPCMDPAR1(0)),
+	dump_register(DEPCMDPAR1(1)),
+	dump_register(DEPCMDPAR1(2)),
+	dump_register(DEPCMDPAR1(3)),
+	dump_register(DEPCMDPAR1(4)),
+	dump_register(DEPCMDPAR1(5)),
+	dump_register(DEPCMDPAR1(6)),
+	dump_register(DEPCMDPAR1(7)),
+	dump_register(DEPCMDPAR1(8)),
+	dump_register(DEPCMDPAR1(9)),
+	dump_register(DEPCMDPAR1(10)),
+	dump_register(DEPCMDPAR1(11)),
+	dump_register(DEPCMDPAR1(12)),
+	dump_register(DEPCMDPAR1(13)),
+	dump_register(DEPCMDPAR1(14)),
+	dump_register(DEPCMDPAR1(15)),
+	dump_register(DEPCMDPAR1(16)),
+	dump_register(DEPCMDPAR1(17)),
+	dump_register(DEPCMDPAR1(18)),
+	dump_register(DEPCMDPAR1(19)),
+	dump_register(DEPCMDPAR1(20)),
+	dump_register(DEPCMDPAR1(21)),
+	dump_register(DEPCMDPAR1(22)),
+	dump_register(DEPCMDPAR1(23)),
+	dump_register(DEPCMDPAR1(24)),
+	dump_register(DEPCMDPAR1(25)),
+	dump_register(DEPCMDPAR1(26)),
+	dump_register(DEPCMDPAR1(27)),
+	dump_register(DEPCMDPAR1(28)),
+	dump_register(DEPCMDPAR1(29)),
+	dump_register(DEPCMDPAR1(30)),
+	dump_register(DEPCMDPAR1(31)),
+
+	dump_register(DEPCMDPAR0(0)),
+	dump_register(DEPCMDPAR0(1)),
+	dump_register(DEPCMDPAR0(2)),
+	dump_register(DEPCMDPAR0(3)),
+	dump_register(DEPCMDPAR0(4)),
+	dump_register(DEPCMDPAR0(5)),
+	dump_register(DEPCMDPAR0(6)),
+	dump_register(DEPCMDPAR0(7)),
+	dump_register(DEPCMDPAR0(8)),
+	dump_register(DEPCMDPAR0(9)),
+	dump_register(DEPCMDPAR0(10)),
+	dump_register(DEPCMDPAR0(11)),
+	dump_register(DEPCMDPAR0(12)),
+	dump_register(DEPCMDPAR0(13)),
+	dump_register(DEPCMDPAR0(14)),
+	dump_register(DEPCMDPAR0(15)),
+	dump_register(DEPCMDPAR0(16)),
+	dump_register(DEPCMDPAR0(17)),
+	dump_register(DEPCMDPAR0(18)),
+	dump_register(DEPCMDPAR0(19)),
+	dump_register(DEPCMDPAR0(20)),
+	dump_register(DEPCMDPAR0(21)),
+	dump_register(DEPCMDPAR0(22)),
+	dump_register(DEPCMDPAR0(23)),
+	dump_register(DEPCMDPAR0(24)),
+	dump_register(DEPCMDPAR0(25)),
+	dump_register(DEPCMDPAR0(26)),
+	dump_register(DEPCMDPAR0(27)),
+	dump_register(DEPCMDPAR0(28)),
+	dump_register(DEPCMDPAR0(29)),
+	dump_register(DEPCMDPAR0(30)),
+	dump_register(DEPCMDPAR0(31)),
+
+	dump_register(DEPCMD(0)),
+	dump_register(DEPCMD(1)),
+	dump_register(DEPCMD(2)),
+	dump_register(DEPCMD(3)),
+	dump_register(DEPCMD(4)),
+	dump_register(DEPCMD(5)),
+	dump_register(DEPCMD(6)),
+	dump_register(DEPCMD(7)),
+	dump_register(DEPCMD(8)),
+	dump_register(DEPCMD(9)),
+	dump_register(DEPCMD(10)),
+	dump_register(DEPCMD(11)),
+	dump_register(DEPCMD(12)),
+	dump_register(DEPCMD(13)),
+	dump_register(DEPCMD(14)),
+	dump_register(DEPCMD(15)),
+	dump_register(DEPCMD(16)),
+	dump_register(DEPCMD(17)),
+	dump_register(DEPCMD(18)),
+	dump_register(DEPCMD(19)),
+	dump_register(DEPCMD(20)),
+	dump_register(DEPCMD(21)),
+	dump_register(DEPCMD(22)),
+	dump_register(DEPCMD(23)),
+	dump_register(DEPCMD(24)),
+	dump_register(DEPCMD(25)),
+	dump_register(DEPCMD(26)),
+	dump_register(DEPCMD(27)),
+	dump_register(DEPCMD(28)),
+	dump_register(DEPCMD(29)),
+	dump_register(DEPCMD(30)),
+	dump_register(DEPCMD(31)),
+
+	dump_register(OCFG),
+	dump_register(OCTL),
+	dump_register(OEVTEN),
+	dump_register(OSTS),
+};
+
+static int dwc3_regdump_show(struct seq_file *s, void *unused)
+{
+	struct dwc3		*dwc = s->private;
+	int			i;
+
+	seq_printf(s, "DesignWare USB3 Core Register Dump\n");
+
+	for (i = 0; i < ARRAY_SIZE(dwc3_regs); i++) {
+		seq_printf(s, "%-20s :    %08x\n", dwc3_regs[i].name,
+				dwc3_readl(dwc->regs, dwc3_regs[i].offset));
+	}
+
+	return 0;
+}
+
+static int dwc3_regdump_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, dwc3_regdump_show, inode->i_private);
+}
+
+static const struct file_operations dwc3_regdump_fops = {
+	.open			= dwc3_regdump_open,
+	.read			= seq_read,
+	.release		= single_release,
+};
+
+int __devinit dwc3_debugfs_init(struct dwc3 *dwc)
+{
+	struct dentry		*root;
+	struct dentry		*file;
+	int			ret;
+
+	root = debugfs_create_dir(dev_name(dwc->dev), NULL);
+	if (IS_ERR(root)){
+		ret = PTR_ERR(root);
+		goto err0;
+	}
+
+	dwc->root = root;
+
+	file = debugfs_create_file("regdump", S_IRUGO, root, dwc,
+			&dwc3_regdump_fops);
+	if (IS_ERR(file)) {
+		ret = PTR_ERR(file);
+		goto err1;
+	}
+	return 0;
+
+err1:
+	debugfs_remove_recursive(root);
+
+err0:
+	return ret;
+}
+
+void __devexit dwc3_debugfs_exit(struct dwc3 *dwc)
+{
+	debugfs_remove_recursive(dwc->root);
+	dwc->root = NULL;
+}

+ 401 - 0
drivers/usb/dwc3/dwc3-omap.c

@@ -0,0 +1,401 @@
+/**
+ * dwc3-omap.c - OMAP Specific Glue layer
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/platform_data/dwc3-omap.h>
+#include <linux/dma-mapping.h>
+#include <linux/ioport.h>
+#include <linux/io.h>
+#include <linux/module.h>
+
+#include "io.h"
+
+/*
+ * All these registers belong to OMAP's Wrapper around the
+ * DesignWare USB3 Core.
+ */
+
+#define USBOTGSS_REVISION			0x0000
+#define USBOTGSS_SYSCONFIG			0x0010
+#define USBOTGSS_IRQ_EOI			0x0020
+#define USBOTGSS_IRQSTATUS_RAW_0		0x0024
+#define USBOTGSS_IRQSTATUS_0			0x0028
+#define USBOTGSS_IRQENABLE_SET_0		0x002c
+#define USBOTGSS_IRQENABLE_CLR_0		0x0030
+#define USBOTGSS_IRQSTATUS_RAW_1		0x0034
+#define USBOTGSS_IRQSTATUS_1			0x0038
+#define USBOTGSS_IRQENABLE_SET_1		0x003c
+#define USBOTGSS_IRQENABLE_CLR_1		0x0040
+#define USBOTGSS_UTMI_OTG_CTRL			0x0080
+#define USBOTGSS_UTMI_OTG_STATUS		0x0084
+#define USBOTGSS_MMRAM_OFFSET			0x0100
+#define USBOTGSS_FLADJ				0x0104
+#define USBOTGSS_DEBUG_CFG			0x0108
+#define USBOTGSS_DEBUG_DATA			0x010c
+
+/* SYSCONFIG REGISTER */
+#define USBOTGSS_SYSCONFIG_DMADISABLE		(1 << 16)
+#define USBOTGSS_SYSCONFIG_STANDBYMODE(x)	((x) << 4)
+
+#define USBOTGSS_STANDBYMODE_FORCE_STANDBY	0
+#define USBOTGSS_STANDBYMODE_NO_STANDBY		1
+#define USBOTGSS_STANDBYMODE_SMART_STANDBY	2
+#define USBOTGSS_STANDBYMODE_SMART_WAKEUP	3
+
+#define USBOTGSS_STANDBYMODE_MASK		(0x03 << 4)
+
+#define USBOTGSS_SYSCONFIG_IDLEMODE(x)		((x) << 2)
+
+#define USBOTGSS_IDLEMODE_FORCE_IDLE		0
+#define USBOTGSS_IDLEMODE_NO_IDLE		1
+#define USBOTGSS_IDLEMODE_SMART_IDLE		2
+#define USBOTGSS_IDLEMODE_SMART_WAKEUP		3
+
+#define USBOTGSS_IDLEMODE_MASK			(0x03 << 2)
+
+/* IRQ_EOI REGISTER */
+#define USBOTGSS_IRQ_EOI_LINE_NUMBER		(1 << 0)
+
+/* IRQS0 BITS */
+#define USBOTGSS_IRQO_COREIRQ_ST		(1 << 0)
+
+/* IRQ1 BITS */
+#define USBOTGSS_IRQ1_DMADISABLECLR		(1 << 17)
+#define USBOTGSS_IRQ1_OEVT			(1 << 16)
+#define USBOTGSS_IRQ1_DRVVBUS_RISE		(1 << 13)
+#define USBOTGSS_IRQ1_CHRGVBUS_RISE		(1 << 12)
+#define USBOTGSS_IRQ1_DISCHRGVBUS_RISE		(1 << 11)
+#define USBOTGSS_IRQ1_IDPULLUP_RISE		(1 << 8)
+#define USBOTGSS_IRQ1_DRVVBUS_FALL		(1 << 5)
+#define USBOTGSS_IRQ1_CHRGVBUS_FALL		(1 << 4)
+#define USBOTGSS_IRQ1_DISCHRGVBUS_FALL		(1 << 3)
+#define USBOTGSS_IRQ1_IDPULLUP_FALL		(1 << 0)
+
+/* UTMI_OTG_CTRL REGISTER */
+#define USBOTGSS_UTMI_OTG_CTRL_DRVVBUS		(1 << 5)
+#define USBOTGSS_UTMI_OTG_CTRL_CHRGVBUS		(1 << 4)
+#define USBOTGSS_UTMI_OTG_CTRL_DISCHRGVBUS	(1 << 3)
+#define USBOTGSS_UTMI_OTG_CTRL_IDPULLUP		(1 << 0)
+
+/* UTMI_OTG_STATUS REGISTER */
+#define USBOTGSS_UTMI_OTG_STATUS_SW_MODE	(1 << 31)
+#define USBOTGSS_UTMI_OTG_STATUS_POWERPRESENT	(1 << 9)
+#define USBOTGSS_UTMI_OTG_STATUS_TXBITSTUFFENABLE (1 << 8)
+#define USBOTGSS_UTMI_OTG_STATUS_IDDIG		(1 << 4)
+#define USBOTGSS_UTMI_OTG_STATUS_SESSEND	(1 << 3)
+#define USBOTGSS_UTMI_OTG_STATUS_SESSVALID	(1 << 2)
+#define USBOTGSS_UTMI_OTG_STATUS_VBUSVALID	(1 << 1)
+
+struct dwc3_omap {
+	/* device lock */
+	spinlock_t		lock;
+
+	struct platform_device	*dwc3;
+	struct device		*dev;
+
+	int			irq;
+	void __iomem		*base;
+
+	void			*context;
+	u32			resource_size;
+
+	u32			dma_status:1;
+};
+
+static irqreturn_t dwc3_omap_interrupt(int irq, void *_omap)
+{
+	struct dwc3_omap	*omap = _omap;
+	u32			reg;
+
+	spin_lock(&omap->lock);
+
+	reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_1);
+
+	if (reg & USBOTGSS_IRQ1_DMADISABLECLR) {
+		dev_dbg(omap->dev, "DMA Disable was Cleared\n");
+		omap->dma_status = false;
+	}
+
+	if (reg & USBOTGSS_IRQ1_OEVT)
+		dev_dbg(omap->dev, "OTG Event\n");
+
+	if (reg & USBOTGSS_IRQ1_DRVVBUS_RISE)
+		dev_dbg(omap->dev, "DRVVBUS Rise\n");
+
+	if (reg & USBOTGSS_IRQ1_CHRGVBUS_RISE)
+		dev_dbg(omap->dev, "CHRGVBUS Rise\n");
+
+	if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_RISE)
+		dev_dbg(omap->dev, "DISCHRGVBUS Rise\n");
+
+	if (reg & USBOTGSS_IRQ1_IDPULLUP_RISE)
+		dev_dbg(omap->dev, "IDPULLUP Rise\n");
+
+	if (reg & USBOTGSS_IRQ1_DRVVBUS_FALL)
+		dev_dbg(omap->dev, "DRVVBUS Fall\n");
+
+	if (reg & USBOTGSS_IRQ1_CHRGVBUS_FALL)
+		dev_dbg(omap->dev, "CHRGVBUS Fall\n");
+
+	if (reg & USBOTGSS_IRQ1_DISCHRGVBUS_FALL)
+		dev_dbg(omap->dev, "DISCHRGVBUS Fall\n");
+
+	if (reg & USBOTGSS_IRQ1_IDPULLUP_FALL)
+		dev_dbg(omap->dev, "IDPULLUP Fall\n");
+
+	dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_1, reg);
+
+	reg = dwc3_readl(omap->base, USBOTGSS_IRQSTATUS_0);
+	dwc3_writel(omap->base, USBOTGSS_IRQSTATUS_0, reg);
+
+	spin_unlock(&omap->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int __devinit dwc3_omap_probe(struct platform_device *pdev)
+{
+	struct dwc3_omap_data	*pdata = pdev->dev.platform_data;
+	struct platform_device	*dwc3;
+	struct dwc3_omap	*omap;
+	struct resource		*res;
+
+	int			ret = -ENOMEM;
+	int			irq;
+
+	u32			reg;
+
+	void __iomem		*base;
+	void			*context;
+
+	omap = kzalloc(sizeof(*omap), GFP_KERNEL);
+	if (!omap) {
+		dev_err(&pdev->dev, "not enough memory\n");
+		goto err0;
+	}
+
+	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;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (!res) {
+		dev_err(&pdev->dev, "missing memory base resource\n");
+		ret = -EINVAL;
+		goto err1;
+	}
+
+	base = ioremap_nocache(res->start, resource_size(res));
+	if (!base) {
+		dev_err(&pdev->dev, "ioremap failed\n");
+		goto err1;
+	}
+
+	dwc3 = platform_device_alloc("dwc3-omap", -1);
+	if (!dwc3) {
+		dev_err(&pdev->dev, "couldn't allocate dwc3 device\n");
+		goto err2;
+	}
+
+	context = kzalloc(resource_size(res), GFP_KERNEL);
+	if (!context) {
+		dev_err(&pdev->dev, "couldn't allocate dwc3 context memory\n");
+		goto err3;
+	}
+
+	spin_lock_init(&omap->lock);
+	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;
+	omap->resource_size = resource_size(res);
+	omap->context	= context;
+	omap->dev	= &pdev->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");
+	} 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);
+		}
+	}
+
+	dwc3_writel(omap->base, USBOTGSS_UTMI_OTG_STATUS, reg);
+
+	/* check the DMA Status */
+	reg = dwc3_readl(omap->base, USBOTGSS_SYSCONFIG);
+	omap->dma_status = !!(reg & USBOTGSS_SYSCONFIG_DMADISABLE);
+
+	/* Set No-Idle and No-Standby */
+	reg &= ~(USBOTGSS_STANDBYMODE_MASK
+			| USBOTGSS_IDLEMODE_MASK);
+
+	reg |= (USBOTGSS_SYSCONFIG_STANDBYMODE(USBOTGSS_STANDBYMODE_NO_STANDBY)
+		| USBOTGSS_SYSCONFIG_IDLEMODE(USBOTGSS_IDLEMODE_NO_IDLE));
+
+	dwc3_writel(omap->base, USBOTGSS_SYSCONFIG, reg);
+
+	ret = request_irq(omap->irq, dwc3_omap_interrupt, 0,
+			"dwc3-omap", omap);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to request IRQ #%d --> %d\n",
+				omap->irq, ret);
+		goto err4;
+	}
+
+	/* enable all IRQs */
+	reg = USBOTGSS_IRQO_COREIRQ_ST;
+	dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_0, reg);
+
+	reg = (USBOTGSS_IRQ1_OEVT |
+			USBOTGSS_IRQ1_DRVVBUS_RISE |
+			USBOTGSS_IRQ1_CHRGVBUS_RISE |
+			USBOTGSS_IRQ1_DISCHRGVBUS_RISE |
+			USBOTGSS_IRQ1_IDPULLUP_RISE |
+			USBOTGSS_IRQ1_DRVVBUS_FALL |
+			USBOTGSS_IRQ1_CHRGVBUS_FALL |
+			USBOTGSS_IRQ1_DISCHRGVBUS_FALL |
+			USBOTGSS_IRQ1_IDPULLUP_FALL);
+
+	dwc3_writel(omap->base, USBOTGSS_IRQENABLE_SET_1, reg);
+
+	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 err5;
+	}
+
+	ret = platform_device_add(dwc3);
+	if (ret) {
+		dev_err(&pdev->dev, "failed to register dwc3 device\n");
+		goto err5;
+	}
+
+	return 0;
+
+err5:
+	free_irq(omap->irq, omap);
+
+err4:
+	kfree(omap->context);
+
+err3:
+	platform_device_put(dwc3);
+
+err2:
+	iounmap(base);
+
+err1:
+	kfree(omap);
+
+err0:
+	return ret;
+}
+
+static int __devexit dwc3_omap_remove(struct platform_device *pdev)
+{
+	struct dwc3_omap	*omap = platform_get_drvdata(pdev);
+
+	platform_device_unregister(omap->dwc3);
+
+	free_irq(omap->irq, omap);
+	iounmap(omap->base);
+
+	kfree(omap->context);
+	kfree(omap);
+
+	return 0;
+}
+
+static const struct of_device_id of_dwc3_matach[] = {
+	{
+		"ti,dwc3",
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, of_dwc3_matach);
+
+static struct platform_driver dwc3_omap_driver = {
+	.probe		= dwc3_omap_probe,
+	.remove		= __devexit_p(dwc3_omap_remove),
+	.driver		= {
+		.name	= "omap-dwc3",
+		.of_match_table	= of_dwc3_matach,
+	},
+};
+
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_DESCRIPTION("DesignWare USB3 OMAP Glue Layer");
+
+static int __devinit dwc3_omap_init(void)
+{
+	return platform_driver_register(&dwc3_omap_driver);
+}
+module_init(dwc3_omap_init);
+
+static void __exit dwc3_omap_exit(void)
+{
+	platform_driver_unregister(&dwc3_omap_driver);
+}
+module_exit(dwc3_omap_exit);

+ 219 - 0
drivers/usb/dwc3/dwc3-pci.c

@@ -0,0 +1,219 @@
+/**
+ * dwc3-pci.c - PCI Specific glue layer
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+/* FIXME define these in <linux/pci_ids.h> */
+#define PCI_VENDOR_ID_SYNOPSYS		0x16c3
+#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3	0xabcd
+
+#define DWC3_PCI_DEVS_POSSIBLE	32
+
+struct dwc3_pci {
+	struct device		*dev;
+	struct platform_device	*dwc3;
+};
+
+static DECLARE_BITMAP(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
+
+static int dwc3_pci_get_device_id(struct dwc3_pci *glue)
+{
+	int		id;
+
+again:
+	id = find_first_zero_bit(dwc3_pci_devs, DWC3_PCI_DEVS_POSSIBLE);
+	if (id < DWC3_PCI_DEVS_POSSIBLE) {
+		int old;
+
+		old = test_and_set_bit(id, dwc3_pci_devs);
+		if (old)
+			goto again;
+	} else {
+		dev_err(glue->dev, "no space for new device\n");
+		id = -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void dwc3_pci_put_device_id(struct dwc3_pci *glue, int id)
+{
+	int			ret;
+
+	if (id < 0)
+		return;
+
+	ret = test_bit(id, dwc3_pci_devs);
+	WARN(!ret, "Device: %s\nID %d not in use\n",
+			dev_driver_string(glue->dev), id);
+	clear_bit(id, dwc3_pci_devs);
+}
+
+static int __devinit dwc3_pci_probe(struct pci_dev *pci,
+		const struct pci_device_id *id)
+{
+	struct resource		res[2];
+	struct platform_device	*dwc3;
+	struct dwc3_pci		*glue;
+	int			ret = -ENOMEM;
+	int			devid;
+
+	glue = kzalloc(sizeof(*glue), GFP_KERNEL);
+	if (!glue) {
+		dev_err(&pci->dev, "not enough memory\n");
+		goto err0;
+	}
+
+	glue->dev	= &pci->dev;
+
+	ret = pci_enable_device(pci);
+	if (ret) {
+		dev_err(&pci->dev, "failed to enable pci device\n");
+		goto err1;
+	}
+
+	pci_set_power_state(pci, PCI_D0);
+	pci_set_master(pci);
+
+	devid = dwc3_pci_get_device_id(glue);
+	if (devid < 0)
+		goto err2;
+
+	dwc3 = platform_device_alloc("dwc3-pci", devid);
+	if (!dwc3) {
+		dev_err(&pci->dev, "couldn't allocate dwc3 device\n");
+		goto err3;
+	}
+
+	memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
+
+	res[0].start	= pci_resource_start(pci, 0);
+	res[0].end	= pci_resource_end(pci, 0);
+	res[0].name	= "dwc_usb3";
+	res[0].flags	= IORESOURCE_MEM;
+
+	res[1].start	= pci->irq;
+	res[1].name	= "dwc_usb3";
+	res[1].flags	= IORESOURCE_IRQ;
+
+	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;
+	}
+
+	pci_set_drvdata(pci, glue);
+
+	dma_set_coherent_mask(&dwc3->dev, pci->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;
+
+	ret = platform_device_add(dwc3);
+	if (ret) {
+		dev_err(&pci->dev, "failed to register dwc3 device\n");
+		goto err4;
+	}
+
+	return 0;
+
+err4:
+	pci_set_drvdata(pci, NULL);
+	platform_device_put(dwc3);
+
+err3:
+	dwc3_pci_put_device_id(glue, devid);
+
+err2:
+	pci_disable_device(pci);
+
+err1:
+	kfree(pci);
+
+err0:
+	return ret;
+}
+
+static void __devexit dwc3_pci_remove(struct pci_dev *pci)
+{
+	struct dwc3_pci	*glue = pci_get_drvdata(pci);
+
+	dwc3_pci_put_device_id(glue, glue->dwc3->id);
+	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) = {
+	{
+		PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
+				PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
+	},
+	{  }	/* Terminating Entry */
+};
+MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
+
+static struct pci_driver dwc3_pci_driver = {
+	.name		= "pci-dwc3",
+	.id_table	= dwc3_pci_id_table,
+	.probe		= dwc3_pci_probe,
+	.remove		= __devexit_p(dwc3_pci_remove),
+};
+
+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);

+ 804 - 0
drivers/usb/dwc3/ep0.c

@@ -0,0 +1,804 @@
+/**
+ * ep0.c - DesignWare USB3 DRD Controller Endpoint 0 Handling
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event);
+
+static const char *dwc3_ep0_state_string(enum dwc3_ep0_state state)
+{
+	switch (state) {
+	case EP0_UNCONNECTED:
+		return "Unconnected";
+	case EP0_SETUP_PHASE:
+		return "Setup Phase";
+	case EP0_DATA_PHASE:
+		return "Data Phase";
+	case EP0_STATUS_PHASE:
+		return "Status Phase";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+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_ep			*dep;
+
+	int				ret;
+
+	dep = dwc->eps[epnum];
+	if (dep->flags & DWC3_EP_BUSY) {
+		dev_vdbg(dwc->dev, "%s: still busy\n", dep->name);
+		return 0;
+	}
+
+	trb_hw = dwc->ep0_trb;
+	memset(&trb, 0, sizeof(trb));
+
+	trb.trbctl = type;
+	trb.bplh = buf_dma;
+	trb.length = len;
+
+	trb.hwo	= 1;
+	trb.lst	= 1;
+	trb.ioc	= 1;
+	trb.isp_imi = 1;
+
+	dwc3_trb_to_hw(&trb, trb_hw);
+
+	memset(&params, 0, sizeof(params));
+	params.param0 = upper_32_bits(dwc->ep0_trb_addr);
+	params.param1 = lower_32_bits(dwc->ep0_trb_addr);
+
+	ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+			DWC3_DEPCMD_STARTTRANSFER, &params);
+	if (ret < 0) {
+		dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n");
+		return ret;
+	}
+
+	dep->flags |= DWC3_EP_BUSY;
+	dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
+			dep->number);
+
+	dwc->ep0_next_event = DWC3_EP0_COMPLETE;
+
+	return 0;
+}
+
+static int __dwc3_gadget_ep0_queue(struct dwc3_ep *dep,
+		struct dwc3_request *req)
+{
+	int			ret = 0;
+
+	req->request.actual	= 0;
+	req->request.status	= -EINPROGRESS;
+	req->epnum		= dep->number;
+
+	list_add_tail(&req->list, &dep->request_list);
+
+	/*
+	 * Gadget driver might not be quick enough to queue a request
+	 * before we get a Transfer Not Ready event on this endpoint.
+	 *
+	 * In that case, we will set DWC3_EP_PENDING_REQUEST. When that
+	 * flag is set, it's telling us that as soon as Gadget queues the
+	 * required request, we should kick the transfer here because the
+	 * IRQ we were waiting for is long gone.
+	 */
+	if (dep->flags & DWC3_EP_PENDING_REQUEST) {
+		struct dwc3	*dwc = dep->dwc;
+		unsigned	direction;
+		u32		type;
+
+		direction = !!(dep->flags & DWC3_EP0_DIR_IN);
+
+		if (dwc->ep0state == EP0_STATUS_PHASE) {
+			type = dwc->three_stage_setup
+				? DWC3_TRBCTL_CONTROL_STATUS3
+				: DWC3_TRBCTL_CONTROL_STATUS2;
+		} else if (dwc->ep0state == EP0_DATA_PHASE) {
+			type = DWC3_TRBCTL_CONTROL_DATA;
+		} else {
+			/* should never happen */
+			WARN_ON(1);
+			return 0;
+		}
+
+		ret = dwc3_ep0_start_trans(dwc, direction,
+				req->request.dma, req->request.length, type);
+		dep->flags &= ~(DWC3_EP_PENDING_REQUEST |
+				DWC3_EP0_DIR_IN);
+	}
+
+	return ret;
+}
+
+int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
+		gfp_t gfp_flags)
+{
+	struct dwc3_request		*req = to_dwc3_request(request);
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+	struct dwc3			*dwc = dep->dwc;
+
+	unsigned long			flags;
+
+	int				ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	if (!dep->desc) {
+		dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
+				request, dep->name);
+		ret = -ESHUTDOWN;
+		goto out;
+	}
+
+	/* we share one TRB for ep0/1 */
+	if (!list_empty(&dwc->eps[0]->request_list) ||
+			!list_empty(&dwc->eps[1]->request_list) ||
+			dwc->ep0_status_pending) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	dev_vdbg(dwc->dev, "queueing request %p to %s length %d, state '%s'\n",
+			request, dep->name, request->length,
+			dwc3_ep0_state_string(dwc->ep0state));
+
+	ret = __dwc3_gadget_ep0_queue(dep, req);
+
+out:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static void dwc3_ep0_stall_and_restart(struct dwc3 *dwc)
+{
+	struct dwc3_ep		*dep = dwc->eps[0];
+
+	/* stall is always issued on EP0 */
+	__dwc3_gadget_ep_set_halt(dwc->eps[0], 1);
+	dwc->eps[0]->flags = DWC3_EP_ENABLED;
+
+	if (!list_empty(&dep->request_list)) {
+		struct dwc3_request	*req;
+
+		req = next_request(&dep->request_list);
+		dwc3_gadget_giveback(dep, req, -ECONNRESET);
+	}
+
+	dwc->ep0state = EP0_SETUP_PHASE;
+	dwc3_ep0_out_start(dwc);
+}
+
+void dwc3_ep0_out_start(struct dwc3 *dwc)
+{
+	int				ret;
+
+	ret = dwc3_ep0_start_trans(dwc, 0, dwc->ctrl_req_addr, 8,
+			DWC3_TRBCTL_CONTROL_SETUP);
+	WARN_ON(ret < 0);
+}
+
+static struct dwc3_ep *dwc3_wIndex_to_dep(struct dwc3 *dwc, __le16 wIndex_le)
+{
+	struct dwc3_ep		*dep;
+	u32			windex = le16_to_cpu(wIndex_le);
+	u32			epnum;
+
+	epnum = (windex & USB_ENDPOINT_NUMBER_MASK) << 1;
+	if ((windex & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
+		epnum |= 1;
+
+	dep = dwc->eps[epnum];
+	if (dep->flags & DWC3_EP_ENABLED)
+		return dep;
+
+	return NULL;
+}
+
+static void dwc3_ep0_send_status_response(struct dwc3 *dwc)
+{
+	dwc3_ep0_start_trans(dwc, 1, dwc->setup_buf_addr,
+			dwc->ep0_usb_req.length,
+			DWC3_TRBCTL_CONTROL_DATA);
+}
+
+/*
+ * ch 9.4.5
+ */
+static int dwc3_ep0_handle_status(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+	struct dwc3_ep		*dep;
+	u32			recip;
+	u16			usb_status = 0;
+	__le16			*response_pkt;
+
+	recip = ctrl->bRequestType & USB_RECIP_MASK;
+	switch (recip) {
+	case USB_RECIP_DEVICE:
+		/*
+		 * We are self-powered. U1/U2/LTM will be set later
+		 * once we handle this states. RemoteWakeup is 0 on SS
+		 */
+		usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
+		break;
+
+	case USB_RECIP_INTERFACE:
+		/*
+		 * Function Remote Wake Capable	D0
+		 * Function Remote Wakeup	D1
+		 */
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		dep = dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
+		if (!dep)
+		       return -EINVAL;
+
+		if (dep->flags & DWC3_EP_STALL)
+			usb_status = 1 << USB_ENDPOINT_HALT;
+		break;
+	default:
+		return -EINVAL;
+	};
+
+	response_pkt = (__le16 *) dwc->setup_buf;
+	*response_pkt = cpu_to_le16(usb_status);
+	dwc->ep0_usb_req.length = sizeof(*response_pkt);
+	dwc->ep0_status_pending = 1;
+
+	return 0;
+}
+
+static int dwc3_ep0_handle_feature(struct dwc3 *dwc,
+		struct usb_ctrlrequest *ctrl, int set)
+{
+	struct dwc3_ep		*dep;
+	u32			recip;
+	u32			wValue;
+	u32			wIndex;
+	u32			reg;
+	int			ret;
+	u32			mode;
+
+	wValue = le16_to_cpu(ctrl->wValue);
+	wIndex = le16_to_cpu(ctrl->wIndex);
+	recip = ctrl->bRequestType & USB_RECIP_MASK;
+	switch (recip) {
+	case USB_RECIP_DEVICE:
+
+		/*
+		 * 9.4.1 says only only for SS, in AddressState only for
+		 * default control pipe
+		 */
+		switch (wValue) {
+		case USB_DEVICE_U1_ENABLE:
+		case USB_DEVICE_U2_ENABLE:
+		case USB_DEVICE_LTM_ENABLE:
+			if (dwc->dev_state != DWC3_CONFIGURED_STATE)
+				return -EINVAL;
+			if (dwc->speed != DWC3_DSTS_SUPERSPEED)
+				return -EINVAL;
+		}
+
+		/* XXX add U[12] & LTM */
+		switch (wValue) {
+		case USB_DEVICE_REMOTE_WAKEUP:
+			break;
+		case USB_DEVICE_U1_ENABLE:
+			break;
+		case USB_DEVICE_U2_ENABLE:
+			break;
+		case USB_DEVICE_LTM_ENABLE:
+			break;
+
+		case USB_DEVICE_TEST_MODE:
+			if ((wIndex & 0xff) != 0)
+				return -EINVAL;
+			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;
+		}
+		break;
+
+	case USB_RECIP_INTERFACE:
+		switch (wValue) {
+		case USB_INTRF_FUNC_SUSPEND:
+			if (wIndex & USB_INTRF_FUNC_SUSPEND_LP)
+				/* XXX enable Low power suspend */
+				;
+			if (wIndex & USB_INTRF_FUNC_SUSPEND_RW)
+				/* XXX enable remote wakeup */
+				;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	case USB_RECIP_ENDPOINT:
+		switch (wValue) {
+		case USB_ENDPOINT_HALT:
+
+			dep =  dwc3_wIndex_to_dep(dwc, ctrl->wIndex);
+			if (!dep)
+				return -EINVAL;
+			ret = __dwc3_gadget_ep_set_halt(dep, set);
+			if (ret)
+				return -EINVAL;
+			break;
+		default:
+			return -EINVAL;
+		}
+		break;
+
+	default:
+		return -EINVAL;
+	};
+
+	return 0;
+}
+
+static int dwc3_ep0_set_address(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+	u32 addr;
+	u32 reg;
+
+	addr = le16_to_cpu(ctrl->wValue);
+	if (addr > 127)
+		return -EINVAL;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+	reg &= ~(DWC3_DCFG_DEVADDR_MASK);
+	reg |= DWC3_DCFG_DEVADDR(addr);
+	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+	if (addr)
+		dwc->dev_state = DWC3_ADDRESS_STATE;
+	else
+		dwc->dev_state = DWC3_DEFAULT_STATE;
+
+	return 0;
+}
+
+static int dwc3_ep0_delegate_req(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+	int ret;
+
+	spin_unlock(&dwc->lock);
+	ret = dwc->gadget_driver->setup(&dwc->gadget, ctrl);
+	spin_lock(&dwc->lock);
+	return ret;
+}
+
+static int dwc3_ep0_set_config(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+	u32 cfg;
+	int ret;
+
+	dwc->start_config_issued = false;
+	cfg = le16_to_cpu(ctrl->wValue);
+
+	switch (dwc->dev_state) {
+	case DWC3_DEFAULT_STATE:
+		return -EINVAL;
+		break;
+
+	case DWC3_ADDRESS_STATE:
+		ret = dwc3_ep0_delegate_req(dwc, ctrl);
+		/* if the cfg matches and the cfg is non zero */
+		if (!ret && cfg)
+			dwc->dev_state = DWC3_CONFIGURED_STATE;
+		break;
+
+	case DWC3_CONFIGURED_STATE:
+		ret = dwc3_ep0_delegate_req(dwc, ctrl);
+		if (!cfg)
+			dwc->dev_state = DWC3_ADDRESS_STATE;
+		break;
+	}
+	return 0;
+}
+
+static int dwc3_ep0_std_request(struct dwc3 *dwc, struct usb_ctrlrequest *ctrl)
+{
+	int ret;
+
+	switch (ctrl->bRequest) {
+	case USB_REQ_GET_STATUS:
+		dev_vdbg(dwc->dev, "USB_REQ_GET_STATUS\n");
+		ret = dwc3_ep0_handle_status(dwc, ctrl);
+		break;
+	case USB_REQ_CLEAR_FEATURE:
+		dev_vdbg(dwc->dev, "USB_REQ_CLEAR_FEATURE\n");
+		ret = dwc3_ep0_handle_feature(dwc, ctrl, 0);
+		break;
+	case USB_REQ_SET_FEATURE:
+		dev_vdbg(dwc->dev, "USB_REQ_SET_FEATURE\n");
+		ret = dwc3_ep0_handle_feature(dwc, ctrl, 1);
+		break;
+	case USB_REQ_SET_ADDRESS:
+		dev_vdbg(dwc->dev, "USB_REQ_SET_ADDRESS\n");
+		ret = dwc3_ep0_set_address(dwc, ctrl);
+		break;
+	case USB_REQ_SET_CONFIGURATION:
+		dev_vdbg(dwc->dev, "USB_REQ_SET_CONFIGURATION\n");
+		ret = dwc3_ep0_set_config(dwc, ctrl);
+		break;
+	default:
+		dev_vdbg(dwc->dev, "Forwarding to gadget driver\n");
+		ret = dwc3_ep0_delegate_req(dwc, ctrl);
+		break;
+	};
+
+	return ret;
+}
+
+static void dwc3_ep0_inspect_setup(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	struct usb_ctrlrequest *ctrl = dwc->ctrl_req;
+	int ret;
+	u32 len;
+
+	if (!dwc->gadget_driver)
+		goto err;
+
+	len = le16_to_cpu(ctrl->wLength);
+	if (!len) {
+		dwc->three_stage_setup = false;
+		dwc->ep0_expect_in = false;
+		dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
+	} else {
+		dwc->three_stage_setup = true;
+		dwc->ep0_expect_in = !!(ctrl->bRequestType & USB_DIR_IN);
+		dwc->ep0_next_event = DWC3_EP0_NRDY_DATA;
+	}
+
+	if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
+		ret = dwc3_ep0_std_request(dwc, ctrl);
+	else
+		ret = dwc3_ep0_delegate_req(dwc, ctrl);
+
+	if (ret >= 0)
+		return;
+
+err:
+	dwc3_ep0_stall_and_restart(dwc);
+}
+
+static void dwc3_ep0_complete_data(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	struct dwc3_request	*r = NULL;
+	struct usb_request	*ur;
+	struct dwc3_trb		trb;
+	struct dwc3_ep		*dep;
+	u32			transferred;
+	u8			epnum;
+
+	epnum = event->endpoint_number;
+	dep = dwc->eps[epnum];
+
+	dwc->ep0_next_event = DWC3_EP0_NRDY_STATUS;
+
+	if (!dwc->ep0_status_pending) {
+		r = next_request(&dwc->eps[0]->request_list);
+		ur = &r->request;
+	} else {
+		ur = &dwc->ep0_usb_req;
+		dwc->ep0_status_pending = 0;
+	}
+
+	dwc3_trb_to_nat(dwc->ep0_trb, &trb);
+
+	if (dwc->ep0_bounced) {
+		struct dwc3_ep	*ep0 = dwc->eps[0];
+
+		transferred = min_t(u32, ur->length,
+				ep0->endpoint.maxpacket - trb.length);
+		memcpy(ur->buf, dwc->ep0_bounce, transferred);
+		dwc->ep0_bounced = false;
+	} else {
+		transferred = ur->length - trb.length;
+		ur->actual += transferred;
+	}
+
+	if ((epnum & 1) && ur->actual < ur->length) {
+		/* for some reason we did not get everything out */
+
+		dwc3_ep0_stall_and_restart(dwc);
+	} else {
+		/*
+		 * handle the case where we have to send a zero packet. This
+		 * seems to be case when req.length > maxpacket. Could it be?
+		 */
+		if (r)
+			dwc3_gadget_giveback(dep, r, 0);
+	}
+}
+
+static void dwc3_ep0_complete_req(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	struct dwc3_request	*r;
+	struct dwc3_ep		*dep;
+
+	dep = dwc->eps[0];
+
+	if (!list_empty(&dep->request_list)) {
+		r = next_request(&dep->request_list);
+
+		dwc3_gadget_giveback(dep, r, 0);
+	}
+
+	dwc->ep0state = EP0_SETUP_PHASE;
+	dwc3_ep0_out_start(dwc);
+}
+
+static void dwc3_ep0_xfer_complete(struct dwc3 *dwc,
+			const struct dwc3_event_depevt *event)
+{
+	struct dwc3_ep		*dep = dwc->eps[event->endpoint_number];
+
+	dep->flags &= ~DWC3_EP_BUSY;
+
+	switch (dwc->ep0state) {
+	case EP0_SETUP_PHASE:
+		dev_vdbg(dwc->dev, "Inspecting Setup Bytes\n");
+		dwc3_ep0_inspect_setup(dwc, event);
+		break;
+
+	case EP0_DATA_PHASE:
+		dev_vdbg(dwc->dev, "Data Phase\n");
+		dwc3_ep0_complete_data(dwc, event);
+		break;
+
+	case EP0_STATUS_PHASE:
+		dev_vdbg(dwc->dev, "Status Phase\n");
+		dwc3_ep0_complete_req(dwc, event);
+		break;
+	default:
+		WARN(true, "UNKNOWN ep0state %d\n", dwc->ep0state);
+	}
+}
+
+static void dwc3_ep0_do_control_setup(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	dwc->ep0state = EP0_SETUP_PHASE;
+	dwc3_ep0_out_start(dwc);
+}
+
+static void dwc3_ep0_do_control_data(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	struct dwc3_ep		*dep;
+	struct dwc3_request	*req;
+	int			ret;
+
+	dep = dwc->eps[0];
+	dwc->ep0state = EP0_DATA_PHASE;
+
+	if (dwc->ep0_status_pending) {
+		dwc3_ep0_send_status_response(dwc);
+		return;
+	}
+
+	if (list_empty(&dep->request_list)) {
+		dev_vdbg(dwc->dev, "pending request for EP0 Data phase\n");
+		dep->flags |= DWC3_EP_PENDING_REQUEST;
+
+		if (event->endpoint_number)
+			dep->flags |= DWC3_EP0_DIR_IN;
+		return;
+	}
+
+	req = next_request(&dep->request_list);
+	req->direction = !!event->endpoint_number;
+
+	dwc->ep0state = EP0_DATA_PHASE;
+	if (req->request.length == 0) {
+		ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
+				dwc->ctrl_req_addr, 0,
+				DWC3_TRBCTL_CONTROL_DATA);
+	} else if ((req->request.length % dep->endpoint.maxpacket)
+			&& (event->endpoint_number == 0)) {
+		dwc3_map_buffer_to_dma(req);
+
+		WARN_ON(req->request.length > dep->endpoint.maxpacket);
+
+		dwc->ep0_bounced = true;
+
+		/*
+		 * REVISIT in case request length is bigger than EP0
+		 * wMaxPacketSize, we will need two chained TRBs to handle
+		 * the transfer.
+		 */
+		ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
+				dwc->ep0_bounce_addr, dep->endpoint.maxpacket,
+				DWC3_TRBCTL_CONTROL_DATA);
+	} else {
+		dwc3_map_buffer_to_dma(req);
+
+		ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
+				req->request.dma, req->request.length,
+				DWC3_TRBCTL_CONTROL_DATA);
+	}
+
+	WARN_ON(ret < 0);
+}
+
+static void dwc3_ep0_do_control_status(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	u32			type;
+	int			ret;
+
+	dwc->ep0state = EP0_STATUS_PHASE;
+
+	type = dwc->three_stage_setup ? DWC3_TRBCTL_CONTROL_STATUS3
+		: DWC3_TRBCTL_CONTROL_STATUS2;
+
+	ret = dwc3_ep0_start_trans(dwc, event->endpoint_number,
+			dwc->ctrl_req_addr, 0, type);
+
+	WARN_ON(ret < 0);
+}
+
+static void dwc3_ep0_xfernotready(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	switch (event->status) {
+	case DEPEVT_STATUS_CONTROL_SETUP:
+		dev_vdbg(dwc->dev, "Control Setup\n");
+		dwc3_ep0_do_control_setup(dwc, event);
+		break;
+
+	case DEPEVT_STATUS_CONTROL_DATA:
+		dev_vdbg(dwc->dev, "Control Data\n");
+
+		if (dwc->ep0_next_event != DWC3_EP0_NRDY_DATA) {
+			dev_vdbg(dwc->dev, "Expected %d got %d\n",
+					dwc->ep0_next_event,
+					DWC3_EP0_NRDY_DATA);
+
+			dwc3_ep0_stall_and_restart(dwc);
+			return;
+		}
+
+		/*
+		 * One of the possible error cases is when Host _does_
+		 * request for Data Phase, but it does so on the wrong
+		 * direction.
+		 *
+		 * Here, we already know ep0_next_event is DATA (see above),
+		 * so we only need to check for direction.
+		 */
+		if (dwc->ep0_expect_in != event->endpoint_number) {
+			dev_vdbg(dwc->dev, "Wrong direction for Data phase\n");
+			dwc3_ep0_stall_and_restart(dwc);
+			return;
+		}
+
+		dwc3_ep0_do_control_data(dwc, event);
+		break;
+
+	case DEPEVT_STATUS_CONTROL_STATUS:
+		dev_vdbg(dwc->dev, "Control Status\n");
+
+		if (dwc->ep0_next_event != DWC3_EP0_NRDY_STATUS) {
+			dev_vdbg(dwc->dev, "Expected %d got %d\n",
+					dwc->ep0_next_event,
+					DWC3_EP0_NRDY_STATUS);
+
+			dwc3_ep0_stall_and_restart(dwc);
+			return;
+		}
+		dwc3_ep0_do_control_status(dwc, event);
+	}
+}
+
+void dwc3_ep0_interrupt(struct dwc3 *dwc,
+		const const struct dwc3_event_depevt *event)
+{
+	u8			epnum = event->endpoint_number;
+
+	dev_dbg(dwc->dev, "%s while ep%d%s in state '%s'\n",
+			dwc3_ep_event_string(event->endpoint_event),
+			epnum >> 1, (epnum & 1) ? "in" : "out",
+			dwc3_ep0_state_string(dwc->ep0state));
+
+	switch (event->endpoint_event) {
+	case DWC3_DEPEVT_XFERCOMPLETE:
+		dwc3_ep0_xfer_complete(dwc, event);
+		break;
+
+	case DWC3_DEPEVT_XFERNOTREADY:
+		dwc3_ep0_xfernotready(dwc, event);
+		break;
+
+	case DWC3_DEPEVT_XFERINPROGRESS:
+	case DWC3_DEPEVT_RXTXFIFOEVT:
+	case DWC3_DEPEVT_STREAMEVT:
+	case DWC3_DEPEVT_EPCMDCMPLT:
+		break;
+	}
+}

+ 2104 - 0
drivers/usb/dwc3/gadget.c

@@ -0,0 +1,2104 @@
+/**
+ * gadget.c - DesignWare USB3 DRD Controller Gadget Framework Link
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/list.h>
+#include <linux/dma-mapping.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include "core.h"
+#include "gadget.h"
+#include "io.h"
+
+#define	DMA_ADDR_INVALID	(~(dma_addr_t)0)
+
+void dwc3_map_buffer_to_dma(struct dwc3_request *req)
+{
+	struct dwc3			*dwc = req->dep->dwc;
+
+	if (req->request.length == 0) {
+		/* req->request.dma = dwc->setup_buf_addr; */
+		return;
+	}
+
+	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;
+	}
+}
+
+void dwc3_unmap_buffer_from_dma(struct dwc3_request *req)
+{
+	struct dwc3			*dwc = req->dep->dwc;
+
+	if (req->request.length == 0) {
+		req->request.dma = DMA_ADDR_INVALID;
+		return;
+	}
+
+	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;
+	}
+}
+
+void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
+		int status)
+{
+	struct dwc3			*dwc = dep->dwc;
+
+	if (req->queued) {
+		dep->busy_slot++;
+		/*
+		 * Skip LINK TRB. We can't use req->trb and check for
+		 * DWC3_TRBCTL_LINK_TRB because it points the TRB we just
+		 * completed (not the LINK TRB).
+		 */
+		if (((dep->busy_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
+				usb_endpoint_xfer_isoc(dep->desc))
+			dep->busy_slot++;
+	}
+	list_del(&req->list);
+
+	if (req->request.status == -EINPROGRESS)
+		req->request.status = status;
+
+	dwc3_unmap_buffer_from_dma(req);
+
+	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);
+	spin_lock(&dwc->lock);
+}
+
+static const char *dwc3_gadget_ep_cmd_string(u8 cmd)
+{
+	switch (cmd) {
+	case DWC3_DEPCMD_DEPSTARTCFG:
+		return "Start New Configuration";
+	case DWC3_DEPCMD_ENDTRANSFER:
+		return "End Transfer";
+	case DWC3_DEPCMD_UPDATETRANSFER:
+		return "Update Transfer";
+	case DWC3_DEPCMD_STARTTRANSFER:
+		return "Start Transfer";
+	case DWC3_DEPCMD_CLEARSTALL:
+		return "Clear Stall";
+	case DWC3_DEPCMD_SETSTALL:
+		return "Set Stall";
+	case DWC3_DEPCMD_GETSEQNUMBER:
+		return "Get Data Sequence Number";
+	case DWC3_DEPCMD_SETTRANSFRESOURCE:
+		return "Set Endpoint Transfer Resource";
+	case DWC3_DEPCMD_SETEPCONFIG:
+		return "Set Endpoint Configuration";
+	default:
+		return "UNKNOWN command";
+	}
+}
+
+int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
+		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
+{
+	struct dwc3_ep		*dep = dwc->eps[ep];
+	u32			timeout = 500;
+	u32			reg;
+
+	dev_vdbg(dwc->dev, "%s: cmd '%s' params %08x %08x %08x\n",
+			dep->name,
+			dwc3_gadget_ep_cmd_string(cmd), params->param0,
+			params->param1, params->param2);
+
+	dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0);
+	dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1);
+	dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2);
+
+	dwc3_writel(dwc->regs, DWC3_DEPCMD(ep), cmd | DWC3_DEPCMD_CMDACT);
+	do {
+		reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep));
+		if (!(reg & DWC3_DEPCMD_CMDACT)) {
+			dev_vdbg(dwc->dev, "Command Complete --> %d\n",
+					DWC3_DEPCMD_STATUS(reg));
+			return 0;
+		}
+
+		/*
+		 * We can't sleep here, because it is also called from
+		 * interrupt context.
+		 */
+		timeout--;
+		if (!timeout)
+			return -ETIMEDOUT;
+
+		udelay(1);
+	} while (1);
+}
+
+static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep,
+		struct dwc3_trb_hw *trb)
+{
+	u32		offset = (char *) trb - (char *) dep->trb_pool;
+
+	return dep->trb_pool_dma + offset;
+}
+
+static int dwc3_alloc_trb_pool(struct dwc3_ep *dep)
+{
+	struct dwc3		*dwc = dep->dwc;
+
+	if (dep->trb_pool)
+		return 0;
+
+	if (dep->number == 0 || dep->number == 1)
+		return 0;
+
+	dep->trb_pool = dma_alloc_coherent(dwc->dev,
+			sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
+			&dep->trb_pool_dma, GFP_KERNEL);
+	if (!dep->trb_pool) {
+		dev_err(dep->dwc->dev, "failed to allocate trb pool for %s\n",
+				dep->name);
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+static void dwc3_free_trb_pool(struct dwc3_ep *dep)
+{
+	struct dwc3		*dwc = dep->dwc;
+
+	dma_free_coherent(dwc->dev, sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
+			dep->trb_pool, dep->trb_pool_dma);
+
+	dep->trb_pool = NULL;
+	dep->trb_pool_dma = 0;
+}
+
+static int dwc3_gadget_start_config(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+	u32			cmd;
+
+	memset(&params, 0x00, sizeof(params));
+
+	if (dep->number != 1) {
+		cmd = DWC3_DEPCMD_DEPSTARTCFG;
+		/* XferRscIdx == 0 for ep0 and 2 for the remaining */
+		if (dep->number > 1) {
+			if (dwc->start_config_issued)
+				return 0;
+			dwc->start_config_issued = true;
+			cmd |= DWC3_DEPCMD_PARAM(2);
+		}
+
+		return dwc3_send_gadget_ep_cmd(dwc, 0, cmd, &params);
+	}
+
+	return 0;
+}
+
+static int dwc3_gadget_set_ep_config(struct dwc3 *dwc, struct dwc3_ep *dep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+
+	memset(&params, 0x00, sizeof(params));
+
+	params.param0 = DWC3_DEPCFG_EP_TYPE(usb_endpoint_type(desc))
+		| DWC3_DEPCFG_MAX_PACKET_SIZE(usb_endpoint_maxp(desc))
+		| DWC3_DEPCFG_BURST_SIZE(dep->endpoint.maxburst);
+
+	params.param1 = DWC3_DEPCFG_XFER_COMPLETE_EN
+		| DWC3_DEPCFG_XFER_NOT_READY_EN;
+
+	if (usb_endpoint_xfer_bulk(desc) && dep->endpoint.max_streams) {
+		params.param1 |= DWC3_DEPCFG_STREAM_CAPABLE
+			| DWC3_DEPCFG_STREAM_EVENT_EN;
+		dep->stream_capable = true;
+	}
+
+	if (usb_endpoint_xfer_isoc(desc))
+		params.param1 |= DWC3_DEPCFG_XFER_IN_PROGRESS_EN;
+
+	/*
+	 * We are doing 1:1 mapping for endpoints, meaning
+	 * Physical Endpoints 2 maps to Logical Endpoint 2 and
+	 * so on. We consider the direction bit as part of the physical
+	 * endpoint number. So USB endpoint 0x81 is 0x03.
+	 */
+	params.param1 |= DWC3_DEPCFG_EP_NUMBER(dep->number);
+
+	/*
+	 * We must use the lower 16 TX FIFOs even though
+	 * HW might have more
+	 */
+	if (dep->direction)
+		params.param0 |= DWC3_DEPCFG_FIFO_NUMBER(dep->number >> 1);
+
+	if (desc->bInterval) {
+		params.param1 |= DWC3_DEPCFG_BINTERVAL_M1(desc->bInterval - 1);
+		dep->interval = 1 << (desc->bInterval - 1);
+	}
+
+	return dwc3_send_gadget_ep_cmd(dwc, dep->number,
+			DWC3_DEPCMD_SETEPCONFIG, &params);
+}
+
+static int dwc3_gadget_set_xfer_resource(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+
+	memset(&params, 0x00, sizeof(params));
+
+	params.param0 = DWC3_DEPXFERCFG_NUM_XFER_RES(1);
+
+	return dwc3_send_gadget_ep_cmd(dwc, dep->number,
+			DWC3_DEPCMD_SETTRANSFRESOURCE, &params);
+}
+
+/**
+ * __dwc3_gadget_ep_enable - Initializes a HW endpoint
+ * @dep: endpoint to be initialized
+ * @desc: USB Endpoint Descriptor
+ *
+ * Caller should take care of locking
+ */
+static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	struct dwc3		*dwc = dep->dwc;
+	u32			reg;
+	int			ret = -ENOMEM;
+
+	if (!(dep->flags & DWC3_EP_ENABLED)) {
+		ret = dwc3_gadget_start_config(dwc, dep);
+		if (ret)
+			return ret;
+	}
+
+	ret = dwc3_gadget_set_ep_config(dwc, dep, desc);
+	if (ret)
+		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;
+
+		ret = dwc3_gadget_set_xfer_resource(dwc, dep);
+		if (ret)
+			return ret;
+
+		dep->desc = desc;
+		dep->type = usb_endpoint_type(desc);
+		dep->flags |= DWC3_EP_ENABLED;
+
+		reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
+		reg |= DWC3_DALEPENA_EP(dep->number);
+		dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
+
+		if (!usb_endpoint_xfer_isoc(desc))
+			return 0;
+
+		memset(&trb_link, 0, sizeof(trb_link));
+
+		/* Link TRB for ISOC. The HWO but 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_hw = &dep->trb_pool[DWC3_TRB_NUM - 1];
+		dwc3_trb_to_hw(&trb_link, trb_link_hw);
+	}
+
+	return 0;
+}
+
+static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum);
+static void dwc3_remove_requests(struct dwc3 *dwc, struct dwc3_ep *dep)
+{
+	struct dwc3_request		*req;
+
+	if (!list_empty(&dep->req_queued))
+		dwc3_stop_active_transfer(dwc, dep->number);
+
+	while (!list_empty(&dep->request_list)) {
+		req = next_request(&dep->request_list);
+
+		dwc3_gadget_giveback(dep, req, -ESHUTDOWN);
+	}
+}
+
+/**
+ * __dwc3_gadget_ep_disable - Disables a HW endpoint
+ * @dep: the endpoint to disable
+ *
+ * This function also removes requests which are currently processed ny the
+ * hardware and those which are not yet scheduled.
+ * Caller should take care of locking.
+ */
+static int __dwc3_gadget_ep_disable(struct dwc3_ep *dep)
+{
+	struct dwc3		*dwc = dep->dwc;
+	u32			reg;
+
+	dwc3_remove_requests(dwc, dep);
+
+	reg = dwc3_readl(dwc->regs, DWC3_DALEPENA);
+	reg &= ~DWC3_DALEPENA_EP(dep->number);
+	dwc3_writel(dwc->regs, DWC3_DALEPENA, reg);
+
+	dep->stream_capable = false;
+	dep->desc = NULL;
+	dep->type = 0;
+	dep->flags = 0;
+
+	return 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_ep0_enable(struct usb_ep *ep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	return -EINVAL;
+}
+
+static int dwc3_gadget_ep0_disable(struct usb_ep *ep)
+{
+	return -EINVAL;
+}
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_ep_enable(struct usb_ep *ep,
+		const struct usb_endpoint_descriptor *desc)
+{
+	struct dwc3_ep			*dep;
+	struct dwc3			*dwc;
+	unsigned long			flags;
+	int				ret;
+
+	if (!ep || !desc || desc->bDescriptorType != USB_DT_ENDPOINT) {
+		pr_debug("dwc3: invalid parameters\n");
+		return -EINVAL;
+	}
+
+	if (!desc->wMaxPacketSize) {
+		pr_debug("dwc3: missing wMaxPacketSize\n");
+		return -EINVAL;
+	}
+
+	dep = to_dwc3_ep(ep);
+	dwc = dep->dwc;
+
+	switch (usb_endpoint_type(desc)) {
+	case USB_ENDPOINT_XFER_CONTROL:
+		strncat(dep->name, "-control", sizeof(dep->name));
+		break;
+	case USB_ENDPOINT_XFER_ISOC:
+		strncat(dep->name, "-isoc", sizeof(dep->name));
+		break;
+	case USB_ENDPOINT_XFER_BULK:
+		strncat(dep->name, "-bulk", sizeof(dep->name));
+		break;
+	case USB_ENDPOINT_XFER_INT:
+		strncat(dep->name, "-int", sizeof(dep->name));
+		break;
+	default:
+		dev_err(dwc->dev, "invalid endpoint transfer type\n");
+	}
+
+	if (dep->flags & DWC3_EP_ENABLED) {
+		dev_WARN_ONCE(dwc->dev, true, "%s is already enabled\n",
+				dep->name);
+		return 0;
+	}
+
+	dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	ret = __dwc3_gadget_ep_enable(dep, desc);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static int dwc3_gadget_ep_disable(struct usb_ep *ep)
+{
+	struct dwc3_ep			*dep;
+	struct dwc3			*dwc;
+	unsigned long			flags;
+	int				ret;
+
+	if (!ep) {
+		pr_debug("dwc3: invalid parameters\n");
+		return -EINVAL;
+	}
+
+	dep = to_dwc3_ep(ep);
+	dwc = dep->dwc;
+
+	if (!(dep->flags & DWC3_EP_ENABLED)) {
+		dev_WARN_ONCE(dwc->dev, true, "%s is already disabled\n",
+				dep->name);
+		return 0;
+	}
+
+	snprintf(dep->name, sizeof(dep->name), "ep%d%s",
+			dep->number >> 1,
+			(dep->number & 1) ? "in" : "out");
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	ret = __dwc3_gadget_ep_disable(dep);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static struct usb_request *dwc3_gadget_ep_alloc_request(struct usb_ep *ep,
+	gfp_t gfp_flags)
+{
+	struct dwc3_request		*req;
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+	struct dwc3			*dwc = dep->dwc;
+
+	req = kzalloc(sizeof(*req), gfp_flags);
+	if (!req) {
+		dev_err(dwc->dev, "not enough memory\n");
+		return NULL;
+	}
+
+	req->epnum	= dep->number;
+	req->dep	= dep;
+	req->request.dma = DMA_ADDR_INVALID;
+
+	return &req->request;
+}
+
+static void dwc3_gadget_ep_free_request(struct usb_ep *ep,
+		struct usb_request *request)
+{
+	struct dwc3_request		*req = to_dwc3_request(request);
+
+	kfree(req);
+}
+
+/*
+ * dwc3_prepare_trbs - setup TRBs from requests
+ * @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.
+ */
+static struct dwc3_request *dwc3_prepare_trbs(struct dwc3_ep *dep,
+		bool starting)
+{
+	struct dwc3_request	*req, *n, *ret = NULL;
+	struct dwc3_trb_hw	*trb_hw;
+	struct dwc3_trb		trb;
+	u32			trbs_left;
+
+	BUILD_BUG_ON_NOT_POWER_OF_2(DWC3_TRB_NUM);
+
+	/* the first request must not be queued */
+	trbs_left = (dep->busy_slot - dep->free_slot) & DWC3_TRB_MASK;
+	/*
+	 * if busy & slot are equal than it is either full or empty. If we are
+	 * starting to proceed requests then we are empty. Otherwise we ar
+	 * full and don't do anything
+	 */
+	if (!trbs_left) {
+		if (!starting)
+			return NULL;
+		trbs_left = DWC3_TRB_NUM;
+		/*
+		 * 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
+		 * 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
+		 * processed from the first TRB until the last one. Since we
+		 * don't wrap around we have to start at the beginning.
+		 */
+		if (usb_endpoint_xfer_isoc(dep->desc)) {
+			dep->busy_slot = 1;
+			dep->free_slot = 1;
+		} else {
+			dep->busy_slot = 0;
+			dep->free_slot = 0;
+		}
+	}
+
+	/* The last TRB is a link TRB, not used for xfer */
+	if ((trbs_left <= 1) && usb_endpoint_xfer_isoc(dep->desc))
+		return NULL;
+
+	list_for_each_entry_safe(req, n, &dep->request_list, list) {
+		unsigned int last_one = 0;
+		unsigned int cur_slot;
+
+		trb_hw = &dep->trb_pool[dep->free_slot & DWC3_TRB_MASK];
+		cur_slot = dep->free_slot;
+		dep->free_slot++;
+
+		/* Skip the LINK-TRB on ISOC */
+		if (((cur_slot & DWC3_TRB_MASK) == DWC3_TRB_NUM - 1) &&
+				usb_endpoint_xfer_isoc(dep->desc))
+			continue;
+
+		dwc3_gadget_move_request_queued(req);
+		memset(&trb, 0, sizeof(trb));
+		trbs_left--;
+
+		/* Is our TRB pool empty? */
+		if (!trbs_left)
+			last_one = 1;
+		/* Is this the last request? */
+		if (list_empty(&dep->request_list))
+			last_one = 1;
+
+		/*
+		 * FIXME we shouldn't need to set LST bit always but we are
+		 * facing some weird problem with the Hardware where it doesn't
+		 * complete even though it has been previously started.
+		 *
+		 * While we're debugging the problem, as a workaround to
+		 * multiple TRBs handling, use only one TRB at a time.
+		 */
+		last_one = 1;
+
+		req->trb = trb_hw;
+		if (!ret)
+			ret = req;
+
+		trb.bplh = req->request.dma;
+
+		if (usb_endpoint_xfer_isoc(dep->desc)) {
+			trb.isp_imi = true;
+			trb.csp = true;
+		} else {
+			trb.lst = last_one;
+		}
+
+		if (usb_endpoint_xfer_bulk(dep->desc) && dep->stream_capable)
+			trb.sid_sofn = req->request.stream_id;
+
+		switch (usb_endpoint_type(dep->desc)) {
+		case USB_ENDPOINT_XFER_CONTROL:
+			trb.trbctl = DWC3_TRBCTL_CONTROL_SETUP;
+			break;
+
+		case USB_ENDPOINT_XFER_ISOC:
+			trb.trbctl = DWC3_TRBCTL_ISOCHRONOUS_FIRST;
+
+			/* IOC every DWC3_TRB_NUM / 4 so we can refill */
+			if (!(cur_slot % (DWC3_TRB_NUM / 4)))
+				trb.ioc = last_one;
+			break;
+
+		case USB_ENDPOINT_XFER_BULK:
+		case USB_ENDPOINT_XFER_INT:
+			trb.trbctl = DWC3_TRBCTL_NORMAL;
+			break;
+		default:
+			/*
+			 * This is only possible with faulty memory because we
+			 * checked it already :)
+			 */
+			BUG();
+		}
+
+		trb.length	= req->request.length;
+		trb.hwo = true;
+
+		dwc3_trb_to_hw(&trb, trb_hw);
+		req->trb_dma = dwc3_trb_dma_offset(dep, trb_hw);
+
+		if (last_one)
+			break;
+	}
+
+	return ret;
+}
+
+static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
+		int start_new)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+	struct dwc3_request		*req;
+	struct dwc3			*dwc = dep->dwc;
+	int				ret;
+	u32				cmd;
+
+	if (start_new && (dep->flags & DWC3_EP_BUSY)) {
+		dev_vdbg(dwc->dev, "%s: endpoint busy\n", dep->name);
+		return -EBUSY;
+	}
+	dep->flags &= ~DWC3_EP_PENDING_REQUEST;
+
+	/*
+	 * If we are getting here after a short-out-packet we don't enqueue any
+	 * new requests as we try to set the IOC bit only on the last request.
+	 */
+	if (start_new) {
+		if (list_empty(&dep->req_queued))
+			dwc3_prepare_trbs(dep, start_new);
+
+		/* req points to the first request which will be sent */
+		req = next_request(&dep->req_queued);
+	} else {
+		/*
+		 * req points to the first request where HWO changed
+		 * from 0 to 1
+		 */
+		req = dwc3_prepare_trbs(dep, start_new);
+	}
+	if (!req) {
+		dep->flags |= DWC3_EP_PENDING_REQUEST;
+		return 0;
+	}
+
+	memset(&params, 0, sizeof(params));
+	params.param0 = upper_32_bits(req->trb_dma);
+	params.param1 = lower_32_bits(req->trb_dma);
+
+	if (start_new)
+		cmd = DWC3_DEPCMD_STARTTRANSFER;
+	else
+		cmd = DWC3_DEPCMD_UPDATETRANSFER;
+
+	cmd |= DWC3_DEPCMD_PARAM(cmd_param);
+	ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
+	if (ret < 0) {
+		dev_dbg(dwc->dev, "failed to send STARTTRANSFER command\n");
+
+		/*
+		 * 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.
+		 */
+		dwc3_unmap_buffer_from_dma(req);
+		list_del(&req->list);
+		return ret;
+	}
+
+	dep->flags |= DWC3_EP_BUSY;
+	dep->res_trans_idx = dwc3_gadget_ep_get_transfer_index(dwc,
+			dep->number);
+	if (!dep->res_trans_idx)
+		printk_once(KERN_ERR "%s() res_trans_idx is invalid\n", __func__);
+	return 0;
+}
+
+static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
+{
+	req->request.actual	= 0;
+	req->request.status	= -EINPROGRESS;
+	req->direction		= dep->direction;
+	req->epnum		= dep->number;
+
+	/*
+	 * We only add to our list of requests now and
+	 * start consuming the list once we get XferNotReady
+	 * IRQ.
+	 *
+	 * That way, we avoid doing anything that we don't need
+	 * to do now and defer it until the point we receive a
+	 * particular token from the Host side.
+	 *
+	 * This will also avoid Host cancelling URBs due to too
+	 * many NACKs.
+	 */
+	dwc3_map_buffer_to_dma(req);
+	list_add_tail(&req->list, &dep->request_list);
+
+	/*
+	 * There is one special case: XferNotReady with
+	 * empty list of requests. We need to kick the
+	 * transfer here in that situation, otherwise
+	 * we will be NAKing forever.
+	 *
+	 * If we get XferNotReady before gadget driver
+	 * has a chance to queue a request, we will ACK
+	 * the IRQ but won't be able to receive the data
+	 * until the next request is queued. The following
+	 * code is handling exactly that.
+	 */
+	if (dep->flags & DWC3_EP_PENDING_REQUEST) {
+		int ret;
+		int start_trans;
+
+		start_trans = 1;
+		if (usb_endpoint_xfer_isoc(dep->endpoint.desc) &&
+				dep->flags & DWC3_EP_BUSY)
+			start_trans = 0;
+
+		ret =  __dwc3_gadget_kick_transfer(dep, 0, start_trans);
+		if (ret && ret != -EBUSY) {
+			struct dwc3	*dwc = dep->dwc;
+
+			dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
+					dep->name);
+		}
+	};
+
+	return 0;
+}
+
+static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
+	gfp_t gfp_flags)
+{
+	struct dwc3_request		*req = to_dwc3_request(request);
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+	struct dwc3			*dwc = dep->dwc;
+
+	unsigned long			flags;
+
+	int				ret;
+
+	if (!dep->desc) {
+		dev_dbg(dwc->dev, "trying to queue request %p to disabled %s\n",
+				request, ep->name);
+		return -ESHUTDOWN;
+	}
+
+	dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
+			request, ep->name, request->length);
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	ret = __dwc3_gadget_ep_queue(dep, req);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static int dwc3_gadget_ep_dequeue(struct usb_ep *ep,
+		struct usb_request *request)
+{
+	struct dwc3_request		*req = to_dwc3_request(request);
+	struct dwc3_request		*r = NULL;
+
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+	struct dwc3			*dwc = dep->dwc;
+
+	unsigned long			flags;
+	int				ret = 0;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+
+	list_for_each_entry(r, &dep->request_list, list) {
+		if (r == req)
+			break;
+	}
+
+	if (r != req) {
+		list_for_each_entry(r, &dep->req_queued, list) {
+			if (r == req)
+				break;
+		}
+		if (r == req) {
+			/* wait until it is processed */
+			dwc3_stop_active_transfer(dwc, dep->number);
+			goto out0;
+		}
+		dev_err(dwc->dev, "request %p was not queued to %s\n",
+				request, ep->name);
+		ret = -EINVAL;
+		goto out0;
+	}
+
+	/* giveback the request */
+	dwc3_gadget_giveback(dep, req, -ECONNRESET);
+
+out0:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value)
+{
+	struct dwc3_gadget_ep_cmd_params	params;
+	struct dwc3				*dwc = dep->dwc;
+	int					ret;
+
+	memset(&params, 0x00, sizeof(params));
+
+	if (value) {
+		if (dep->number == 0 || dep->number == 1) {
+			/*
+			 * Whenever EP0 is stalled, we will restart
+			 * the state machine, thus moving back to
+			 * Setup Phase
+			 */
+			dwc->ep0state = EP0_SETUP_PHASE;
+		}
+
+		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+			DWC3_DEPCMD_SETSTALL, &params);
+		if (ret)
+			dev_err(dwc->dev, "failed to %s STALL on %s\n",
+					value ? "set" : "clear",
+					dep->name);
+		else
+			dep->flags |= DWC3_EP_STALL;
+	} else {
+		if (dep->flags & DWC3_EP_WEDGE)
+			return 0;
+
+		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+			DWC3_DEPCMD_CLEARSTALL, &params);
+		if (ret)
+			dev_err(dwc->dev, "failed to %s STALL on %s\n",
+					value ? "set" : "clear",
+					dep->name);
+		else
+			dep->flags &= ~DWC3_EP_STALL;
+	}
+
+	return ret;
+}
+
+static int dwc3_gadget_ep_set_halt(struct usb_ep *ep, int value)
+{
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+	struct dwc3			*dwc = dep->dwc;
+
+	unsigned long			flags;
+
+	int				ret;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+
+	if (usb_endpoint_xfer_isoc(dep->desc)) {
+		dev_err(dwc->dev, "%s is of Isochronous type\n", dep->name);
+		ret = -EINVAL;
+		goto out;
+	}
+
+	ret = __dwc3_gadget_ep_set_halt(dep, value);
+out:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static int dwc3_gadget_ep_set_wedge(struct usb_ep *ep)
+{
+	struct dwc3_ep			*dep = to_dwc3_ep(ep);
+
+	dep->flags |= DWC3_EP_WEDGE;
+
+	return dwc3_gadget_ep_set_halt(ep, 1);
+}
+
+/* -------------------------------------------------------------------------- */
+
+static struct usb_endpoint_descriptor dwc3_gadget_ep0_desc = {
+	.bLength	= USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType = USB_DT_ENDPOINT,
+	.bmAttributes	= USB_ENDPOINT_XFER_CONTROL,
+};
+
+static const struct usb_ep_ops dwc3_gadget_ep0_ops = {
+	.enable		= dwc3_gadget_ep0_enable,
+	.disable	= dwc3_gadget_ep0_disable,
+	.alloc_request	= dwc3_gadget_ep_alloc_request,
+	.free_request	= dwc3_gadget_ep_free_request,
+	.queue		= dwc3_gadget_ep0_queue,
+	.dequeue	= dwc3_gadget_ep_dequeue,
+	.set_halt	= dwc3_gadget_ep_set_halt,
+	.set_wedge	= dwc3_gadget_ep_set_wedge,
+};
+
+static const struct usb_ep_ops dwc3_gadget_ep_ops = {
+	.enable		= dwc3_gadget_ep_enable,
+	.disable	= dwc3_gadget_ep_disable,
+	.alloc_request	= dwc3_gadget_ep_alloc_request,
+	.free_request	= dwc3_gadget_ep_free_request,
+	.queue		= dwc3_gadget_ep_queue,
+	.dequeue	= dwc3_gadget_ep_dequeue,
+	.set_halt	= dwc3_gadget_ep_set_halt,
+	.set_wedge	= dwc3_gadget_ep_set_wedge,
+};
+
+/* -------------------------------------------------------------------------- */
+
+static int dwc3_gadget_get_frame(struct usb_gadget *g)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	u32			reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+	return DWC3_DSTS_SOFFN(reg);
+}
+
+static int dwc3_gadget_wakeup(struct usb_gadget *g)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+
+	unsigned long		timeout;
+	unsigned long		flags;
+
+	u32			reg;
+
+	int			ret = 0;
+
+	u8			link_state;
+	u8			speed;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+
+	/*
+	 * According to the Databook Remote wakeup request should
+	 * be issued only when the device is in early suspend state.
+	 *
+	 * We can check that via USB Link State bits in DSTS register.
+	 */
+	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+
+	speed = reg & DWC3_DSTS_CONNECTSPD;
+	if (speed == DWC3_DSTS_SUPERSPEED) {
+		dev_dbg(dwc->dev, "no wakeup on SuperSpeed\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	link_state = DWC3_DSTS_USBLNKST(reg);
+
+	switch (link_state) {
+	case DWC3_LINK_STATE_RX_DET:	/* in HS, means Early Suspend */
+	case DWC3_LINK_STATE_U3:	/* in HS, means SUSPEND */
+		break;
+	default:
+		dev_dbg(dwc->dev, "can't wakeup from link state %d\n",
+				link_state);
+		ret = -EINVAL;
+		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);
+
+	/* 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 */
+	timeout = jiffies + msecs_to_jiffies(100);
+
+	while (!(time_after(jiffies, timeout))) {
+		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+
+		/* in HS, means ON */
+		if (DWC3_DSTS_USBLNKST(reg) == DWC3_LINK_STATE_U0)
+			break;
+	}
+
+	if (DWC3_DSTS_USBLNKST(reg) != DWC3_LINK_STATE_U0) {
+		dev_err(dwc->dev, "failed to send remote wakeup\n");
+		ret = -EINVAL;
+	}
+
+out:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
+		int is_selfpowered)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+
+	dwc->is_selfpowered = !!is_selfpowered;
+
+	return 0;
+}
+
+static void dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on)
+{
+	u32			reg;
+	u32			timeout = 500;
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	if (is_on)
+		reg |= DWC3_DCTL_RUN_STOP;
+	else
+		reg &= ~DWC3_DCTL_RUN_STOP;
+
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+	do {
+		reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+		if (is_on) {
+			if (!(reg & DWC3_DSTS_DEVCTRLHLT))
+				break;
+		} else {
+			if (reg & DWC3_DSTS_DEVCTRLHLT)
+				break;
+		}
+		timeout--;
+		if (!timeout)
+			break;
+		udelay(1);
+	} while (1);
+
+	dev_vdbg(dwc->dev, "gadget %s data soft-%s\n",
+			dwc->gadget_driver
+			? dwc->gadget_driver->function : "no-function",
+			is_on ? "connect" : "disconnect");
+}
+
+static int dwc3_gadget_pullup(struct usb_gadget *g, int is_on)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	unsigned long		flags;
+
+	is_on = !!is_on;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+	dwc3_gadget_run_stop(dwc, is_on);
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return 0;
+}
+
+static int dwc3_gadget_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	struct dwc3_ep		*dep;
+	unsigned long		flags;
+	int			ret = 0;
+	u32			reg;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+
+	if (dwc->gadget_driver) {
+		dev_err(dwc->dev, "%s is already bound to %s\n",
+				dwc->gadget.name,
+				dwc->gadget_driver->driver.name);
+		ret = -EBUSY;
+		goto err0;
+	}
+
+	dwc->gadget_driver	= driver;
+	dwc->gadget.dev.driver	= &driver->driver;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+
+	reg &= ~DWC3_GCTL_SCALEDOWN(3);
+	reg &= ~DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_OTG);
+	reg &= ~DWC3_GCTL_DISSCRAMBLE;
+	reg |= DWC3_GCTL_PRTCAPDIR(DWC3_GCTL_PRTCAP_DEVICE);
+
+	switch (DWC3_GHWPARAMS1_EN_PWROPT(dwc->hwparams.hwparams0)) {
+	case DWC3_GHWPARAMS1_EN_PWROPT_CLK:
+		reg &= ~DWC3_GCTL_DSBLCLKGTNG;
+		break;
+	default:
+		dev_dbg(dwc->dev, "No power optimization available\n");
+	}
+
+	/*
+	 * WORKAROUND: DWC3 revisions <1.90a have a bug
+	 * when The device fails to connect at SuperSpeed
+	 * and falls back to high-speed mode which causes
+	 * the device to enter in a Connect/Disconnect loop
+	 */
+	if (dwc->revision < DWC3_REVISION_190A)
+		reg |= DWC3_GCTL_U2RSTECN;
+
+	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+	reg &= ~(DWC3_DCFG_SPEED_MASK);
+	reg |= DWC3_DCFG_SUPERSPEED;
+	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+	dwc->start_config_issued = false;
+
+	/* Start with SuperSpeed Default */
+	dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+
+	dep = dwc->eps[0];
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+	if (ret) {
+		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+		goto err0;
+	}
+
+	dep = dwc->eps[1];
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+	if (ret) {
+		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+		goto err1;
+	}
+
+	/* begin to receive SETUP packets */
+	dwc->ep0state = EP0_SETUP_PHASE;
+	dwc3_ep0_out_start(dwc);
+
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return 0;
+
+err1:
+	__dwc3_gadget_ep_disable(dwc->eps[0]);
+
+err0:
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return ret;
+}
+
+static int dwc3_gadget_stop(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
+{
+	struct dwc3		*dwc = gadget_to_dwc(g);
+	unsigned long		flags;
+
+	spin_lock_irqsave(&dwc->lock, flags);
+
+	__dwc3_gadget_ep_disable(dwc->eps[0]);
+	__dwc3_gadget_ep_disable(dwc->eps[1]);
+
+	dwc->gadget_driver	= NULL;
+	dwc->gadget.dev.driver	= NULL;
+
+	spin_unlock_irqrestore(&dwc->lock, flags);
+
+	return 0;
+}
+static const struct usb_gadget_ops dwc3_gadget_ops = {
+	.get_frame		= dwc3_gadget_get_frame,
+	.wakeup			= dwc3_gadget_wakeup,
+	.set_selfpowered	= dwc3_gadget_set_selfpowered,
+	.pullup			= dwc3_gadget_pullup,
+	.udc_start		= dwc3_gadget_start,
+	.udc_stop		= dwc3_gadget_stop,
+};
+
+/* -------------------------------------------------------------------------- */
+
+static int __devinit dwc3_gadget_init_endpoints(struct dwc3 *dwc)
+{
+	struct dwc3_ep			*dep;
+	u8				epnum;
+
+	INIT_LIST_HEAD(&dwc->gadget.ep_list);
+
+	for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+		dep = kzalloc(sizeof(*dep), GFP_KERNEL);
+		if (!dep) {
+			dev_err(dwc->dev, "can't allocate endpoint %d\n",
+					epnum);
+			return -ENOMEM;
+		}
+
+		dep->dwc = dwc;
+		dep->number = epnum;
+		dwc->eps[epnum] = dep;
+
+		snprintf(dep->name, sizeof(dep->name), "ep%d%s", epnum >> 1,
+				(epnum & 1) ? "in" : "out");
+		dep->endpoint.name = dep->name;
+		dep->direction = (epnum & 1);
+
+		if (epnum == 0 || epnum == 1) {
+			dep->endpoint.maxpacket = 512;
+			dep->endpoint.ops = &dwc3_gadget_ep0_ops;
+			if (!epnum)
+				dwc->gadget.ep0 = &dep->endpoint;
+		} else {
+			int		ret;
+
+			dep->endpoint.maxpacket = 1024;
+			dep->endpoint.ops = &dwc3_gadget_ep_ops;
+			list_add_tail(&dep->endpoint.ep_list,
+					&dwc->gadget.ep_list);
+
+			ret = dwc3_alloc_trb_pool(dep);
+			if (ret) {
+				dev_err(dwc->dev, "%s: failed to allocate TRB pool\n", dep->name);
+				return ret;
+			}
+		}
+		INIT_LIST_HEAD(&dep->request_list);
+		INIT_LIST_HEAD(&dep->req_queued);
+	}
+
+	return 0;
+}
+
+static void dwc3_gadget_free_endpoints(struct dwc3 *dwc)
+{
+	struct dwc3_ep			*dep;
+	u8				epnum;
+
+	for (epnum = 0; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+		dep = dwc->eps[epnum];
+		dwc3_free_trb_pool(dep);
+
+		if (epnum != 0 && epnum != 1)
+			list_del(&dep->endpoint.ep_list);
+
+		kfree(dep);
+	}
+}
+
+static void dwc3_gadget_release(struct device *dev)
+{
+	dev_dbg(dev, "%s\n", __func__);
+}
+
+/* -------------------------------------------------------------------------- */
+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;
+	unsigned int		count;
+	unsigned int		s_pkt = 0;
+
+	do {
+		req = next_request(&dep->req_queued);
+		if (!req)
+			break;
+
+		dwc3_trb_to_nat(req->trb, &trb);
+
+		if (trb.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
+			 * 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;
+
+		if (dep->direction) {
+			if (count) {
+				dev_err(dwc->dev, "incomplete IN transfer %s\n",
+						dep->name);
+				status = -ECONNRESET;
+			}
+		} else {
+			if (count && (event->status & DEPEVT_STATUS_SHORT))
+				s_pkt = 1;
+		}
+
+		/*
+		 * We assume here we will always receive the entire data block
+		 * which we should receive. Meaning, if we program RX to
+		 * receive 4K but we receive only 2K, we assume that's all we
+		 * should receive and we simply bounce the request back to the
+		 * gadget driver for further processing.
+		 */
+		req->request.actual += req->request.length - count;
+		dwc3_gadget_giveback(dep, req, status);
+		if (s_pkt)
+			break;
+		if ((event->status & DEPEVT_STATUS_LST) && trb.lst)
+			break;
+		if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
+			break;
+	} while (1);
+
+	if ((event->status & DEPEVT_STATUS_IOC) && trb.ioc)
+		return 0;
+	return 1;
+}
+
+static void dwc3_endpoint_transfer_complete(struct dwc3 *dwc,
+		struct dwc3_ep *dep, const struct dwc3_event_depevt *event,
+		int start_new)
+{
+	unsigned		status = 0;
+	int			clean_busy;
+
+	if (event->status & DEPEVT_STATUS_BUSERR)
+		status = -ECONNRESET;
+
+	clean_busy =  dwc3_cleanup_done_reqs(dwc, dep, event, status);
+	if (clean_busy) {
+		dep->flags &= ~DWC3_EP_BUSY;
+		dep->res_trans_idx = 0;
+	}
+}
+
+static void dwc3_gadget_start_isoc(struct dwc3 *dwc,
+		struct dwc3_ep *dep, const struct dwc3_event_depevt *event)
+{
+	u32 uf;
+
+	if (list_empty(&dep->request_list)) {
+		dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
+			dep->name);
+		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;
+	}
+
+	__dwc3_gadget_kick_transfer(dep, uf, 1);
+}
+
+static void dwc3_process_ep_cmd_complete(struct dwc3_ep *dep,
+		const struct dwc3_event_depevt *event)
+{
+	struct dwc3 *dwc = dep->dwc;
+	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
+	 * 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
+	 * the end of the list.
+	 */
+	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 */
+}
+
+static void dwc3_ep_cmd_compl(struct dwc3_ep *dep,
+		const struct dwc3_event_depevt *event)
+{
+	u32 param = event->parameters;
+	u32 cmd_type = (param >> 8) & ((1 << 5) - 1);
+
+	switch (cmd_type) {
+	case DWC3_DEPCMD_ENDTRANSFER:
+		dwc3_process_ep_cmd_complete(dep, event);
+		break;
+	case DWC3_DEPCMD_STARTTRANSFER:
+		dep->res_trans_idx = param & 0x7f;
+		break;
+	default:
+		printk(KERN_ERR "%s() unknown /unexpected type: %d\n",
+				__func__, cmd_type);
+		break;
+	};
+}
+
+static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
+		const struct dwc3_event_depevt *event)
+{
+	struct dwc3_ep		*dep;
+	u8			epnum = event->endpoint_number;
+
+	dep = dwc->eps[epnum];
+
+	dev_vdbg(dwc->dev, "%s: %s\n", dep->name,
+			dwc3_ep_event_string(event->endpoint_event));
+
+	if (epnum == 0 || epnum == 1) {
+		dwc3_ep0_interrupt(dwc, event);
+		return;
+	}
+
+	switch (event->endpoint_event) {
+	case DWC3_DEPEVT_XFERCOMPLETE:
+		if (usb_endpoint_xfer_isoc(dep->desc)) {
+			dev_dbg(dwc->dev, "%s is an Isochronous endpoint\n",
+					dep->name);
+			return;
+		}
+
+		dwc3_endpoint_transfer_complete(dwc, dep, event, 1);
+		break;
+	case DWC3_DEPEVT_XFERINPROGRESS:
+		if (!usb_endpoint_xfer_isoc(dep->desc)) {
+			dev_dbg(dwc->dev, "%s is not an Isochronous endpoint\n",
+					dep->name);
+			return;
+		}
+
+		dwc3_endpoint_transfer_complete(dwc, dep, event, 0);
+		break;
+	case DWC3_DEPEVT_XFERNOTREADY:
+		if (usb_endpoint_xfer_isoc(dep->desc)) {
+			dwc3_gadget_start_isoc(dwc, dep, event);
+		} else {
+			int ret;
+
+			dev_vdbg(dwc->dev, "%s: reason %s\n",
+					dep->name, event->status
+					? "Transfer Active"
+					: "Transfer Not Active");
+
+			ret = __dwc3_gadget_kick_transfer(dep, 0, 1);
+			if (!ret || ret == -EBUSY)
+				return;
+
+			dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
+					dep->name);
+		}
+
+		break;
+	case DWC3_DEPEVT_STREAMEVT:
+		if (!usb_endpoint_xfer_bulk(dep->desc)) {
+			dev_err(dwc->dev, "Stream event for non-Bulk %s\n",
+					dep->name);
+			return;
+		}
+
+		switch (event->status) {
+		case DEPEVT_STREAMEVT_FOUND:
+			dev_vdbg(dwc->dev, "Stream %d found and started\n",
+					event->parameters);
+
+			break;
+		case DEPEVT_STREAMEVT_NOTFOUND:
+			/* FALLTHROUGH */
+		default:
+			dev_dbg(dwc->dev, "Couldn't find suitable stream\n");
+		}
+		break;
+	case DWC3_DEPEVT_RXTXFIFOEVT:
+		dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name);
+		break;
+	case DWC3_DEPEVT_EPCMDCMPLT:
+		dwc3_ep_cmd_compl(dep, event);
+		break;
+	}
+}
+
+static void dwc3_disconnect_gadget(struct dwc3 *dwc)
+{
+	if (dwc->gadget_driver && dwc->gadget_driver->disconnect) {
+		spin_unlock(&dwc->lock);
+		dwc->gadget_driver->disconnect(&dwc->gadget);
+		spin_lock(&dwc->lock);
+	}
+}
+
+static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum)
+{
+	struct dwc3_ep *dep;
+	struct dwc3_gadget_ep_cmd_params params;
+	u32 cmd;
+	int ret;
+
+	dep = dwc->eps[epnum];
+
+	WARN_ON(!dep->res_trans_idx);
+	if (dep->res_trans_idx) {
+		cmd = DWC3_DEPCMD_ENDTRANSFER;
+		cmd |= DWC3_DEPCMD_HIPRI_FORCERM | DWC3_DEPCMD_CMDIOC;
+		cmd |= DWC3_DEPCMD_PARAM(dep->res_trans_idx);
+		memset(&params, 0, sizeof(params));
+		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number, cmd, &params);
+		WARN_ON_ONCE(ret);
+		dep->res_trans_idx = 0;
+	}
+}
+
+static void dwc3_stop_active_transfers(struct dwc3 *dwc)
+{
+	u32 epnum;
+
+	for (epnum = 2; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+		struct dwc3_ep *dep;
+
+		dep = dwc->eps[epnum];
+		if (!(dep->flags & DWC3_EP_ENABLED))
+			continue;
+
+		dwc3_remove_requests(dwc, dep);
+	}
+}
+
+static void dwc3_clear_stall_all_ep(struct dwc3 *dwc)
+{
+	u32 epnum;
+
+	for (epnum = 1; epnum < DWC3_ENDPOINTS_NUM; epnum++) {
+		struct dwc3_ep *dep;
+		struct dwc3_gadget_ep_cmd_params params;
+		int ret;
+
+		dep = dwc->eps[epnum];
+
+		if (!(dep->flags & DWC3_EP_STALL))
+			continue;
+
+		dep->flags &= ~DWC3_EP_STALL;
+
+		memset(&params, 0, sizeof(params));
+		ret = dwc3_send_gadget_ep_cmd(dwc, dep->number,
+				DWC3_DEPCMD_CLEARSTALL, &params);
+		WARN_ON_ONCE(ret);
+	}
+}
+
+static void dwc3_gadget_disconnect_interrupt(struct dwc3 *dwc)
+{
+	dev_vdbg(dwc->dev, "%s\n", __func__);
+#if 0
+	XXX
+	U1/U2 is powersave optimization. Skip it for now. Anyway we need to
+	enable it before we can disable it.
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	reg &= ~DWC3_DCTL_INITU1ENA;
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+	reg &= ~DWC3_DCTL_INITU2ENA;
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+#endif
+
+	dwc3_stop_active_transfers(dwc);
+	dwc3_disconnect_gadget(dwc);
+	dwc->start_config_issued = false;
+
+	dwc->gadget.speed = USB_SPEED_UNKNOWN;
+}
+
+static void dwc3_gadget_usb3_phy_power(struct dwc3 *dwc, int on)
+{
+	u32			reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
+
+	if (on)
+		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
+	else
+		reg |= DWC3_GUSB3PIPECTL_SUSPHY;
+
+	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
+}
+
+static void dwc3_gadget_usb2_phy_power(struct dwc3 *dwc, int on)
+{
+	u32			reg;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
+
+	if (on)
+		reg &= ~DWC3_GUSB2PHYCFG_SUSPHY;
+	else
+		reg |= DWC3_GUSB2PHYCFG_SUSPHY;
+
+	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
+}
+
+static void dwc3_gadget_reset_interrupt(struct dwc3 *dwc)
+{
+	u32			reg;
+
+	dev_vdbg(dwc->dev, "%s\n", __func__);
+
+	/* Enable PHYs */
+	dwc3_gadget_usb2_phy_power(dwc, true);
+	dwc3_gadget_usb3_phy_power(dwc, true);
+
+	if (dwc->gadget.speed != USB_SPEED_UNKNOWN)
+		dwc3_disconnect_gadget(dwc);
+
+	reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+	reg &= ~DWC3_DCTL_TSTCTRL_MASK;
+	dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+	dwc3_stop_active_transfers(dwc);
+	dwc3_clear_stall_all_ep(dwc);
+	dwc->start_config_issued = false;
+
+	/* Reset device address to zero */
+	reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+	reg &= ~(DWC3_DCFG_DEVADDR_MASK);
+	dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+}
+
+static void dwc3_update_ram_clk_sel(struct dwc3 *dwc, u32 speed)
+{
+	u32 reg;
+	u32 usb30_clock = DWC3_GCTL_CLK_BUS;
+
+	/*
+	 * We change the clock only at SS but I dunno why I would want to do
+	 * this. Maybe it becomes part of the power saving plan.
+	 */
+
+	if (speed != DWC3_DSTS_SUPERSPEED)
+		return;
+
+	/*
+	 * RAMClkSel is reset to 0 after USB reset, so it must be reprogrammed
+	 * each time on Connect Done.
+	 */
+	if (!usb30_clock)
+		return;
+
+	reg = dwc3_readl(dwc->regs, DWC3_GCTL);
+	reg |= DWC3_GCTL_RAMCLKSEL(usb30_clock);
+	dwc3_writel(dwc->regs, DWC3_GCTL, reg);
+}
+
+static void dwc3_gadget_disable_phy(struct dwc3 *dwc, u8 speed)
+{
+	switch (speed) {
+	case USB_SPEED_SUPER:
+		dwc3_gadget_usb2_phy_power(dwc, false);
+		break;
+	case USB_SPEED_HIGH:
+	case USB_SPEED_FULL:
+	case USB_SPEED_LOW:
+		dwc3_gadget_usb3_phy_power(dwc, false);
+		break;
+	}
+}
+
+static void dwc3_gadget_conndone_interrupt(struct dwc3 *dwc)
+{
+	struct dwc3_gadget_ep_cmd_params params;
+	struct dwc3_ep		*dep;
+	int			ret;
+	u32			reg;
+	u8			speed;
+
+	dev_vdbg(dwc->dev, "%s\n", __func__);
+
+	memset(&params, 0x00, sizeof(params));
+
+	reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+	speed = reg & DWC3_DSTS_CONNECTSPD;
+	dwc->speed = speed;
+
+	dwc3_update_ram_clk_sel(dwc, speed);
+
+	switch (speed) {
+	case DWC3_DCFG_SUPERSPEED:
+		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+		dwc->gadget.ep0->maxpacket = 512;
+		dwc->gadget.speed = USB_SPEED_SUPER;
+		break;
+	case DWC3_DCFG_HIGHSPEED:
+		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
+		dwc->gadget.ep0->maxpacket = 64;
+		dwc->gadget.speed = USB_SPEED_HIGH;
+		break;
+	case DWC3_DCFG_FULLSPEED2:
+	case DWC3_DCFG_FULLSPEED1:
+		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(64);
+		dwc->gadget.ep0->maxpacket = 64;
+		dwc->gadget.speed = USB_SPEED_FULL;
+		break;
+	case DWC3_DCFG_LOWSPEED:
+		dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(8);
+		dwc->gadget.ep0->maxpacket = 8;
+		dwc->gadget.speed = USB_SPEED_LOW;
+		break;
+	}
+
+	/* Disable unneded PHY */
+	dwc3_gadget_disable_phy(dwc, dwc->gadget.speed);
+
+	dep = dwc->eps[0];
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+	if (ret) {
+		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+		return;
+	}
+
+	dep = dwc->eps[1];
+	ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc);
+	if (ret) {
+		dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+		return;
+	}
+
+	/*
+	 * Configure PHY via GUSB3PIPECTLn if required.
+	 *
+	 * Update GTXFIFOSIZn
+	 *
+	 * In both cases reset values should be sufficient.
+	 */
+}
+
+static void dwc3_gadget_wakeup_interrupt(struct dwc3 *dwc)
+{
+	dev_vdbg(dwc->dev, "%s\n", __func__);
+
+	/*
+	 * TODO take core out of low power mode when that's
+	 * implemented.
+	 */
+
+	dwc->gadget_driver->resume(&dwc->gadget);
+}
+
+static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
+		unsigned int evtinfo)
+{
+	/*  The fith bit says SuperSpeed yes or no. */
+	dwc->link_state = evtinfo & DWC3_LINK_STATE_MASK;
+
+	dev_vdbg(dwc->dev, "%s link %d\n", __func__, dwc->link_state);
+}
+
+static void dwc3_gadget_interrupt(struct dwc3 *dwc,
+		const struct dwc3_event_devt *event)
+{
+	switch (event->type) {
+	case DWC3_DEVICE_EVENT_DISCONNECT:
+		dwc3_gadget_disconnect_interrupt(dwc);
+		break;
+	case DWC3_DEVICE_EVENT_RESET:
+		dwc3_gadget_reset_interrupt(dwc);
+		break;
+	case DWC3_DEVICE_EVENT_CONNECT_DONE:
+		dwc3_gadget_conndone_interrupt(dwc);
+		break;
+	case DWC3_DEVICE_EVENT_WAKEUP:
+		dwc3_gadget_wakeup_interrupt(dwc);
+		break;
+	case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
+		dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
+		break;
+	case DWC3_DEVICE_EVENT_EOPF:
+		dev_vdbg(dwc->dev, "End of Periodic Frame\n");
+		break;
+	case DWC3_DEVICE_EVENT_SOF:
+		dev_vdbg(dwc->dev, "Start of Periodic Frame\n");
+		break;
+	case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
+		dev_vdbg(dwc->dev, "Erratic Error\n");
+		break;
+	case DWC3_DEVICE_EVENT_CMD_CMPL:
+		dev_vdbg(dwc->dev, "Command Complete\n");
+		break;
+	case DWC3_DEVICE_EVENT_OVERFLOW:
+		dev_vdbg(dwc->dev, "Overflow\n");
+		break;
+	default:
+		dev_dbg(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
+	}
+}
+
+static void dwc3_process_event_entry(struct dwc3 *dwc,
+		const union dwc3_event *event)
+{
+	/* Endpoint IRQ, handle it and return early */
+	if (event->type.is_devspec == 0) {
+		/* depevt */
+		return dwc3_endpoint_interrupt(dwc, &event->depevt);
+	}
+
+	switch (event->type.type) {
+	case DWC3_EVENT_TYPE_DEV:
+		dwc3_gadget_interrupt(dwc, &event->devt);
+		break;
+	/* REVISIT what to do with Carkit and I2C events ? */
+	default:
+		dev_err(dwc->dev, "UNKNOWN IRQ type %d\n", event->raw);
+	}
+}
+
+static irqreturn_t dwc3_process_event_buf(struct dwc3 *dwc, u32 buf)
+{
+	struct dwc3_event_buffer *evt;
+	int left;
+	u32 count;
+
+	count = dwc3_readl(dwc->regs, DWC3_GEVNTCOUNT(buf));
+	count &= DWC3_GEVNTCOUNT_MASK;
+	if (!count)
+		return IRQ_NONE;
+
+	evt = dwc->ev_buffs[buf];
+	left = count;
+
+	while (left > 0) {
+		union dwc3_event event;
+
+		memcpy(&event.raw, (evt->buf + evt->lpos), sizeof(event.raw));
+		dwc3_process_event_entry(dwc, &event);
+		/*
+		 * XXX we wrap around correctly to the next entry as almost all
+		 * entries are 4 bytes in size. There is one entry which has 12
+		 * bytes which is a regular entry followed by 8 bytes data. ATM
+		 * I don't know how things are organized if were get next to the
+		 * a boundary so I worry about that once we try to handle that.
+		 */
+		evt->lpos = (evt->lpos + 4) % DWC3_EVENT_BUFFERS_SIZE;
+		left -= 4;
+
+		dwc3_writel(dwc->regs, DWC3_GEVNTCOUNT(buf), 4);
+	}
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t dwc3_interrupt(int irq, void *_dwc)
+{
+	struct dwc3			*dwc = _dwc;
+	int				i;
+	irqreturn_t			ret = IRQ_NONE;
+
+	spin_lock(&dwc->lock);
+
+	for (i = 0; i < DWC3_EVENT_BUFFERS_NUM; i++) {
+		irqreturn_t status;
+
+		status = dwc3_process_event_buf(dwc, i);
+		if (status == IRQ_HANDLED)
+			ret = status;
+	}
+
+	spin_unlock(&dwc->lock);
+
+	return ret;
+}
+
+/**
+ * dwc3_gadget_init - Initializes gadget related registers
+ * @dwc: Pointer to out controller context structure
+ *
+ * Returns 0 on success otherwise negative errno.
+ */
+int __devinit dwc3_gadget_init(struct dwc3 *dwc)
+{
+	u32					reg;
+	int					ret;
+	int					irq;
+
+	dwc->ctrl_req = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+			&dwc->ctrl_req_addr, GFP_KERNEL);
+	if (!dwc->ctrl_req) {
+		dev_err(dwc->dev, "failed to allocate ctrl request\n");
+		ret = -ENOMEM;
+		goto err0;
+	}
+
+	dwc->ep0_trb = dma_alloc_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+			&dwc->ep0_trb_addr, GFP_KERNEL);
+	if (!dwc->ep0_trb) {
+		dev_err(dwc->dev, "failed to allocate ep0 trb\n");
+		ret = -ENOMEM;
+		goto err1;
+	}
+
+	dwc->setup_buf = dma_alloc_coherent(dwc->dev,
+			sizeof(*dwc->setup_buf) * 2,
+			&dwc->setup_buf_addr, GFP_KERNEL);
+	if (!dwc->setup_buf) {
+		dev_err(dwc->dev, "failed to allocate setup buffer\n");
+		ret = -ENOMEM;
+		goto err2;
+	}
+
+	dwc->ep0_bounce = dma_alloc_coherent(dwc->dev,
+			512, &dwc->ep0_bounce_addr, GFP_KERNEL);
+	if (!dwc->ep0_bounce) {
+		dev_err(dwc->dev, "failed to allocate ep0 bounce buffer\n");
+		ret = -ENOMEM;
+		goto err3;
+	}
+
+	dev_set_name(&dwc->gadget.dev, "gadget");
+
+	dwc->gadget.ops			= &dwc3_gadget_ops;
+	dwc->gadget.is_dualspeed	= true;
+	dwc->gadget.speed		= USB_SPEED_UNKNOWN;
+	dwc->gadget.dev.parent		= dwc->dev;
+
+	dma_set_coherent_mask(&dwc->gadget.dev, dwc->dev->coherent_dma_mask);
+
+	dwc->gadget.dev.dma_parms	= dwc->dev->dma_parms;
+	dwc->gadget.dev.dma_mask	= dwc->dev->dma_mask;
+	dwc->gadget.dev.release		= dwc3_gadget_release;
+	dwc->gadget.name		= "dwc3-gadget";
+
+	/*
+	 * REVISIT: Here we should clear all pending IRQs to be
+	 * sure we're starting from a well known location.
+	 */
+
+	ret = dwc3_gadget_init_endpoints(dwc);
+	if (ret)
+		goto err4;
+
+	irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+
+	ret = request_irq(irq, dwc3_interrupt, IRQF_SHARED,
+			"dwc3", dwc);
+	if (ret) {
+		dev_err(dwc->dev, "failed to request irq #%d --> %d\n",
+				irq, ret);
+		goto err5;
+	}
+
+	/* Enable all but Start and End of Frame IRQs */
+	reg = (DWC3_DEVTEN_VNDRDEVTSTRCVEDEN |
+			DWC3_DEVTEN_EVNTOVERFLOWEN |
+			DWC3_DEVTEN_CMDCMPLTEN |
+			DWC3_DEVTEN_ERRTICERREN |
+			DWC3_DEVTEN_WKUPEVTEN |
+			DWC3_DEVTEN_ULSTCNGEN |
+			DWC3_DEVTEN_CONNECTDONEEN |
+			DWC3_DEVTEN_USBRSTEN |
+			DWC3_DEVTEN_DISCONNEVTEN);
+	dwc3_writel(dwc->regs, DWC3_DEVTEN, reg);
+
+	ret = device_register(&dwc->gadget.dev);
+	if (ret) {
+		dev_err(dwc->dev, "failed to register gadget device\n");
+		put_device(&dwc->gadget.dev);
+		goto err6;
+	}
+
+	ret = usb_add_gadget_udc(dwc->dev, &dwc->gadget);
+	if (ret) {
+		dev_err(dwc->dev, "failed to register udc\n");
+		goto err7;
+	}
+
+	return 0;
+
+err7:
+	device_unregister(&dwc->gadget.dev);
+
+err6:
+	dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
+	free_irq(irq, dwc);
+
+err5:
+	dwc3_gadget_free_endpoints(dwc);
+
+err4:
+	dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
+			dwc->ep0_bounce_addr);
+
+err3:
+	dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
+			dwc->setup_buf, dwc->setup_buf_addr);
+
+err2:
+	dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+			dwc->ep0_trb, dwc->ep0_trb_addr);
+
+err1:
+	dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+			dwc->ctrl_req, dwc->ctrl_req_addr);
+
+err0:
+	return ret;
+}
+
+void dwc3_gadget_exit(struct dwc3 *dwc)
+{
+	int			irq;
+	int			i;
+
+	usb_del_gadget_udc(&dwc->gadget);
+	irq = platform_get_irq(to_platform_device(dwc->dev), 0);
+
+	dwc3_writel(dwc->regs, DWC3_DEVTEN, 0x00);
+	free_irq(irq, dwc);
+
+	for (i = 0; i < ARRAY_SIZE(dwc->eps); i++)
+		__dwc3_gadget_ep_disable(dwc->eps[i]);
+
+	dwc3_gadget_free_endpoints(dwc);
+
+	dma_free_coherent(dwc->dev, 512, dwc->ep0_bounce,
+			dwc->ep0_bounce_addr);
+
+	dma_free_coherent(dwc->dev, sizeof(*dwc->setup_buf) * 2,
+			dwc->setup_buf, dwc->setup_buf_addr);
+
+	dma_free_coherent(dwc->dev, sizeof(*dwc->ep0_trb),
+			dwc->ep0_trb, dwc->ep0_trb_addr);
+
+	dma_free_coherent(dwc->dev, sizeof(*dwc->ctrl_req),
+			dwc->ctrl_req, dwc->ctrl_req_addr);
+
+	device_unregister(&dwc->gadget.dev);
+}

+ 211 - 0
drivers/usb/dwc3/gadget.h

@@ -0,0 +1,211 @@
+/**
+ * gadget.h - DesignWare USB3 DRD Gadget Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DRIVERS_USB_DWC3_GADGET_H
+#define __DRIVERS_USB_DWC3_GADGET_H
+
+#include <linux/list.h>
+#include <linux/usb/gadget.h>
+#include "io.h"
+
+struct dwc3;
+#define to_dwc3_ep(ep)		(container_of(ep, struct dwc3_ep, endpoint))
+#define gadget_to_dwc(g)	(container_of(g, struct dwc3, gadget))
+
+/* DEPCFG parameter 1 */
+#define DWC3_DEPCFG_INT_NUM(n)		((n) << 0)
+#define DWC3_DEPCFG_XFER_COMPLETE_EN	(1 << 8)
+#define DWC3_DEPCFG_XFER_IN_PROGRESS_EN	(1 << 9)
+#define DWC3_DEPCFG_XFER_NOT_READY_EN	(1 << 10)
+#define DWC3_DEPCFG_FIFO_ERROR_EN	(1 << 11)
+#define DWC3_DEPCFG_STREAM_EVENT_EN	(1 << 13)
+#define DWC3_DEPCFG_BINTERVAL_M1(n)	((n) << 16)
+#define DWC3_DEPCFG_STREAM_CAPABLE	(1 << 24)
+#define DWC3_DEPCFG_EP_NUMBER(n)	((n) << 25)
+#define DWC3_DEPCFG_BULK_BASED		(1 << 30)
+#define DWC3_DEPCFG_FIFO_BASED		(1 << 31)
+
+/* DEPCFG parameter 0 */
+#define DWC3_DEPCFG_EP_TYPE(n)		((n) << 1)
+#define DWC3_DEPCFG_MAX_PACKET_SIZE(n)	((n) << 3)
+#define DWC3_DEPCFG_FIFO_NUMBER(n)	((n) << 17)
+#define DWC3_DEPCFG_BURST_SIZE(n)	((n) << 22)
+#define DWC3_DEPCFG_DATA_SEQ_NUM(n)	((n) << 26)
+#define DWC3_DEPCFG_IGN_SEQ_NUM		(1 << 31)
+
+/* DEPXFERCFG parameter 0 */
+#define DWC3_DEPXFERCFG_NUM_XFER_RES(n)	((n) & 0xffff)
+
+struct dwc3_gadget_ep_cmd_params {
+	u32	param2;
+	u32	param1;
+	u32	param0;
+};
+
+/* -------------------------------------------------------------------------- */
+
+struct dwc3_request {
+	struct usb_request	request;
+	struct list_head	list;
+	struct dwc3_ep		*dep;
+
+	u8			epnum;
+	struct dwc3_trb_hw	*trb;
+	dma_addr_t		trb_dma;
+
+	unsigned		direction:1;
+	unsigned		mapped:1;
+	unsigned		queued:1;
+};
+#define to_dwc3_request(r)	(container_of(r, struct dwc3_request, request))
+
+static inline struct dwc3_request *next_request(struct list_head *list)
+{
+	if (list_empty(list))
+		return NULL;
+
+	return list_first_entry(list, struct dwc3_request, list);
+}
+
+static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req)
+{
+	struct dwc3_ep		*dep = req->dep;
+
+	req->queued = true;
+	list_move_tail(&req->list, &dep->req_queued);
+}
+
+#if defined(CONFIG_USB_GADGET_DWC3) || defined(CONFIG_USB_GADGET_DWC3_MODULE)
+int dwc3_gadget_init(struct dwc3 *dwc);
+void dwc3_gadget_exit(struct dwc3 *dwc);
+#else
+static inline int dwc3_gadget_init(struct dwc3 *dwc) { return 0; }
+static inline void dwc3_gadget_exit(struct dwc3 *dwc) { }
+static inline int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
+		unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
+{
+	return 0;
+}
+#endif
+
+void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
+		int status);
+
+void dwc3_ep0_interrupt(struct dwc3 *dwc, const struct dwc3_event_depevt *event);
+void dwc3_ep0_out_start(struct dwc3 *dwc);
+int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request,
+		gfp_t gfp_flags);
+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
+ * @dwc: DesignWare USB3 Pointer
+ * @number: DWC endpoint number
+ *
+ * Caller should take care of locking
+ */
+static inline u32 dwc3_gadget_ep_get_transfer_index(struct dwc3 *dwc, u8 number)
+{
+	u32			res_id;
+
+	res_id = dwc3_readl(dwc->regs, DWC3_DEPCMD(number));
+
+	return DWC3_DEPCMD_GET_RSC_IDX(res_id);
+}
+
+/**
+ * dwc3_gadget_event_string - returns event name
+ * @event: the event code
+ */
+static inline const char *dwc3_gadget_event_string(u8 event)
+{
+	switch (event) {
+	case DWC3_DEVICE_EVENT_DISCONNECT:
+		return "Disconnect";
+	case DWC3_DEVICE_EVENT_RESET:
+		return "Reset";
+	case DWC3_DEVICE_EVENT_CONNECT_DONE:
+		return "Connection Done";
+	case DWC3_DEVICE_EVENT_LINK_STATUS_CHANGE:
+		return "Link Status Change";
+	case DWC3_DEVICE_EVENT_WAKEUP:
+		return "WakeUp";
+	case DWC3_DEVICE_EVENT_EOPF:
+		return "End-Of-Frame";
+	case DWC3_DEVICE_EVENT_SOF:
+		return "Start-Of-Frame";
+	case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
+		return "Erratic Error";
+	case DWC3_DEVICE_EVENT_CMD_CMPL:
+		return "Command Complete";
+	case DWC3_DEVICE_EVENT_OVERFLOW:
+		return "Overflow";
+	}
+
+	return "UNKNOWN";
+}
+
+/**
+ * dwc3_ep_event_string - returns event name
+ * @event: then event code
+ */
+static inline const char *dwc3_ep_event_string(u8 event)
+{
+	switch (event) {
+	case DWC3_DEPEVT_XFERCOMPLETE:
+		return "Transfer Complete";
+	case DWC3_DEPEVT_XFERINPROGRESS:
+		return "Transfer In-Progress";
+	case DWC3_DEPEVT_XFERNOTREADY:
+		return "Transfer Not Ready";
+	case DWC3_DEPEVT_RXTXFIFOEVT:
+		return "FIFO";
+	case DWC3_DEPEVT_STREAMEVT:
+		return "Stream";
+	case DWC3_DEPEVT_EPCMDCMPLT:
+		return "Endpoint Command Complete";
+	}
+
+	return "UNKNOWN";
+}
+
+#endif /* __DRIVERS_USB_DWC3_GADGET_H */

+ 54 - 0
drivers/usb/dwc3/io.h

@@ -0,0 +1,54 @@
+/**
+ * io.h - DesignWare USB3 DRD IO Header
+ *
+ * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Authors: Felipe Balbi <balbi@ti.com>,
+ *	    Sebastian Andrzej Siewior <bigeasy@linutronix.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions, and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The names of the above-listed copyright holders may not be used
+ *    to endorse or promote products derived from this software without
+ *    specific prior written permission.
+ *
+ * ALTERNATIVELY, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2, as published by the Free
+ * Software Foundation.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __DRIVERS_USB_DWC3_IO_H
+#define __DRIVERS_USB_DWC3_IO_H
+
+#include <asm/io.h>
+
+static inline u32 dwc3_readl(void __iomem *base, u32 offset)
+{
+	return readl(base + offset);
+}
+
+static inline void dwc3_writel(void __iomem *base, u32 offset, u32 value)
+{
+	writel(value, base + offset);
+}
+
+#endif /* __DRIVERS_USB_DWC3_IO_H */

+ 42 - 5
drivers/usb/gadget/Kconfig

@@ -96,6 +96,22 @@ config USB_GADGET_VBUS_DRAW
 	   This value will be used except for system-specific gadget
 	   drivers that have more specific information.
 
+config USB_GADGET_STORAGE_NUM_BUFFERS
+	int "Number of storage pipeline buffers"
+	range 2 4
+	default 2
+	help
+	   Usually 2 buffers are enough to establish a good buffering
+	   pipeline. The number may be increased in order to compensate
+	   for a bursty VFS behaviour. For instance there may be CPU wake up
+	   latencies that makes the VFS to appear bursty in a system with
+	   an CPU on-demand governor. Especially if DMA is doing IO to
+	   offload the CPU. In this case the CPU will go into power
+	   save often and spin up occasionally to move data within VFS.
+	   If selecting USB_GADGET_DEBUG_FILES this value may be set by
+	   a module parameter as well.
+	   If unsure, say 2.
+
 #
 # USB Peripheral Controller Support
 #
@@ -255,12 +271,11 @@ config USB_S3C_HSOTG
 	  integrated into the S3C64XX series SoC.
 
 config USB_IMX
-	tristate "Freescale IMX USB Peripheral Controller"
-	depends on ARCH_MX1
+	tristate "Freescale i.MX1 USB Peripheral Controller"
+	depends on ARCH_MXC
 	help
-	   Freescale's IMX series include an integrated full speed
-	   USB 1.1 device controller.  The controller in the IMX series
-	   is register-compatible.
+	   Freescale's i.MX1 includes an integrated full speed
+	   USB 1.1 device controller.
 
 	   It has Six fixed-function endpoints, as well as endpoint
 	   zero (for control transfers).
@@ -303,6 +318,18 @@ config USB_PXA_U2O
 	  PXA9xx Processor series include a high speed USB2.0 device
 	  controller, which support high speed and full speed USB peripheral.
 
+config USB_GADGET_DWC3
+	tristate "DesignWare USB3.0 (DRD) Controller"
+	depends on USB_DWC3
+	select USB_GADGET_DUALSPEED
+	select USB_GADGET_SUPERSPEED
+	help
+	  DesignWare USB3.0 controller is a SuperSpeed USB3.0 Controller
+	  which can be configured for peripheral-only, host-only, hub-only
+	  and Dual-Role operation. This Controller was first integrated into
+	  the OMAP5 series of processors. More information about the OMAP5
+	  version of this controller, refer to http://www.ti.com/omap5.
+
 #
 # Controllers available in both integrated and discrete versions
 #
@@ -846,6 +873,16 @@ config USB_G_NOKIA
 	  It's only really useful for N900 hardware. If you're building
 	  a kernel for N900, say Y or M here. If unsure, say N.
 
+config USB_G_ACM_MS
+	tristate "CDC Composite Device (ACM and mass storage)"
+	depends on BLOCK
+	help
+	  This driver provides two functions in one configuration:
+	  a mass storage, and a CDC ACM (serial port) link.
+
+	  Say "y" to link the driver statically, or "m" to build a
+	  dynamically linked module called "g_acm_ms".
+
 config USB_G_MULTI
 	tristate "Multifunction Composite Gadget (EXPERIMENTAL)"
 	depends on BLOCK && NET

+ 3 - 1
drivers/usb/gadget/Makefile

@@ -28,7 +28,7 @@ obj-$(CONFIG_USB_S3C_HSUDC)	+= s3c-hsudc.o
 obj-$(CONFIG_USB_LANGWELL)	+= langwell_udc.o
 obj-$(CONFIG_USB_EG20T)		+= pch_udc.o
 obj-$(CONFIG_USB_PXA_U2O)	+= mv_udc.o
-mv_udc-y			:= mv_udc_core.o mv_udc_phy.o
+mv_udc-y			:= mv_udc_core.o
 obj-$(CONFIG_USB_CI13XXX_MSM)	+= ci13xxx_msm.o
 obj-$(CONFIG_USB_FUSB300)	+= fusb300_udc.o
 
@@ -51,6 +51,7 @@ g_dbgp-y			:= dbgp.o
 g_nokia-y			:= nokia.o
 g_webcam-y			:= webcam.o
 g_ncm-y				:= ncm.o
+g_acm_ms-y			:= acm_ms.o
 
 obj-$(CONFIG_USB_ZERO)		+= g_zero.o
 obj-$(CONFIG_USB_AUDIO)		+= g_audio.o
@@ -69,3 +70,4 @@ obj-$(CONFIG_USB_G_MULTI)	+= g_multi.o
 obj-$(CONFIG_USB_G_NOKIA)	+= g_nokia.o
 obj-$(CONFIG_USB_G_WEBCAM)	+= g_webcam.o
 obj-$(CONFIG_USB_G_NCM)		+= g_ncm.o
+obj-$(CONFIG_USB_G_ACM_MS)	+= g_acm_ms.o

+ 256 - 0
drivers/usb/gadget/acm_ms.c

@@ -0,0 +1,256 @@
+/*
+ * acm_ms.c -- Composite driver, with ACM and mass storage support
+ *
+ * Copyright (C) 2008 David Brownell
+ * Copyright (C) 2008 Nokia Corporation
+ * Author: David Brownell
+ * Modified: Klaus Schwarzkopf <schwarzkopf@sensortherm.de>
+ *
+ * Heavily based on multi.c and cdc2.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/utsname.h>
+
+#include "u_serial.h"
+
+#define DRIVER_DESC		"Composite Gadget (ACM + MS)"
+#define DRIVER_VERSION		"2011/10/10"
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * DO NOT REUSE THESE IDs with a protocol-incompatible driver!!  Ever!!
+ * Instead:  allocate your own, using normal USB-IF procedures.
+ */
+#define ACM_MS_VENDOR_NUM	0x1d6b	/* Linux Foundation */
+#define ACM_MS_PRODUCT_NUM	0x0106	/* Composite Gadget: ACM + MS*/
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Kbuild is not very cooperative with respect to linking separately
+ * compiled library objects into one module.  So for now we won't use
+ * separate compilation ... ensuring init/exit sections work to shrink
+ * the runtime footprint, and giving us at least some parts of what
+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
+ */
+
+#include "composite.c"
+#include "usbstring.c"
+#include "config.c"
+#include "epautoconf.c"
+#include "u_serial.c"
+#include "f_acm.c"
+#include "f_mass_storage.c"
+
+/*-------------------------------------------------------------------------*/
+
+static struct usb_device_descriptor device_desc = {
+	.bLength =		sizeof device_desc,
+	.bDescriptorType =	USB_DT_DEVICE,
+
+	.bcdUSB =		cpu_to_le16(0x0200),
+
+	.bDeviceClass =		USB_CLASS_MISC /* 0xEF */,
+	.bDeviceSubClass =	2,
+	.bDeviceProtocol =	1,
+
+	/* .bMaxPacketSize0 = f(hardware) */
+
+	/* Vendor and product id can be overridden by module parameters.  */
+	.idVendor =		cpu_to_le16(ACM_MS_VENDOR_NUM),
+	.idProduct =		cpu_to_le16(ACM_MS_PRODUCT_NUM),
+	/* .bcdDevice = f(hardware) */
+	/* .iManufacturer = DYNAMIC */
+	/* .iProduct = DYNAMIC */
+	/* NO SERIAL NUMBER */
+	/*.bNumConfigurations =	DYNAMIC*/
+};
+
+static struct usb_otg_descriptor otg_descriptor = {
+	.bLength =		sizeof otg_descriptor,
+	.bDescriptorType =	USB_DT_OTG,
+
+	/*
+	 * REVISIT SRP-only hardware is possible, although
+	 * it would not be called "OTG" ...
+	 */
+	.bmAttributes =		USB_OTG_SRP | USB_OTG_HNP,
+};
+
+static const struct usb_descriptor_header *otg_desc[] = {
+	(struct usb_descriptor_header *) &otg_descriptor,
+	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 *dev_strings[] = {
+	&stringtab_dev,
+	NULL,
+};
+
+/****************************** Configurations ******************************/
+
+static struct fsg_module_parameters fsg_mod_data = { .stall = 1 };
+FSG_MODULE_PARAMETERS(/* no prefix */, fsg_mod_data);
+
+static struct fsg_common fsg_common;
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * We _always_ have both ACM and mass storage functions.
+ */
+static int __init acm_ms_do_config(struct usb_configuration *c)
+{
+	int	status;
+
+	if (gadget_is_otg(c->cdev->gadget)) {
+		c->descriptors = otg_desc;
+		c->bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+	}
+
+
+	status = acm_bind_config(c, 0);
+	if (status < 0)
+		return status;
+
+	status = fsg_bind_config(c->cdev, c, &fsg_common);
+	if (status < 0)
+		return status;
+
+	return 0;
+}
+
+static struct usb_configuration acm_ms_config_driver = {
+	.label			= DRIVER_DESC,
+	.bConfigurationValue	= 1,
+	/* .iConfiguration = DYNAMIC */
+	.bmAttributes		= USB_CONFIG_ATT_SELFPOWER,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init acm_ms_bind(struct usb_composite_dev *cdev)
+{
+	int			gcnum;
+	struct usb_gadget	*gadget = cdev->gadget;
+	int			status;
+	void			*retp;
+
+	/* set up serial link layer */
+	status = gserial_setup(cdev->gadget, 1);
+	if (status < 0)
+		return status;
+
+	/* set up mass storage function */
+	retp = fsg_common_from_params(&fsg_common, cdev, &fsg_mod_data);
+	if (IS_ERR(retp)) {
+		status = PTR_ERR(retp);
+		goto fail0;
+	}
+
+	/* set bcdDevice */
+	gcnum = usb_gadget_controller_number(gadget);
+	if (gcnum >= 0) {
+		device_desc.bcdDevice = cpu_to_le16(0x0300 | gcnum);
+	} else {
+		WARNING(cdev, "controller '%s' not recognized; trying %s\n",
+				gadget->name,
+				acm_ms_config_driver.label);
+		device_desc.bcdDevice =
+			cpu_to_le16(0x0300 | 0x0099);
+	}
+
+	/*
+	 * Allocate string descriptor numbers ... note that string
+	 * contents can be overridden by the composite_dev glue.
+	 */
+
+	/* device descriptor strings: manufacturer, product */
+	snprintf(manufacturer, sizeof manufacturer, "%s %s with %s",
+		init_utsname()->sysname, init_utsname()->release,
+		gadget->name);
+	status = usb_string_id(cdev);
+	if (status < 0)
+		goto fail1;
+	strings_dev[STRING_MANUFACTURER_IDX].id = status;
+	device_desc.iManufacturer = status;
+
+	status = usb_string_id(cdev);
+	if (status < 0)
+		goto fail1;
+	strings_dev[STRING_PRODUCT_IDX].id = status;
+	device_desc.iProduct = status;
+
+	/* register our configuration */
+	status = usb_add_config(cdev, &acm_ms_config_driver, acm_ms_do_config);
+	if (status < 0)
+		goto fail1;
+
+	dev_info(&gadget->dev, "%s, version: " DRIVER_VERSION "\n",
+			DRIVER_DESC);
+	fsg_common_put(&fsg_common);
+	return 0;
+
+	/* error recovery */
+fail1:
+	fsg_common_put(&fsg_common);
+fail0:
+	gserial_cleanup();
+	return status;
+}
+
+static int __exit acm_ms_unbind(struct usb_composite_dev *cdev)
+{
+	gserial_cleanup();
+
+	return 0;
+}
+
+static struct usb_composite_driver acm_ms_driver = {
+	.name		= "g_acm_ms",
+	.dev		= &device_desc,
+	.strings	= dev_strings,
+	.unbind		= __exit_p(acm_ms_unbind),
+};
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Klaus Schwarzkopf <schwarzkopf@sensortherm.de>");
+MODULE_LICENSE("GPL v2");
+
+static int __init init(void)
+{
+	return usb_composite_probe(&acm_ms_driver, acm_ms_bind);
+}
+module_init(init);
+
+static void __exit cleanup(void)
+{
+	usb_composite_unregister(&acm_ms_driver);
+}
+module_exit(cleanup);

+ 3 - 17
drivers/usb/gadget/amd5536udc.c

@@ -8,15 +8,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 /*
@@ -354,7 +345,7 @@ udc_ep_enable(struct usb_ep *usbep, const struct usb_endpoint_descriptor *desc)
 	writel(tmp, &dev->ep[ep->num].regs->ctl);
 
 	/* set max packet size */
-	maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+	maxpacket = usb_endpoint_maxp(desc);
 	tmp = readl(&dev->ep[ep->num].regs->bufout_maxpkt);
 	tmp = AMD_ADDBITS(tmp, maxpacket, UDC_EP_MAX_PKT_SIZE);
 	ep->ep.maxpacket = maxpacket;
@@ -3014,13 +3005,8 @@ __acquires(dev->lock)
 
 		/* link up all endpoints */
 		udc_setup_endpoints(dev);
-		if (dev->gadget.speed == USB_SPEED_HIGH) {
-			dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
-				"high");
-		} else if (dev->gadget.speed == USB_SPEED_FULL) {
-			dev_info(&dev->pdev->dev, "Connect: speed = %s\n",
-				"full");
-		}
+		dev_info(&dev->pdev->dev, "Connect: %s\n",
+			 usb_speed_string(dev->gadget.speed));
 
 		/* init ep 0 */
 		activate_control_endpoints(dev);

+ 0 - 9
drivers/usb/gadget/amd5536udc.h

@@ -8,15 +8,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #ifndef AMD5536UDC_H

+ 11 - 21
drivers/usb/gadget/at91_udc.c

@@ -9,16 +9,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA  02111-1307, USA.
  */
 
 #undef	VERBOSE_DEBUG
@@ -460,7 +450,7 @@ static void nuke(struct at91_ep *ep, int status)
 {
 	struct at91_request *req;
 
-	// terminer chaque requete dans la queue
+	/* terminate any request in the queue */
 	ep->stopped = 1;
 	if (list_empty(&ep->queue))
 		return;
@@ -487,7 +477,7 @@ static int at91_ep_enable(struct usb_ep *_ep,
 			|| !desc || ep->desc
 			|| _ep->name == ep0name
 			|| desc->bDescriptorType != USB_DT_ENDPOINT
-			|| (maxpacket = le16_to_cpu(desc->wMaxPacketSize)) == 0
+			|| (maxpacket = usb_endpoint_maxp(desc)) == 0
 			|| maxpacket > ep->maxpacket) {
 		DBG("bad ep or descriptor\n");
 		return -EINVAL;
@@ -788,7 +778,7 @@ static const struct usb_ep_ops at91_ep_ops = {
 	.queue		= at91_ep_queue,
 	.dequeue	= at91_ep_dequeue,
 	.set_halt	= at91_ep_set_halt,
-	// there's only imprecise fifo status reporting
+	/* there's only imprecise fifo status reporting */
 };
 
 /*-------------------------------------------------------------------------*/
@@ -846,7 +836,7 @@ static void udc_reinit(struct at91_udc *udc)
 		ep->fifo_bank = 0;
 		ep->ep.maxpacket = ep->maxpacket;
 		ep->creg = (void __iomem *) udc->udp_baseaddr + AT91_UDP_CSR(i);
-		// initialiser une queue par endpoint
+		/* initialize one queue per endpoint */
 		INIT_LIST_HEAD(&ep->queue);
 	}
 }
@@ -952,7 +942,7 @@ static int at91_vbus_session(struct usb_gadget *gadget, int is_active)
 	struct at91_udc	*udc = to_udc(gadget);
 	unsigned long	flags;
 
-	// VDBG("vbus %s\n", is_active ? "on" : "off");
+	/* VDBG("vbus %s\n", is_active ? "on" : "off"); */
 	spin_lock_irqsave(&udc->lock, flags);
 	udc->vbus = (is_active != 0);
 	if (udc->driver)
@@ -1003,7 +993,7 @@ static const struct usb_gadget_ops at91_udc_ops = {
 	 * VBUS-powered devices may also also want to support bigger
 	 * power budgets after an appropriate SET_CONFIGURATION.
 	 */
-	// .vbus_power		= at91_vbus_power,
+	/* .vbus_power		= at91_vbus_power, */
 };
 
 /*-------------------------------------------------------------------------*/
@@ -1072,7 +1062,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
 			ep->is_in = 0;
 		}
 	} else {
-		// REVISIT this happens sometimes under load; why??
+		/* REVISIT this happens sometimes under load; why?? */
 		ERR("SETUP len %d, csr %08x\n", rxcount, csr);
 		status = -EINVAL;
 	}
@@ -1451,7 +1441,7 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
 			at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXSUSP);
 			at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXRSM);
 			at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXSUSP);
-			// VDBG("bus suspend\n");
+			/* VDBG("bus suspend\n"); */
 			if (udc->suspended)
 				continue;
 			udc->suspended = 1;
@@ -1473,7 +1463,7 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
 			at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
 			at91_udp_write(udc, AT91_UDP_IER, AT91_UDP_RXSUSP);
 			at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
-			// VDBG("bus resume\n");
+			/* VDBG("bus resume\n"); */
 			if (!udc->suspended)
 				continue;
 			udc->suspended = 0;
@@ -1820,7 +1810,7 @@ static int __init at91udc_probe(struct platform_device *pdev)
 	/* request UDC and maybe VBUS irqs */
 	udc->udp_irq = platform_get_irq(pdev, 0);
 	retval = request_irq(udc->udp_irq, at91_udc_irq,
-			IRQF_DISABLED, driver_name, udc);
+			0, driver_name, udc);
 	if (retval < 0) {
 		DBG("request irq %d failed\n", udc->udp_irq);
 		goto fail1;
@@ -1848,7 +1838,7 @@ static int __init at91udc_probe(struct platform_device *pdev)
 				  jiffies + VBUS_POLL_TIMEOUT);
 		} else {
 			if (request_irq(udc->board.vbus_pin, at91_vbus_irq,
-					IRQF_DISABLED, driver_name, udc)) {
+					0, driver_name, udc)) {
 				DBG("request vbus irq %d failed\n",
 				    udc->board.vbus_pin);
 				retval = -EBUSY;

+ 0 - 10
drivers/usb/gadget/at91_udc.h

@@ -7,16 +7,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the
- * Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
 
 #ifndef AT91_UDC_H

+ 6 - 7
drivers/usb/gadget/atmel_usba_udc.c

@@ -527,7 +527,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 
 	DBG(DBG_GADGET, "%s: ep_enable: desc=%p\n", ep->ep.name, desc);
 
-	maxpacket = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
+	maxpacket = usb_endpoint_maxp(desc) & 0x7ff;
 
 	if (((desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK) != ep->index)
 			|| ep->index == 0
@@ -571,7 +571,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 		 * Bits 11:12 specify number of _additional_
 		 * transactions per microframe.
 		 */
-		nr_trans = ((le16_to_cpu(desc->wMaxPacketSize) >> 11) & 3) + 1;
+		nr_trans = ((usb_endpoint_maxp(desc) >> 11) & 3) + 1;
 		if (nr_trans > 3)
 			return -EINVAL;
 
@@ -1718,13 +1718,12 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
 			spin_lock(&udc->lock);
 		}
 
-		if (status & USBA_HIGH_SPEED) {
-			DBG(DBG_BUS, "High-speed bus reset detected\n");
+		if (status & USBA_HIGH_SPEED)
 			udc->gadget.speed = USB_SPEED_HIGH;
-		} else {
-			DBG(DBG_BUS, "Full-speed bus reset detected\n");
+		else
 			udc->gadget.speed = USB_SPEED_FULL;
-		}
+		DBG(DBG_BUS, "%s bus reset detected\n",
+		    usb_speed_string(udc->gadget.speed));
 
 		ep0 = &usba_ep[0];
 		ep0->desc = &usba_ep0_desc;

+ 0 - 9
drivers/usb/gadget/cdc2.c

@@ -8,15 +8,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #include <linux/kernel.h>

+ 0 - 11
drivers/usb/gadget/ci13xxx_msm.c

@@ -3,17 +3,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 and
  * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- * 02110-1301, USA.
- *
  */
 
 #include <linux/module.h>

+ 1 - 1
drivers/usb/gadget/ci13xxx_udc.c

@@ -2101,7 +2101,7 @@ static int ep_enable(struct usb_ep *ep,
 	mEp->num  = usb_endpoint_num(desc);
 	mEp->type = usb_endpoint_type(desc);
 
-	mEp->ep.maxpacket = __constant_le16_to_cpu(desc->wMaxPacketSize);
+	mEp->ep.maxpacket = usb_endpoint_maxp(desc);
 
 	dbg_event(_usb_addr(mEp), "ENABLE", 0);
 

+ 6 - 31
drivers/usb/gadget/composite.c

@@ -7,15 +7,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 /* #define VERBOSE_DEBUG */
@@ -164,7 +155,7 @@ int config_ep_by_speed(struct usb_gadget *g,
 
 ep_found:
 	/* commit results */
-	_ep->maxpacket = le16_to_cpu(chosen_desc->wMaxPacketSize);
+	_ep->maxpacket = usb_endpoint_maxp(chosen_desc);
 	_ep->desc = chosen_desc;
 	_ep->comp_desc = NULL;
 	_ep->maxburst = 0;
@@ -551,9 +542,9 @@ static int bos_desc(struct usb_composite_dev *cdev)
 	if (cdev->gadget->ops->get_config_params)
 		cdev->gadget->ops->get_config_params(&dcd_config_params);
 	else {
-		dcd_config_params.bU1devExitLat = USB_DEFULT_U1_DEV_EXIT_LAT;
+		dcd_config_params.bU1devExitLat = USB_DEFAULT_U1_DEV_EXIT_LAT;
 		dcd_config_params.bU2DevExitLat =
-			cpu_to_le16(USB_DEFULT_U2_DEV_EXIT_LAT);
+			cpu_to_le16(USB_DEFAULT_U2_DEV_EXIT_LAT);
 	}
 	ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
 	ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
@@ -626,25 +617,9 @@ static int set_config(struct usb_composite_dev *cdev,
 		result = 0;
 	}
 
-	INFO(cdev, "%s speed config #%d: %s\n",
-		({ char *speed;
-		switch (gadget->speed) {
-		case USB_SPEED_LOW:
-			speed = "low";
-			break;
-		case USB_SPEED_FULL:
-			speed = "full";
-			break;
-		case USB_SPEED_HIGH:
-			speed = "high";
-			break;
-		case USB_SPEED_SUPER:
-			speed = "super";
-			break;
-		default:
-			speed = "?";
-			break;
-		} ; speed; }), number, c ? c->label : "unconfigured");
+	INFO(cdev, "%s config #%d: %s\n",
+	     usb_speed_string(gadget->speed),
+	     number, c ? c->label : "unconfigured");
 
 	if (!c)
 		goto done;

+ 0 - 9
drivers/usb/gadget/config.c

@@ -7,15 +7,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #include <linux/errno.h>

+ 0 - 1
drivers/usb/gadget/dbgp.c

@@ -4,7 +4,6 @@
  * Copyright (C) 2010 Stephane Duverger
  *
  * Released under the GPLv2.
- *
  */
 
 /* verbose messages */

+ 2 - 11
drivers/usb/gadget/dummy_hcd.c

@@ -10,15 +10,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 
@@ -439,7 +430,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 	 * maximum packet size.
 	 * For SS devices the wMaxPacketSize is limited by 1024.
 	 */
-	max = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
+	max = usb_endpoint_maxp(desc) & 0x7ff;
 
 	/* drivers must not request bad settings, since lower levels
 	 * (hardware or its drivers) may not check.  some endpoints
@@ -1277,7 +1268,7 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
 		int	tmp;
 
 		/* high bandwidth mode */
-		tmp = le16_to_cpu(ep->desc->wMaxPacketSize);
+		tmp = usb_endpoint_maxp(ep->desc);
 		tmp = (tmp >> 11) & 0x03;
 		tmp *= 8 /* applies to entire frame */;
 		limit += limit * tmp;

+ 1 - 11
drivers/usb/gadget/epautoconf.c

@@ -7,16 +7,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- *
  */
 
 #include <linux/kernel.h>
@@ -158,7 +148,7 @@ ep_matches (
 	 * where it's an output parameter representing the full speed limit.
 	 * the usb spec fixes high speed bulk maxpacket at 512 bytes.
 	 */
-	max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);
+	max = 0x7ff & usb_endpoint_maxp(desc);
 	switch (type) {
 	case USB_ENDPOINT_XFER_INT:
 		/* INT:  limit 64 bytes full speed, 1024 high/super speed */

+ 0 - 9
drivers/usb/gadget/ether.c

@@ -9,15 +9,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 /* #define VERBOSE_DEBUG */

+ 8 - 7
drivers/usb/gadget/f_audio.c

@@ -460,7 +460,7 @@ static int audio_set_endpoint_req(struct usb_function *f,
 
 	switch (ctrl->bRequest) {
 	case UAC_SET_CUR:
-		value = 0;
+		value = len;
 		break;
 
 	case UAC_SET_MIN:
@@ -499,7 +499,7 @@ static int audio_get_endpoint_req(struct usb_function *f,
 	case UAC_GET_MIN:
 	case UAC_GET_MAX:
 	case UAC_GET_RES:
-		value = 3;
+		value = len;
 		break;
 	case UAC_GET_MEM:
 		break;
@@ -681,17 +681,18 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
 
 	status = -ENOMEM;
 
-	/* supcard all relevant hardware speeds... we expect that when
+	/* copy descriptors, and track endpoint copies */
+	f->descriptors = usb_copy_descriptors(f_audio_desc);
+
+	/*
+	 * support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
 	 */
-
-	/* copy descriptors, and track endpoint copies */
 	if (gadget_is_dualspeed(c->cdev->gadget)) {
 		c->highspeed = true;
 		f->hs_descriptors = usb_copy_descriptors(f_audio_desc);
-	} else
-		f->descriptors = usb_copy_descriptors(f_audio_desc);
+	}
 
 	return 0;
 

+ 0 - 9
drivers/usb/gadget/f_ecm.c

@@ -8,15 +8,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 /* #define VERBOSE_DEBUG */

+ 0 - 9
drivers/usb/gadget/f_eem.c

@@ -9,15 +9,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #include <linux/kernel.h>

+ 0 - 9
drivers/usb/gadget/f_fs.c

@@ -12,15 +12,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 

+ 0 - 9
drivers/usb/gadget/f_hid.c

@@ -7,15 +7,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #include <linux/kernel.h>

+ 0 - 9
drivers/usb/gadget/f_loopback.c

@@ -8,15 +8,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 /* #define VERBOSE_DEBUG */

+ 111 - 85
drivers/usb/gadget/f_mass_storage.c

@@ -112,8 +112,7 @@
  * is not loaded (an empty string as "filename" in the fsg_config
  * structure causes error).  The CD-ROM emulation includes a single
  * data track and no audio tracks; hence there need be only one
- * backing file per LUN.  Note also that the CD-ROM block length is
- * set to 512 rather than the more common value 2048.
+ * backing file per LUN.
  *
  *
  * MSF includes support for module parameters.  If gadget using it
@@ -363,7 +362,7 @@ struct fsg_common {
 
 	struct fsg_buffhd	*next_buffhd_to_fill;
 	struct fsg_buffhd	*next_buffhd_to_drain;
-	struct fsg_buffhd	buffhds[FSG_NUM_BUFFERS];
+	struct fsg_buffhd	*buffhds;
 
 	int			cmnd_size;
 	u8			cmnd[MAX_COMMAND_SIZE];
@@ -745,7 +744,6 @@ static int do_read(struct fsg_common *common)
 	u32			amount_left;
 	loff_t			file_offset, file_offset_tmp;
 	unsigned int		amount;
-	unsigned int		partial_page;
 	ssize_t			nread;
 
 	/*
@@ -771,7 +769,7 @@ static int do_read(struct fsg_common *common)
 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
 		return -EINVAL;
 	}
-	file_offset = ((loff_t) lba) << 9;
+	file_offset = ((loff_t) lba) << curlun->blkbits;
 
 	/* Carry out the file reads */
 	amount_left = common->data_size_from_cmnd;
@@ -784,18 +782,10 @@ static int do_read(struct fsg_common *common)
 		 * Try to read the remaining amount.
 		 * But don't read more than the buffer size.
 		 * And don't try to read past the end of the file.
-		 * Finally, if we're not at a page boundary, don't read past
-		 *	the next page.
-		 * If this means reading 0 then we were asked to read past
-		 *	the end of file.
 		 */
 		amount = min(amount_left, FSG_BUFLEN);
 		amount = min((loff_t)amount,
 			     curlun->file_length - file_offset);
-		partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
-		if (partial_page > 0)
-			amount = min(amount, (unsigned int)PAGE_CACHE_SIZE -
-					     partial_page);
 
 		/* Wait for the next buffer to become available */
 		bh = common->next_buffhd_to_fill;
@@ -812,7 +802,8 @@ static int do_read(struct fsg_common *common)
 		if (amount == 0) {
 			curlun->sense_data =
 					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-			curlun->sense_data_info = file_offset >> 9;
+			curlun->sense_data_info =
+					file_offset >> curlun->blkbits;
 			curlun->info_valid = 1;
 			bh->inreq->length = 0;
 			bh->state = BUF_STATE_FULL;
@@ -835,18 +826,25 @@ static int do_read(struct fsg_common *common)
 		} else if (nread < amount) {
 			LDBG(curlun, "partial file read: %d/%u\n",
 			     (int)nread, amount);
-			nread -= (nread & 511);	/* Round down to a block */
+			nread = round_down(nread, curlun->blksize);
 		}
 		file_offset  += nread;
 		amount_left  -= nread;
 		common->residue -= nread;
+
+		/*
+		 * Except at the end of the transfer, nread will be
+		 * equal to the buffer size, which is divisible by the
+		 * bulk-in maxpacket size.
+		 */
 		bh->inreq->length = nread;
 		bh->state = BUF_STATE_FULL;
 
 		/* If an error occurred, report it and its position */
 		if (nread < amount) {
 			curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
-			curlun->sense_data_info = file_offset >> 9;
+			curlun->sense_data_info =
+					file_offset >> curlun->blkbits;
 			curlun->info_valid = 1;
 			break;
 		}
@@ -877,7 +875,6 @@ static int do_write(struct fsg_common *common)
 	u32			amount_left_to_req, amount_left_to_write;
 	loff_t			usb_offset, file_offset, file_offset_tmp;
 	unsigned int		amount;
-	unsigned int		partial_page;
 	ssize_t			nwritten;
 	int			rc;
 
@@ -921,7 +918,7 @@ static int do_write(struct fsg_common *common)
 
 	/* Carry out the file writes */
 	get_some_more = 1;
-	file_offset = usb_offset = ((loff_t) lba) << 9;
+	file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
 	amount_left_to_req = common->data_size_from_cmnd;
 	amount_left_to_write = common->data_size_from_cmnd;
 
@@ -933,41 +930,21 @@ static int do_write(struct fsg_common *common)
 
 			/*
 			 * Figure out how much we want to get:
-			 * Try to get the remaining amount.
-			 * But don't get more than the buffer size.
-			 * And don't try to go past the end of the file.
-			 * If we're not at a page boundary,
-			 *	don't go past the next page.
-			 * If this means getting 0, then we were asked
-			 *	to write past the end of file.
-			 * Finally, round down to a block boundary.
+			 * Try to get the remaining amount,
+			 * but not more than the buffer size.
 			 */
 			amount = min(amount_left_to_req, FSG_BUFLEN);
-			amount = min((loff_t)amount,
-				     curlun->file_length - usb_offset);
-			partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
-			if (partial_page > 0)
-				amount = min(amount,
-	(unsigned int)PAGE_CACHE_SIZE - partial_page);
-
-			if (amount == 0) {
+
+			/* Beyond the end of the backing file? */
+			if (usb_offset >= curlun->file_length) {
 				get_some_more = 0;
 				curlun->sense_data =
 					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-				curlun->sense_data_info = usb_offset >> 9;
+				curlun->sense_data_info =
+					usb_offset >> curlun->blkbits;
 				curlun->info_valid = 1;
 				continue;
 			}
-			amount -= amount & 511;
-			if (amount == 0) {
-
-				/*
-				 * Why were we were asked to transfer a
-				 * partial block?
-				 */
-				get_some_more = 0;
-				continue;
-			}
 
 			/* Get the next buffer */
 			usb_offset += amount;
@@ -977,12 +954,11 @@ static int do_write(struct fsg_common *common)
 				get_some_more = 0;
 
 			/*
-			 * amount is always divisible by 512, hence by
-			 * the bulk-out maxpacket size
+			 * Except at the end of the transfer, amount will be
+			 * equal to the buffer size, which is divisible by
+			 * the bulk-out maxpacket size.
 			 */
-			bh->outreq->length = amount;
-			bh->bulk_out_intended_length = amount;
-			bh->outreq->short_not_ok = 1;
+			set_bulk_out_req_length(common, bh, amount);
 			if (!start_out_transfer(common, bh))
 				/* Dunno what to do if common->fsg is NULL */
 				return -EIO;
@@ -1002,7 +978,8 @@ static int do_write(struct fsg_common *common)
 			/* Did something go wrong with the transfer? */
 			if (bh->outreq->status != 0) {
 				curlun->sense_data = SS_COMMUNICATION_FAILURE;
-				curlun->sense_data_info = file_offset >> 9;
+				curlun->sense_data_info =
+					file_offset >> curlun->blkbits;
 				curlun->info_valid = 1;
 				break;
 			}
@@ -1016,6 +993,16 @@ static int do_write(struct fsg_common *common)
 				amount = curlun->file_length - file_offset;
 			}
 
+			/* Don't accept excess data.  The spec doesn't say
+			 * what to do in this case.  We'll ignore the error.
+			 */
+			amount = min(amount, bh->bulk_out_intended_length);
+
+			/* Don't write a partial block */
+			amount = round_down(amount, curlun->blksize);
+			if (amount == 0)
+				goto empty_write;
+
 			/* Perform the write */
 			file_offset_tmp = file_offset;
 			nwritten = vfs_write(curlun->filp,
@@ -1033,8 +1020,7 @@ static int do_write(struct fsg_common *common)
 			} else if (nwritten < amount) {
 				LDBG(curlun, "partial file write: %d/%u\n",
 				     (int)nwritten, amount);
-				nwritten -= (nwritten & 511);
-				/* Round down to a block */
+				nwritten = round_down(nwritten, curlun->blksize);
 			}
 			file_offset += nwritten;
 			amount_left_to_write -= nwritten;
@@ -1043,13 +1029,15 @@ static int do_write(struct fsg_common *common)
 			/* If an error occurred, report it and its position */
 			if (nwritten < amount) {
 				curlun->sense_data = SS_WRITE_ERROR;
-				curlun->sense_data_info = file_offset >> 9;
+				curlun->sense_data_info =
+					file_offset >> curlun->blkbits;
 				curlun->info_valid = 1;
 				break;
 			}
 
+ empty_write:
 			/* Did the host decide to stop early? */
-			if (bh->outreq->actual != bh->outreq->length) {
+			if (bh->outreq->actual < bh->bulk_out_intended_length) {
 				common->short_packet_received = 1;
 				break;
 			}
@@ -1129,8 +1117,8 @@ static int do_verify(struct fsg_common *common)
 		return -EIO;		/* No default reply */
 
 	/* Prepare to carry out the file verify */
-	amount_left = verification_length << 9;
-	file_offset = ((loff_t) lba) << 9;
+	amount_left = verification_length << curlun->blkbits;
+	file_offset = ((loff_t) lba) << curlun->blkbits;
 
 	/* Write out all the dirty buffers before invalidating them */
 	fsg_lun_fsync_sub(curlun);
@@ -1148,8 +1136,6 @@ static int do_verify(struct fsg_common *common)
 		 * Try to read the remaining amount, but not more than
 		 * the buffer size.
 		 * And don't try to read past the end of the file.
-		 * If this means reading 0 then we were asked to read
-		 * past the end of file.
 		 */
 		amount = min(amount_left, FSG_BUFLEN);
 		amount = min((loff_t)amount,
@@ -1157,7 +1143,8 @@ static int do_verify(struct fsg_common *common)
 		if (amount == 0) {
 			curlun->sense_data =
 					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-			curlun->sense_data_info = file_offset >> 9;
+			curlun->sense_data_info =
+				file_offset >> curlun->blkbits;
 			curlun->info_valid = 1;
 			break;
 		}
@@ -1179,11 +1166,12 @@ static int do_verify(struct fsg_common *common)
 		} else if (nread < amount) {
 			LDBG(curlun, "partial file verify: %d/%u\n",
 			     (int)nread, amount);
-			nread -= nread & 511;	/* Round down to a sector */
+			nread = round_down(nread, curlun->blksize);
 		}
 		if (nread == 0) {
 			curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
-			curlun->sense_data_info = file_offset >> 9;
+			curlun->sense_data_info =
+				file_offset >> curlun->blkbits;
 			curlun->info_valid = 1;
 			break;
 		}
@@ -1289,7 +1277,7 @@ static int do_read_capacity(struct fsg_common *common, struct fsg_buffhd *bh)
 
 	put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
 						/* Max logical block */
-	put_unaligned_be32(512, &buf[4]);	/* Block length */
+	put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
 	return 8;
 }
 
@@ -1527,7 +1515,7 @@ static int do_read_format_capacities(struct fsg_common *common,
 
 	put_unaligned_be32(curlun->num_sectors, &buf[0]);
 						/* Number of blocks */
-	put_unaligned_be32(512, &buf[4]);	/* Block length */
+	put_unaligned_be32(curlun->blksize, &buf[4]);/* Block length */
 	buf[4] = 0x02;				/* Current capacity */
 	return 12;
 }
@@ -1607,7 +1595,7 @@ static int throw_away_data(struct fsg_common *common)
 			common->next_buffhd_to_drain = bh->next;
 
 			/* A short packet or an error ends everything */
-			if (bh->outreq->actual != bh->outreq->length ||
+			if (bh->outreq->actual < bh->bulk_out_intended_length ||
 			    bh->outreq->status != 0) {
 				raise_exception(common,
 						FSG_STATE_ABORT_BULK_OUT);
@@ -1623,12 +1611,11 @@ static int throw_away_data(struct fsg_common *common)
 			amount = min(common->usb_amount_left, FSG_BUFLEN);
 
 			/*
-			 * amount is always divisible by 512, hence by
+			 * Except at the end of the transfer, amount will be
+			 * equal to the buffer size, which is divisible by
 			 * the bulk-out maxpacket size.
 			 */
-			bh->outreq->length = amount;
-			bh->bulk_out_intended_length = amount;
-			bh->outreq->short_not_ok = 1;
+			set_bulk_out_req_length(common, bh, amount);
 			if (!start_out_transfer(common, bh))
 				/* Dunno what to do if common->fsg is NULL */
 				return -EIO;
@@ -2022,7 +2009,8 @@ static int do_scsi_command(struct fsg_common *common)
 
 	case READ_6:
 		i = common->cmnd[4];
-		common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+		common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
+				common->curlun->blkbits;
 		reply = check_command(common, 6, DATA_DIR_TO_HOST,
 				      (7<<1) | (1<<4), 1,
 				      "READ(6)");
@@ -2032,7 +2020,8 @@ static int do_scsi_command(struct fsg_common *common)
 
 	case READ_10:
 		common->data_size_from_cmnd =
-				get_unaligned_be16(&common->cmnd[7]) << 9;
+				get_unaligned_be16(&common->cmnd[7]) <<
+						common->curlun->blkbits;
 		reply = check_command(common, 10, DATA_DIR_TO_HOST,
 				      (1<<1) | (0xf<<2) | (3<<7), 1,
 				      "READ(10)");
@@ -2042,7 +2031,8 @@ static int do_scsi_command(struct fsg_common *common)
 
 	case READ_12:
 		common->data_size_from_cmnd =
-				get_unaligned_be32(&common->cmnd[6]) << 9;
+				get_unaligned_be32(&common->cmnd[6]) <<
+						common->curlun->blkbits;
 		reply = check_command(common, 12, DATA_DIR_TO_HOST,
 				      (1<<1) | (0xf<<2) | (0xf<<6), 1,
 				      "READ(12)");
@@ -2142,7 +2132,8 @@ static int do_scsi_command(struct fsg_common *common)
 
 	case WRITE_6:
 		i = common->cmnd[4];
-		common->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+		common->data_size_from_cmnd = (i == 0 ? 256 : i) <<
+					common->curlun->blkbits;
 		reply = check_command(common, 6, DATA_DIR_FROM_HOST,
 				      (7<<1) | (1<<4), 1,
 				      "WRITE(6)");
@@ -2152,7 +2143,8 @@ static int do_scsi_command(struct fsg_common *common)
 
 	case WRITE_10:
 		common->data_size_from_cmnd =
-				get_unaligned_be16(&common->cmnd[7]) << 9;
+				get_unaligned_be16(&common->cmnd[7]) <<
+						common->curlun->blkbits;
 		reply = check_command(common, 10, DATA_DIR_FROM_HOST,
 				      (1<<1) | (0xf<<2) | (3<<7), 1,
 				      "WRITE(10)");
@@ -2162,7 +2154,8 @@ static int do_scsi_command(struct fsg_common *common)
 
 	case WRITE_12:
 		common->data_size_from_cmnd =
-				get_unaligned_be32(&common->cmnd[6]) << 9;
+				get_unaligned_be32(&common->cmnd[6]) <<
+						common->curlun->blkbits;
 		reply = check_command(common, 12, DATA_DIR_FROM_HOST,
 				      (1<<1) | (0xf<<2) | (0xf<<6), 1,
 				      "WRITE(12)");
@@ -2297,7 +2290,6 @@ 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);
-	bh->outreq->short_not_ok = 1;
 	if (!start_out_transfer(common, bh))
 		/* Don't know what to do if common->fsg is NULL */
 		return -EIO;
@@ -2348,7 +2340,7 @@ reset:
 	if (common->fsg) {
 		fsg = common->fsg;
 
-		for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+		for (i = 0; i < fsg_num_buffers; ++i) {
 			struct fsg_buffhd *bh = &common->buffhds[i];
 
 			if (bh->inreq) {
@@ -2401,12 +2393,11 @@ reset:
 		goto reset;
 	fsg->bulk_out->driver_data = common;
 	fsg->bulk_out_enabled = 1;
-	common->bulk_out_maxpacket =
-		le16_to_cpu(fsg->bulk_out->desc->wMaxPacketSize);
+	common->bulk_out_maxpacket = usb_endpoint_maxp(fsg->bulk_out->desc);
 	clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
 
 	/* Allocate the requests */
-	for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+	for (i = 0; i < fsg_num_buffers; ++i) {
 		struct fsg_buffhd	*bh = &common->buffhds[i];
 
 		rc = alloc_request(common, fsg->bulk_in, &bh->inreq);
@@ -2475,7 +2466,7 @@ static void handle_exception(struct fsg_common *common)
 
 	/* Cancel all the pending transfers */
 	if (likely(common->fsg)) {
-		for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+		for (i = 0; i < fsg_num_buffers; ++i) {
 			bh = &common->buffhds[i];
 			if (bh->inreq_busy)
 				usb_ep_dequeue(common->fsg->bulk_in, bh->inreq);
@@ -2487,7 +2478,7 @@ static void handle_exception(struct fsg_common *common)
 		/* Wait until everything is idle */
 		for (;;) {
 			int num_active = 0;
-			for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+			for (i = 0; i < fsg_num_buffers; ++i) {
 				bh = &common->buffhds[i];
 				num_active += bh->inreq_busy + bh->outreq_busy;
 			}
@@ -2510,7 +2501,7 @@ static void handle_exception(struct fsg_common *common)
 	 */
 	spin_lock_irq(&common->lock);
 
-	for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+	for (i = 0; i < fsg_num_buffers; ++i) {
 		bh = &common->buffhds[i];
 		bh->state = BUF_STATE_EMPTY;
 	}
@@ -2719,6 +2710,10 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
 	int nluns, i, rc;
 	char *pathbuf;
 
+	rc = fsg_num_buffers_validate();
+	if (rc != 0)
+		return ERR_PTR(rc);
+
 	/* Find out how many LUNs there should be */
 	nluns = cfg->nluns;
 	if (nluns < 1 || nluns > FSG_MAX_LUNS) {
@@ -2737,6 +2732,14 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
 		common->free_storage_on_release = 0;
 	}
 
+	common->buffhds = kcalloc(fsg_num_buffers,
+				  sizeof *(common->buffhds), GFP_KERNEL);
+	if (!common->buffhds) {
+		if (common->free_storage_on_release)
+			kfree(common);
+		return ERR_PTR(-ENOMEM);
+	}
+
 	common->ops = cfg->ops;
 	common->private_data = cfg->private_data;
 
@@ -2814,7 +2817,7 @@ static struct fsg_common *fsg_common_init(struct fsg_common *common,
 
 	/* Data buffers cyclic list */
 	bh = common->buffhds;
-	i = FSG_NUM_BUFFERS;
+	i = fsg_num_buffers;
 	goto buffhds_first_it;
 	do {
 		bh->next = bh + 1;
@@ -2940,12 +2943,13 @@ static void fsg_common_release(struct kref *ref)
 
 	{
 		struct fsg_buffhd *bh = common->buffhds;
-		unsigned i = FSG_NUM_BUFFERS;
+		unsigned i = fsg_num_buffers;
 		do {
 			kfree(bh->buf);
 		} while (++bh, --i);
 	}
 
+	kfree(common->buffhds);
 	if (common->free_storage_on_release)
 		kfree(common);
 }
@@ -3019,6 +3023,28 @@ static int fsg_bind(struct usb_configuration *c, struct usb_function *f)
 		}
 	}
 
+	if (gadget_is_superspeed(gadget)) {
+		unsigned	max_burst;
+
+		/* Calculate bMaxBurst, we know packet size is 1024 */
+		max_burst = min_t(unsigned, FSG_BUFLEN / 1024, 15);
+
+		fsg_ss_bulk_in_desc.bEndpointAddress =
+			fsg_fs_bulk_in_desc.bEndpointAddress;
+		fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
+
+		fsg_ss_bulk_out_desc.bEndpointAddress =
+			fsg_fs_bulk_out_desc.bEndpointAddress;
+		fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
+
+		f->ss_descriptors = usb_copy_descriptors(fsg_ss_function);
+		if (unlikely(!f->ss_descriptors)) {
+			usb_free_descriptors(f->hs_descriptors);
+			usb_free_descriptors(f->descriptors);
+			return -ENOMEM;
+		}
+	}
+
 	return 0;
 
 autoconf_fail:

+ 998 - 0
drivers/usb/gadget/f_midi.c

@@ -0,0 +1,998 @@
+/*
+ * f_midi.c -- USB MIDI class function driver
+ *
+ * Copyright (C) 2006 Thumtronics Pty Ltd.
+ * Developed for Thumtronics by Grey Innovation
+ * Ben Williamson <ben.williamson@greyinnovation.com>
+ *
+ * Rewritten for the composite framework
+ *   Copyright (C) 2011 Daniel Mack <zonque@gmail.com>
+ *
+ * Based on drivers/usb/gadget/f_audio.c,
+ *   Copyright (C) 2008 Bryan Wu <cooloney@kernel.org>
+ *   Copyright (C) 2008 Analog Devices, Inc
+ *
+ * and drivers/usb/gadget/midi.c,
+ *   Copyright (C) 2006 Thumtronics Pty Ltd.
+ *   Ben Williamson <ben.williamson@greyinnovation.com>
+ *
+ * Licensed under the GPL-2 or later.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/utsname.h>
+#include <linux/device.h>
+
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/rawmidi.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+#include <linux/usb/audio.h>
+#include <linux/usb/midi.h>
+
+MODULE_AUTHOR("Ben Williamson");
+MODULE_LICENSE("GPL v2");
+
+static const char f_midi_shortname[] = "f_midi";
+static const char f_midi_longname[] = "MIDI Gadget";
+
+/*
+ * We can only handle 16 cables on one single endpoint, as cable numbers are
+ * stored in 4-bit fields. And as the interface currently only holds one
+ * single endpoint, this is the maximum number of ports we can allow.
+ */
+#define MAX_PORTS 16
+
+/*
+ * This is a gadget, and the IN/OUT naming is from the host's perspective.
+ * USB -> OUT endpoint -> rawmidi
+ * USB <- IN endpoint  <- rawmidi
+ */
+struct gmidi_in_port {
+	struct f_midi *midi;
+	int active;
+	uint8_t cable;
+	uint8_t state;
+#define STATE_UNKNOWN	0
+#define STATE_1PARAM	1
+#define STATE_2PARAM_1	2
+#define STATE_2PARAM_2	3
+#define STATE_SYSEX_0	4
+#define STATE_SYSEX_1	5
+#define STATE_SYSEX_2	6
+	uint8_t data[2];
+};
+
+struct f_midi {
+	struct usb_function	func;
+	struct usb_gadget	*gadget;
+	struct usb_ep		*in_ep, *out_ep;
+	struct snd_card		*card;
+	struct snd_rawmidi	*rmidi;
+
+	struct snd_rawmidi_substream *in_substream[MAX_PORTS];
+	struct snd_rawmidi_substream *out_substream[MAX_PORTS];
+	struct gmidi_in_port	*in_port[MAX_PORTS];
+
+	unsigned long		out_triggered;
+	struct tasklet_struct	tasklet;
+	unsigned int in_ports;
+	unsigned int out_ports;
+	int index;
+	char *id;
+	unsigned int buflen, qlen;
+};
+
+static inline struct f_midi *func_to_midi(struct usb_function *f)
+{
+	return container_of(f, struct f_midi, func);
+}
+
+static void f_midi_transmit(struct f_midi *midi, struct usb_request *req);
+
+DECLARE_UAC_AC_HEADER_DESCRIPTOR(1);
+DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1);
+DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(16);
+DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(16);
+
+/* B.3.1  Standard AC Interface Descriptor */
+static struct usb_interface_descriptor ac_interface_desc __initdata = {
+	.bLength =		USB_DT_INTERFACE_SIZE,
+	.bDescriptorType =	USB_DT_INTERFACE,
+	/* .bInterfaceNumber =	DYNAMIC */
+	/* .bNumEndpoints =	DYNAMIC */
+	.bInterfaceClass =	USB_CLASS_AUDIO,
+	.bInterfaceSubClass =	USB_SUBCLASS_AUDIOCONTROL,
+	/* .iInterface =	DYNAMIC */
+};
+
+/* B.3.2  Class-Specific AC Interface Descriptor */
+static struct uac1_ac_header_descriptor_1 ac_header_desc __initdata = {
+	.bLength =		UAC_DT_AC_HEADER_SIZE(1),
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubtype =	USB_MS_HEADER,
+	.bcdADC =		cpu_to_le16(0x0100),
+	.wTotalLength =		cpu_to_le16(UAC_DT_AC_HEADER_SIZE(1)),
+	.bInCollection =	1,
+	/* .baInterfaceNr =	DYNAMIC */
+};
+
+/* B.4.1  Standard MS Interface Descriptor */
+static struct usb_interface_descriptor ms_interface_desc __initdata = {
+	.bLength =		USB_DT_INTERFACE_SIZE,
+	.bDescriptorType =	USB_DT_INTERFACE,
+	/* .bInterfaceNumber =	DYNAMIC */
+	.bNumEndpoints =	2,
+	.bInterfaceClass =	USB_CLASS_AUDIO,
+	.bInterfaceSubClass =	USB_SUBCLASS_MIDISTREAMING,
+	/* .iInterface =	DYNAMIC */
+};
+
+/* B.4.2  Class-Specific MS Interface Descriptor */
+static struct usb_ms_header_descriptor ms_header_desc __initdata = {
+	.bLength =		USB_DT_MS_HEADER_SIZE,
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubtype =	USB_MS_HEADER,
+	.bcdMSC =		cpu_to_le16(0x0100),
+	/* .wTotalLength =	DYNAMIC */
+};
+
+/* B.4.3  Embedded MIDI IN Jack Descriptor */
+static struct usb_midi_in_jack_descriptor jack_in_emb_desc = {
+	.bLength =	      USB_DT_MIDI_IN_SIZE,
+	.bDescriptorType =      USB_DT_CS_INTERFACE,
+	.bDescriptorSubtype =   USB_MS_MIDI_IN_JACK,
+	.bJackType =	    USB_MS_EMBEDDED,
+	/* .bJackID =		DYNAMIC */
+};
+
+/* B.4.4  Embedded MIDI OUT Jack Descriptor */
+static struct usb_midi_out_jack_descriptor_16 jack_out_emb_desc = {
+	/* .bLength =		DYNAMIC */
+	.bDescriptorType =	USB_DT_CS_INTERFACE,
+	.bDescriptorSubtype =	USB_MS_MIDI_OUT_JACK,
+	.bJackType =		USB_MS_EMBEDDED,
+	/* .bJackID =		DYNAMIC */
+	/* .bNrInputPins =	DYNAMIC */
+	/* .pins =		DYNAMIC */
+};
+
+/* B.5.1  Standard Bulk OUT Endpoint Descriptor */
+static struct usb_endpoint_descriptor bulk_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_AUDIO_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+};
+
+/* B.5.2  Class-specific MS Bulk OUT Endpoint Descriptor */
+static struct usb_ms_endpoint_descriptor_16 ms_out_desc = {
+	/* .bLength =		DYNAMIC */
+	.bDescriptorType =	USB_DT_CS_ENDPOINT,
+	.bDescriptorSubtype =	USB_MS_GENERAL,
+	/* .bNumEmbMIDIJack =	DYNAMIC */
+	/* .baAssocJackID =	DYNAMIC */
+};
+
+/* B.6.1  Standard Bulk IN Endpoint Descriptor */
+static struct usb_endpoint_descriptor bulk_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_AUDIO_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+};
+
+/* B.6.2  Class-specific MS Bulk IN Endpoint Descriptor */
+static struct usb_ms_endpoint_descriptor_16 ms_in_desc = {
+	/* .bLength =		DYNAMIC */
+	.bDescriptorType =	USB_DT_CS_ENDPOINT,
+	.bDescriptorSubtype =	USB_MS_GENERAL,
+	/* .bNumEmbMIDIJack =	DYNAMIC */
+	/* .baAssocJackID =	DYNAMIC */
+};
+
+/* string IDs are assigned dynamically */
+
+#define STRING_FUNC_IDX			0
+
+static struct usb_string midi_string_defs[] = {
+	[STRING_FUNC_IDX].s = "MIDI function",
+	{  } /* end of list */
+};
+
+static struct usb_gadget_strings midi_stringtab = {
+	.language	= 0x0409,	/* en-us */
+	.strings	= midi_string_defs,
+};
+
+static struct usb_gadget_strings *midi_strings[] = {
+	&midi_stringtab,
+	NULL,
+};
+
+static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
+{
+	struct usb_request *req;
+
+	req = usb_ep_alloc_request(ep, GFP_ATOMIC);
+	if (req) {
+		req->length = length;
+		req->buf = kmalloc(length, GFP_ATOMIC);
+		if (!req->buf) {
+			usb_ep_free_request(ep, req);
+			req = NULL;
+		}
+	}
+	return req;
+}
+
+static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
+{
+	kfree(req->buf);
+	usb_ep_free_request(ep, req);
+}
+
+static const uint8_t f_midi_cin_length[] = {
+	0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1
+};
+
+/*
+ * Receives a chunk of MIDI data.
+ */
+static void f_midi_read_data(struct usb_ep *ep, int cable,
+			     uint8_t *data, int length)
+{
+	struct f_midi *midi = ep->driver_data;
+	struct snd_rawmidi_substream *substream = midi->out_substream[cable];
+
+	if (!substream)
+		/* Nobody is listening - throw it on the floor. */
+		return;
+
+	if (!test_bit(cable, &midi->out_triggered))
+		return;
+
+	snd_rawmidi_receive(substream, data, length);
+}
+
+static void f_midi_handle_out_data(struct usb_ep *ep, struct usb_request *req)
+{
+	unsigned int i;
+	u8 *buf = req->buf;
+
+	for (i = 0; i + 3 < req->actual; i += 4)
+		if (buf[i] != 0) {
+			int cable = buf[i] >> 4;
+			int length = f_midi_cin_length[buf[i] & 0x0f];
+			f_midi_read_data(ep, cable, &buf[i + 1], length);
+		}
+}
+
+static void
+f_midi_complete(struct usb_ep *ep, struct usb_request *req)
+{
+	struct f_midi *midi = ep->driver_data;
+	struct usb_composite_dev *cdev = midi->func.config->cdev;
+	int status = req->status;
+
+	switch (status) {
+	case 0:			 /* normal completion */
+		if (ep == midi->out_ep) {
+			/* We received stuff. req is queued again, below */
+			f_midi_handle_out_data(ep, req);
+		} else if (ep == midi->in_ep) {
+			/* Our transmit completed. See if there's more to go.
+			 * f_midi_transmit eats req, don't queue it again. */
+			f_midi_transmit(midi, req);
+			return;
+		}
+		break;
+
+	/* this endpoint is normally active while we're configured */
+	case -ECONNABORTED:	/* hardware forced ep reset */
+	case -ECONNRESET:	/* request dequeued */
+	case -ESHUTDOWN:	/* disconnect from host */
+		VDBG(cdev, "%s gone (%d), %d/%d\n", ep->name, status,
+				req->actual, req->length);
+		if (ep == midi->out_ep)
+			f_midi_handle_out_data(ep, req);
+
+		free_ep_req(ep, req);
+		return;
+
+	case -EOVERFLOW:	/* buffer overrun on read means that
+				 * we didn't provide a big enough buffer.
+				 */
+	default:
+		DBG(cdev, "%s complete --> %d, %d/%d\n", ep->name,
+				status, req->actual, req->length);
+		break;
+	case -EREMOTEIO:	/* short read */
+		break;
+	}
+
+	status = usb_ep_queue(ep, req, GFP_ATOMIC);
+	if (status) {
+		ERROR(cdev, "kill %s:  resubmit %d bytes --> %d\n",
+				ep->name, req->length, status);
+		usb_ep_set_halt(ep);
+		/* FIXME recover later ... somehow */
+	}
+}
+
+static int f_midi_start_ep(struct f_midi *midi,
+			   struct usb_function *f,
+			   struct usb_ep *ep)
+{
+	int err;
+	struct usb_composite_dev *cdev = f->config->cdev;
+
+	if (ep->driver_data)
+		usb_ep_disable(ep);
+
+	err = config_ep_by_speed(midi->gadget, f, ep);
+	if (err) {
+		ERROR(cdev, "can't configure %s: %d\n", ep->name, err);
+		return err;
+	}
+
+	err = usb_ep_enable(ep);
+	if (err) {
+		ERROR(cdev, "can't start %s: %d\n", ep->name, err);
+		return err;
+	}
+
+	ep->driver_data = midi;
+
+	return 0;
+}
+
+static int f_midi_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
+{
+	struct f_midi *midi = func_to_midi(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
+	unsigned i;
+	int err;
+
+	err = f_midi_start_ep(midi, f, midi->in_ep);
+	if (err)
+		return err;
+
+	err = f_midi_start_ep(midi, f, midi->out_ep);
+	if (err)
+		return err;
+
+	if (midi->out_ep->driver_data)
+		usb_ep_disable(midi->out_ep);
+
+	err = config_ep_by_speed(midi->gadget, f, midi->out_ep);
+	if (err) {
+		ERROR(cdev, "can't configure %s: %d\n",
+		      midi->out_ep->name, err);
+		return err;
+	}
+
+	err = usb_ep_enable(midi->out_ep);
+	if (err) {
+		ERROR(cdev, "can't start %s: %d\n",
+		      midi->out_ep->name, err);
+		return err;
+	}
+
+	midi->out_ep->driver_data = midi;
+
+	/* allocate a bunch of read buffers and queue them all at once. */
+	for (i = 0; i < midi->qlen && err == 0; i++) {
+		struct usb_request *req =
+			alloc_ep_req(midi->out_ep, midi->buflen);
+		if (req == NULL)
+			return -ENOMEM;
+
+		req->complete = f_midi_complete;
+		err = usb_ep_queue(midi->out_ep, req, GFP_ATOMIC);
+		if (err) {
+			ERROR(midi, "%s queue req: %d\n",
+				    midi->out_ep->name, err);
+		}
+	}
+
+	return 0;
+}
+
+static void f_midi_disable(struct usb_function *f)
+{
+	struct f_midi *midi = func_to_midi(f);
+	struct usb_composite_dev *cdev = f->config->cdev;
+
+	DBG(cdev, "disable\n");
+
+	/*
+	 * just disable endpoints, forcing completion of pending i/o.
+	 * all our completion handlers free their requests in this case.
+	 */
+	usb_ep_disable(midi->in_ep);
+	usb_ep_disable(midi->out_ep);
+}
+
+static void f_midi_unbind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct usb_composite_dev *cdev = f->config->cdev;
+	struct f_midi *midi = func_to_midi(f);
+	struct snd_card *card;
+
+	DBG(cdev, "unbind\n");
+
+	/* just to be sure */
+	f_midi_disable(f);
+
+	card = midi->card;
+	midi->card = NULL;
+	if (card)
+		snd_card_free(card);
+
+	kfree(midi->id);
+	midi->id = NULL;
+
+	usb_free_descriptors(f->descriptors);
+	kfree(midi);
+}
+
+static int f_midi_snd_free(struct snd_device *device)
+{
+	return 0;
+}
+
+static void f_midi_transmit_packet(struct usb_request *req, uint8_t p0,
+					uint8_t p1, uint8_t p2, uint8_t p3)
+{
+	unsigned length = req->length;
+	u8 *buf = (u8 *)req->buf + length;
+
+	buf[0] = p0;
+	buf[1] = p1;
+	buf[2] = p2;
+	buf[3] = p3;
+	req->length = length + 4;
+}
+
+/*
+ * Converts MIDI commands to USB MIDI packets.
+ */
+static void f_midi_transmit_byte(struct usb_request *req,
+				 struct gmidi_in_port *port, uint8_t b)
+{
+	uint8_t p0 = port->cable << 4;
+
+	if (b >= 0xf8) {
+		f_midi_transmit_packet(req, p0 | 0x0f, b, 0, 0);
+	} else if (b >= 0xf0) {
+		switch (b) {
+		case 0xf0:
+			port->data[0] = b;
+			port->state = STATE_SYSEX_1;
+			break;
+		case 0xf1:
+		case 0xf3:
+			port->data[0] = b;
+			port->state = STATE_1PARAM;
+			break;
+		case 0xf2:
+			port->data[0] = b;
+			port->state = STATE_2PARAM_1;
+			break;
+		case 0xf4:
+		case 0xf5:
+			port->state = STATE_UNKNOWN;
+			break;
+		case 0xf6:
+			f_midi_transmit_packet(req, p0 | 0x05, 0xf6, 0, 0);
+			port->state = STATE_UNKNOWN;
+			break;
+		case 0xf7:
+			switch (port->state) {
+			case STATE_SYSEX_0:
+				f_midi_transmit_packet(req,
+					p0 | 0x05, 0xf7, 0, 0);
+				break;
+			case STATE_SYSEX_1:
+				f_midi_transmit_packet(req,
+					p0 | 0x06, port->data[0], 0xf7, 0);
+				break;
+			case STATE_SYSEX_2:
+				f_midi_transmit_packet(req,
+					p0 | 0x07, port->data[0],
+					port->data[1], 0xf7);
+				break;
+			}
+			port->state = STATE_UNKNOWN;
+			break;
+		}
+	} else if (b >= 0x80) {
+		port->data[0] = b;
+		if (b >= 0xc0 && b <= 0xdf)
+			port->state = STATE_1PARAM;
+		else
+			port->state = STATE_2PARAM_1;
+	} else { /* b < 0x80 */
+		switch (port->state) {
+		case STATE_1PARAM:
+			if (port->data[0] < 0xf0) {
+				p0 |= port->data[0] >> 4;
+			} else {
+				p0 |= 0x02;
+				port->state = STATE_UNKNOWN;
+			}
+			f_midi_transmit_packet(req, p0, port->data[0], b, 0);
+			break;
+		case STATE_2PARAM_1:
+			port->data[1] = b;
+			port->state = STATE_2PARAM_2;
+			break;
+		case STATE_2PARAM_2:
+			if (port->data[0] < 0xf0) {
+				p0 |= port->data[0] >> 4;
+				port->state = STATE_2PARAM_1;
+			} else {
+				p0 |= 0x03;
+				port->state = STATE_UNKNOWN;
+			}
+			f_midi_transmit_packet(req,
+				p0, port->data[0], port->data[1], b);
+			break;
+		case STATE_SYSEX_0:
+			port->data[0] = b;
+			port->state = STATE_SYSEX_1;
+			break;
+		case STATE_SYSEX_1:
+			port->data[1] = b;
+			port->state = STATE_SYSEX_2;
+			break;
+		case STATE_SYSEX_2:
+			f_midi_transmit_packet(req,
+				p0 | 0x04, port->data[0], port->data[1], b);
+			port->state = STATE_SYSEX_0;
+			break;
+		}
+	}
+}
+
+static void f_midi_transmit(struct f_midi *midi, struct usb_request *req)
+{
+	struct usb_ep *ep = midi->in_ep;
+	int i;
+
+	if (!ep)
+		return;
+
+	if (!req)
+		req = alloc_ep_req(ep, midi->buflen);
+
+	if (!req) {
+		ERROR(midi, "gmidi_transmit: alloc_ep_request failed\n");
+		return;
+	}
+	req->length = 0;
+	req->complete = f_midi_complete;
+
+	for (i = 0; i < MAX_PORTS; i++) {
+		struct gmidi_in_port *port = midi->in_port[i];
+		struct snd_rawmidi_substream *substream = midi->in_substream[i];
+
+		if (!port || !port->active || !substream)
+			continue;
+
+		while (req->length + 3 < midi->buflen) {
+			uint8_t b;
+			if (snd_rawmidi_transmit(substream, &b, 1) != 1) {
+				port->active = 0;
+				break;
+			}
+			f_midi_transmit_byte(req, port, b);
+		}
+	}
+
+	if (req->length > 0)
+		usb_ep_queue(ep, req, GFP_ATOMIC);
+	else
+		free_ep_req(ep, req);
+}
+
+static void f_midi_in_tasklet(unsigned long data)
+{
+	struct f_midi *midi = (struct f_midi *) data;
+	f_midi_transmit(midi, NULL);
+}
+
+static int f_midi_in_open(struct snd_rawmidi_substream *substream)
+{
+	struct f_midi *midi = substream->rmidi->private_data;
+
+	if (!midi->in_port[substream->number])
+		return -EINVAL;
+
+	VDBG(midi, "%s()\n", __func__);
+	midi->in_substream[substream->number] = substream;
+	midi->in_port[substream->number]->state = STATE_UNKNOWN;
+	return 0;
+}
+
+static int f_midi_in_close(struct snd_rawmidi_substream *substream)
+{
+	struct f_midi *midi = substream->rmidi->private_data;
+
+	VDBG(midi, "%s()\n", __func__);
+	return 0;
+}
+
+static void f_midi_in_trigger(struct snd_rawmidi_substream *substream, int up)
+{
+	struct f_midi *midi = substream->rmidi->private_data;
+
+	if (!midi->in_port[substream->number])
+		return;
+
+	VDBG(midi, "%s() %d\n", __func__, up);
+	midi->in_port[substream->number]->active = up;
+	if (up)
+		tasklet_hi_schedule(&midi->tasklet);
+}
+
+static int f_midi_out_open(struct snd_rawmidi_substream *substream)
+{
+	struct f_midi *midi = substream->rmidi->private_data;
+
+	if (substream->number >= MAX_PORTS)
+		return -EINVAL;
+
+	VDBG(midi, "%s()\n", __func__);
+	midi->out_substream[substream->number] = substream;
+	return 0;
+}
+
+static int f_midi_out_close(struct snd_rawmidi_substream *substream)
+{
+	struct f_midi *midi = substream->rmidi->private_data;
+
+	VDBG(midi, "%s()\n", __func__);
+	return 0;
+}
+
+static void f_midi_out_trigger(struct snd_rawmidi_substream *substream, int up)
+{
+	struct f_midi *midi = substream->rmidi->private_data;
+
+	VDBG(midi, "%s()\n", __func__);
+
+	if (up)
+		set_bit(substream->number, &midi->out_triggered);
+	else
+		clear_bit(substream->number, &midi->out_triggered);
+}
+
+static struct snd_rawmidi_ops gmidi_in_ops = {
+	.open = f_midi_in_open,
+	.close = f_midi_in_close,
+	.trigger = f_midi_in_trigger,
+};
+
+static struct snd_rawmidi_ops gmidi_out_ops = {
+	.open = f_midi_out_open,
+	.close = f_midi_out_close,
+	.trigger = f_midi_out_trigger
+};
+
+/* register as a sound "card" */
+static int f_midi_register_card(struct f_midi *midi)
+{
+	struct snd_card *card;
+	struct snd_rawmidi *rmidi;
+	int err;
+	static struct snd_device_ops ops = {
+		.dev_free = f_midi_snd_free,
+	};
+
+	err = snd_card_create(midi->index, midi->id, THIS_MODULE, 0, &card);
+	if (err < 0) {
+		ERROR(midi, "snd_card_create() failed\n");
+		goto fail;
+	}
+	midi->card = card;
+
+	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, midi, &ops);
+	if (err < 0) {
+		ERROR(midi, "snd_device_new() failed: error %d\n", err);
+		goto fail;
+	}
+
+	strcpy(card->driver, f_midi_longname);
+	strcpy(card->longname, f_midi_longname);
+	strcpy(card->shortname, f_midi_shortname);
+
+	/* Set up rawmidi */
+	snd_component_add(card, "MIDI");
+	err = snd_rawmidi_new(card, card->longname, 0,
+			      midi->out_ports, midi->in_ports, &rmidi);
+	if (err < 0) {
+		ERROR(midi, "snd_rawmidi_new() failed: error %d\n", err);
+		goto fail;
+	}
+	midi->rmidi = rmidi;
+	strcpy(rmidi->name, card->shortname);
+	rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
+			    SNDRV_RAWMIDI_INFO_INPUT |
+			    SNDRV_RAWMIDI_INFO_DUPLEX;
+	rmidi->private_data = midi;
+
+	/*
+	 * Yes, rawmidi OUTPUT = USB IN, and rawmidi INPUT = USB OUT.
+	 * It's an upside-down world being a gadget.
+	 */
+	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &gmidi_in_ops);
+	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &gmidi_out_ops);
+
+	snd_card_set_dev(card, &midi->gadget->dev);
+
+	/* register it - we're ready to go */
+	err = snd_card_register(card);
+	if (err < 0) {
+		ERROR(midi, "snd_card_register() failed\n");
+		goto fail;
+	}
+
+	VDBG(midi, "%s() finished ok\n", __func__);
+	return 0;
+
+fail:
+	if (midi->card) {
+		snd_card_free(midi->card);
+		midi->card = NULL;
+	}
+	return err;
+}
+
+/* MIDI function driver setup/binding */
+
+static int __init
+f_midi_bind(struct usb_configuration *c, struct usb_function *f)
+{
+	struct usb_descriptor_header *midi_function[(MAX_PORTS * 2) + 12];
+	struct usb_midi_in_jack_descriptor jack_in_ext_desc[MAX_PORTS];
+	struct usb_midi_out_jack_descriptor_1 jack_out_ext_desc[MAX_PORTS];
+	struct usb_composite_dev *cdev = c->cdev;
+	struct f_midi *midi = func_to_midi(f);
+	int status, n, jack = 1, i = 0;
+
+	/* maybe allocate device-global string ID */
+	if (midi_string_defs[0].id == 0) {
+		status = usb_string_id(c->cdev);
+		if (status < 0)
+			goto fail;
+		midi_string_defs[0].id = status;
+	}
+
+	/* We have two interfaces, AudioControl and MIDIStreaming */
+	status = usb_interface_id(c, f);
+	if (status < 0)
+		goto fail;
+	ac_interface_desc.bInterfaceNumber = status;
+
+	status = usb_interface_id(c, f);
+	if (status < 0)
+		goto fail;
+	ms_interface_desc.bInterfaceNumber = status;
+	ac_header_desc.baInterfaceNr[0] = status;
+
+	status = -ENODEV;
+
+	/* allocate instance-specific endpoints */
+	midi->in_ep = usb_ep_autoconfig(cdev->gadget, &bulk_in_desc);
+	if (!midi->in_ep)
+		goto fail;
+	midi->in_ep->driver_data = cdev;	/* claim */
+
+	midi->out_ep = usb_ep_autoconfig(cdev->gadget, &bulk_out_desc);
+	if (!midi->out_ep)
+		goto fail;
+	midi->out_ep->driver_data = cdev;	/* claim */
+
+	/*
+	 * construct the function's descriptor set. As the number of
+	 * input and output MIDI ports is configurable, we have to do
+	 * it that way.
+	 */
+
+	/* add the headers - these are always the same */
+	midi_function[i++] = (struct usb_descriptor_header *) &ac_interface_desc;
+	midi_function[i++] = (struct usb_descriptor_header *) &ac_header_desc;
+	midi_function[i++] = (struct usb_descriptor_header *) &ms_interface_desc;
+
+	/* calculate the header's wTotalLength */
+	n = USB_DT_MS_HEADER_SIZE
+		+ (1 + midi->in_ports) * USB_DT_MIDI_IN_SIZE
+		+ (1 + midi->out_ports) * USB_DT_MIDI_OUT_SIZE(1);
+	ms_header_desc.wTotalLength = cpu_to_le16(n);
+
+	midi_function[i++] = (struct usb_descriptor_header *) &ms_header_desc;
+
+	/* we have one embedded IN jack */
+	jack_in_emb_desc.bJackID = jack++;
+	midi_function[i++] = (struct usb_descriptor_header *) &jack_in_emb_desc;
+
+	/* and a dynamic amount of external IN jacks */
+	for (n = 0; n < midi->in_ports; n++) {
+		struct usb_midi_in_jack_descriptor *ext = &jack_in_ext_desc[n];
+
+		ext->bLength =			USB_DT_MIDI_IN_SIZE;
+		ext->bDescriptorType =		USB_DT_CS_INTERFACE;
+		ext->bDescriptorSubtype =	USB_MS_MIDI_IN_JACK;
+		ext->bJackType =		USB_MS_EXTERNAL;
+		ext->bJackID =			jack++;
+		ext->iJack =			0;
+
+		midi_function[i++] = (struct usb_descriptor_header *) ext;
+	}
+
+	/* one embedded OUT jack ... */
+	jack_out_emb_desc.bLength = USB_DT_MIDI_OUT_SIZE(midi->in_ports);
+	jack_out_emb_desc.bJackID = jack++;
+	jack_out_emb_desc.bNrInputPins = midi->in_ports;
+	/* ... which referencess all external IN jacks */
+	for (n = 0; n < midi->in_ports; n++) {
+		jack_out_emb_desc.pins[n].baSourceID = jack_in_ext_desc[n].bJackID;
+		jack_out_emb_desc.pins[n].baSourcePin =	1;
+	}
+
+	midi_function[i++] = (struct usb_descriptor_header *) &jack_out_emb_desc;
+
+	/* and multiple external OUT jacks ... */
+	for (n = 0; n < midi->out_ports; n++) {
+		struct usb_midi_out_jack_descriptor_1 *ext = &jack_out_ext_desc[n];
+		int m;
+
+		ext->bLength =			USB_DT_MIDI_OUT_SIZE(1);
+		ext->bDescriptorType =		USB_DT_CS_INTERFACE;
+		ext->bDescriptorSubtype =	USB_MS_MIDI_OUT_JACK;
+		ext->bJackType =		USB_MS_EXTERNAL;
+		ext->bJackID =			jack++;
+		ext->bNrInputPins =		1;
+		ext->iJack =			0;
+		/* ... which all reference the same embedded IN jack */
+		for (m = 0; m < midi->out_ports; m++) {
+			ext->pins[m].baSourceID =	jack_in_emb_desc.bJackID;
+			ext->pins[m].baSourcePin =	1;
+		}
+
+		midi_function[i++] = (struct usb_descriptor_header *) ext;
+	}
+
+	/* configure the endpoint descriptors ... */
+	ms_out_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->in_ports);
+	ms_out_desc.bNumEmbMIDIJack = midi->in_ports;
+	for (n = 0; n < midi->in_ports; n++)
+		ms_out_desc.baAssocJackID[n] = jack_in_emb_desc.bJackID;
+
+	ms_in_desc.bLength = USB_DT_MS_ENDPOINT_SIZE(midi->out_ports);
+	ms_in_desc.bNumEmbMIDIJack = midi->out_ports;
+	for (n = 0; n < midi->out_ports; n++)
+		ms_in_desc.baAssocJackID[n] = jack_out_emb_desc.bJackID;
+
+	/* ... and add them to the list */
+	midi_function[i++] = (struct usb_descriptor_header *) &bulk_out_desc;
+	midi_function[i++] = (struct usb_descriptor_header *) &ms_out_desc;
+	midi_function[i++] = (struct usb_descriptor_header *) &bulk_in_desc;
+	midi_function[i++] = (struct usb_descriptor_header *) &ms_in_desc;
+	midi_function[i++] = NULL;
+
+	/*
+	 * support all relevant hardware speeds... we expect that when
+	 * hardware is dual speed, all bulk-capable endpoints work at
+	 * both speeds
+	 */
+	/* copy descriptors, and track endpoint copies */
+	if (gadget_is_dualspeed(c->cdev->gadget)) {
+		c->highspeed = true;
+		bulk_in_desc.wMaxPacketSize = cpu_to_le16(512);
+		bulk_out_desc.wMaxPacketSize = cpu_to_le16(512);
+		f->hs_descriptors = usb_copy_descriptors(midi_function);
+	} else {
+		f->descriptors = usb_copy_descriptors(midi_function);
+	}
+
+	return 0;
+
+fail:
+	/* we might as well release our claims on endpoints */
+	if (midi->out_ep)
+		midi->out_ep->driver_data = NULL;
+	if (midi->in_ep)
+		midi->in_ep->driver_data = NULL;
+
+	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
+
+	return status;
+}
+
+/**
+ * f_midi_bind_config - add USB MIDI function to a configuration
+ * @c: the configuration to supcard the USB audio function
+ * @index: the soundcard index to use for the ALSA device creation
+ * @id: the soundcard id to use for the ALSA device creation
+ * @buflen: the buffer length to use
+ * @qlen the number of read requests to pre-allocate
+ * Context: single threaded during gadget setup
+ *
+ * Returns zero on success, else negative errno.
+ */
+int __init f_midi_bind_config(struct usb_configuration *c,
+			      int index, char *id,
+			      unsigned int in_ports,
+			      unsigned int out_ports,
+			      unsigned int buflen,
+			      unsigned int qlen)
+{
+	struct f_midi *midi;
+	int status, i;
+
+	/* sanity check */
+	if (in_ports > MAX_PORTS || out_ports > MAX_PORTS)
+		return -EINVAL;
+
+	/* allocate and initialize one new instance */
+	midi = kzalloc(sizeof *midi, GFP_KERNEL);
+	if (!midi) {
+		status = -ENOMEM;
+		goto fail;
+	}
+
+	for (i = 0; i < in_ports; i++) {
+		struct gmidi_in_port *port = kzalloc(sizeof(*port), GFP_KERNEL);
+		if (!port) {
+			status = -ENOMEM;
+			goto setup_fail;
+		}
+
+		port->midi = midi;
+		port->active = 0;
+		port->cable = i;
+		midi->in_port[i] = port;
+	}
+
+	midi->gadget = c->cdev->gadget;
+	tasklet_init(&midi->tasklet, f_midi_in_tasklet, (unsigned long) midi);
+
+	/* set up ALSA midi devices */
+	midi->in_ports = in_ports;
+	midi->out_ports = out_ports;
+	status = f_midi_register_card(midi);
+	if (status < 0)
+		goto setup_fail;
+
+	midi->func.name        = "gmidi function";
+	midi->func.strings     = midi_strings;
+	midi->func.bind        = f_midi_bind;
+	midi->func.unbind      = f_midi_unbind;
+	midi->func.set_alt     = f_midi_set_alt;
+	midi->func.disable     = f_midi_disable;
+
+	midi->id = kstrdup(id, GFP_KERNEL);
+	midi->index = index;
+	midi->buflen = buflen;
+	midi->qlen = qlen;
+
+	status = usb_add_function(c, &midi->func);
+	if (status)
+		goto setup_fail;
+
+	return 0;
+
+setup_fail:
+	for (--i; i >= 0; i--)
+		kfree(midi->in_port[i]);
+	kfree(midi);
+fail:
+	return status;
+}
+

+ 0 - 9
drivers/usb/gadget/f_ncm.c

@@ -13,15 +13,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #include <linux/kernel.h>

+ 0 - 9
drivers/usb/gadget/f_obex.c

@@ -10,15 +10,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
 
 /* #define VERBOSE_DEBUG */

+ 0 - 10
drivers/usb/gadget/f_phonet.c

@@ -8,16 +8,6 @@
  * 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.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
  */
 
 #include <linux/mm.h>

+ 0 - 9
drivers/usb/gadget/f_rndis.c

@@ -11,15 +11,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 /* #define VERBOSE_DEBUG */

+ 0 - 9
drivers/usb/gadget/f_sourcesink.c

@@ -8,15 +8,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 /* #define VERBOSE_DEBUG */

+ 0 - 9
drivers/usb/gadget/f_subset.c

@@ -8,15 +8,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #include <linux/slab.h>

+ 0 - 1
drivers/usb/gadget/f_uvc.c

@@ -8,7 +8,6 @@
  *	it under the terms of the GNU General Public License as published by
  *	the Free Software Foundation; either version 2 of the License, or
  *	(at your option) any later version.
- *
  */
 
 #include <linux/kernel.h>

+ 0 - 1
drivers/usb/gadget/f_uvc.h

@@ -8,7 +8,6 @@
  *	it under the terms of the GNU General Public License as published by
  *	the Free Software Foundation; either version 2 of the License, or
  *	(at your option) any later version.
- *
  */
 
 #ifndef _F_UVC_H_

+ 139 - 115
drivers/usb/gadget/file_storage.c

@@ -69,8 +69,7 @@
  * each LUN would be settable independently as a disk drive or a CD-ROM
  * drive, but currently all LUNs have to be the same type.  The CD-ROM
  * emulation includes a single data track and no audio tracks; hence there
- * need be only one backing file per LUN.  Note also that the CD-ROM block
- * length is set to 512 rather than the more common value 2048.
+ * need be only one backing file per LUN.
  *
  * Requirements are modest; only a bulk-in and a bulk-out endpoint are
  * needed (an interrupt-out endpoint is also needed for CBI).  The memory
@@ -461,7 +460,6 @@ struct fsg_dev {
 
 	struct fsg_buffhd	*next_buffhd_to_fill;
 	struct fsg_buffhd	*next_buffhd_to_drain;
-	struct fsg_buffhd	buffhds[FSG_NUM_BUFFERS];
 
 	int			thread_wakeup_needed;
 	struct completion	thread_notifier;
@@ -488,6 +486,8 @@ struct fsg_dev {
 	unsigned int		nluns;
 	struct fsg_lun		*luns;
 	struct fsg_lun		*curlun;
+	/* Must be the last entry */
+	struct fsg_buffhd	buffhds[];
 };
 
 typedef void (*fsg_routine_t)(struct fsg_dev *);
@@ -586,7 +586,19 @@ dev_qualifier = {
 	.bNumConfigurations =	1,
 };
 
+static int populate_bos(struct fsg_dev *fsg, u8 *buf)
+{
+	memcpy(buf, &fsg_bos_desc, USB_DT_BOS_SIZE);
+	buf += USB_DT_BOS_SIZE;
+
+	memcpy(buf, &fsg_ext_cap_desc, USB_DT_USB_EXT_CAP_SIZE);
+	buf += USB_DT_USB_EXT_CAP_SIZE;
 
+	memcpy(buf, &fsg_ss_cap_desc, USB_DT_USB_SS_CAP_SIZE);
+
+	return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE
+		+ USB_DT_USB_EXT_CAP_SIZE;
+}
 
 /*
  * Config descriptors must agree with the code that sets configurations
@@ -935,7 +947,8 @@ static int standard_setup_req(struct fsg_dev *fsg,
 			break;
 		case USB_DT_DEVICE_QUALIFIER:
 			VDBG(fsg, "get device qualifier\n");
-			if (!gadget_is_dualspeed(fsg->gadget))
+			if (!gadget_is_dualspeed(fsg->gadget) ||
+					fsg->gadget->speed == USB_SPEED_SUPER)
 				break;
 			/*
 			 * Assume ep0 uses the same maxpacket value for both
@@ -948,7 +961,8 @@ static int standard_setup_req(struct fsg_dev *fsg,
 
 		case USB_DT_OTHER_SPEED_CONFIG:
 			VDBG(fsg, "get other-speed config descriptor\n");
-			if (!gadget_is_dualspeed(fsg->gadget))
+			if (!gadget_is_dualspeed(fsg->gadget) ||
+					fsg->gadget->speed == USB_SPEED_SUPER)
 				break;
 			goto get_config;
 		case USB_DT_CONFIG:
@@ -967,7 +981,15 @@ get_config:
 			value = usb_gadget_get_string(&fsg_stringtab,
 					w_value & 0xff, req->buf);
 			break;
+
+		case USB_DT_BOS:
+			VDBG(fsg, "get bos descriptor\n");
+
+			if (gadget_is_superspeed(fsg->gadget))
+				value = populate_bos(fsg, req->buf);
+			break;
 		}
+
 		break;
 
 	/* One config, two speeds */
@@ -1136,7 +1158,6 @@ static int do_read(struct fsg_dev *fsg)
 	u32			amount_left;
 	loff_t			file_offset, file_offset_tmp;
 	unsigned int		amount;
-	unsigned int		partial_page;
 	ssize_t			nread;
 
 	/* Get the starting Logical Block Address and check that it's
@@ -1158,7 +1179,7 @@ static int do_read(struct fsg_dev *fsg)
 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
 		return -EINVAL;
 	}
-	file_offset = ((loff_t) lba) << 9;
+	file_offset = ((loff_t) lba) << curlun->blkbits;
 
 	/* Carry out the file reads */
 	amount_left = fsg->data_size_from_cmnd;
@@ -1171,17 +1192,10 @@ static int do_read(struct fsg_dev *fsg)
 		 * Try to read the remaining amount.
 		 * But don't read more than the buffer size.
 		 * And don't try to read past the end of the file.
-		 * Finally, if we're not at a page boundary, don't read past
-		 *	the next page.
-		 * If this means reading 0 then we were asked to read past
-		 *	the end of file. */
+		 */
 		amount = min((unsigned int) amount_left, mod_data.buflen);
 		amount = min((loff_t) amount,
 				curlun->file_length - file_offset);
-		partial_page = file_offset & (PAGE_CACHE_SIZE - 1);
-		if (partial_page > 0)
-			amount = min(amount, (unsigned int) PAGE_CACHE_SIZE -
-					partial_page);
 
 		/* Wait for the next buffer to become available */
 		bh = fsg->next_buffhd_to_fill;
@@ -1196,7 +1210,7 @@ static int do_read(struct fsg_dev *fsg)
 		if (amount == 0) {
 			curlun->sense_data =
 					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-			curlun->sense_data_info = file_offset >> 9;
+			curlun->sense_data_info = file_offset >> curlun->blkbits;
 			curlun->info_valid = 1;
 			bh->inreq->length = 0;
 			bh->state = BUF_STATE_FULL;
@@ -1221,18 +1235,23 @@ static int do_read(struct fsg_dev *fsg)
 		} else if (nread < amount) {
 			LDBG(curlun, "partial file read: %d/%u\n",
 					(int) nread, amount);
-			nread -= (nread & 511);	// Round down to a block
+			nread = round_down(nread, curlun->blksize);
 		}
 		file_offset  += nread;
 		amount_left  -= nread;
 		fsg->residue -= nread;
+
+		/* Except at the end of the transfer, nread will be
+		 * equal to the buffer size, which is divisible by the
+		 * bulk-in maxpacket size.
+		 */
 		bh->inreq->length = nread;
 		bh->state = BUF_STATE_FULL;
 
 		/* If an error occurred, report it and its position */
 		if (nread < amount) {
 			curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
-			curlun->sense_data_info = file_offset >> 9;
+			curlun->sense_data_info = file_offset >> curlun->blkbits;
 			curlun->info_valid = 1;
 			break;
 		}
@@ -1262,7 +1281,6 @@ static int do_write(struct fsg_dev *fsg)
 	u32			amount_left_to_req, amount_left_to_write;
 	loff_t			usb_offset, file_offset, file_offset_tmp;
 	unsigned int		amount;
-	unsigned int		partial_page;
 	ssize_t			nwritten;
 	int			rc;
 
@@ -1303,7 +1321,7 @@ static int do_write(struct fsg_dev *fsg)
 
 	/* Carry out the file writes */
 	get_some_more = 1;
-	file_offset = usb_offset = ((loff_t) lba) << 9;
+	file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits;
 	amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd;
 
 	while (amount_left_to_write > 0) {
@@ -1313,38 +1331,20 @@ static int do_write(struct fsg_dev *fsg)
 		if (bh->state == BUF_STATE_EMPTY && get_some_more) {
 
 			/* Figure out how much we want to get:
-			 * Try to get the remaining amount.
-			 * But don't get more than the buffer size.
-			 * And don't try to go past the end of the file.
-			 * If we're not at a page boundary,
-			 *	don't go past the next page.
-			 * If this means getting 0, then we were asked
-			 *	to write past the end of file.
-			 * Finally, round down to a block boundary. */
+			 * Try to get the remaining amount,
+			 * but not more than the buffer size.
+			 */
 			amount = min(amount_left_to_req, mod_data.buflen);
-			amount = min((loff_t) amount, curlun->file_length -
-					usb_offset);
-			partial_page = usb_offset & (PAGE_CACHE_SIZE - 1);
-			if (partial_page > 0)
-				amount = min(amount,
-	(unsigned int) PAGE_CACHE_SIZE - partial_page);
-
-			if (amount == 0) {
+
+			/* Beyond the end of the backing file? */
+			if (usb_offset >= curlun->file_length) {
 				get_some_more = 0;
 				curlun->sense_data =
 					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-				curlun->sense_data_info = usb_offset >> 9;
+				curlun->sense_data_info = usb_offset >> curlun->blkbits;
 				curlun->info_valid = 1;
 				continue;
 			}
-			amount -= (amount & 511);
-			if (amount == 0) {
-
-				/* Why were we were asked to transfer a
-				 * partial block? */
-				get_some_more = 0;
-				continue;
-			}
 
 			/* Get the next buffer */
 			usb_offset += amount;
@@ -1353,11 +1353,11 @@ static int do_write(struct fsg_dev *fsg)
 			if (amount_left_to_req == 0)
 				get_some_more = 0;
 
-			/* amount is always divisible by 512, hence by
-			 * the bulk-out maxpacket size */
-			bh->outreq->length = bh->bulk_out_intended_length =
-					amount;
-			bh->outreq->short_not_ok = 1;
+			/* Except at the end of the transfer, amount will be
+			 * equal to the buffer size, which is divisible by
+			 * the bulk-out maxpacket size.
+			 */
+			set_bulk_out_req_length(fsg, bh, amount);
 			start_transfer(fsg, fsg->bulk_out, bh->outreq,
 					&bh->outreq_busy, &bh->state);
 			fsg->next_buffhd_to_fill = bh->next;
@@ -1376,7 +1376,7 @@ static int do_write(struct fsg_dev *fsg)
 			/* Did something go wrong with the transfer? */
 			if (bh->outreq->status != 0) {
 				curlun->sense_data = SS_COMMUNICATION_FAILURE;
-				curlun->sense_data_info = file_offset >> 9;
+				curlun->sense_data_info = file_offset >> curlun->blkbits;
 				curlun->info_valid = 1;
 				break;
 			}
@@ -1390,6 +1390,16 @@ static int do_write(struct fsg_dev *fsg)
 				amount = curlun->file_length - file_offset;
 			}
 
+			/* Don't accept excess data.  The spec doesn't say
+			 * what to do in this case.  We'll ignore the error.
+			 */
+			amount = min(amount, bh->bulk_out_intended_length);
+
+			/* Don't write a partial block */
+			amount = round_down(amount, curlun->blksize);
+			if (amount == 0)
+				goto empty_write;
+
 			/* Perform the write */
 			file_offset_tmp = file_offset;
 			nwritten = vfs_write(curlun->filp,
@@ -1408,8 +1418,7 @@ static int do_write(struct fsg_dev *fsg)
 			} else if (nwritten < amount) {
 				LDBG(curlun, "partial file write: %d/%u\n",
 						(int) nwritten, amount);
-				nwritten -= (nwritten & 511);
-						// Round down to a block
+				nwritten = round_down(nwritten, curlun->blksize);
 			}
 			file_offset += nwritten;
 			amount_left_to_write -= nwritten;
@@ -1418,13 +1427,14 @@ static int do_write(struct fsg_dev *fsg)
 			/* If an error occurred, report it and its position */
 			if (nwritten < amount) {
 				curlun->sense_data = SS_WRITE_ERROR;
-				curlun->sense_data_info = file_offset >> 9;
+				curlun->sense_data_info = file_offset >> curlun->blkbits;
 				curlun->info_valid = 1;
 				break;
 			}
 
+ empty_write:
 			/* Did the host decide to stop early? */
-			if (bh->outreq->actual != bh->outreq->length) {
+			if (bh->outreq->actual < bh->bulk_out_intended_length) {
 				fsg->short_packet_received = 1;
 				break;
 			}
@@ -1500,8 +1510,8 @@ static int do_verify(struct fsg_dev *fsg)
 		return -EIO;		// No default reply
 
 	/* Prepare to carry out the file verify */
-	amount_left = verification_length << 9;
-	file_offset = ((loff_t) lba) << 9;
+	amount_left = verification_length << curlun->blkbits;
+	file_offset = ((loff_t) lba) << curlun->blkbits;
 
 	/* Write out all the dirty buffers before invalidating them */
 	fsg_lun_fsync_sub(curlun);
@@ -1519,15 +1529,14 @@ static int do_verify(struct fsg_dev *fsg)
 		 * Try to read the remaining amount, but not more than
 		 * the buffer size.
 		 * And don't try to read past the end of the file.
-		 * If this means reading 0 then we were asked to read
-		 * past the end of file. */
+		 */
 		amount = min((unsigned int) amount_left, mod_data.buflen);
 		amount = min((loff_t) amount,
 				curlun->file_length - file_offset);
 		if (amount == 0) {
 			curlun->sense_data =
 					SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
-			curlun->sense_data_info = file_offset >> 9;
+			curlun->sense_data_info = file_offset >> curlun->blkbits;
 			curlun->info_valid = 1;
 			break;
 		}
@@ -1550,11 +1559,11 @@ static int do_verify(struct fsg_dev *fsg)
 		} else if (nread < amount) {
 			LDBG(curlun, "partial file verify: %d/%u\n",
 					(int) nread, amount);
-			nread -= (nread & 511);	// Round down to a sector
+			nread = round_down(nread, curlun->blksize);
 		}
 		if (nread == 0) {
 			curlun->sense_data = SS_UNRECOVERED_READ_ERROR;
-			curlun->sense_data_info = file_offset >> 9;
+			curlun->sense_data_info = file_offset >> curlun->blkbits;
 			curlun->info_valid = 1;
 			break;
 		}
@@ -1668,7 +1677,7 @@ static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh)
 
 	put_unaligned_be32(curlun->num_sectors - 1, &buf[0]);
 						/* Max logical block */
-	put_unaligned_be32(512, &buf[4]);	/* Block length */
+	put_unaligned_be32(curlun->blksize, &buf[4]);	/* Block length */
 	return 8;
 }
 
@@ -1890,7 +1899,7 @@ static int do_read_format_capacities(struct fsg_dev *fsg,
 
 	put_unaligned_be32(curlun->num_sectors, &buf[0]);
 						/* Number of blocks */
-	put_unaligned_be32(512, &buf[4]);	/* Block length */
+	put_unaligned_be32(curlun->blksize, &buf[4]);	/* Block length */
 	buf[4] = 0x02;				/* Current capacity */
 	return 12;
 }
@@ -1969,7 +1978,7 @@ static int throw_away_data(struct fsg_dev *fsg)
 			fsg->next_buffhd_to_drain = bh->next;
 
 			/* A short packet or an error ends everything */
-			if (bh->outreq->actual != bh->outreq->length ||
+			if (bh->outreq->actual < bh->bulk_out_intended_length ||
 					bh->outreq->status != 0) {
 				raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT);
 				return -EINTR;
@@ -1983,11 +1992,11 @@ static int throw_away_data(struct fsg_dev *fsg)
 			amount = min(fsg->usb_amount_left,
 					(u32) mod_data.buflen);
 
-			/* amount is always divisible by 512, hence by
-			 * the bulk-out maxpacket size */
-			bh->outreq->length = bh->bulk_out_intended_length =
-					amount;
-			bh->outreq->short_not_ok = 1;
+			/* Except at the end of the transfer, amount will be
+			 * equal to the buffer size, which is divisible by
+			 * the bulk-out maxpacket size.
+			 */
+			set_bulk_out_req_length(fsg, bh, amount);
 			start_transfer(fsg, fsg->bulk_out, bh->outreq,
 					&bh->outreq_busy, &bh->state);
 			fsg->next_buffhd_to_fill = bh->next;
@@ -2415,7 +2424,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
 
 	case READ_6:
 		i = fsg->cmnd[4];
-		fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+		fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits;
 		if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST,
 				(7<<1) | (1<<4), 1,
 				"READ(6)")) == 0)
@@ -2424,7 +2433,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
 
 	case READ_10:
 		fsg->data_size_from_cmnd =
-				get_unaligned_be16(&fsg->cmnd[7]) << 9;
+				get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits;
 		if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST,
 				(1<<1) | (0xf<<2) | (3<<7), 1,
 				"READ(10)")) == 0)
@@ -2433,7 +2442,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
 
 	case READ_12:
 		fsg->data_size_from_cmnd =
-				get_unaligned_be32(&fsg->cmnd[6]) << 9;
+				get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits;
 		if ((reply = check_command(fsg, 12, DATA_DIR_TO_HOST,
 				(1<<1) | (0xf<<2) | (0xf<<6), 1,
 				"READ(12)")) == 0)
@@ -2519,7 +2528,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
 
 	case WRITE_6:
 		i = fsg->cmnd[4];
-		fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << 9;
+		fsg->data_size_from_cmnd = (i == 0 ? 256 : i) << fsg->curlun->blkbits;
 		if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST,
 				(7<<1) | (1<<4), 1,
 				"WRITE(6)")) == 0)
@@ -2528,7 +2537,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
 
 	case WRITE_10:
 		fsg->data_size_from_cmnd =
-				get_unaligned_be16(&fsg->cmnd[7]) << 9;
+				get_unaligned_be16(&fsg->cmnd[7]) << fsg->curlun->blkbits;
 		if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST,
 				(1<<1) | (0xf<<2) | (3<<7), 1,
 				"WRITE(10)")) == 0)
@@ -2537,7 +2546,7 @@ static int do_scsi_command(struct fsg_dev *fsg)
 
 	case WRITE_12:
 		fsg->data_size_from_cmnd =
-				get_unaligned_be32(&fsg->cmnd[6]) << 9;
+				get_unaligned_be32(&fsg->cmnd[6]) << fsg->curlun->blkbits;
 		if ((reply = check_command(fsg, 12, DATA_DIR_FROM_HOST,
 				(1<<1) | (0xf<<2) | (0xf<<6), 1,
 				"WRITE(12)")) == 0)
@@ -2666,7 +2675,6 @@ 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);
-		bh->outreq->short_not_ok = 1;
 		start_transfer(fsg, fsg->bulk_out, bh->outreq,
 				&bh->outreq_busy, &bh->state);
 
@@ -2752,7 +2760,7 @@ static int do_set_interface(struct fsg_dev *fsg, int altsetting)
 
 reset:
 	/* Deallocate the requests */
-	for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+	for (i = 0; i < fsg_num_buffers; ++i) {
 		struct fsg_buffhd *bh = &fsg->buffhds[i];
 
 		if (bh->inreq) {
@@ -2791,29 +2799,32 @@ reset:
 
 	/* Enable the endpoints */
 	d = fsg_ep_desc(fsg->gadget,
-			&fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
+			&fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc,
+			&fsg_ss_bulk_in_desc);
 	if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0)
 		goto reset;
 	fsg->bulk_in_enabled = 1;
 
 	d = fsg_ep_desc(fsg->gadget,
-			&fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
+			&fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc,
+			&fsg_ss_bulk_out_desc);
 	if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0)
 		goto reset;
 	fsg->bulk_out_enabled = 1;
-	fsg->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize);
+	fsg->bulk_out_maxpacket = usb_endpoint_maxp(d);
 	clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
 
 	if (transport_is_cbi()) {
 		d = fsg_ep_desc(fsg->gadget,
-				&fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc);
+				&fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc,
+				&fsg_ss_intr_in_desc);
 		if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0)
 			goto reset;
 		fsg->intr_in_enabled = 1;
 	}
 
 	/* Allocate the requests */
-	for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+	for (i = 0; i < fsg_num_buffers; ++i) {
 		struct fsg_buffhd	*bh = &fsg->buffhds[i];
 
 		if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0)
@@ -2862,17 +2873,10 @@ static int do_set_config(struct fsg_dev *fsg, u8 new_config)
 		fsg->config = new_config;
 		if ((rc = do_set_interface(fsg, 0)) != 0)
 			fsg->config = 0;	// Reset on errors
-		else {
-			char *speed;
-
-			switch (fsg->gadget->speed) {
-			case USB_SPEED_LOW:	speed = "low";	break;
-			case USB_SPEED_FULL:	speed = "full";	break;
-			case USB_SPEED_HIGH:	speed = "high";	break;
-			default: 		speed = "?";	break;
-			}
-			INFO(fsg, "%s speed config #%d\n", speed, fsg->config);
-		}
+		else
+			INFO(fsg, "%s config #%d\n",
+			     usb_speed_string(fsg->gadget->speed),
+			     fsg->config);
 	}
 	return rc;
 }
@@ -2909,7 +2913,7 @@ static void handle_exception(struct fsg_dev *fsg)
 	/* Cancel all the pending transfers */
 	if (fsg->intreq_busy)
 		usb_ep_dequeue(fsg->intr_in, fsg->intreq);
-	for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+	for (i = 0; i < fsg_num_buffers; ++i) {
 		bh = &fsg->buffhds[i];
 		if (bh->inreq_busy)
 			usb_ep_dequeue(fsg->bulk_in, bh->inreq);
@@ -2920,7 +2924,7 @@ static void handle_exception(struct fsg_dev *fsg)
 	/* Wait until everything is idle */
 	for (;;) {
 		num_active = fsg->intreq_busy;
-		for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+		for (i = 0; i < fsg_num_buffers; ++i) {
 			bh = &fsg->buffhds[i];
 			num_active += bh->inreq_busy + bh->outreq_busy;
 		}
@@ -2942,7 +2946,7 @@ static void handle_exception(struct fsg_dev *fsg)
 	 * state, and the exception.  Then invoke the handler. */
 	spin_lock_irq(&fsg->lock);
 
-	for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+	for (i = 0; i < fsg_num_buffers; ++i) {
 		bh = &fsg->buffhds[i];
 		bh->state = BUF_STATE_EMPTY;
 	}
@@ -3149,6 +3153,15 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
 	DBG(fsg, "unbind\n");
 	clear_bit(REGISTERED, &fsg->atomic_bitflags);
 
+	/* If the thread isn't already dead, tell it to exit now */
+	if (fsg->state != FSG_STATE_TERMINATED) {
+		raise_exception(fsg, FSG_STATE_EXIT);
+		wait_for_completion(&fsg->thread_notifier);
+
+		/* The cleanup routine waits for this completion also */
+		complete(&fsg->thread_notifier);
+	}
+
 	/* Unregister the sysfs attribute files and the LUNs */
 	for (i = 0; i < fsg->nluns; ++i) {
 		curlun = &fsg->luns[i];
@@ -3162,17 +3175,8 @@ static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget)
 		}
 	}
 
-	/* If the thread isn't already dead, tell it to exit now */
-	if (fsg->state != FSG_STATE_TERMINATED) {
-		raise_exception(fsg, FSG_STATE_EXIT);
-		wait_for_completion(&fsg->thread_notifier);
-
-		/* The cleanup routine waits for this completion also */
-		complete(&fsg->thread_notifier);
-	}
-
 	/* Free the data buffers */
-	for (i = 0; i < FSG_NUM_BUFFERS; ++i)
+	for (i = 0; i < fsg_num_buffers; ++i)
 		kfree(fsg->buffhds[i].buf);
 
 	/* Free the request and buffer for endpoint 0 */
@@ -3445,6 +3449,24 @@ static int __init fsg_bind(struct usb_gadget *gadget)
 			fsg_fs_intr_in_desc.bEndpointAddress;
 	}
 
+	if (gadget_is_superspeed(gadget)) {
+		unsigned		max_burst;
+
+		fsg_ss_function[i + FSG_SS_FUNCTION_PRE_EP_ENTRIES] = NULL;
+
+		/* Calculate bMaxBurst, we know packet size is 1024 */
+		max_burst = min_t(unsigned, mod_data.buflen / 1024, 15);
+
+		/* Assume endpoint addresses are the same for both speeds */
+		fsg_ss_bulk_in_desc.bEndpointAddress =
+			fsg_fs_bulk_in_desc.bEndpointAddress;
+		fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst;
+
+		fsg_ss_bulk_out_desc.bEndpointAddress =
+			fsg_fs_bulk_out_desc.bEndpointAddress;
+		fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst;
+	}
+
 	if (gadget_is_otg(gadget))
 		fsg_otg_desc.bmAttributes |= USB_OTG_HNP;
 
@@ -3460,7 +3482,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
 	req->complete = ep0_complete;
 
 	/* Allocate the data buffers */
-	for (i = 0; i < FSG_NUM_BUFFERS; ++i) {
+	for (i = 0; i < fsg_num_buffers; ++i) {
 		struct fsg_buffhd	*bh = &fsg->buffhds[i];
 
 		/* Allocate for the bulk-in endpoint.  We assume that
@@ -3471,7 +3493,7 @@ static int __init fsg_bind(struct usb_gadget *gadget)
 			goto out;
 		bh->next = bh + 1;
 	}
-	fsg->buffhds[FSG_NUM_BUFFERS - 1].next = &fsg->buffhds[0];
+	fsg->buffhds[fsg_num_buffers - 1].next = &fsg->buffhds[0];
 
 	/* This should reflect the actual gadget power source */
 	usb_gadget_set_selfpowered(gadget);
@@ -3561,11 +3583,7 @@ static void fsg_resume(struct usb_gadget *gadget)
 /*-------------------------------------------------------------------------*/
 
 static struct usb_gadget_driver		fsg_driver = {
-#ifdef CONFIG_USB_GADGET_DUALSPEED
-	.speed		= USB_SPEED_HIGH,
-#else
-	.speed		= USB_SPEED_FULL,
-#endif
+	.speed		= USB_SPEED_SUPER,
 	.function	= (char *) fsg_string_product,
 	.unbind		= fsg_unbind,
 	.disconnect	= fsg_disconnect,
@@ -3587,7 +3605,9 @@ static int __init fsg_alloc(void)
 {
 	struct fsg_dev		*fsg;
 
-	fsg = kzalloc(sizeof *fsg, GFP_KERNEL);
+	fsg = kzalloc(sizeof *fsg +
+		      fsg_num_buffers * sizeof *(fsg->buffhds), GFP_KERNEL);
+
 	if (!fsg)
 		return -ENOMEM;
 	spin_lock_init(&fsg->lock);
@@ -3605,6 +3625,10 @@ static int __init fsg_init(void)
 	int		rc;
 	struct fsg_dev	*fsg;
 
+	rc = fsg_num_buffers_validate();
+	if (rc != 0)
+		return rc;
+
 	if ((rc = fsg_alloc()) != 0)
 		return rc;
 	fsg = the_fsg;

+ 1 - 1
drivers/usb/gadget/fsl_qe_udc.c

@@ -540,7 +540,7 @@ static int qe_ep_init(struct qe_udc *udc,
 	int reval = 0;
 	u16 max = 0;
 
-	max = le16_to_cpu(desc->wMaxPacketSize);
+	max = usb_endpoint_maxp(desc);
 
 	/* check the max package size validate for this endpoint */
 	/* Refer to USB2.0 spec table 9-13,

+ 20 - 35
drivers/usb/gadget/fsl_udc_core.c

@@ -559,7 +559,7 @@ static int fsl_ep_enable(struct usb_ep *_ep,
 	if (!udc->driver || (udc->gadget.speed == USB_SPEED_UNKNOWN))
 		return -ESHUTDOWN;
 
-	max = le16_to_cpu(desc->wMaxPacketSize);
+	max = usb_endpoint_maxp(desc);
 
 	/* Disable automatic zlp generation.  Driver is responsible to indicate
 	 * explicitly through req->req.zero.  This is needed to enable multi-td
@@ -1715,34 +1715,31 @@ static void dtd_complete_irq(struct fsl_udc *udc)
 	}
 }
 
+static inline enum usb_device_speed portscx_device_speed(u32 reg)
+{
+	switch (speed & PORTSCX_PORT_SPEED_MASK) {
+	case PORTSCX_PORT_SPEED_HIGH:
+		return USB_SPEED_HIGH;
+	case PORTSCX_PORT_SPEED_FULL:
+		return USB_SPEED_FULL;
+	case PORTSCX_PORT_SPEED_LOW:
+		return USB_SPEED_LOW;
+	default:
+		return USB_SPEED_UNKNOWN;
+	}
+}
+
 /* Process a port change interrupt */
 static void port_change_irq(struct fsl_udc *udc)
 {
-	u32 speed;
-
 	if (udc->bus_reset)
 		udc->bus_reset = 0;
 
 	/* Bus resetting is finished */
-	if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET)) {
+	if (!(fsl_readl(&dr_regs->portsc1) & PORTSCX_PORT_RESET))
 		/* Get the speed */
-		speed = (fsl_readl(&dr_regs->portsc1)
-				& PORTSCX_PORT_SPEED_MASK);
-		switch (speed) {
-		case PORTSCX_PORT_SPEED_HIGH:
-			udc->gadget.speed = USB_SPEED_HIGH;
-			break;
-		case PORTSCX_PORT_SPEED_FULL:
-			udc->gadget.speed = USB_SPEED_FULL;
-			break;
-		case PORTSCX_PORT_SPEED_LOW:
-			udc->gadget.speed = USB_SPEED_LOW;
-			break;
-		default:
-			udc->gadget.speed = USB_SPEED_UNKNOWN;
-			break;
-		}
-	}
+		udc->gadget.speed =
+			portscx_device_speed(fsl_readl(&dr_regs->portsc1));
 
 	/* Update USB state */
 	if (!udc->resume_state)
@@ -2167,20 +2164,8 @@ static int fsl_proc_read(char *page, char **start, off_t off, int count,
 			default:
 				s = "None"; break;
 			}
-			s;} ), ( {
-			char *s;
-			switch (tmp_reg & PORTSCX_PORT_SPEED_UNDEF) {
-			case PORTSCX_PORT_SPEED_FULL:
-				s = "Full Speed"; break;
-			case PORTSCX_PORT_SPEED_LOW:
-				s = "Low Speed"; break;
-			case PORTSCX_PORT_SPEED_HIGH:
-				s = "High Speed"; break;
-			default:
-				s = "Undefined"; break;
-			}
-			s;
-		} ),
+			s;} ),
+		usb_speed_string(portscx_device_speed(tmp_reg)),
 		(tmp_reg & PORTSCX_PHY_LOW_POWER_SPD) ?
 		"Normal PHY mode" : "Low power mode",
 		(tmp_reg & PORTSCX_PORT_RESET) ? "In Reset" :

+ 3 - 13
drivers/usb/gadget/fusb300_udc.c

@@ -8,16 +8,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
  */
 #include <linux/dma-mapping.h>
 #include <linux/err.h>
@@ -220,7 +210,7 @@ static int config_ep(struct fusb300_ep *ep,
 
 	info.type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
 	info.dir_in = (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ? 1 : 0;
-	info.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+	info.maxpacket = usb_endpoint_maxp(desc);
 	info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
 
 	if ((info.type == USB_ENDPOINT_XFER_INT) ||
@@ -1479,7 +1469,7 @@ static int __init fusb300_probe(struct platform_device *pdev)
 	fusb300->gadget.name = udc_name;
 	fusb300->reg = reg;
 
-	ret = request_irq(ires->start, fusb300_irq, IRQF_DISABLED | IRQF_SHARED,
+	ret = request_irq(ires->start, fusb300_irq, IRQF_SHARED,
 			  udc_name, fusb300);
 	if (ret < 0) {
 		pr_err("request_irq error (%d)\n", ret);
@@ -1487,7 +1477,7 @@ static int __init fusb300_probe(struct platform_device *pdev)
 	}
 
 	ret = request_irq(ires1->start, fusb300_irq,
-			IRQF_DISABLED | IRQF_SHARED, udc_name, fusb300);
+			IRQF_SHARED, udc_name, fusb300);
 	if (ret < 0) {
 		pr_err("request_irq1 error (%d)\n", ret);
 		goto clean_up;

+ 0 - 10
drivers/usb/gadget/fusb300_udc.h

@@ -8,16 +8,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
  */
 
 

+ 0 - 9
drivers/usb/gadget/g_ffs.c

@@ -8,15 +8,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #define pr_fmt(fmt) "g_ffs: " fmt

+ 3 - 0
drivers/usb/gadget/gadget_chips.h

@@ -31,6 +31,7 @@
 #define gadget_is_ci13xxx_msm(g)	(!strcmp("ci13xxx_msm", (g)->name))
 #define gadget_is_ci13xxx_pci(g)	(!strcmp("ci13xxx_pci", (g)->name))
 #define gadget_is_dummy(g)		(!strcmp("dummy_udc", (g)->name))
+#define gadget_is_dwc3(g)		(!strcmp("dwc3-gadget", (g)->name))
 #define gadget_is_fsl_qe(g)		(!strcmp("fsl_qe_udc", (g)->name))
 #define gadget_is_fsl_usb2(g)		(!strcmp("fsl-usb2-udc", (g)->name))
 #define gadget_is_goku(g)		(!strcmp("goku_udc", (g)->name))
@@ -115,6 +116,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x30;
 	else if (gadget_is_net2272(gadget))
 		return 0x31;
+	else if (gadget_is_dwc3(gadget))
+		return 0x32;
 
 	return -ENOENT;
 }

+ 88 - 1204
drivers/usb/gadget/gmidi.c

@@ -36,134 +36,43 @@
 
 #include "gadget_chips.h"
 
-
-/*
- * Kbuild is not very cooperative with respect to linking separately
- * compiled library objects into one module.  So for now we won't use
- * separate compilation ... ensuring init/exit sections work to shrink
- * the runtime footprint, and giving us at least some parts of what
- * a "gcc --combine ... part1.c part2.c part3.c ... " build would.
- */
+#include "composite.c"
 #include "usbstring.c"
 #include "config.c"
 #include "epautoconf.c"
+#include "f_midi.c"
 
 /*-------------------------------------------------------------------------*/
 
-
 MODULE_AUTHOR("Ben Williamson");
 MODULE_LICENSE("GPL v2");
 
-#define DRIVER_VERSION "25 Jul 2006"
-
 static const char shortname[] = "g_midi";
 static const char longname[] = "MIDI Gadget";
 
 static int index = SNDRV_DEFAULT_IDX1;
-static char *id = SNDRV_DEFAULT_STR1;
-
-module_param(index, int, 0444);
+module_param(index, int, S_IRUGO);
 MODULE_PARM_DESC(index, "Index value for the USB MIDI Gadget adapter.");
-module_param(id, charp, 0444);
-MODULE_PARM_DESC(id, "ID string for the USB MIDI Gadget adapter.");
-
-/* Some systems will want different product identifiers published in the
- * device descriptor, either numbers or strings or both.  These string
- * parameters are in UTF-8 (superset of ASCII's 7 bit characters).
- */
-
-static ushort idVendor;
-module_param(idVendor, ushort, S_IRUGO);
-MODULE_PARM_DESC(idVendor, "USB Vendor ID");
-
-static ushort idProduct;
-module_param(idProduct, ushort, S_IRUGO);
-MODULE_PARM_DESC(idProduct, "USB Product ID");
-
-static ushort bcdDevice;
-module_param(bcdDevice, ushort, S_IRUGO);
-MODULE_PARM_DESC(bcdDevice, "USB Device version (BCD)");
-
-static char *iManufacturer;
-module_param(iManufacturer, charp, S_IRUGO);
-MODULE_PARM_DESC(iManufacturer, "USB Manufacturer string");
-
-static char *iProduct;
-module_param(iProduct, charp, S_IRUGO);
-MODULE_PARM_DESC(iProduct, "USB Product string");
-
-static char *iSerialNumber;
-module_param(iSerialNumber, charp, S_IRUGO);
-MODULE_PARM_DESC(iSerialNumber, "SerialNumber");
-
-/*
- * this version autoconfigures as much as possible,
- * which is reasonable for most "bulk-only" drivers.
- */
-static const char *EP_IN_NAME;
-static const char *EP_OUT_NAME;
 
+static char *id = SNDRV_DEFAULT_STR1;
+module_param(id, charp, S_IRUGO);
+MODULE_PARM_DESC(id, "ID string for the USB MIDI Gadget adapter.");
 
-/* big enough to hold our biggest descriptor */
-#define USB_BUFSIZ 256
-
-
-/* This is a gadget, and the IN/OUT naming is from the host's perspective.
-   USB -> OUT endpoint -> rawmidi
-   USB <- IN endpoint  <- rawmidi */
-struct gmidi_in_port {
-	struct gmidi_device* dev;
-	int active;
-	uint8_t cable;		/* cable number << 4 */
-	uint8_t state;
-#define STATE_UNKNOWN	0
-#define STATE_1PARAM	1
-#define STATE_2PARAM_1	2
-#define STATE_2PARAM_2	3
-#define STATE_SYSEX_0	4
-#define STATE_SYSEX_1	5
-#define STATE_SYSEX_2	6
-	uint8_t data[2];
-};
-
-struct gmidi_device {
-	spinlock_t		lock;
-	struct usb_gadget	*gadget;
-	struct usb_request	*req;		/* for control responses */
-	u8			config;
-	struct usb_ep		*in_ep, *out_ep;
-	struct snd_card		*card;
-	struct snd_rawmidi	*rmidi;
-	struct snd_rawmidi_substream *in_substream;
-	struct snd_rawmidi_substream *out_substream;
-
-	/* For the moment we only support one port in
-	   each direction, but in_port is kept as a
-	   separate struct so we can have more later. */
-	struct gmidi_in_port	in_port;
-	unsigned long		out_triggered;
-	struct tasklet_struct	tasklet;
-};
-
-static void gmidi_transmit(struct gmidi_device* dev, struct usb_request* req);
-
-
-#define DBG(d, fmt, args...) \
-	dev_dbg(&(d)->gadget->dev , fmt , ## args)
-#define VDBG(d, fmt, args...) \
-	dev_vdbg(&(d)->gadget->dev , fmt , ## args)
-#define ERROR(d, fmt, args...) \
-	dev_err(&(d)->gadget->dev , fmt , ## args)
-#define INFO(d, fmt, args...) \
-	dev_info(&(d)->gadget->dev , fmt , ## args)
-
-
-static unsigned buflen = 256;
-static unsigned qlen = 32;
-
+static unsigned int buflen = 256;
 module_param(buflen, uint, S_IRUGO);
+MODULE_PARM_DESC(buflen, "MIDI buffer length");
+
+static unsigned int qlen = 32;
 module_param(qlen, uint, S_IRUGO);
+MODULE_PARM_DESC(qlen, "USB read request queue length");
 
+static unsigned int in_ports = 1;
+module_param(in_ports, uint, S_IRUGO);
+MODULE_PARM_DESC(in_ports, "Number of MIDI input ports");
+
+static unsigned int out_ports = 1;
+module_param(out_ports, uint, S_IRUGO);
+MODULE_PARM_DESC(out_ports, "Number of MIDI output ports");
 
 /* Thanks to Grey Innovation for donating this product ID.
  *
@@ -173,1149 +82,124 @@ module_param(qlen, uint, S_IRUGO);
 #define DRIVER_VENDOR_NUM	0x17b3		/* Grey Innovation */
 #define DRIVER_PRODUCT_NUM	0x0004		/* Linux-USB "MIDI Gadget" */
 
+/* string IDs are assigned dynamically */
 
-/*
- * DESCRIPTORS ... most are static, but strings and (full)
- * configuration descriptors are built on demand.
- */
-
-#define STRING_MANUFACTURER	25
-#define STRING_PRODUCT		42
-#define STRING_SERIAL		101
-#define STRING_MIDI_GADGET	250
+#define STRING_MANUFACTURER_IDX		0
+#define STRING_PRODUCT_IDX		1
+#define STRING_DESCRIPTION_IDX		2
 
-/* We only have the one configuration, it's number 1. */
-#define	GMIDI_CONFIG		1
-
-/* We have two interfaces- AudioControl and MIDIStreaming */
-#define GMIDI_AC_INTERFACE	0
-#define GMIDI_MS_INTERFACE	1
-#define GMIDI_NUM_INTERFACES	2
-
-DECLARE_UAC_AC_HEADER_DESCRIPTOR(1);
-DECLARE_USB_MIDI_OUT_JACK_DESCRIPTOR(1);
-DECLARE_USB_MS_ENDPOINT_DESCRIPTOR(1);
-
-/* B.1  Device Descriptor */
 static struct usb_device_descriptor device_desc = {
 	.bLength =		USB_DT_DEVICE_SIZE,
 	.bDescriptorType =	USB_DT_DEVICE,
-	.bcdUSB =		cpu_to_le16(0x0200),
+	.bcdUSB =		__constant_cpu_to_le16(0x0200),
 	.bDeviceClass =		USB_CLASS_PER_INTERFACE,
-	.idVendor =		cpu_to_le16(DRIVER_VENDOR_NUM),
-	.idProduct =		cpu_to_le16(DRIVER_PRODUCT_NUM),
-	.iManufacturer =	STRING_MANUFACTURER,
-	.iProduct =		STRING_PRODUCT,
+	.idVendor =		__constant_cpu_to_le16(DRIVER_VENDOR_NUM),
+	.idProduct =		__constant_cpu_to_le16(DRIVER_PRODUCT_NUM),
+	/* .iManufacturer =	DYNAMIC */
+	/* .iProduct =		DYNAMIC */
 	.bNumConfigurations =	1,
 };
 
-/* B.2  Configuration Descriptor */
-static struct usb_config_descriptor config_desc = {
-	.bLength =		USB_DT_CONFIG_SIZE,
-	.bDescriptorType =	USB_DT_CONFIG,
-	/* compute wTotalLength on the fly */
-	.bNumInterfaces =	GMIDI_NUM_INTERFACES,
-	.bConfigurationValue =	GMIDI_CONFIG,
-	.iConfiguration =	STRING_MIDI_GADGET,
-	/*
-	 * FIXME: When embedding this driver in a device,
-	 * these need to be set to reflect the actual
-	 * power properties of the device. Is it selfpowered?
-	 */
-	.bmAttributes =		USB_CONFIG_ATT_ONE,
-	.bMaxPower =		CONFIG_USB_GADGET_VBUS_DRAW / 2,
-};
-
-/* B.3.1  Standard AC Interface Descriptor */
-static const struct usb_interface_descriptor ac_interface_desc = {
-	.bLength =		USB_DT_INTERFACE_SIZE,
-	.bDescriptorType =	USB_DT_INTERFACE,
-	.bInterfaceNumber =	GMIDI_AC_INTERFACE,
-	.bNumEndpoints =	0,
-	.bInterfaceClass =	USB_CLASS_AUDIO,
-	.bInterfaceSubClass =	USB_SUBCLASS_AUDIOCONTROL,
-	.iInterface =		STRING_MIDI_GADGET,
-};
-
-/* B.3.2  Class-Specific AC Interface Descriptor */
-static const struct uac1_ac_header_descriptor_1 ac_header_desc = {
-	.bLength =		UAC_DT_AC_HEADER_SIZE(1),
-	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubtype =	USB_MS_HEADER,
-	.bcdADC =		cpu_to_le16(0x0100),
-	.wTotalLength =		cpu_to_le16(UAC_DT_AC_HEADER_SIZE(1)),
-	.bInCollection =	1,
-	.baInterfaceNr = {
-		[0] =		GMIDI_MS_INTERFACE,
-	}
-};
-
-/* B.4.1  Standard MS Interface Descriptor */
-static const struct usb_interface_descriptor ms_interface_desc = {
-	.bLength =		USB_DT_INTERFACE_SIZE,
-	.bDescriptorType =	USB_DT_INTERFACE,
-	.bInterfaceNumber =	GMIDI_MS_INTERFACE,
-	.bNumEndpoints =	2,
-	.bInterfaceClass =	USB_CLASS_AUDIO,
-	.bInterfaceSubClass =	USB_SUBCLASS_MIDISTREAMING,
-	.iInterface =		STRING_MIDI_GADGET,
+static struct usb_string strings_dev[] = {
+	[STRING_MANUFACTURER_IDX].s	= "Grey Innovation",
+	[STRING_PRODUCT_IDX].s		= "MIDI Gadget",
+	[STRING_DESCRIPTION_IDX].s	= "MIDI",
+	{  } /* end of list */
 };
 
-/* B.4.2  Class-Specific MS Interface Descriptor */
-static const struct usb_ms_header_descriptor ms_header_desc = {
-	.bLength =		USB_DT_MS_HEADER_SIZE,
-	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubtype =	USB_MS_HEADER,
-	.bcdMSC =		cpu_to_le16(0x0100),
-	.wTotalLength =		cpu_to_le16(USB_DT_MS_HEADER_SIZE
-				+ 2*USB_DT_MIDI_IN_SIZE
-				+ 2*USB_DT_MIDI_OUT_SIZE(1)),
-};
-
-#define JACK_IN_EMB	1
-#define JACK_IN_EXT	2
-#define JACK_OUT_EMB	3
-#define JACK_OUT_EXT	4
-
-/* B.4.3  MIDI IN Jack Descriptors */
-static const struct usb_midi_in_jack_descriptor jack_in_emb_desc = {
-	.bLength =		USB_DT_MIDI_IN_SIZE,
-	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubtype =	USB_MS_MIDI_IN_JACK,
-	.bJackType =		USB_MS_EMBEDDED,
-	.bJackID =		JACK_IN_EMB,
-};
-
-static const struct usb_midi_in_jack_descriptor jack_in_ext_desc = {
-	.bLength =		USB_DT_MIDI_IN_SIZE,
-	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubtype =	USB_MS_MIDI_IN_JACK,
-	.bJackType =		USB_MS_EXTERNAL,
-	.bJackID =		JACK_IN_EXT,
-};
-
-/* B.4.4  MIDI OUT Jack Descriptors */
-static const struct usb_midi_out_jack_descriptor_1 jack_out_emb_desc = {
-	.bLength =		USB_DT_MIDI_OUT_SIZE(1),
-	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubtype =	USB_MS_MIDI_OUT_JACK,
-	.bJackType =		USB_MS_EMBEDDED,
-	.bJackID =		JACK_OUT_EMB,
-	.bNrInputPins =		1,
-	.pins = {
-		[0] = {
-			.baSourceID =	JACK_IN_EXT,
-			.baSourcePin =	1,
-		}
-	}
-};
-
-static const struct usb_midi_out_jack_descriptor_1 jack_out_ext_desc = {
-	.bLength =		USB_DT_MIDI_OUT_SIZE(1),
-	.bDescriptorType =	USB_DT_CS_INTERFACE,
-	.bDescriptorSubtype =	USB_MS_MIDI_OUT_JACK,
-	.bJackType =		USB_MS_EXTERNAL,
-	.bJackID =		JACK_OUT_EXT,
-	.bNrInputPins =		1,
-	.pins = {
-		[0] = {
-			.baSourceID =	JACK_IN_EMB,
-			.baSourcePin =	1,
-		}
-	}
-};
-
-/* B.5.1  Standard Bulk OUT Endpoint Descriptor */
-static struct usb_endpoint_descriptor bulk_out_desc = {
-	.bLength =		USB_DT_ENDPOINT_AUDIO_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bEndpointAddress =	USB_DIR_OUT,
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-};
-
-/* B.5.2  Class-specific MS Bulk OUT Endpoint Descriptor */
-static const struct usb_ms_endpoint_descriptor_1 ms_out_desc = {
-	.bLength =		USB_DT_MS_ENDPOINT_SIZE(1),
-	.bDescriptorType =	USB_DT_CS_ENDPOINT,
-	.bDescriptorSubtype =	USB_MS_GENERAL,
-	.bNumEmbMIDIJack =	1,
-	.baAssocJackID = {
-		[0] =		JACK_IN_EMB,
-	}
-};
-
-/* B.6.1  Standard Bulk IN Endpoint Descriptor */
-static struct usb_endpoint_descriptor bulk_in_desc = {
-	.bLength =		USB_DT_ENDPOINT_AUDIO_SIZE,
-	.bDescriptorType =	USB_DT_ENDPOINT,
-	.bEndpointAddress =	USB_DIR_IN,
-	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
-};
-
-/* B.6.2  Class-specific MS Bulk IN Endpoint Descriptor */
-static const struct usb_ms_endpoint_descriptor_1 ms_in_desc = {
-	.bLength =		USB_DT_MS_ENDPOINT_SIZE(1),
-	.bDescriptorType =	USB_DT_CS_ENDPOINT,
-	.bDescriptorSubtype =	USB_MS_GENERAL,
-	.bNumEmbMIDIJack =	1,
-	.baAssocJackID = {
-		[0] =		JACK_OUT_EMB,
-	}
-};
-
-static const struct usb_descriptor_header *gmidi_function [] = {
-	(struct usb_descriptor_header *)&ac_interface_desc,
-	(struct usb_descriptor_header *)&ac_header_desc,
-	(struct usb_descriptor_header *)&ms_interface_desc,
-
-	(struct usb_descriptor_header *)&ms_header_desc,
-	(struct usb_descriptor_header *)&jack_in_emb_desc,
-	(struct usb_descriptor_header *)&jack_in_ext_desc,
-	(struct usb_descriptor_header *)&jack_out_emb_desc,
-	(struct usb_descriptor_header *)&jack_out_ext_desc,
-	/* If you add more jacks, update ms_header_desc.wTotalLength */
-
-	(struct usb_descriptor_header *)&bulk_out_desc,
-	(struct usb_descriptor_header *)&ms_out_desc,
-	(struct usb_descriptor_header *)&bulk_in_desc,
-	(struct usb_descriptor_header *)&ms_in_desc,
-	NULL,
-};
-
-static char manufacturer[50];
-static char product_desc[40] = "MIDI Gadget";
-static char serial_number[20];
-
-/* static strings, in UTF-8 */
-static struct usb_string strings [] = {
-	{ STRING_MANUFACTURER, manufacturer, },
-	{ STRING_PRODUCT, product_desc, },
-	{ STRING_SERIAL, serial_number, },
-	{ STRING_MIDI_GADGET, longname, },
-	{  }			/* end of list */
-};
-
-static struct usb_gadget_strings stringtab = {
+static struct usb_gadget_strings stringtab_dev = {
 	.language	= 0x0409,	/* en-us */
-	.strings	= strings,
+	.strings	= strings_dev,
 };
 
-static int config_buf(struct usb_gadget *gadget,
-		u8 *buf, u8 type, unsigned index)
-{
-	int len;
-
-	/* only one configuration */
-	if (index != 0) {
-		return -EINVAL;
-	}
-	len = usb_gadget_config_buf(&config_desc,
-			buf, USB_BUFSIZ, gmidi_function);
-	if (len < 0) {
-		return len;
-	}
-	((struct usb_config_descriptor *)buf)->bDescriptorType = type;
-	return len;
-}
-
-static struct usb_request *alloc_ep_req(struct usb_ep *ep, unsigned length)
-{
-	struct usb_request	*req;
-
-	req = usb_ep_alloc_request(ep, GFP_ATOMIC);
-	if (req) {
-		req->length = length;
-		req->buf = kmalloc(length, GFP_ATOMIC);
-		if (!req->buf) {
-			usb_ep_free_request(ep, req);
-			req = NULL;
-		}
-	}
-	return req;
-}
-
-static void free_ep_req(struct usb_ep *ep, struct usb_request *req)
-{
-	kfree(req->buf);
-	usb_ep_free_request(ep, req);
-}
-
-static const uint8_t gmidi_cin_length[] = {
-	0, 0, 2, 3, 3, 1, 2, 3, 3, 3, 3, 3, 2, 2, 3, 1
+static struct usb_gadget_strings *dev_strings[] = {
+	&stringtab_dev,
+	NULL,
 };
 
-/*
- * Receives a chunk of MIDI data.
- */
-static void gmidi_read_data(struct usb_ep *ep, int cable,
-				   uint8_t *data, int length)
-{
-	struct gmidi_device *dev = ep->driver_data;
-	/* cable is ignored, because for now we only have one. */
-
-	if (!dev->out_substream) {
-		/* Nobody is listening - throw it on the floor. */
-		return;
-	}
-	if (!test_bit(dev->out_substream->number, &dev->out_triggered)) {
-		return;
-	}
-	snd_rawmidi_receive(dev->out_substream, data, length);
-}
-
-static void gmidi_handle_out_data(struct usb_ep *ep, struct usb_request *req)
-{
-	unsigned i;
-	u8 *buf = req->buf;
-
-	for (i = 0; i + 3 < req->actual; i += 4) {
-		if (buf[i] != 0) {
-			int cable = buf[i] >> 4;
-			int length = gmidi_cin_length[buf[i] & 0x0f];
-			gmidi_read_data(ep, cable, &buf[i + 1], length);
-		}
-	}
-}
-
-static void gmidi_complete(struct usb_ep *ep, struct usb_request *req)
-{
-	struct gmidi_device *dev = ep->driver_data;
-	int status = req->status;
-
-	switch (status) {
-	case 0:				/* normal completion */
-		if (ep == dev->out_ep) {
-			/* we received stuff.
-			   req is queued again, below */
-			gmidi_handle_out_data(ep, req);
-		} else if (ep == dev->in_ep) {
-			/* our transmit completed.
-			   see if there's more to go.
-			   gmidi_transmit eats req, don't queue it again. */
-			gmidi_transmit(dev, req);
-			return;
-		}
-		break;
-
-	/* this endpoint is normally active while we're configured */
-	case -ECONNABORTED:		/* hardware forced ep reset */
-	case -ECONNRESET:		/* request dequeued */
-	case -ESHUTDOWN:		/* disconnect from host */
-		VDBG(dev, "%s gone (%d), %d/%d\n", ep->name, status,
-				req->actual, req->length);
-		if (ep == dev->out_ep) {
-			gmidi_handle_out_data(ep, req);
-		}
-		free_ep_req(ep, req);
-		return;
-
-	case -EOVERFLOW:		/* buffer overrun on read means that
-					 * we didn't provide a big enough
-					 * buffer.
-					 */
-	default:
-		DBG(dev, "%s complete --> %d, %d/%d\n", ep->name,
-				status, req->actual, req->length);
-		break;
-	case -EREMOTEIO:		/* short read */
-		break;
-	}
-
-	status = usb_ep_queue(ep, req, GFP_ATOMIC);
-	if (status) {
-		ERROR(dev, "kill %s:  resubmit %d bytes --> %d\n",
-				ep->name, req->length, status);
-		usb_ep_set_halt(ep);
-		/* FIXME recover later ... somehow */
-	}
-}
-
-static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags)
-{
-	int err = 0;
-	struct usb_request *req;
-	struct usb_ep *ep;
-	unsigned i;
-
-	dev->in_ep->desc = &bulk_in_desc;
-	err = usb_ep_enable(dev->in_ep);
-	if (err) {
-		ERROR(dev, "can't start %s: %d\n", dev->in_ep->name, err);
-		goto fail;
-	}
-	dev->in_ep->driver_data = dev;
-
-	dev->out_ep->desc = &bulk_out_desc;
-	err = usb_ep_enable(dev->out_ep);
-	if (err) {
-		ERROR(dev, "can't start %s: %d\n", dev->out_ep->name, err);
-		goto fail;
-	}
-	dev->out_ep->driver_data = dev;
-
-	/* allocate a bunch of read buffers and queue them all at once. */
-	ep = dev->out_ep;
-	for (i = 0; i < qlen && err == 0; i++) {
-		req = alloc_ep_req(ep, buflen);
-		if (req) {
-			req->complete = gmidi_complete;
-			err = usb_ep_queue(ep, req, GFP_ATOMIC);
-			if (err) {
-				DBG(dev, "%s queue req: %d\n", ep->name, err);
-			}
-		} else {
-			err = -ENOMEM;
-		}
-	}
-fail:
-	/* caller is responsible for cleanup on error */
-	return err;
-}
-
-
-static void gmidi_reset_config(struct gmidi_device *dev)
-{
-	if (dev->config == 0) {
-		return;
-	}
-
-	DBG(dev, "reset config\n");
-
-	/* just disable endpoints, forcing completion of pending i/o.
-	 * all our completion handlers free their requests in this case.
-	 */
-	usb_ep_disable(dev->in_ep);
-	usb_ep_disable(dev->out_ep);
-	dev->config = 0;
-}
-
-/* change our operational config.  this code must agree with the code
- * that returns config descriptors, and altsetting code.
- *
- * it's also responsible for power management interactions. some
- * configurations might not work with our current power sources.
- *
- * note that some device controller hardware will constrain what this
- * code can do, perhaps by disallowing more than one configuration or
- * by limiting configuration choices (like the pxa2xx).
- */
-static int
-gmidi_set_config(struct gmidi_device *dev, unsigned number, gfp_t gfp_flags)
-{
-	int result = 0;
-	struct usb_gadget *gadget = dev->gadget;
-
-#if 0
-	/* FIXME */
-	/* Hacking this bit out fixes a bug where on receipt of two
-	   USB_REQ_SET_CONFIGURATION messages, we end up with no
-	   buffered OUT requests waiting for data. This is clearly
-	   hiding a bug elsewhere, because if the config didn't
-	   change then we really shouldn't do anything. */
-	/* Having said that, when we do "change" from config 1
-	   to config 1, we at least gmidi_reset_config() which
-	   clears out any requests on endpoints, so it's not like
-	   we leak or anything. */
-	if (number == dev->config) {
-		return 0;
-	}
-#endif
-
-	gmidi_reset_config(dev);
-
-	switch (number) {
-	case GMIDI_CONFIG:
-		result = set_gmidi_config(dev, gfp_flags);
-		break;
-	default:
-		result = -EINVAL;
-		/* FALL THROUGH */
-	case 0:
-		return result;
-	}
-
-	if (!result && (!dev->in_ep || !dev->out_ep)) {
-		result = -ENODEV;
-	}
-	if (result) {
-		gmidi_reset_config(dev);
-	} else {
-		char *speed;
-
-		switch (gadget->speed) {
-		case USB_SPEED_LOW:	speed = "low"; break;
-		case USB_SPEED_FULL:	speed = "full"; break;
-		case USB_SPEED_HIGH:	speed = "high"; break;
-		default:		speed = "?"; break;
-		}
-
-		dev->config = number;
-		INFO(dev, "%s speed\n", speed);
-	}
-	return result;
-}
-
-
-static void gmidi_setup_complete(struct usb_ep *ep, struct usb_request *req)
-{
-	if (req->status || req->actual != req->length) {
-		DBG((struct gmidi_device *) ep->driver_data,
-				"setup complete --> %d, %d/%d\n",
-				req->status, req->actual, req->length);
-	}
-}
-
-/*
- * The setup() callback implements all the ep0 functionality that's
- * not handled lower down, in hardware or the hardware driver (like
- * device and endpoint feature flags, and their status).  It's all
- * housekeeping for the gadget function we're implementing.  Most of
- * the work is in config-specific setup.
- */
-static int gmidi_setup(struct usb_gadget *gadget,
-			const struct usb_ctrlrequest *ctrl)
-{
-	struct gmidi_device *dev = get_gadget_data(gadget);
-	struct usb_request *req = dev->req;
-	int value = -EOPNOTSUPP;
-	u16 w_index = le16_to_cpu(ctrl->wIndex);
-	u16 w_value = le16_to_cpu(ctrl->wValue);
-	u16 w_length = le16_to_cpu(ctrl->wLength);
-
-	/* usually this stores reply data in the pre-allocated ep0 buffer,
-	 * but config change events will reconfigure hardware.
-	 */
-	req->zero = 0;
-	switch (ctrl->bRequest) {
-
-	case USB_REQ_GET_DESCRIPTOR:
-		if (ctrl->bRequestType != USB_DIR_IN) {
-			goto unknown;
-		}
-		switch (w_value >> 8) {
-
-		case USB_DT_DEVICE:
-			device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
-			value = min(w_length, (u16) sizeof(device_desc));
-			memcpy(req->buf, &device_desc, value);
-			break;
-		case USB_DT_CONFIG:
-			value = config_buf(gadget, req->buf,
-					w_value >> 8,
-					w_value & 0xff);
-			if (value >= 0) {
-				value = min(w_length, (u16)value);
-			}
-			break;
-
-		case USB_DT_STRING:
-			/* wIndex == language code.
-			 * this driver only handles one language, you can
-			 * add string tables for other languages, using
-			 * any UTF-8 characters
-			 */
-			value = usb_gadget_get_string(&stringtab,
-					w_value & 0xff, req->buf);
-			if (value >= 0) {
-				value = min(w_length, (u16)value);
-			}
-			break;
-		}
-		break;
-
-	/* currently two configs, two speeds */
-	case USB_REQ_SET_CONFIGURATION:
-		if (ctrl->bRequestType != 0) {
-			goto unknown;
-		}
-		if (gadget->a_hnp_support) {
-			DBG(dev, "HNP available\n");
-		} else if (gadget->a_alt_hnp_support) {
-			DBG(dev, "HNP needs a different root port\n");
-		} else {
-			VDBG(dev, "HNP inactive\n");
-		}
-		spin_lock(&dev->lock);
-		value = gmidi_set_config(dev, w_value, GFP_ATOMIC);
-		spin_unlock(&dev->lock);
-		break;
-	case USB_REQ_GET_CONFIGURATION:
-		if (ctrl->bRequestType != USB_DIR_IN) {
-			goto unknown;
-		}
-		*(u8 *)req->buf = dev->config;
-		value = min(w_length, (u16)1);
-		break;
-
-	/* until we add altsetting support, or other interfaces,
-	 * only 0/0 are possible.  pxa2xx only supports 0/0 (poorly)
-	 * and already killed pending endpoint I/O.
-	 */
-	case USB_REQ_SET_INTERFACE:
-		if (ctrl->bRequestType != USB_RECIP_INTERFACE) {
-			goto unknown;
-		}
-		spin_lock(&dev->lock);
-		if (dev->config && w_index < GMIDI_NUM_INTERFACES
-			&& w_value == 0)
-		{
-			u8 config = dev->config;
-
-			/* resets interface configuration, forgets about
-			 * previous transaction state (queued bufs, etc)
-			 * and re-inits endpoint state (toggle etc)
-			 * no response queued, just zero status == success.
-			 * if we had more than one interface we couldn't
-			 * use this "reset the config" shortcut.
-			 */
-			gmidi_reset_config(dev);
-			gmidi_set_config(dev, config, GFP_ATOMIC);
-			value = 0;
-		}
-		spin_unlock(&dev->lock);
-		break;
-	case USB_REQ_GET_INTERFACE:
-		if (ctrl->bRequestType != (USB_DIR_IN|USB_RECIP_INTERFACE)) {
-			goto unknown;
-		}
-		if (!dev->config) {
-			break;
-		}
-		if (w_index >= GMIDI_NUM_INTERFACES) {
-			value = -EDOM;
-			break;
-		}
-		*(u8 *)req->buf = 0;
-		value = min(w_length, (u16)1);
-		break;
-
-	default:
-unknown:
-		VDBG(dev, "unknown control req%02x.%02x v%04x i%04x l%d\n",
-			ctrl->bRequestType, ctrl->bRequest,
-			w_value, w_index, w_length);
-	}
-
-	/* respond with data transfer before status phase? */
-	if (value >= 0) {
-		req->length = value;
-		req->zero = value < w_length;
-		value = usb_ep_queue(gadget->ep0, req, GFP_ATOMIC);
-		if (value < 0) {
-			DBG(dev, "ep_queue --> %d\n", value);
-			req->status = 0;
-			gmidi_setup_complete(gadget->ep0, req);
-		}
-	}
-
-	/* device either stalls (value < 0) or reports success */
-	return value;
-}
-
-static void gmidi_disconnect(struct usb_gadget *gadget)
-{
-	struct gmidi_device *dev = get_gadget_data(gadget);
-	unsigned long flags;
-
-	spin_lock_irqsave(&dev->lock, flags);
-	gmidi_reset_config(dev);
-
-	/* a more significant application might have some non-usb
-	 * activities to quiesce here, saving resources like power
-	 * or pushing the notification up a network stack.
-	 */
-	spin_unlock_irqrestore(&dev->lock, flags);
-
-	/* next we may get setup() calls to enumerate new connections;
-	 * or an unbind() during shutdown (including removing module).
-	 */
-}
-
-static void /* __init_or_exit */ gmidi_unbind(struct usb_gadget *gadget)
-{
-	struct gmidi_device *dev = get_gadget_data(gadget);
-	struct snd_card *card;
-
-	DBG(dev, "unbind\n");
-
-	card = dev->card;
-	dev->card = NULL;
-	if (card) {
-		snd_card_free(card);
-	}
-
-	/* we've already been disconnected ... no i/o is active */
-	if (dev->req) {
-		dev->req->length = USB_BUFSIZ;
-		free_ep_req(gadget->ep0, dev->req);
-	}
-	kfree(dev);
-	set_gadget_data(gadget, NULL);
-}
-
-static int gmidi_snd_free(struct snd_device *device)
+static int __exit midi_unbind(struct usb_composite_dev *dev)
 {
 	return 0;
 }
 
-static void gmidi_transmit_packet(struct usb_request *req, uint8_t p0,
-					uint8_t p1, uint8_t p2, uint8_t p3)
-{
-	unsigned length = req->length;
-	u8 *buf = (u8 *)req->buf + length;
-
-	buf[0] = p0;
-	buf[1] = p1;
-	buf[2] = p2;
-	buf[3] = p3;
-	req->length = length + 4;
-}
-
-/*
- * Converts MIDI commands to USB MIDI packets.
- */
-static void gmidi_transmit_byte(struct usb_request *req,
-				struct gmidi_in_port *port, uint8_t b)
-{
-	uint8_t p0 = port->cable;
-
-	if (b >= 0xf8) {
-		gmidi_transmit_packet(req, p0 | 0x0f, b, 0, 0);
-	} else if (b >= 0xf0) {
-		switch (b) {
-		case 0xf0:
-			port->data[0] = b;
-			port->state = STATE_SYSEX_1;
-			break;
-		case 0xf1:
-		case 0xf3:
-			port->data[0] = b;
-			port->state = STATE_1PARAM;
-			break;
-		case 0xf2:
-			port->data[0] = b;
-			port->state = STATE_2PARAM_1;
-			break;
-		case 0xf4:
-		case 0xf5:
-			port->state = STATE_UNKNOWN;
-			break;
-		case 0xf6:
-			gmidi_transmit_packet(req, p0 | 0x05, 0xf6, 0, 0);
-			port->state = STATE_UNKNOWN;
-			break;
-		case 0xf7:
-			switch (port->state) {
-			case STATE_SYSEX_0:
-				gmidi_transmit_packet(req,
-					p0 | 0x05, 0xf7, 0, 0);
-				break;
-			case STATE_SYSEX_1:
-				gmidi_transmit_packet(req,
-					p0 | 0x06, port->data[0], 0xf7, 0);
-				break;
-			case STATE_SYSEX_2:
-				gmidi_transmit_packet(req,
-					p0 | 0x07, port->data[0],
-					port->data[1], 0xf7);
-				break;
-			}
-			port->state = STATE_UNKNOWN;
-			break;
-		}
-	} else if (b >= 0x80) {
-		port->data[0] = b;
-		if (b >= 0xc0 && b <= 0xdf)
-			port->state = STATE_1PARAM;
-		else
-			port->state = STATE_2PARAM_1;
-	} else { /* b < 0x80 */
-		switch (port->state) {
-		case STATE_1PARAM:
-			if (port->data[0] < 0xf0) {
-				p0 |= port->data[0] >> 4;
-			} else {
-				p0 |= 0x02;
-				port->state = STATE_UNKNOWN;
-			}
-			gmidi_transmit_packet(req, p0, port->data[0], b, 0);
-			break;
-		case STATE_2PARAM_1:
-			port->data[1] = b;
-			port->state = STATE_2PARAM_2;
-			break;
-		case STATE_2PARAM_2:
-			if (port->data[0] < 0xf0) {
-				p0 |= port->data[0] >> 4;
-				port->state = STATE_2PARAM_1;
-			} else {
-				p0 |= 0x03;
-				port->state = STATE_UNKNOWN;
-			}
-			gmidi_transmit_packet(req,
-				p0, port->data[0], port->data[1], b);
-			break;
-		case STATE_SYSEX_0:
-			port->data[0] = b;
-			port->state = STATE_SYSEX_1;
-			break;
-		case STATE_SYSEX_1:
-			port->data[1] = b;
-			port->state = STATE_SYSEX_2;
-			break;
-		case STATE_SYSEX_2:
-			gmidi_transmit_packet(req,
-				p0 | 0x04, port->data[0], port->data[1], b);
-			port->state = STATE_SYSEX_0;
-			break;
-		}
-	}
-}
-
-static void gmidi_transmit(struct gmidi_device *dev, struct usb_request *req)
-{
-	struct usb_ep *ep = dev->in_ep;
-	struct gmidi_in_port *port = &dev->in_port;
-
-	if (!ep) {
-		return;
-	}
-	if (!req) {
-		req = alloc_ep_req(ep, buflen);
-	}
-	if (!req) {
-		ERROR(dev, "gmidi_transmit: alloc_ep_request failed\n");
-		return;
-	}
-	req->length = 0;
-	req->complete = gmidi_complete;
-
-	if (port->active) {
-		while (req->length + 3 < buflen) {
-			uint8_t b;
-			if (snd_rawmidi_transmit(dev->in_substream, &b, 1)
-				!= 1)
-			{
-				port->active = 0;
-				break;
-			}
-			gmidi_transmit_byte(req, port, b);
-		}
-	}
-	if (req->length > 0) {
-		usb_ep_queue(ep, req, GFP_ATOMIC);
-	} else {
-		free_ep_req(ep, req);
-	}
-}
-
-static void gmidi_in_tasklet(unsigned long data)
-{
-	struct gmidi_device *dev = (struct gmidi_device *)data;
-
-	gmidi_transmit(dev, NULL);
-}
-
-static int gmidi_in_open(struct snd_rawmidi_substream *substream)
-{
-	struct gmidi_device *dev = substream->rmidi->private_data;
-
-	VDBG(dev, "gmidi_in_open\n");
-	dev->in_substream = substream;
-	dev->in_port.state = STATE_UNKNOWN;
-	return 0;
-}
-
-static int gmidi_in_close(struct snd_rawmidi_substream *substream)
-{
-	struct gmidi_device *dev = substream->rmidi->private_data;
-
-	VDBG(dev, "gmidi_in_close\n");
-	return 0;
-}
-
-static void gmidi_in_trigger(struct snd_rawmidi_substream *substream, int up)
-{
-	struct gmidi_device *dev = substream->rmidi->private_data;
-
-	VDBG(dev, "gmidi_in_trigger %d\n", up);
-	dev->in_port.active = up;
-	if (up) {
-		tasklet_hi_schedule(&dev->tasklet);
-	}
-}
-
-static int gmidi_out_open(struct snd_rawmidi_substream *substream)
-{
-	struct gmidi_device *dev = substream->rmidi->private_data;
-
-	VDBG(dev, "gmidi_out_open\n");
-	dev->out_substream = substream;
-	return 0;
-}
-
-static int gmidi_out_close(struct snd_rawmidi_substream *substream)
-{
-	struct gmidi_device *dev = substream->rmidi->private_data;
-
-	VDBG(dev, "gmidi_out_close\n");
-	return 0;
-}
-
-static void gmidi_out_trigger(struct snd_rawmidi_substream *substream, int up)
-{
-	struct gmidi_device *dev = substream->rmidi->private_data;
-
-	VDBG(dev, "gmidi_out_trigger %d\n", up);
-	if (up) {
-		set_bit(substream->number, &dev->out_triggered);
-	} else {
-		clear_bit(substream->number, &dev->out_triggered);
-	}
-}
-
-static struct snd_rawmidi_ops gmidi_in_ops = {
-	.open = gmidi_in_open,
-	.close = gmidi_in_close,
-	.trigger = gmidi_in_trigger,
+static struct usb_configuration midi_config = {
+	.label		= "MIDI Gadget",
+	.bConfigurationValue = 1,
+	/* .iConfiguration = DYNAMIC */
+	.bmAttributes	= USB_CONFIG_ATT_ONE,
+	.bMaxPower	= CONFIG_USB_GADGET_VBUS_DRAW / 2,
 };
 
-static struct snd_rawmidi_ops gmidi_out_ops = {
-	.open = gmidi_out_open,
-	.close = gmidi_out_close,
-	.trigger = gmidi_out_trigger
-};
-
-/* register as a sound "card" */
-static int gmidi_register_card(struct gmidi_device *dev)
+static int __init midi_bind_config(struct usb_configuration *c)
 {
-	struct snd_card *card;
-	struct snd_rawmidi *rmidi;
-	int err;
-	int out_ports = 1;
-	int in_ports = 1;
-	static struct snd_device_ops ops = {
-		.dev_free = gmidi_snd_free,
-	};
-
-	err = snd_card_create(index, id, THIS_MODULE, 0, &card);
-	if (err < 0) {
-		ERROR(dev, "snd_card_create failed\n");
-		goto fail;
-	}
-	dev->card = card;
-
-	err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, dev, &ops);
-	if (err < 0) {
-		ERROR(dev, "snd_device_new failed: error %d\n", err);
-		goto fail;
-	}
-
-	strcpy(card->driver, longname);
-	strcpy(card->longname, longname);
-	strcpy(card->shortname, shortname);
-
-	/* Set up rawmidi */
-	dev->in_port.dev = dev;
-	dev->in_port.active = 0;
-	snd_component_add(card, "MIDI");
-	err = snd_rawmidi_new(card, "USB MIDI Gadget", 0,
-			      out_ports, in_ports, &rmidi);
-	if (err < 0) {
-		ERROR(dev, "snd_rawmidi_new failed: error %d\n", err);
-		goto fail;
-	}
-	dev->rmidi = rmidi;
-	strcpy(rmidi->name, card->shortname);
-	rmidi->info_flags = SNDRV_RAWMIDI_INFO_OUTPUT |
-			    SNDRV_RAWMIDI_INFO_INPUT |
-			    SNDRV_RAWMIDI_INFO_DUPLEX;
-	rmidi->private_data = dev;
-
-	/* Yes, rawmidi OUTPUT = USB IN, and rawmidi INPUT = USB OUT.
-	   It's an upside-down world being a gadget. */
-	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT, &gmidi_in_ops);
-	snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT, &gmidi_out_ops);
-
-	snd_card_set_dev(card, &dev->gadget->dev);
-
-	/* register it - we're ready to go */
-	err = snd_card_register(card);
-	if (err < 0) {
-		ERROR(dev, "snd_card_register failed\n");
-		goto fail;
-	}
-
-	VDBG(dev, "gmidi_register_card finished ok\n");
-	return 0;
-
-fail:
-	if (dev->card) {
-		snd_card_free(dev->card);
-		dev->card = NULL;
-	}
-	return err;
+	return f_midi_bind_config(c, index, id,
+				  in_ports, out_ports,
+				  buflen, qlen);
 }
 
-/*
- * Creates an output endpoint, and initializes output ports.
- */
-static int __init gmidi_bind(struct usb_gadget *gadget)
+static int __init midi_bind(struct usb_composite_dev *cdev)
 {
-	struct gmidi_device *dev;
-	struct usb_ep *in_ep, *out_ep;
-	int gcnum, err = 0;
+	struct usb_gadget *gadget = cdev->gadget;
+	int gcnum, status;
 
-	/* support optional vendor/distro customization */
-	if (idVendor) {
-		if (!idProduct) {
-			pr_err("idVendor needs idProduct!\n");
-			return -ENODEV;
-		}
-		device_desc.idVendor = cpu_to_le16(idVendor);
-		device_desc.idProduct = cpu_to_le16(idProduct);
-		if (bcdDevice) {
-			device_desc.bcdDevice = cpu_to_le16(bcdDevice);
-		}
-	}
-	if (iManufacturer) {
-		strlcpy(manufacturer, iManufacturer, sizeof(manufacturer));
-	} else {
-		snprintf(manufacturer, sizeof(manufacturer), "%s %s with %s",
-			init_utsname()->sysname, init_utsname()->release,
-			gadget->name);
-	}
-	if (iProduct) {
-		strlcpy(product_desc, iProduct, sizeof(product_desc));
-	}
-	if (iSerialNumber) {
-		device_desc.iSerialNumber = STRING_SERIAL,
-		strlcpy(serial_number, iSerialNumber, sizeof(serial_number));
-	}
+	status = usb_string_id(cdev);
+	if (status < 0)
+		return status;
+	strings_dev[STRING_MANUFACTURER_IDX].id = status;
+	device_desc.iManufacturer = status;
 
-	/* Bulk-only drivers like this one SHOULD be able to
-	 * autoconfigure on any sane usb controller driver,
-	 * but there may also be important quirks to address.
-	 */
-	usb_ep_autoconfig_reset(gadget);
-	in_ep = usb_ep_autoconfig(gadget, &bulk_in_desc);
-	if (!in_ep) {
-autoconf_fail:
-		pr_err("%s: can't autoconfigure on %s\n",
-			shortname, gadget->name);
-		return -ENODEV;
-	}
-	EP_IN_NAME = in_ep->name;
-	in_ep->driver_data = in_ep;	/* claim */
+	status = usb_string_id(cdev);
+	if (status < 0)
+		return status;
+	strings_dev[STRING_PRODUCT_IDX].id = status;
+	device_desc.iProduct = status;
 
-	out_ep = usb_ep_autoconfig(gadget, &bulk_out_desc);
-	if (!out_ep) {
-		goto autoconf_fail;
-	}
-	EP_OUT_NAME = out_ep->name;
-	out_ep->driver_data = out_ep;	/* claim */
+	/* config description */
+	status = usb_string_id(cdev);
+	if (status < 0)
+		return status;
+	strings_dev[STRING_DESCRIPTION_IDX].id = status;
+
+	midi_config.iConfiguration = status;
 
 	gcnum = usb_gadget_controller_number(gadget);
-	if (gcnum >= 0) {
-		device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
-	} else {
+	if (gcnum < 0) {
 		/* gmidi is so simple (no altsettings) that
 		 * it SHOULD NOT have problems with bulk-capable hardware.
 		 * so warn about unrecognized controllers, don't panic.
 		 */
 		pr_warning("%s: controller '%s' not recognized\n",
-			shortname, gadget->name);
+			   __func__, gadget->name);
 		device_desc.bcdDevice = cpu_to_le16(0x9999);
+	} else {
+		device_desc.bcdDevice = cpu_to_le16(0x0200 + gcnum);
 	}
 
+	status = usb_add_config(cdev, &midi_config, midi_bind_config);
+	if (status < 0)
+		return status;
 
-	/* ok, we made sense of the hardware ... */
-	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
-	if (!dev) {
-		return -ENOMEM;
-	}
-	spin_lock_init(&dev->lock);
-	dev->gadget = gadget;
-	dev->in_ep = in_ep;
-	dev->out_ep = out_ep;
-	set_gadget_data(gadget, dev);
-	tasklet_init(&dev->tasklet, gmidi_in_tasklet, (unsigned long)dev);
-
-	/* preallocate control response and buffer */
-	dev->req = alloc_ep_req(gadget->ep0, USB_BUFSIZ);
-	if (!dev->req) {
-		err = -ENOMEM;
-		goto fail;
-	}
-
-	dev->req->complete = gmidi_setup_complete;
-
-	gadget->ep0->driver_data = dev;
-
-	INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname);
-	INFO(dev, "using %s, OUT %s IN %s\n", gadget->name,
-		EP_OUT_NAME, EP_IN_NAME);
-
-	/* register as an ALSA sound card */
-	err = gmidi_register_card(dev);
-	if (err < 0) {
-		goto fail;
-	}
-
-	VDBG(dev, "gmidi_bind finished ok\n");
+	pr_info("%s\n", longname);
 	return 0;
-
-fail:
-	gmidi_unbind(gadget);
-	return err;
-}
-
-
-static void gmidi_suspend(struct usb_gadget *gadget)
-{
-	struct gmidi_device *dev = get_gadget_data(gadget);
-
-	if (gadget->speed == USB_SPEED_UNKNOWN) {
-		return;
-	}
-
-	DBG(dev, "suspend\n");
-}
-
-static void gmidi_resume(struct usb_gadget *gadget)
-{
-	struct gmidi_device *dev = get_gadget_data(gadget);
-
-	DBG(dev, "resume\n");
 }
 
-
-static struct usb_gadget_driver gmidi_driver = {
-	.speed		= USB_SPEED_FULL,
-	.function	= (char *)longname,
-	.unbind		= gmidi_unbind,
-
-	.setup		= gmidi_setup,
-	.disconnect	= gmidi_disconnect,
-
-	.suspend	= gmidi_suspend,
-	.resume		= gmidi_resume,
-
-	.driver		= {
-		.name		= (char *)shortname,
-		.owner		= THIS_MODULE,
-	},
+static struct usb_composite_driver midi_driver = {
+	.name		= (char *) longname,
+	.dev		= &device_desc,
+	.strings	= dev_strings,
+	.max_speed	= USB_SPEED_HIGH,
+	.unbind		= __exit_p(midi_unbind),
 };
 
-static int __init gmidi_init(void)
+static int __init midi_init(void)
 {
-	return usb_gadget_probe_driver(&gmidi_driver, gmidi_bind);
+	return usb_composite_probe(&midi_driver, midi_bind);
 }
-module_init(gmidi_init);
+module_init(midi_init);
 
-static void __exit gmidi_cleanup(void)
+static void __exit midi_cleanup(void)
 {
-	usb_gadget_unregister_driver(&gmidi_driver);
+	usb_composite_unregister(&midi_driver);
 }
-module_exit(gmidi_cleanup);
+module_exit(midi_cleanup);
 

+ 0 - 9
drivers/usb/gadget/hid.c

@@ -9,15 +9,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 

+ 2 - 2
drivers/usb/gadget/imx_udc.c

@@ -689,7 +689,7 @@ static int imx_ep_enable(struct usb_ep *usb_ep,
 		return -EINVAL;
 	}
 
-	if (imx_ep->fifosize < le16_to_cpu(desc->wMaxPacketSize)) {
+	if (imx_ep->fifosize < usb_endpoint_maxp(desc)) {
 		D_ERR(imx_usb->dev,
 			"<%s> bad %s maxpacket\n", __func__, usb_ep->name);
 		return -ERANGE;
@@ -1478,7 +1478,7 @@ static int __init imx_udc_probe(struct platform_device *pdev)
 
 	for (i = 0; i < IMX_USB_NB_EP + 1; i++) {
 		ret = request_irq(imx_usb->usbd_int[i], intr_handler(i),
-				     IRQF_DISABLED, driver_name, imx_usb);
+				     0, driver_name, imx_usb);
 		if (ret) {
 			dev_err(&pdev->dev, "can't get irq %i, err %d\n",
 				imx_usb->usbd_int[i], ret);

+ 0 - 5
drivers/usb/gadget/imx_udc.h

@@ -8,11 +8,6 @@
  *	it under the terms of the GNU General Public License as published by
  *	the Free Software Foundation; either version 2 of the License, or
  *	(at your option) any later version.
- *
- *	This program is distributed in the hope that it will be useful,
- *	but WITHOUT ANY WARRANTY; without even the implied warranty of
- *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *	GNU General Public License for more details.
  */
 
 #ifndef __LINUX_USB_GADGET_IMX_H

+ 0 - 9
drivers/usb/gadget/inode.c

@@ -8,15 +8,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 

+ 46 - 101
drivers/usb/gadget/langwell_udc.c

@@ -5,16 +5,6 @@
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
  * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
  */
 
 
@@ -60,9 +50,6 @@ static const char driver_name[] = "langwell_udc";
 static const char driver_desc[] = DRIVER_DESC;
 
 
-/* controller device global variable */
-static struct langwell_udc	*the_controller;
-
 /* for endpoint 0 operations */
 static const struct usb_endpoint_descriptor
 langwell_ep0_desc = {
@@ -283,7 +270,7 @@ static int langwell_ep_enable(struct usb_ep *_ep,
 	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
 		return -ESHUTDOWN;
 
-	max = le16_to_cpu(desc->wMaxPacketSize);
+	max = usb_endpoint_maxp(desc);
 
 	/*
 	 * disable HW zero length termination select
@@ -1321,9 +1308,12 @@ static int langwell_pullup(struct usb_gadget *_gadget, int is_on)
 	return 0;
 }
 
-static int langwell_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *));
-static int langwell_stop(struct usb_gadget_driver *driver);
+static int langwell_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver);
+
+static int langwell_stop(struct usb_gadget *g,
+		struct usb_gadget_driver *driver);
+
 /* device controller usb_gadget_ops structure */
 static const struct usb_gadget_ops langwell_ops = {
 
@@ -1345,8 +1335,8 @@ static const struct usb_gadget_ops langwell_ops = {
 	/* D+ pullup, software-controlled connect/disconnect to USB host */
 	.pullup		= langwell_pullup,
 
-	.start		= langwell_start,
-	.stop		= langwell_stop,
+	.udc_start	= langwell_start,
+	.udc_stop	= langwell_stop,
 };
 
 
@@ -1561,7 +1551,7 @@ static void stop_activity(struct langwell_udc *dev,
 static ssize_t show_function(struct device *_dev,
 		struct device_attribute *attr, char *buf)
 {
-	struct langwell_udc	*dev = the_controller;
+	struct langwell_udc	*dev = dev_get_drvdata(_dev);
 
 	if (!dev->driver || !dev->driver->function
 			|| strlen(dev->driver->function) > PAGE_SIZE)
@@ -1572,11 +1562,25 @@ static ssize_t show_function(struct device *_dev,
 static DEVICE_ATTR(function, S_IRUGO, show_function, NULL);
 
 
+static inline enum usb_device_speed lpm_device_speed(u32 reg)
+{
+	switch (LPM_PSPD(reg)) {
+	case LPM_SPEED_HIGH:
+		return USB_SPEED_HIGH;
+	case LPM_SPEED_FULL:
+		return USB_SPEED_FULL;
+	case LPM_SPEED_LOW:
+		return USB_SPEED_LOW;
+	default:
+		return USB_SPEED_UNKNOWN;
+	}
+}
+
 /* device "langwell_udc" sysfs attribute file */
 static ssize_t show_langwell_udc(struct device *_dev,
 		struct device_attribute *attr, char *buf)
 {
-	struct langwell_udc	*dev = the_controller;
+	struct langwell_udc	*dev = dev_get_drvdata(_dev);
 	struct langwell_request *req;
 	struct langwell_ep	*ep = NULL;
 	char			*next;
@@ -1700,20 +1704,7 @@ static ssize_t show_langwell_udc(struct device *_dev,
 		"BmAttributes: %d\n\n",
 		LPM_PTS(tmp_reg),
 		(tmp_reg & LPM_STS) ? 1 : 0,
-		({
-			char	*s;
-			switch (LPM_PSPD(tmp_reg)) {
-			case LPM_SPEED_FULL:
-				s = "Full Speed"; break;
-			case LPM_SPEED_LOW:
-				s = "Low Speed"; break;
-			case LPM_SPEED_HIGH:
-				s = "High Speed"; break;
-			default:
-				s = "Unknown Speed"; break;
-			}
-			s;
-		}),
+		usb_speed_string(lpm_device_speed(tmp_reg)),
 		(tmp_reg & LPM_PFSC) ? "Force Full Speed" : "Not Force",
 		(tmp_reg & LPM_PHCD) ? "Disabled" : "Enabled",
 		LPM_BA(tmp_reg));
@@ -1821,7 +1812,7 @@ static DEVICE_ATTR(langwell_udc, S_IRUGO, show_langwell_udc, NULL);
 static ssize_t store_remote_wakeup(struct device *_dev,
 		struct device_attribute *attr, const char *buf, size_t count)
 {
-	struct langwell_udc	*dev = the_controller;
+	struct langwell_udc	*dev = dev_get_drvdata(_dev);
 	unsigned long		flags;
 	ssize_t			rc = count;
 
@@ -1857,21 +1848,15 @@ static DEVICE_ATTR(remote_wakeup, S_IWUSR, NULL, store_remote_wakeup);
  * the driver might get unbound.
  */
 
-static int langwell_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+static int langwell_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
-	struct langwell_udc	*dev = the_controller;
+	struct langwell_udc	*dev = gadget_to_langwell(g);
 	unsigned long		flags;
 	int			retval;
 
-	if (!dev)
-		return -ENODEV;
-
 	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
 
-	if (dev->driver)
-		return -EBUSY;
-
 	spin_lock_irqsave(&dev->lock, flags);
 
 	/* hook up the driver ... */
@@ -1881,18 +1866,9 @@ static int langwell_start(struct usb_gadget_driver *driver,
 
 	spin_unlock_irqrestore(&dev->lock, flags);
 
-	retval = bind(&dev->gadget);
-	if (retval) {
-		dev_dbg(&dev->pdev->dev, "bind to driver %s --> %d\n",
-				driver->driver.name, retval);
-		dev->driver = NULL;
-		dev->gadget.dev.driver = NULL;
-		return retval;
-	}
-
 	retval = device_create_file(&dev->pdev->dev, &dev_attr_function);
 	if (retval)
-		goto err_unbind;
+		goto err;
 
 	dev->usb_state = USB_STATE_ATTACHED;
 	dev->ep0_state = WAIT_FOR_SETUP;
@@ -1909,31 +1885,27 @@ static int langwell_start(struct usb_gadget_driver *driver,
 	dev_info(&dev->pdev->dev, "register driver: %s\n",
 			driver->driver.name);
 	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
+
 	return 0;
 
-err_unbind:
-	driver->unbind(&dev->gadget);
+err:
 	dev->gadget.dev.driver = NULL;
 	dev->driver = NULL;
 
 	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
+
 	return retval;
 }
 
 /* unregister gadget driver */
-static int langwell_stop(struct usb_gadget_driver *driver)
+static int langwell_stop(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
-	struct langwell_udc	*dev = the_controller;
+	struct langwell_udc	*dev = gadget_to_langwell(g);
 	unsigned long		flags;
 
-	if (!dev)
-		return -ENODEV;
-
 	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
 
-	if (unlikely(!driver || !driver->unbind))
-		return -EINVAL;
-
 	/* exit PHY low power suspend */
 	if (dev->pdev->device != 0x0829)
 		langwell_phy_low_power(dev, 0);
@@ -1956,8 +1928,6 @@ static int langwell_stop(struct usb_gadget_driver *driver)
 	stop_activity(dev, driver);
 	spin_unlock_irqrestore(&dev->lock, flags);
 
-	/* unbind gadget driver */
-	driver->unbind(&dev->gadget);
 	dev->gadget.dev.driver = NULL;
 	dev->driver = NULL;
 
@@ -1966,6 +1936,7 @@ static int langwell_stop(struct usb_gadget_driver *driver)
 	dev_info(&dev->pdev->dev, "unregistered driver '%s'\n",
 			driver->driver.name);
 	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
+
 	return 0;
 }
 
@@ -2657,12 +2628,10 @@ done:
 	dev_vdbg(&dev->pdev->dev, "<--- %s()\n", __func__);
 }
 
-
 /* port change detect interrupt handler */
 static void handle_port_change(struct langwell_udc *dev)
 {
 	u32	portsc1, devlc;
-	u32	speed;
 
 	dev_vdbg(&dev->pdev->dev, "---> %s()\n", __func__);
 
@@ -2677,24 +2646,9 @@ static void handle_port_change(struct langwell_udc *dev)
 	/* bus reset is finished */
 	if (!(portsc1 & PORTS_PR)) {
 		/* get the speed */
-		speed = LPM_PSPD(devlc);
-		switch (speed) {
-		case LPM_SPEED_HIGH:
-			dev->gadget.speed = USB_SPEED_HIGH;
-			break;
-		case LPM_SPEED_FULL:
-			dev->gadget.speed = USB_SPEED_FULL;
-			break;
-		case LPM_SPEED_LOW:
-			dev->gadget.speed = USB_SPEED_LOW;
-			break;
-		default:
-			dev->gadget.speed = USB_SPEED_UNKNOWN;
-			break;
-		}
-		dev_vdbg(&dev->pdev->dev,
-				"speed = %d, dev->gadget.speed = %d\n",
-				speed, dev->gadget.speed);
+		dev->gadget.speed = lpm_device_speed(devlc);
+		dev_vdbg(&dev->pdev->dev, "dev->gadget.speed = %d\n",
+			dev->gadget.speed);
 	}
 
 	/* LPM L0 to L1 */
@@ -2999,7 +2953,7 @@ static irqreturn_t langwell_irq(int irq, void *_dev)
 /* release device structure */
 static void gadget_release(struct device *_dev)
 {
-	struct langwell_udc	*dev = the_controller;
+	struct langwell_udc	*dev = dev_get_drvdata(_dev);
 
 	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
 
@@ -3057,7 +3011,7 @@ static void sram_deinit(struct langwell_udc *dev)
 /* tear down the binding between this driver and the pci device */
 static void langwell_udc_remove(struct pci_dev *pdev)
 {
-	struct langwell_udc	*dev = the_controller;
+	struct langwell_udc	*dev = pci_get_drvdata(pdev);
 
 	DECLARE_COMPLETION(done);
 
@@ -3124,8 +3078,6 @@ static void langwell_udc_remove(struct pci_dev *pdev)
 
 	/* free dev, wait for the release() finished */
 	wait_for_completion(&done);
-
-	the_controller = NULL;
 }
 
 
@@ -3144,11 +3096,6 @@ static int langwell_udc_probe(struct pci_dev *pdev,
 	size_t			size;
 	int			retval;
 
-	if (the_controller) {
-		dev_warn(&pdev->dev, "ignoring\n");
-		return -EBUSY;
-	}
-
 	/* alloc, and start init */
 	dev = kzalloc(sizeof *dev, GFP_KERNEL);
 	if (dev == NULL) {
@@ -3368,8 +3315,6 @@ static int langwell_udc_probe(struct pci_dev *pdev,
 			"After langwell_udc_probe(), print all registers:\n");
 	print_all_registers(dev);
 
-	the_controller = dev;
-
 	retval = device_register(&dev->gadget.dev);
 	if (retval)
 		goto error;
@@ -3404,7 +3349,7 @@ error:
 /* device controller suspend */
 static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state)
 {
-	struct langwell_udc	*dev = the_controller;
+	struct langwell_udc	*dev = pci_get_drvdata(pdev);
 
 	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
 
@@ -3452,7 +3397,7 @@ static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state)
 /* device controller resume */
 static int langwell_udc_resume(struct pci_dev *pdev)
 {
-	struct langwell_udc	*dev = the_controller;
+	struct langwell_udc	*dev = pci_get_drvdata(pdev);
 	size_t			size;
 
 	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
@@ -3534,7 +3479,7 @@ static int langwell_udc_resume(struct pci_dev *pdev)
 /* pci driver shutdown */
 static void langwell_udc_shutdown(struct pci_dev *pdev)
 {
-	struct langwell_udc	*dev = the_controller;
+	struct langwell_udc	*dev = pci_get_drvdata(pdev);
 	u32			usbmode;
 
 	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);

+ 2 - 10
drivers/usb/gadget/langwell_udc.h

@@ -5,16 +5,6 @@
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
  * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- *
  */
 
 #include <linux/usb/langwell_udc.h>
@@ -231,3 +221,5 @@ struct langwell_udc {
 	u16			dev_status;
 };
 
+#define gadget_to_langwell(g)	container_of((g), struct langwell_udc, gadget)
+

+ 3 - 13
drivers/usb/gadget/m66592-udc.c

@@ -8,16 +8,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
  */
 
 #include <linux/module.h>
@@ -370,7 +360,7 @@ static void m66592_ep_setting(struct m66592 *m66592, struct m66592_ep *ep,
 
 	ep->pipectr = get_pipectr_addr(pipenum);
 	ep->pipenum = pipenum;
-	ep->ep.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+	ep->ep.maxpacket = usb_endpoint_maxp(desc);
 	m66592->pipenum2ep[pipenum] = ep;
 	m66592->epaddr2ep[desc->bEndpointAddress&USB_ENDPOINT_NUMBER_MASK] = ep;
 	INIT_LIST_HEAD(&ep->queue);
@@ -447,7 +437,7 @@ static int alloc_pipe_config(struct m66592_ep *ep,
 	ep->type = info.type;
 
 	info.epnum = desc->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-	info.maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+	info.maxpacket = usb_endpoint_maxp(desc);
 	info.interval = desc->bInterval;
 	if (desc->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
 		info.dir_in = 1;
@@ -1674,7 +1664,7 @@ static int __init m66592_probe(struct platform_device *pdev)
 	m66592->timer.data = (unsigned long)m66592;
 	m66592->reg = reg;
 
-	ret = request_irq(ires->start, m66592_irq, IRQF_DISABLED | IRQF_SHARED,
+	ret = request_irq(ires->start, m66592_irq, IRQF_SHARED,
 			udc_name, m66592);
 	if (ret < 0) {
 		pr_err("request_irq error (%d)\n", ret);

+ 0 - 10
drivers/usb/gadget/m66592-udc.h

@@ -8,16 +8,6 @@
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
  */
 
 #ifndef __M66592_UDC_H__

+ 1 - 10
drivers/usb/gadget/mass_storage.c

@@ -10,15 +10,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 
@@ -169,7 +160,7 @@ static struct usb_composite_driver msg_driver = {
 	.name		= "g_mass_storage",
 	.dev		= &msg_device_desc,
 	.iProduct	= DRIVER_DESC,
-	.max_speed	= USB_SPEED_HIGH,
+	.max_speed	= USB_SPEED_SUPER,
 	.needs_serial	= 1,
 };
 

+ 0 - 9
drivers/usb/gadget/multi.c

@@ -10,15 +10,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 

+ 22 - 4
drivers/usb/gadget/mv_udc.h

@@ -1,3 +1,11 @@
+/*
+ * Copyright (C) 2011 Marvell International Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute  it and/or modify it
+ * under  the terms of  the GNU General  Public License as published by the
+ * Free Software Foundation;  either version 2 of the  License, or (at your
+ * option) any later version.
+ */
 
 #ifndef __MV_UDC_H
 #define __MV_UDC_H
@@ -194,14 +202,25 @@ struct mv_udc {
 	unsigned int		ep0_dir;
 
 	unsigned int		dev_addr;
+	unsigned int		test_mode;
 
 	int			errors;
 	unsigned		softconnect:1,
 				vbus_active:1,
 				remote_wakeup:1,
 				softconnected:1,
-				force_fs:1;
-	struct clk		*clk;
+				force_fs:1,
+				clock_gating:1,
+				active:1;
+
+	struct work_struct	vbus_work;
+	struct workqueue_struct *qwork;
+
+	struct mv_usb_platform_data     *pdata;
+
+	/* some SOC has mutiple clock sources for USB*/
+	unsigned int    clknum;
+	struct clk      *clk[0];
 };
 
 /* endpoint data structure */
@@ -225,6 +244,7 @@ struct mv_req {
 	struct mv_dtd		*dtd, *head, *tail;
 	struct mv_ep		*ep;
 	struct list_head	queue;
+	unsigned int            test_mode;
 	unsigned		dtd_count;
 	unsigned		mapped:1;
 };
@@ -289,6 +309,4 @@ struct mv_dtd {
 	struct mv_dtd *next_dtd_virt;
 };
 
-extern int mv_udc_phy_init(unsigned int base);
-
 #endif

File diff suppressed because it is too large
+ 434 - 114
drivers/usb/gadget/mv_udc_core.c


+ 0 - 214
drivers/usb/gadget/mv_udc_phy.c

@@ -1,214 +0,0 @@
-#include <linux/delay.h>
-#include <linux/timer.h>
-#include <linux/io.h>
-#include <linux/errno.h>
-
-#include <mach/cputype.h>
-
-#ifdef CONFIG_ARCH_MMP
-
-#define UTMI_REVISION		0x0
-#define UTMI_CTRL		0x4
-#define UTMI_PLL		0x8
-#define UTMI_TX			0xc
-#define UTMI_RX			0x10
-#define UTMI_IVREF		0x14
-#define UTMI_T0			0x18
-#define UTMI_T1			0x1c
-#define UTMI_T2			0x20
-#define UTMI_T3			0x24
-#define UTMI_T4			0x28
-#define UTMI_T5			0x2c
-#define UTMI_RESERVE		0x30
-#define UTMI_USB_INT		0x34
-#define UTMI_DBG_CTL		0x38
-#define UTMI_OTG_ADDON		0x3c
-
-/* For UTMICTRL Register */
-#define UTMI_CTRL_USB_CLK_EN			(1 << 31)
-/* pxa168 */
-#define UTMI_CTRL_SUSPEND_SET1			(1 << 30)
-#define UTMI_CTRL_SUSPEND_SET2			(1 << 29)
-#define UTMI_CTRL_RXBUF_PDWN			(1 << 24)
-#define UTMI_CTRL_TXBUF_PDWN			(1 << 11)
-
-#define UTMI_CTRL_INPKT_DELAY_SHIFT		30
-#define UTMI_CTRL_INPKT_DELAY_SOF_SHIFT		28
-#define UTMI_CTRL_PU_REF_SHIFT			20
-#define UTMI_CTRL_ARC_PULLDN_SHIFT		12
-#define UTMI_CTRL_PLL_PWR_UP_SHIFT		1
-#define UTMI_CTRL_PWR_UP_SHIFT			0
-/* For UTMI_PLL Register */
-#define UTMI_PLL_CLK_BLK_EN_SHIFT		24
-#define UTMI_PLL_FBDIV_SHIFT			4
-#define UTMI_PLL_REFDIV_SHIFT			0
-#define UTMI_PLL_FBDIV_MASK			0x00000FF0
-#define UTMI_PLL_REFDIV_MASK			0x0000000F
-#define UTMI_PLL_ICP_MASK			0x00007000
-#define UTMI_PLL_KVCO_MASK			0x00031000
-#define UTMI_PLL_PLLCALI12_SHIFT		29
-#define UTMI_PLL_PLLCALI12_MASK			(0x3 << 29)
-#define UTMI_PLL_PLLVDD18_SHIFT			27
-#define UTMI_PLL_PLLVDD18_MASK			(0x3 << 27)
-#define UTMI_PLL_PLLVDD12_SHIFT			25
-#define UTMI_PLL_PLLVDD12_MASK			(0x3 << 25)
-#define UTMI_PLL_KVCO_SHIFT			15
-#define UTMI_PLL_ICP_SHIFT			12
-/* For UTMI_TX Register */
-#define UTMI_TX_REG_EXT_FS_RCAL_SHIFT		27
-#define UTMI_TX_REG_EXT_FS_RCAL_MASK		(0xf << 27)
-#define UTMI_TX_REG_EXT_FS_RCAL_EN_MASK		26
-#define UTMI_TX_REG_EXT_FS_RCAL_EN		(0x1 << 26)
-#define UTMI_TX_LOW_VDD_EN_SHIFT		11
-#define UTMI_TX_IMPCAL_VTH_SHIFT		14
-#define UTMI_TX_IMPCAL_VTH_MASK			(0x7 << 14)
-#define UTMI_TX_CK60_PHSEL_SHIFT		17
-#define UTMI_TX_CK60_PHSEL_MASK			(0xf << 17)
-#define UTMI_TX_TXVDD12_SHIFT                   22
-#define UTMI_TX_TXVDD12_MASK			(0x3 << 22)
-#define UTMI_TX_AMP_SHIFT			0
-#define UTMI_TX_AMP_MASK			(0x7 << 0)
-/* For UTMI_RX Register */
-#define UTMI_RX_SQ_THRESH_SHIFT			4
-#define UTMI_RX_SQ_THRESH_MASK			(0xf << 4)
-#define UTMI_REG_SQ_LENGTH_SHIFT		15
-#define UTMI_REG_SQ_LENGTH_MASK			(0x3 << 15)
-
-#define REG_RCAL_START				0x00001000
-#define VCOCAL_START				0x00200000
-#define KVCO_EXT				0x00400000
-#define PLL_READY				0x00800000
-#define CLK_BLK_EN				0x01000000
-#endif
-
-static unsigned int u2o_read(unsigned int base, unsigned int offset)
-{
-	return readl(base + offset);
-}
-
-static void u2o_set(unsigned int base, unsigned int offset, unsigned int value)
-{
-	unsigned int reg;
-
-	reg = readl(base + offset);
-	reg |= value;
-	writel(reg, base + offset);
-	readl(base + offset);
-}
-
-static void u2o_clear(unsigned int base, unsigned int offset,
-	unsigned int value)
-{
-	unsigned int reg;
-
-	reg = readl(base + offset);
-	reg &= ~value;
-	writel(reg, base + offset);
-	readl(base + offset);
-}
-
-static void u2o_write(unsigned int base, unsigned int offset,
-	unsigned int value)
-{
-	writel(value, base + offset);
-	readl(base + offset);
-}
-
-#ifdef CONFIG_ARCH_MMP
-int mv_udc_phy_init(unsigned int base)
-{
-	unsigned long timeout;
-
-	/* Initialize the USB PHY power */
-	if (cpu_is_pxa910()) {
-		u2o_set(base, UTMI_CTRL, (1 << UTMI_CTRL_INPKT_DELAY_SOF_SHIFT)
-			| (1 << UTMI_CTRL_PU_REF_SHIFT));
-	}
-
-	u2o_set(base, UTMI_CTRL, 1 << UTMI_CTRL_PLL_PWR_UP_SHIFT);
-	u2o_set(base, UTMI_CTRL, 1 << UTMI_CTRL_PWR_UP_SHIFT);
-
-	/* UTMI_PLL settings */
-	u2o_clear(base, UTMI_PLL, UTMI_PLL_PLLVDD18_MASK
-		| UTMI_PLL_PLLVDD12_MASK | UTMI_PLL_PLLCALI12_MASK
-		| UTMI_PLL_FBDIV_MASK | UTMI_PLL_REFDIV_MASK
-		| UTMI_PLL_ICP_MASK | UTMI_PLL_KVCO_MASK);
-
-	u2o_set(base, UTMI_PLL, (0xee << UTMI_PLL_FBDIV_SHIFT)
-		| (0xb << UTMI_PLL_REFDIV_SHIFT)
-		| (3 << UTMI_PLL_PLLVDD18_SHIFT)
-		| (3 << UTMI_PLL_PLLVDD12_SHIFT)
-		| (3 << UTMI_PLL_PLLCALI12_SHIFT)
-		| (1 << UTMI_PLL_ICP_SHIFT) | (3 << UTMI_PLL_KVCO_SHIFT));
-
-	/* UTMI_TX */
-	u2o_clear(base, UTMI_TX, UTMI_TX_REG_EXT_FS_RCAL_EN_MASK
-		| UTMI_TX_TXVDD12_MASK
-		| UTMI_TX_CK60_PHSEL_MASK | UTMI_TX_IMPCAL_VTH_MASK
-		| UTMI_TX_REG_EXT_FS_RCAL_MASK | UTMI_TX_AMP_MASK);
-	u2o_set(base, UTMI_TX, (3 << UTMI_TX_TXVDD12_SHIFT)
-		| (4 << UTMI_TX_CK60_PHSEL_SHIFT)
-		| (4 << UTMI_TX_IMPCAL_VTH_SHIFT)
-		| (8 << UTMI_TX_REG_EXT_FS_RCAL_SHIFT)
-		| (3 << UTMI_TX_AMP_SHIFT));
-
-	/* UTMI_RX */
-	u2o_clear(base, UTMI_RX, UTMI_RX_SQ_THRESH_MASK
-		| UTMI_REG_SQ_LENGTH_MASK);
-	if (cpu_is_pxa168())
-		u2o_set(base, UTMI_RX, (7 << UTMI_RX_SQ_THRESH_SHIFT)
-			| (2 << UTMI_REG_SQ_LENGTH_SHIFT));
-	else
-		u2o_set(base, UTMI_RX, (0x7 << UTMI_RX_SQ_THRESH_SHIFT)
-			| (2 << UTMI_REG_SQ_LENGTH_SHIFT));
-
-	/* UTMI_IVREF */
-	if (cpu_is_pxa168())
-		/*
-		 * fixing Microsoft Altair board interface with NEC hub issue -
-		 * Set UTMI_IVREF from 0x4a3 to 0x4bf
-		 */
-		u2o_write(base, UTMI_IVREF, 0x4bf);
-
-	/* calibrate */
-	timeout = jiffies + 100;
-	while ((u2o_read(base, UTMI_PLL) & PLL_READY) == 0) {
-		if (time_after(jiffies, timeout))
-			return -ETIME;
-		cpu_relax();
-	}
-
-	/* toggle VCOCAL_START bit of UTMI_PLL */
-	udelay(200);
-	u2o_set(base, UTMI_PLL, VCOCAL_START);
-	udelay(40);
-	u2o_clear(base, UTMI_PLL, VCOCAL_START);
-
-	/* toggle REG_RCAL_START bit of UTMI_TX */
-	udelay(200);
-	u2o_set(base, UTMI_TX, REG_RCAL_START);
-	udelay(40);
-	u2o_clear(base, UTMI_TX, REG_RCAL_START);
-	udelay(200);
-
-	/* make sure phy is ready */
-	timeout = jiffies + 100;
-	while ((u2o_read(base, UTMI_PLL) & PLL_READY) == 0) {
-		if (time_after(jiffies, timeout))
-			return -ETIME;
-		cpu_relax();
-	}
-
-	if (cpu_is_pxa168()) {
-		u2o_set(base, UTMI_RESERVE, 1 << 5);
-		/* Turn on UTMI PHY OTG extension */
-		u2o_write(base, UTMI_OTG_ADDON, 1);
-	}
-	return 0;
-}
-#else
-int mv_udc_phy_init(unsigned int base)
-{
-	return 0;
-}
-#endif

+ 0 - 9
drivers/usb/gadget/ncm.c

@@ -14,15 +14,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 /* #define DEBUG */

+ 0 - 6
drivers/usb/gadget/ndis.h

@@ -10,12 +10,6 @@
  *
  * This source code is offered for use in the public domain. You may
  * use, modify or distribute it freely.
- *
- * This code is distributed in the hope that it will be useful but
- * WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
- * DISCLAIMED. This includes but is not limited to warranties of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
  */
 
 #ifndef _LINUX_NDIS_H

+ 22 - 56
drivers/usb/gadget/net2272.c

@@ -204,7 +204,7 @@ net2272_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
 		return -ESHUTDOWN;
 
-	max = le16_to_cpu(desc->wMaxPacketSize) & 0x1fff;
+	max = usb_endpoint_maxp(desc) & 0x1fff;
 
 	spin_lock_irqsave(&dev->lock, flags);
 	_ep->maxpacket = max & 0x7fff;
@@ -1172,17 +1172,18 @@ net2272_pullup(struct usb_gadget *_gadget, int is_on)
 	return 0;
 }
 
-static int net2272_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *));
-static int net2272_stop(struct usb_gadget_driver *driver);
+static int net2272_start(struct usb_gadget *_gadget,
+		struct usb_gadget_driver *driver);
+static int net2272_stop(struct usb_gadget *_gadget,
+		struct usb_gadget_driver *driver);
 
 static const struct usb_gadget_ops net2272_ops = {
-	.get_frame       = net2272_get_frame,
-	.wakeup          = net2272_wakeup,
+	.get_frame	= net2272_get_frame,
+	.wakeup		= net2272_wakeup,
 	.set_selfpowered = net2272_set_selfpowered,
-	.pullup			= net2272_pullup,
-	.start			= net2272_start,
-	.stop			= net2272_stop,
+	.pullup		= net2272_pullup,
+	.udc_start	= net2272_start,
+	.udc_stop	= net2272_stop,
 };
 
 /*---------------------------------------------------------------------------*/
@@ -1356,8 +1357,6 @@ net2272_set_fifo_mode(struct net2272 *dev, int mode)
 
 /*---------------------------------------------------------------------------*/
 
-static struct net2272 *the_controller;
-
 static void
 net2272_usb_reset(struct net2272 *dev)
 {
@@ -1453,20 +1452,17 @@ net2272_ep0_start(struct net2272 *dev)
  * disconnect is reported.  then a host may connect again, or
  * the driver might get unbound.
  */
-static int net2272_start(struct usb_gadget_driver *driver,
-	int (*bind)(struct usb_gadget *))
+static int net2272_start(struct usb_gadget *_gadget,
+		struct usb_gadget_driver *driver)
 {
-	struct net2272 *dev = the_controller;
-	int ret;
+	struct net2272 *dev;
 	unsigned i;
 
-	if (!driver || !bind || !driver->unbind || !driver->setup ||
+	if (!driver || !driver->unbind || !driver->setup ||
 	    driver->speed != USB_SPEED_HIGH)
 		return -EINVAL;
-	if (!dev)
-		return -ENODEV;
-	if (dev->driver)
-		return -EBUSY;
+
+	dev = container_of(_gadget, struct net2272, gadget);
 
 	for (i = 0; i < 4; ++i)
 		dev->ep[i].irqs = 0;
@@ -1475,14 +1471,6 @@ static int net2272_start(struct usb_gadget_driver *driver,
 	driver->driver.bus = NULL;
 	dev->driver = driver;
 	dev->gadget.dev.driver = &driver->driver;
-	ret = bind(&dev->gadget);
-	if (ret) {
-		dev_dbg(dev->dev, "bind to driver %s --> %d\n",
-			driver->driver.name, ret);
-		dev->driver = NULL;
-		dev->gadget.dev.driver = NULL;
-		return ret;
-	}
 
 	/* ... then enable host detection and ep0; and we're ready
 	 * for set_configuration as well as eventual disconnect.
@@ -1510,33 +1498,21 @@ stop_activity(struct net2272 *dev, struct usb_gadget_driver *driver)
 	for (i = 0; i < 4; ++i)
 		net2272_dequeue_all(&dev->ep[i]);
 
-	/* report disconnect; the driver is already quiesced */
-	if (driver) {
-		spin_unlock(&dev->lock);
-		driver->disconnect(&dev->gadget);
-		spin_lock(&dev->lock);
-
-	}
 	net2272_usb_reinit(dev);
 }
 
-static int net2272_stop(struct usb_gadget_driver *driver)
+static int net2272_stop(struct usb_gadget *_gadget,
+		struct usb_gadget_driver *driver)
 {
-	struct net2272 *dev = the_controller;
+	struct net2272 *dev;
 	unsigned long flags;
 
-	if (!dev)
-		return -ENODEV;
-	if (!driver || driver != dev->driver)
-		return -EINVAL;
+	dev = container_of(_gadget, struct net2272, gadget);
 
 	spin_lock_irqsave(&dev->lock, flags);
 	stop_activity(dev, driver);
 	spin_unlock_irqrestore(&dev->lock, flags);
 
-	net2272_pullup(&dev->gadget, 0);
-
-	driver->unbind(&dev->gadget);
 	dev->gadget.dev.driver = NULL;
 	dev->driver = NULL;
 
@@ -1764,8 +1740,8 @@ net2272_handle_stat0_irqs(struct net2272 *dev, u8 stat)
 				dev->gadget.speed = USB_SPEED_HIGH;
 			else
 				dev->gadget.speed = USB_SPEED_FULL;
-			dev_dbg(dev->dev, "%s speed\n",
-				(dev->gadget.speed == USB_SPEED_HIGH) ? "high" : "full");
+			dev_dbg(dev->dev, "%s\n",
+				usb_speed_string(dev->gadget.speed));
 		}
 
 		ep = &dev->ep[0];
@@ -2238,7 +2214,6 @@ net2272_remove(struct net2272 *dev)
 	device_remove_file(dev->dev, &dev_attr_registers);
 
 	dev_info(dev->dev, "unbind\n");
-	the_controller = NULL;
 }
 
 static struct net2272 * __devinit
@@ -2246,11 +2221,6 @@ net2272_probe_init(struct device *dev, unsigned int irq)
 {
 	struct net2272 *ret;
 
-	if (the_controller) {
-		dev_warn(dev, "ignoring\n");
-		return ERR_PTR(-EBUSY);
-	}
-
 	if (!irq) {
 		dev_dbg(dev, "No IRQ!\n");
 		return ERR_PTR(-ENODEV);
@@ -2307,8 +2277,6 @@ net2272_probe_fin(struct net2272 *dev, unsigned int irqflags)
 		dma_mode_string());
 	dev_info(dev->dev, "version: %s\n", driver_vers);
 
-	the_controller = dev;
-
 	ret = device_register(&dev->gadget.dev);
 	if (ret)
 		goto err_irq;
@@ -2684,8 +2652,6 @@ net2272_plat_probe(struct platform_device *pdev)
 	dev_info(&pdev->dev, "running in 16-bit, %sbyte swap local bus mode\n",
 		(net2272_read(dev, LOCCTL) & (1 << BYTE_SWAP)) ? "" : "no ");
 
-	the_controller = dev;
-
 	return 0;
 
  err_io:

+ 20 - 67
drivers/usb/gadget/net2280.c

@@ -33,15 +33,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #undef	DEBUG		/* messages on error and most fault paths */
@@ -169,7 +160,7 @@ net2280_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 		return -EDOM;
 
 	/* sanity check ep-e/ep-f since their fifos are small */
-	max = le16_to_cpu (desc->wMaxPacketSize) & 0x1fff;
+	max = usb_endpoint_maxp (desc) & 0x1fff;
 	if (ep->num > 4 && max > 64)
 		return -ERANGE;
 
@@ -1410,17 +1401,18 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on)
 	return 0;
 }
 
-static int net2280_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *));
-static int net2280_stop(struct usb_gadget_driver *driver);
+static int net2280_start(struct usb_gadget *_gadget,
+		struct usb_gadget_driver *driver);
+static int net2280_stop(struct usb_gadget *_gadget,
+		struct usb_gadget_driver *driver);
 
 static const struct usb_gadget_ops net2280_ops = {
 	.get_frame	= net2280_get_frame,
 	.wakeup		= net2280_wakeup,
 	.set_selfpowered = net2280_set_selfpowered,
 	.pullup		= net2280_pullup,
-	.start		= net2280_start,
-	.stop		= net2280_stop,
+	.udc_start	= net2280_start,
+	.udc_stop	= net2280_stop,
 };
 
 /*-------------------------------------------------------------------------*/
@@ -1640,7 +1632,7 @@ show_queues (struct device *_dev, struct device_attribute *attr, char *buf)
 				 default:
 					val = "iso"; break;
 				 }; val; }),
-				le16_to_cpu (d->wMaxPacketSize) & 0x1fff,
+				usb_endpoint_maxp (d) & 0x1fff,
 				ep->dma ? "dma" : "pio", ep->fifo_size
 				);
 		} else /* ep0 should only have one transfer queued */
@@ -1753,8 +1745,6 @@ static void set_fifo_mode (struct net2280 *dev, int mode)
  * perhaps to bind specific drivers to specific devices.
  */
 
-static struct net2280	*the_controller;
-
 static void usb_reset (struct net2280 *dev)
 {
 	u32	tmp;
@@ -1880,10 +1870,10 @@ static void ep0_start (struct net2280 *dev)
  * disconnect is reported.  then a host may connect again, or
  * the driver might get unbound.
  */
-static int net2280_start(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+static int net2280_start(struct usb_gadget *_gadget,
+		struct usb_gadget_driver *driver)
 {
-	struct net2280		*dev = the_controller;
+	struct net2280		*dev;
 	int			retval;
 	unsigned		i;
 
@@ -1891,14 +1881,11 @@ static int net2280_start(struct usb_gadget_driver *driver,
 	 * (dev->usb->xcvrdiag & FORCE_FULL_SPEED_MODE)
 	 * "must not be used in normal operation"
 	 */
-	if (!driver
-			|| driver->speed != USB_SPEED_HIGH
-			|| !bind || !driver->setup)
+	if (!driver || driver->speed != USB_SPEED_HIGH
+			|| !driver->setup)
 		return -EINVAL;
-	if (!dev)
-		return -ENODEV;
-	if (dev->driver)
-		return -EBUSY;
+
+	dev = container_of (_gadget, struct net2280, gadget);
 
 	for (i = 0; i < 7; i++)
 		dev->ep [i].irqs = 0;
@@ -1908,14 +1895,6 @@ static int net2280_start(struct usb_gadget_driver *driver,
 	driver->driver.bus = NULL;
 	dev->driver = driver;
 	dev->gadget.dev.driver = &driver->driver;
-	retval = bind(&dev->gadget);
-	if (retval) {
-		DEBUG (dev, "bind to driver %s --> %d\n",
-				driver->driver.name, retval);
-		dev->driver = NULL;
-		dev->gadget.dev.driver = NULL;
-		return retval;
-	}
 
 	retval = device_create_file (&dev->pdev->dev, &dev_attr_function);
 	if (retval) goto err_unbind;
@@ -1961,33 +1940,21 @@ stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver)
 	for (i = 0; i < 7; i++)
 		nuke (&dev->ep [i]);
 
-	/* report disconnect; the driver is already quiesced */
-	if (driver) {
-		spin_unlock (&dev->lock);
-		driver->disconnect (&dev->gadget);
-		spin_lock (&dev->lock);
-	}
-
 	usb_reinit (dev);
 }
 
-static int net2280_stop(struct usb_gadget_driver *driver)
+static int net2280_stop(struct usb_gadget *_gadget,
+		struct usb_gadget_driver *driver)
 {
-	struct net2280	*dev = the_controller;
+	struct net2280	*dev;
 	unsigned long	flags;
 
-	if (!dev)
-		return -ENODEV;
-	if (!driver || driver != dev->driver || !driver->unbind)
-		return -EINVAL;
+	dev = container_of (_gadget, struct net2280, gadget);
 
 	spin_lock_irqsave (&dev->lock, flags);
 	stop_activity (dev, driver);
 	spin_unlock_irqrestore (&dev->lock, flags);
 
-	net2280_pullup (&dev->gadget, 0);
-
-	driver->unbind (&dev->gadget);
 	dev->gadget.dev.driver = NULL;
 	dev->driver = NULL;
 
@@ -2266,9 +2233,7 @@ static void handle_stat0_irqs (struct net2280 *dev, u32 stat)
 			else
 				dev->gadget.speed = USB_SPEED_FULL;
 			net2280_led_speed (dev, dev->gadget.speed);
-			DEBUG (dev, "%s speed\n",
-				(dev->gadget.speed == USB_SPEED_HIGH)
-					? "high" : "full");
+			DEBUG(dev, "%s\n", usb_speed_string(dev->gadget.speed));
 		}
 
 		ep = &dev->ep [0];
@@ -2709,8 +2674,6 @@ static void net2280_remove (struct pci_dev *pdev)
 	pci_set_drvdata (pdev, NULL);
 
 	INFO (dev, "unbind\n");
-
-	the_controller = NULL;
 }
 
 /* wrap this driver around the specified device, but
@@ -2724,14 +2687,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
 	void			__iomem *base = NULL;
 	int			retval, i;
 
-	/* if you want to support more than one controller in a system,
-	 * usb_gadget_driver_{register,unregister}() must change.
-	 */
-	if (the_controller) {
-		dev_warn (&pdev->dev, "ignoring\n");
-		return -EBUSY;
-	}
-
 	/* alloc, and start init */
 	dev = kzalloc (sizeof *dev, GFP_KERNEL);
 	if (dev == NULL){
@@ -2858,8 +2813,6 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
 			use_dma
 				? (use_dma_chaining ? "chaining" : "enabled")
 				: "disabled");
-	the_controller = dev;
-
 	retval = device_register (&dev->gadget.dev);
 	if (retval) goto done;
 	retval = device_create_file (&pdev->dev, &dev_attr_registers);

+ 0 - 9
drivers/usb/gadget/net2280.h

@@ -11,15 +11,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #include <linux/usb/net2280.h>

+ 4 - 14
drivers/usb/gadget/omap_udc.c

@@ -10,15 +10,6 @@
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
 #undef	DEBUG
@@ -166,15 +157,14 @@ static int omap_ep_enable(struct usb_ep *_ep,
 	if (!_ep || !desc || ep->desc
 			|| desc->bDescriptorType != USB_DT_ENDPOINT
 			|| ep->bEndpointAddress != desc->bEndpointAddress
-			|| ep->maxpacket < le16_to_cpu
-						(desc->wMaxPacketSize)) {
+			|| ep->maxpacket < usb_endpoint_maxp(desc)) {
 		DBG("%s, bad ep or descriptor\n", __func__);
 		return -EINVAL;
 	}
-	maxp = le16_to_cpu (desc->wMaxPacketSize);
+	maxp = usb_endpoint_maxp(desc);
 	if ((desc->bmAttributes == USB_ENDPOINT_XFER_BULK
 				&& maxp != ep->maxpacket)
-			|| le16_to_cpu(desc->wMaxPacketSize) > ep->maxpacket
+			|| usb_endpoint_maxp(desc) > ep->maxpacket
 			|| !desc->wMaxPacketSize) {
 		DBG("%s, bad %s maxpacket\n", __func__, _ep->name);
 		return -ERANGE;
@@ -2968,7 +2958,7 @@ known:
 	}
 #ifdef	USE_ISO
 	status = request_irq(pdev->resource[3].start, omap_udc_iso_irq,
-			IRQF_DISABLED, "omap_udc iso", udc);
+			0, "omap_udc iso", udc);
 	if (status != 0) {
 		ERR("can't get irq %d, err %d\n",
 			(int) pdev->resource[3].start, status);

Some files were not shown because too many files changed in this diff