Quellcode durchsuchen

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

* 'usb-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb-2.6: (115 commits)
  EHCI: fix direction handling for interrupt data toggles
  USB: serial: add IDs for WinChipHead USB->RS232 adapter
  USB: OHCI: fix another regression for NVIDIA controllers
  usb: gadget: m66592-udc: add pullup function
  usb: gadget: m66592-udc: add function for external controller
  usb: gadget: r8a66597-udc: add pullup function
  usb: renesas_usbhs: support multi driver
  usb: renesas_usbhs: inaccessible pipe is not an error
  usb: renesas_usbhs: care buff alignment when dma handler
  USB: PL2303: correctly handle baudrates above 115200
  usb: r8a66597-hcd: fixup USB_PORT_STAT_C_SUSPEND shift
  usb: renesas_usbhs: compile/config are rescued
  usb: renesas_usbhs: fixup comment-out
  usb: update email address in ohci-sh and r8a66597-hcd
  usb: r8a66597-hcd: add function for external controller
  EHCI: only power off port if over-current is active
  USB: mon: Allow to use usbmon without debugfs
  USB: EHCI: go back to using the system clock for QH unlinks
  ehci: add pci quirk for Ordissimo and RM Slate 100 too
  ehci: refactor pci quirk to use standard dmi_check_system method
  ...

Fix up trivial conflicts in Documentation/feature-removal-schedule.txt
Linus Torvalds vor 14 Jahren
Ursprung
Commit
f549953c15
100 geänderte Dateien mit 6905 neuen und 1775 gelöschten Zeilen
  1. 23 0
      Documentation/ABI/testing/sysfs-module
  2. 7 0
      Documentation/feature-removal-schedule.txt
  3. 5 0
      Documentation/kernel-parameters.txt
  4. 2 0
      Documentation/usb/ehci.txt
  5. 3 3
      Documentation/usb/gadget_hid.txt
  6. 0 10
      arch/arm/mach-omap2/usb-musb.c
  7. 19 19
      drivers/usb/atm/ueagle-atm.c
  8. 2 2
      drivers/usb/atm/usbatm.c
  9. 3 4
      drivers/usb/class/usblp.c
  10. 16 1
      drivers/usb/core/hcd.c
  11. 100 213
      drivers/usb/gadget/Kconfig
  12. 2 0
      drivers/usb/gadget/Makefile
  13. 13 5
      drivers/usb/gadget/amd5536udc.c
  14. 15 5
      drivers/usb/gadget/at91_udc.c
  15. 22 4
      drivers/usb/gadget/atmel_usba_udc.c
  16. 1 0
      drivers/usb/gadget/audio.c
  17. 1 0
      drivers/usb/gadget/cdc2.c
  18. 1 0
      drivers/usb/gadget/ci13xxx_msm.c
  19. 44 18
      drivers/usb/gadget/ci13xxx_udc.c
  20. 339 24
      drivers/usb/gadget/composite.c
  21. 0 25
      drivers/usb/gadget/config.c
  22. 6 4
      drivers/usb/gadget/dbgp.c
  23. 794 368
      drivers/usb/gadget/dummy_hcd.c
  24. 104 28
      drivers/usb/gadget/epautoconf.c
  25. 1 0
      drivers/usb/gadget/ether.c
  26. 15 35
      drivers/usb/gadget/f_acm.c
  27. 2 3
      drivers/usb/gadget/f_audio.c
  28. 115 37
      drivers/usb/gadget/f_ecm.c
  29. 66 24
      drivers/usb/gadget/f_eem.c
  30. 2 1
      drivers/usb/gadget/f_fs.c
  31. 7 15
      drivers/usb/gadget/f_hid.c
  32. 63 9
      drivers/usb/gadget/f_loopback.c
  33. 13 20
      drivers/usb/gadget/f_mass_storage.c
  34. 19 39
      drivers/usb/gadget/f_ncm.c
  35. 9 23
      drivers/usb/gadget/f_obex.c
  36. 8 9
      drivers/usb/gadget/f_phonet.c
  37. 113 38
      drivers/usb/gadget/f_rndis.c
  38. 8 24
      drivers/usb/gadget/f_serial.c
  39. 64 7
      drivers/usb/gadget/f_sourcesink.c
  40. 71 24
      drivers/usb/gadget/f_subset.c
  41. 5 3
      drivers/usb/gadget/f_uvc.c
  42. 10 5
      drivers/usb/gadget/file_storage.c
  43. 16 4
      drivers/usb/gadget/fsl_qe_udc.c
  44. 16 4
      drivers/usb/gadget/fsl_udc_core.c
  45. 19 92
      drivers/usb/gadget/fusb300_udc.c
  46. 1 0
      drivers/usb/gadget/g_ffs.c
  47. 35 143
      drivers/usb/gadget/gadget_chips.h
  48. 5 4
      drivers/usb/gadget/gmidi.c
  49. 14 5
      drivers/usb/gadget/goku_udc.c
  50. 1 0
      drivers/usb/gadget/hid.c
  51. 15 5
      drivers/usb/gadget/imx_udc.c
  52. 6 5
      drivers/usb/gadget/inode.c
  53. 19 13
      drivers/usb/gadget/langwell_udc.c
  54. 54 8
      drivers/usb/gadget/m66592-udc.c
  55. 22 18
      drivers/usb/gadget/m66592-udc.h
  56. 1 0
      drivers/usb/gadget/mass_storage.c
  57. 1 0
      drivers/usb/gadget/multi.c
  58. 13 8
      drivers/usb/gadget/mv_udc_core.c
  59. 1 0
      drivers/usb/gadget/ncm.c
  60. 2752 0
      drivers/usb/gadget/net2272.c
  61. 601 0
      drivers/usb/gadget/net2272.h
  62. 13 61
      drivers/usb/gadget/net2280.c
  63. 1 0
      drivers/usb/gadget/nokia.c
  64. 17 5
      drivers/usb/gadget/omap_udc.c
  65. 12 4
      drivers/usb/gadget/pch_udc.c
  66. 23 17
      drivers/usb/gadget/printer.c
  67. 13 6
      drivers/usb/gadget/pxa25x_udc.c
  68. 16 7
      drivers/usb/gadget/pxa27x_udc.c
  69. 58 13
      drivers/usb/gadget/r8a66597-udc.c
  70. 1 1
      drivers/usb/gadget/r8a66597-udc.h
  71. 15 4
      drivers/usb/gadget/s3c-hsotg.c
  72. 13 4
      drivers/usb/gadget/s3c-hsudc.c
  73. 28 32
      drivers/usb/gadget/s3c2410_udc.c
  74. 1 0
      drivers/usb/gadget/serial.c
  75. 1 1
      drivers/usb/gadget/storage_common.c
  76. 13 11
      drivers/usb/gadget/u_ether.c
  77. 0 4
      drivers/usb/gadget/u_ether.h
  78. 2 2
      drivers/usb/gadget/u_serial.c
  79. 0 2
      drivers/usb/gadget/u_serial.h
  80. 484 0
      drivers/usb/gadget/udc-core.c
  81. 1 0
      drivers/usb/gadget/webcam.c
  82. 1 0
      drivers/usb/gadget/zero.c
  83. 13 8
      drivers/usb/host/ehci-hcd.c
  84. 2 76
      drivers/usb/host/ehci-hub.c
  85. 1 19
      drivers/usb/host/ehci-msm.c
  86. 42 43
      drivers/usb/host/ehci-q.c
  87. 95 0
      drivers/usb/host/ehci-s5p.c
  88. 7 10
      drivers/usb/host/ehci-sched.c
  89. 190 0
      drivers/usb/host/ehci-sysfs.c
  90. 5 1
      drivers/usb/host/ehci.h
  91. 1 1
      drivers/usb/host/ohci-sh.c
  92. 49 7
      drivers/usb/host/pci-quirks.c
  93. 3 3
      drivers/usb/host/r8a66597-hcd.c
  94. 21 17
      drivers/usb/host/r8a66597.h
  95. 11 11
      drivers/usb/host/xhci-dbg.c
  96. 13 13
      drivers/usb/host/xhci-mem.c
  97. 17 25
      drivers/usb/host/xhci-ring.c
  98. 4 6
      drivers/usb/host/xhci.c
  99. 7 0
      drivers/usb/host/xhci.h
  100. 6 3
      drivers/usb/mon/mon_text.c

+ 23 - 0
Documentation/ABI/testing/sysfs-module

@@ -10,3 +10,26 @@ KernelVersion:	2.6.35
 Contact:	masa-korg@dsn.okisemi.com
 Contact:	masa-korg@dsn.okisemi.com
 Description:	Write/read Option ROM data.
 Description:	Write/read Option ROM data.
 
 
+
+What:		/sys/module/ehci_hcd/drivers/.../uframe_periodic_max
+Date:		July 2011
+KernelVersion:	3.1
+Contact:	Kirill Smelkov <kirr@mns.spb.ru>
+Description:	Maximum time allowed for periodic transfers per microframe (μs)
+
+		[ USB 2.0 sets maximum allowed time for periodic transfers per
+		  microframe to be 80%, that is 100 microseconds out of 125
+		  microseconds (full microframe).
+
+		  However there are cases, when 80% max isochronous bandwidth is
+		  too limiting. For example two video streams could require 110
+		  microseconds of isochronous bandwidth per microframe to work
+		  together. ]
+
+		Through this setting it is possible to raise the limit so that
+		the host controller would allow allocating more than 100
+		microseconds of periodic bandwidth per microframe.
+
+		Beware, non-standard modes are usually not thoroughly tested by
+		hardware designers, and the hardware can malfunction when this
+		setting differ from default 100.

+ 7 - 0
Documentation/feature-removal-schedule.txt

@@ -569,3 +569,10 @@ Why:	Just opening a V4L device should not change the state of the hardware
 Who:	Hans Verkuil <hans.verkuil@cisco.com>
 Who:	Hans Verkuil <hans.verkuil@cisco.com>
 
 
 ----------------------------
 ----------------------------
+
+What:	g_file_storage driver
+When:	3.8
+Why:	This driver has been superseded by g_mass_storage.
+Who:	Alan Stern <stern@rowland.harvard.edu>
+
+----------------------------

+ 5 - 0
Documentation/kernel-parameters.txt

@@ -2545,6 +2545,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
 	unknown_nmi_panic
 	unknown_nmi_panic
 			[X86] Cause panic on unknown NMI.
 			[X86] Cause panic on unknown NMI.
 
 
+	usbcore.authorized_default=
+			[USB] Default USB device authorization:
+			(default -1 = authorized except for wireless USB,
+			0 = not authorized, 1 = authorized)
+
 	usbcore.autosuspend=
 	usbcore.autosuspend=
 			[USB] The autosuspend time delay (in seconds) used
 			[USB] The autosuspend time delay (in seconds) used
 			for newly-detected USB devices (default 2).  This
 			for newly-detected USB devices (default 2).  This

+ 2 - 0
Documentation/usb/ehci.txt

@@ -210,3 +210,5 @@ TBD:  Interrupt and ISO transfer performance issues.  Those periodic
 transfers are fully scheduled, so the main issue is likely to be how
 transfers are fully scheduled, so the main issue is likely to be how
 to trigger "high bandwidth" modes.
 to trigger "high bandwidth" modes.
 
 
+TBD:  More than standard 80% periodic bandwidth allocation is possible
+through sysfs uframe_periodic_max parameter. Describe that.

+ 3 - 3
Documentation/usb/gadget_hid.txt

@@ -81,8 +81,8 @@ Send and receive HID reports
 	to do this.
 	to do this.
 
 
 	hid_gadget_test is a small interactive program to test the HID
 	hid_gadget_test is a small interactive program to test the HID
- 	gadget driver. To use, point it at a hidg device and set the
- 	device type (keyboard / mouse / joystick) - E.G.:
+	gadget driver. To use, point it at a hidg device and set the
+	device type (keyboard / mouse / joystick) - E.G.:
 
 
 		# hid_gadget_test /dev/hidg0 keyboard
 		# hid_gadget_test /dev/hidg0 keyboard
 
 
@@ -97,7 +97,7 @@ Send and receive HID reports
 	HID gadget.
 	HID gadget.
 
 
 	Another interesting example is the caps lock test. Type
 	Another interesting example is the caps lock test. Type
-	-caps-lock and hit return. A report is then sent by the
+	--caps-lock and hit return. A report is then sent by the
 	gadget and you should receive the host answer, corresponding
 	gadget and you should receive the host answer, corresponding
 	to the caps lock LED status.
 	to the caps lock LED status.
 
 

+ 0 - 10
arch/arm/mach-omap2/usb-musb.c

@@ -33,8 +33,6 @@
 #include <plat/omap_device.h>
 #include <plat/omap_device.h>
 #include "mux.h"
 #include "mux.h"
 
 
-#if defined(CONFIG_USB_MUSB_OMAP2PLUS) || defined (CONFIG_USB_MUSB_AM35X)
-
 static struct musb_hdrc_config musb_config = {
 static struct musb_hdrc_config musb_config = {
 	.multipoint	= 1,
 	.multipoint	= 1,
 	.dyn_fifo	= 1,
 	.dyn_fifo	= 1,
@@ -175,11 +173,3 @@ void __init usb_musb_init(struct omap_musb_board_data *musb_board_data)
 	if (cpu_is_omap44xx())
 	if (cpu_is_omap44xx())
 		omap4430_phy_init(dev);
 		omap4430_phy_init(dev);
 }
 }
-
-#else
-void __init usb_musb_init(struct omap_musb_board_data *board_data)
-{
-	if (cpu_is_omap44xx())
-		omap4430_phy_init(NULL);
-}
-#endif /* CONFIG_USB_MUSB_SOC */

+ 19 - 19
drivers/usb/atm/ueagle-atm.c

@@ -116,14 +116,14 @@ struct uea_cmvs_v1 {
 	u32 address;
 	u32 address;
 	u16 offset;
 	u16 offset;
 	u32 data;
 	u32 data;
-} __attribute__ ((packed));
+} __packed;
 
 
 struct uea_cmvs_v2 {
 struct uea_cmvs_v2 {
 	u32 group;
 	u32 group;
 	u32 address;
 	u32 address;
 	u32 offset;
 	u32 offset;
 	u32 data;
 	u32 data;
-} __attribute__ ((packed));
+} __packed;
 
 
 /* information about currently processed cmv */
 /* information about currently processed cmv */
 struct cmv_dsc_e1 {
 struct cmv_dsc_e1 {
@@ -352,7 +352,7 @@ struct block_index {
 	__le32 PageAddress;
 	__le32 PageAddress;
 	__le16 dummy1;
 	__le16 dummy1;
 	__le16 PageNumber;
 	__le16 PageNumber;
-} __attribute__ ((packed));
+} __packed;
 
 
 #define E4_IS_BOOT_PAGE(PageSize) ((le32_to_cpu(PageSize)) & 0x80000000)
 #define E4_IS_BOOT_PAGE(PageSize) ((le32_to_cpu(PageSize)) & 0x80000000)
 #define E4_PAGE_BYTES(PageSize) ((le32_to_cpu(PageSize) & 0x7fffffff) * 4)
 #define E4_PAGE_BYTES(PageSize) ((le32_to_cpu(PageSize) & 0x7fffffff) * 4)
@@ -367,7 +367,7 @@ struct l1_code {
 	u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER];
 	u8 page_number_to_block_index[E4_MAX_PAGE_NUMBER];
 	struct block_index page_header[E4_NO_SWAPPAGE_HEADERS];
 	struct block_index page_header[E4_NO_SWAPPAGE_HEADERS];
 	u8 code[0];
 	u8 code[0];
-} __attribute__ ((packed));
+} __packed;
 
 
 /* structures describing a block within a DSP page */
 /* structures describing a block within a DSP page */
 struct block_info_e1 {
 struct block_info_e1 {
@@ -377,7 +377,7 @@ struct block_info_e1 {
 	__le16 wOvlOffset;
 	__le16 wOvlOffset;
 	__le16 wOvl;		/* overlay */
 	__le16 wOvl;		/* overlay */
 	__le16 wLast;
 	__le16 wLast;
-} __attribute__ ((packed));
+} __packed;
 #define E1_BLOCK_INFO_SIZE 12
 #define E1_BLOCK_INFO_SIZE 12
 
 
 struct block_info_e4 {
 struct block_info_e4 {
@@ -387,7 +387,7 @@ struct block_info_e4 {
 	__be32 dwSize;
 	__be32 dwSize;
 	__be32 dwAddress;
 	__be32 dwAddress;
 	__be16 wReserved;
 	__be16 wReserved;
-} __attribute__ ((packed));
+} __packed;
 #define E4_BLOCK_INFO_SIZE 14
 #define E4_BLOCK_INFO_SIZE 14
 
 
 #define UEA_BIHDR 0xabcd
 #define UEA_BIHDR 0xabcd
@@ -467,7 +467,7 @@ struct cmv_e1 {
 	__le32 dwSymbolicAddress;
 	__le32 dwSymbolicAddress;
 	__le16 wOffsetAddress;
 	__le16 wOffsetAddress;
 	__le32 dwData;
 	__le32 dwData;
-} __attribute__ ((packed));
+} __packed;
 
 
 struct cmv_e4 {
 struct cmv_e4 {
 	__be16 wGroup;
 	__be16 wGroup;
@@ -475,17 +475,17 @@ struct cmv_e4 {
 	__be16 wOffset;
 	__be16 wOffset;
 	__be16 wAddress;
 	__be16 wAddress;
 	__be32 dwData[6];
 	__be32 dwData[6];
-} __attribute__ ((packed));
+} __packed;
 
 
 /* structures representing swap information */
 /* structures representing swap information */
 struct swap_info_e1 {
 struct swap_info_e1 {
 	__u8 bSwapPageNo;
 	__u8 bSwapPageNo;
 	__u8 bOvl;		/* overlay */
 	__u8 bOvl;		/* overlay */
-} __attribute__ ((packed));
+} __packed;
 
 
 struct swap_info_e4 {
 struct swap_info_e4 {
 	__u8 bSwapPageNo;
 	__u8 bSwapPageNo;
-} __attribute__ ((packed));
+} __packed;
 
 
 /* structures representing interrupt data */
 /* structures representing interrupt data */
 #define e1_bSwapPageNo	u.e1.s1.swapinfo.bSwapPageNo
 #define e1_bSwapPageNo	u.e1.s1.swapinfo.bSwapPageNo
@@ -499,23 +499,23 @@ union intr_data_e1 {
 	struct {
 	struct {
 		struct swap_info_e1 swapinfo;
 		struct swap_info_e1 swapinfo;
 		__le16 wDataSize;
 		__le16 wDataSize;
-	} __attribute__ ((packed)) s1;
+	} __packed s1;
 	struct {
 	struct {
 		struct cmv_e1 cmv;
 		struct cmv_e1 cmv;
 		__le16 wDataSize;
 		__le16 wDataSize;
-	} __attribute__ ((packed)) s2;
-} __attribute__ ((packed));
+	} __packed s2;
+} __packed;
 
 
 union intr_data_e4 {
 union intr_data_e4 {
 	struct {
 	struct {
 		struct swap_info_e4 swapinfo;
 		struct swap_info_e4 swapinfo;
 		__le16 wDataSize;
 		__le16 wDataSize;
-	} __attribute__ ((packed)) s1;
+	} __packed s1;
 	struct {
 	struct {
 		struct cmv_e4 cmv;
 		struct cmv_e4 cmv;
 		__le16 wDataSize;
 		__le16 wDataSize;
-	} __attribute__ ((packed)) s2;
-} __attribute__ ((packed));
+	} __packed s2;
+} __packed;
 
 
 struct intr_pkt {
 struct intr_pkt {
 	__u8 bType;
 	__u8 bType;
@@ -528,15 +528,15 @@ struct intr_pkt {
 		union intr_data_e1 e1;
 		union intr_data_e1 e1;
 		union intr_data_e4 e4;
 		union intr_data_e4 e4;
 	} u;
 	} u;
-} __attribute__ ((packed));
+} __packed;
 
 
 #define E1_INTR_PKT_SIZE 28
 #define E1_INTR_PKT_SIZE 28
 #define E4_INTR_PKT_SIZE 64
 #define E4_INTR_PKT_SIZE 64
 
 
 static struct usb_driver uea_driver;
 static struct usb_driver uea_driver;
 static DEFINE_MUTEX(uea_mutex);
 static DEFINE_MUTEX(uea_mutex);
-static const char *chip_name[] = {"ADI930", "Eagle I", "Eagle II", "Eagle III",
-								"Eagle IV"};
+static const char * const chip_name[] = {
+	"ADI930", "Eagle I", "Eagle II", "Eagle III", "Eagle IV"};
 
 
 static int modem_index;
 static int modem_index;
 static unsigned int debug;
 static unsigned int debug;

+ 2 - 2
drivers/usb/atm/usbatm.c

@@ -81,6 +81,7 @@
 #include <linux/timer.h>
 #include <linux/timer.h>
 #include <linux/wait.h>
 #include <linux/wait.h>
 #include <linux/kthread.h>
 #include <linux/kthread.h>
+#include <linux/ratelimit.h>
 
 
 #ifdef VERBOSE_DEBUG
 #ifdef VERBOSE_DEBUG
 static int usbatm_print_packet(const unsigned char *data, int len);
 static int usbatm_print_packet(const unsigned char *data, int len);
@@ -668,8 +669,7 @@ static int usbatm_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
 	/* racy disconnection check - fine */
 	/* racy disconnection check - fine */
 	if (!instance || instance->disconnected) {
 	if (!instance || instance->disconnected) {
 #ifdef DEBUG
 #ifdef DEBUG
-		if (printk_ratelimit())
-			printk(KERN_DEBUG "%s: %s!\n", __func__, instance ? "disconnected" : "NULL instance");
+		printk_ratelimited(KERN_DEBUG "%s: %s!\n", __func__, instance ? "disconnected" : "NULL instance");
 #endif
 #endif
 		err = -ENODEV;
 		err = -ENODEV;
 		goto fail;
 		goto fail;

+ 3 - 4
drivers/usb/class/usblp.c

@@ -58,6 +58,7 @@
 #include <linux/mutex.h>
 #include <linux/mutex.h>
 #undef DEBUG
 #undef DEBUG
 #include <linux/usb.h>
 #include <linux/usb.h>
+#include <linux/ratelimit.h>
 
 
 /*
 /*
  * Version Information
  * Version Information
@@ -348,8 +349,7 @@ static int usblp_check_status(struct usblp *usblp, int err)
 	mutex_lock(&usblp->mut);
 	mutex_lock(&usblp->mut);
 	if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) {
 	if ((error = usblp_read_status(usblp, usblp->statusbuf)) < 0) {
 		mutex_unlock(&usblp->mut);
 		mutex_unlock(&usblp->mut);
-		if (printk_ratelimit())
-			printk(KERN_ERR
+		printk_ratelimited(KERN_ERR
 				"usblp%d: error %d reading printer status\n",
 				"usblp%d: error %d reading printer status\n",
 				usblp->minor, error);
 				usblp->minor, error);
 		return 0;
 		return 0;
@@ -653,8 +653,7 @@ static long usblp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 
 
 		case LPGETSTATUS:
 		case LPGETSTATUS:
 			if ((retval = usblp_read_status(usblp, usblp->statusbuf))) {
 			if ((retval = usblp_read_status(usblp, usblp->statusbuf))) {
-				if (printk_ratelimit())
-					printk(KERN_ERR "usblp%d:"
+				printk_ratelimited(KERN_ERR "usblp%d:"
 					    "failed reading printer status (%d)\n",
 					    "failed reading printer status (%d)\n",
 					    usblp->minor, retval);
 					    usblp->minor, retval);
 				retval = -EIO;
 				retval = -EIO;

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

@@ -337,6 +337,17 @@ static const u8 ss_rh_config_descriptor[] = {
 	0x02, 0x00   /* __le16 ss_wBytesPerInterval; 15 bits for max 15 ports */
 	0x02, 0x00   /* __le16 ss_wBytesPerInterval; 15 bits for max 15 ports */
 };
 };
 
 
+/* authorized_default behaviour:
+ * -1 is authorized for all devices except wireless (old behaviour)
+ * 0 is unauthorized for all devices
+ * 1 is authorized for all devices
+ */
+static int authorized_default = -1;
+module_param(authorized_default, int, S_IRUGO|S_IWUSR);
+MODULE_PARM_DESC(authorized_default,
+		"Default USB device authorization: 0 is not authorized, 1 is "
+		"authorized, -1 is authorized except for wireless USB (default, "
+		"old behaviour");
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 /**
 /**
@@ -2371,7 +2382,11 @@ int usb_add_hcd(struct usb_hcd *hcd,
 
 
 	dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
 	dev_info(hcd->self.controller, "%s\n", hcd->product_desc);
 
 
-	hcd->authorized_default = hcd->wireless? 0 : 1;
+	/* Keep old behaviour if authorized_default is not in [0, 1]. */
+	if (authorized_default < 0 || authorized_default > 1)
+		hcd->authorized_default = hcd->wireless? 0 : 1;
+	else
+		hcd->authorized_default = authorized_default;
 	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
 
 
 	/* HC is in reset state, but accessible.  Now do the one-time init,
 	/* HC is in reset state, but accessible.  Now do the one-time init,

+ 100 - 213
drivers/usb/gadget/Kconfig

@@ -96,9 +96,6 @@ config USB_GADGET_VBUS_DRAW
 	   This value will be used except for system-specific gadget
 	   This value will be used except for system-specific gadget
 	   drivers that have more specific information.
 	   drivers that have more specific information.
 
 
-config	USB_GADGET_SELECTED
-	boolean
-
 #
 #
 # USB Peripheral Controller Support
 # USB Peripheral Controller Support
 #
 #
@@ -122,10 +119,9 @@ choice
 # Integrated controllers
 # Integrated controllers
 #
 #
 
 
-config USB_GADGET_AT91
-	boolean "Atmel AT91 USB Device Port"
+config USB_AT91
+	tristate "Atmel AT91 USB Device Port"
 	depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9 && !ARCH_AT91SAM9G45
 	depends on ARCH_AT91 && !ARCH_AT91SAM9RL && !ARCH_AT91CAP9 && !ARCH_AT91SAM9G45
-	select USB_GADGET_SELECTED
 	help
 	help
 	   Many Atmel AT91 processors (such as the AT91RM2000) have a
 	   Many Atmel AT91 processors (such as the AT91RM2000) have a
 	   full speed USB Device Port with support for five configurable
 	   full speed USB Device Port with support for five configurable
@@ -135,27 +131,16 @@ config USB_GADGET_AT91
 	   dynamically linked module called "at91_udc" and force all
 	   dynamically linked module called "at91_udc" and force all
 	   gadget drivers to also be dynamically linked.
 	   gadget drivers to also be dynamically linked.
 
 
-config USB_AT91
-	tristate
-	depends on USB_GADGET_AT91
-	default USB_GADGET
-
-config USB_GADGET_ATMEL_USBA
-	boolean "Atmel USBA"
+config USB_ATMEL_USBA
+	tristate "Atmel USBA"
 	select USB_GADGET_DUALSPEED
 	select USB_GADGET_DUALSPEED
 	depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
 	depends on AVR32 || ARCH_AT91CAP9 || ARCH_AT91SAM9RL || ARCH_AT91SAM9G45
 	help
 	help
 	  USBA is the integrated high-speed USB Device controller on
 	  USBA is the integrated high-speed USB Device controller on
 	  the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
 	  the AT32AP700x, some AT91SAM9 and AT91CAP9 processors from Atmel.
 
 
-config USB_ATMEL_USBA
-	tristate
-	depends on USB_GADGET_ATMEL_USBA
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_FSL_USB2
-	boolean "Freescale Highspeed USB DR Peripheral Controller"
+config USB_FSL_USB2
+	tristate "Freescale Highspeed USB DR Peripheral Controller"
 	depends on FSL_SOC || ARCH_MXC
 	depends on FSL_SOC || ARCH_MXC
 	select USB_GADGET_DUALSPEED
 	select USB_GADGET_DUALSPEED
 	select USB_FSL_MPH_DR_OF if OF
 	select USB_FSL_MPH_DR_OF if OF
@@ -170,26 +155,15 @@ config USB_GADGET_FSL_USB2
 	   dynamically linked module called "fsl_usb2_udc" and force
 	   dynamically linked module called "fsl_usb2_udc" and force
 	   all gadget drivers to also be dynamically linked.
 	   all gadget drivers to also be dynamically linked.
 
 
-config USB_FSL_USB2
-	tristate
-	depends on USB_GADGET_FSL_USB2
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_FUSB300
-	boolean "Faraday FUSB300 USB Peripheral Controller"
+config USB_FUSB300
+	tristate "Faraday FUSB300 USB Peripheral Controller"
+	depends on !PHYS_ADDR_T_64BIT
 	select USB_GADGET_DUALSPEED
 	select USB_GADGET_DUALSPEED
 	help
 	help
 	   Faraday usb device controller FUSB300 driver
 	   Faraday usb device controller FUSB300 driver
 
 
-config USB_FUSB300
-	tristate
-	depends on USB_GADGET_FUSB300
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_OMAP
-	boolean "OMAP USB Device Controller"
+config USB_OMAP
+	tristate "OMAP USB Device Controller"
 	depends on ARCH_OMAP
 	depends on ARCH_OMAP
 	select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
 	select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
 	select USB_OTG_UTILS if ARCH_OMAP
 	select USB_OTG_UTILS if ARCH_OMAP
@@ -204,14 +178,8 @@ config USB_GADGET_OMAP
 	   dynamically linked module called "omap_udc" and force all
 	   dynamically linked module called "omap_udc" and force all
 	   gadget drivers to also be dynamically linked.
 	   gadget drivers to also be dynamically linked.
 
 
-config USB_OMAP
-	tristate
-	depends on USB_GADGET_OMAP
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_PXA25X
-	boolean "PXA 25x or IXP 4xx"
+config USB_PXA25X
+	tristate "PXA 25x or IXP 4xx"
 	depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
 	depends on (ARCH_PXA && PXA25x) || ARCH_IXP4XX
 	select USB_OTG_UTILS
 	select USB_OTG_UTILS
 	help
 	help
@@ -226,24 +194,18 @@ config USB_GADGET_PXA25X
 	   dynamically linked module called "pxa25x_udc" and force all
 	   dynamically linked module called "pxa25x_udc" and force all
 	   gadget drivers to also be dynamically linked.
 	   gadget drivers to also be dynamically linked.
 
 
-config USB_PXA25X
-	tristate
-	depends on USB_GADGET_PXA25X
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
 # if there's only one gadget driver, using only two bulk endpoints,
 # if there's only one gadget driver, using only two bulk endpoints,
 # don't waste memory for the other endpoints
 # don't waste memory for the other endpoints
 config USB_PXA25X_SMALL
 config USB_PXA25X_SMALL
-	depends on USB_GADGET_PXA25X
+	depends on USB_PXA25X
 	bool
 	bool
 	default n if USB_ETH_RNDIS
 	default n if USB_ETH_RNDIS
 	default y if USB_ZERO
 	default y if USB_ZERO
 	default y if USB_ETH
 	default y if USB_ETH
 	default y if USB_G_SERIAL
 	default y if USB_G_SERIAL
 
 
-config USB_GADGET_R8A66597
-	boolean "Renesas R8A66597 USB Peripheral Controller"
+config USB_R8A66597
+	tristate "Renesas R8A66597 USB Peripheral Controller"
 	select USB_GADGET_DUALSPEED
 	select USB_GADGET_DUALSPEED
 	help
 	help
 	   R8A66597 is a discrete USB host and peripheral controller chip that
 	   R8A66597 is a discrete USB host and peripheral controller chip that
@@ -254,32 +216,22 @@ config USB_GADGET_R8A66597
 	   dynamically linked module called "r8a66597_udc" and force all
 	   dynamically linked module called "r8a66597_udc" and force all
 	   gadget drivers to also be dynamically linked.
 	   gadget drivers to also be dynamically linked.
 
 
-config USB_R8A66597
-	tristate
-	depends on USB_GADGET_R8A66597
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_RENESAS_USBHS
-	boolean "Renesas USBHS"
+config USB_RENESAS_USBHS_UDC
+	tristate 'Renesas USBHS controller'
+	depends on SUPERH || ARCH_SHMOBILE
 	depends on USB_RENESAS_USBHS
 	depends on USB_RENESAS_USBHS
 	select USB_GADGET_DUALSPEED
 	select USB_GADGET_DUALSPEED
 	help
 	help
-	   Renesas USBHS is a discrete USB host and peripheral controller
-	   chip that supports both full and high speed USB 2.0 data transfers.
-	   platform is able to configure endpoint (pipe) style
+	   Renesas USBHS is a discrete USB host and peripheral controller chip
+	   that supports both full and high speed USB 2.0 data transfers.
+	   It has nine or more configurable endpoints, and endpoint zero.
 
 
-	   Say "y" to enable the gadget specific portion of the USBHS driver.
-
-
-config USB_RENESAS_USBHS_UDC
-	tristate
-	depends on USB_GADGET_RENESAS_USBHS
-	default USB_GADGET
-	select USB_GADGET_SELECTED
+	   Say "y" to link the driver statically, or "m" to build a
+	   dynamically linked module called "renesas_usbhs" and force all
+	   gadget drivers to also be dynamically linked.
 
 
-config USB_GADGET_PXA27X
-	boolean "PXA 27x"
+config USB_PXA27X
+	tristate "PXA 27x"
 	depends on ARCH_PXA && (PXA27x || PXA3xx)
 	depends on ARCH_PXA && (PXA27x || PXA3xx)
 	select USB_OTG_UTILS
 	select USB_OTG_UTILS
 	help
 	help
@@ -293,14 +245,8 @@ config USB_GADGET_PXA27X
 	   dynamically linked module called "pxa27x_udc" and force all
 	   dynamically linked module called "pxa27x_udc" and force all
 	   gadget drivers to also be dynamically linked.
 	   gadget drivers to also be dynamically linked.
 
 
-config USB_PXA27X
-	tristate
-	depends on USB_GADGET_PXA27X
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_S3C_HSOTG
-	boolean "S3C HS/OtG USB Device controller"
+config USB_S3C_HSOTG
+	tristate "S3C HS/OtG USB Device controller"
 	depends on S3C_DEV_USB_HSOTG
 	depends on S3C_DEV_USB_HSOTG
 	select USB_GADGET_S3C_HSOTG_PIO
 	select USB_GADGET_S3C_HSOTG_PIO
 	select USB_GADGET_DUALSPEED
 	select USB_GADGET_DUALSPEED
@@ -308,14 +254,8 @@ config USB_GADGET_S3C_HSOTG
 	  The Samsung S3C64XX USB2.0 high-speed gadget controller
 	  The Samsung S3C64XX USB2.0 high-speed gadget controller
 	  integrated into the S3C64XX series SoC.
 	  integrated into the S3C64XX series SoC.
 
 
-config USB_S3C_HSOTG
-	tristate
-	depends on USB_GADGET_S3C_HSOTG
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_IMX
-	boolean "Freescale IMX USB Peripheral Controller"
+config USB_IMX
+	tristate "Freescale IMX USB Peripheral Controller"
 	depends on ARCH_MX1
 	depends on ARCH_MX1
 	help
 	help
 	   Freescale's IMX series include an integrated full speed
 	   Freescale's IMX series include an integrated full speed
@@ -329,14 +269,8 @@ config USB_GADGET_IMX
 	   dynamically linked module called "imx_udc" and force all
 	   dynamically linked module called "imx_udc" and force all
 	   gadget drivers to also be dynamically linked.
 	   gadget drivers to also be dynamically linked.
 
 
-config USB_IMX
-	tristate
-	depends on USB_GADGET_IMX
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_S3C2410
-	boolean "S3C2410 USB Device Controller"
+config USB_S3C2410
+	tristate "S3C2410 USB Device Controller"
 	depends on ARCH_S3C2410
 	depends on ARCH_S3C2410
 	help
 	help
 	  Samsung's S3C2410 is an ARM-4 processor with an integrated
 	  Samsung's S3C2410 is an ARM-4 processor with an integrated
@@ -346,18 +280,12 @@ config USB_GADGET_S3C2410
 	  This driver has been tested on the S3C2410, S3C2412, and
 	  This driver has been tested on the S3C2410, S3C2412, and
 	  S3C2440 processors.
 	  S3C2440 processors.
 
 
-config USB_S3C2410
-	tristate
-	depends on USB_GADGET_S3C2410
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
 config USB_S3C2410_DEBUG
 config USB_S3C2410_DEBUG
 	boolean "S3C2410 udc debug messages"
 	boolean "S3C2410 udc debug messages"
-	depends on USB_GADGET_S3C2410
+	depends on USB_S3C2410
 
 
-config USB_GADGET_S3C_HSUDC
-	boolean "S3C2416, S3C2443 and S3C2450 USB Device Controller"
+config USB_S3C_HSUDC
+	tristate "S3C2416, S3C2443 and S3C2450 USB Device Controller"
 	depends on ARCH_S3C2410
 	depends on ARCH_S3C2410
 	select USB_GADGET_DUALSPEED
 	select USB_GADGET_DUALSPEED
 	help
 	help
@@ -367,41 +295,29 @@ config USB_GADGET_S3C_HSUDC
 
 
 	  This driver has been tested on S3C2416 and S3C2450 processors.
 	  This driver has been tested on S3C2416 and S3C2450 processors.
 
 
-config USB_S3C_HSUDC
-	tristate
-	depends on USB_GADGET_S3C_HSUDC
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_PXA_U2O
-	boolean "PXA9xx Processor USB2.0 controller"
+config USB_PXA_U2O
+	tristate "PXA9xx Processor USB2.0 controller"
+	depends on ARCH_MMP
 	select USB_GADGET_DUALSPEED
 	select USB_GADGET_DUALSPEED
 	help
 	help
 	  PXA9xx Processor series include a high speed USB2.0 device
 	  PXA9xx Processor series include a high speed USB2.0 device
 	  controller, which support high speed and full speed USB peripheral.
 	  controller, which support high speed and full speed USB peripheral.
 
 
-config USB_PXA_U2O
-	tristate
-	depends on USB_GADGET_PXA_U2O
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
 #
 #
 # Controllers available in both integrated and discrete versions
 # Controllers available in both integrated and discrete versions
 #
 #
 
 
 # musb builds in ../musb along with host support
 # musb builds in ../musb along with host support
 config USB_GADGET_MUSB_HDRC
 config USB_GADGET_MUSB_HDRC
-	boolean "Inventra HDRC USB Peripheral (TI, ADI, ...)"
+	tristate "Inventra HDRC USB Peripheral (TI, ADI, ...)"
 	depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
 	depends on USB_MUSB_HDRC && (USB_MUSB_PERIPHERAL || USB_MUSB_OTG)
 	select USB_GADGET_DUALSPEED
 	select USB_GADGET_DUALSPEED
-	select USB_GADGET_SELECTED
 	help
 	help
 	  This OTG-capable silicon IP is used in dual designs including
 	  This OTG-capable silicon IP is used in dual designs including
 	  the TI DaVinci, OMAP 243x, OMAP 343x, TUSB 6010, and ADI Blackfin
 	  the TI DaVinci, OMAP 243x, OMAP 343x, TUSB 6010, and ADI Blackfin
 
 
-config USB_GADGET_M66592
-	boolean "Renesas M66592 USB Peripheral Controller"
+config USB_M66592
+	tristate "Renesas M66592 USB Peripheral Controller"
 	select USB_GADGET_DUALSPEED
 	select USB_GADGET_DUALSPEED
 	help
 	help
 	   M66592 is a discrete USB peripheral controller chip that
 	   M66592 is a discrete USB peripheral controller chip that
@@ -412,18 +328,12 @@ config USB_GADGET_M66592
 	   dynamically linked module called "m66592_udc" and force all
 	   dynamically linked module called "m66592_udc" and force all
 	   gadget drivers to also be dynamically linked.
 	   gadget drivers to also be dynamically linked.
 
 
-config USB_M66592
-	tristate
-	depends on USB_GADGET_M66592
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
 #
 #
 # Controllers available only in discrete form (and all PCI controllers)
 # Controllers available only in discrete form (and all PCI controllers)
 #
 #
 
 
-config USB_GADGET_AMD5536UDC
-	boolean "AMD5536 UDC"
+config USB_AMD5536UDC
+	tristate "AMD5536 UDC"
 	depends on PCI
 	depends on PCI
 	select USB_GADGET_DUALSPEED
 	select USB_GADGET_DUALSPEED
 	help
 	help
@@ -437,14 +347,8 @@ config USB_GADGET_AMD5536UDC
 	   dynamically linked module called "amd5536udc" and force all
 	   dynamically linked module called "amd5536udc" and force all
 	   gadget drivers to also be dynamically linked.
 	   gadget drivers to also be dynamically linked.
 
 
-config USB_AMD5536UDC
-	tristate
-	depends on USB_GADGET_AMD5536UDC
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_FSL_QE
-	boolean "Freescale QE/CPM USB Device Controller"
+config USB_FSL_QE
+	tristate "Freescale QE/CPM USB Device Controller"
 	depends on FSL_SOC && (QUICC_ENGINE || CPM)
 	depends on FSL_SOC && (QUICC_ENGINE || CPM)
 	help
 	help
 	   Some of Freescale PowerPC processors have a Full Speed
 	   Some of Freescale PowerPC processors have a Full Speed
@@ -456,14 +360,8 @@ config USB_GADGET_FSL_QE
 	   Set CONFIG_USB_GADGET to "m" to build this driver as a
 	   Set CONFIG_USB_GADGET to "m" to build this driver as a
 	   dynamically linked module called "fsl_qe_udc".
 	   dynamically linked module called "fsl_qe_udc".
 
 
-config USB_FSL_QE
-	tristate
-	depends on USB_GADGET_FSL_QE
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_CI13XXX_PCI
-	boolean "MIPS USB CI13xxx PCI UDC"
+config USB_CI13XXX_PCI
+	tristate "MIPS USB CI13xxx PCI UDC"
 	depends on PCI
 	depends on PCI
 	select USB_GADGET_DUALSPEED
 	select USB_GADGET_DUALSPEED
 	help
 	help
@@ -474,14 +372,31 @@ config USB_GADGET_CI13XXX_PCI
 	  dynamically linked module called "ci13xxx_udc" and force all
 	  dynamically linked module called "ci13xxx_udc" and force all
 	  gadget drivers to also be dynamically linked.
 	  gadget drivers to also be dynamically linked.
 
 
-config USB_CI13XXX_PCI
-	tristate
-	depends on USB_GADGET_CI13XXX_PCI
-	default USB_GADGET
-	select USB_GADGET_SELECTED
+config USB_NET2272
+	tristate "PLX NET2272"
+	select USB_GADGET_DUALSPEED
+	help
+	  PLX NET2272 is a USB peripheral controller which supports
+	  both full and high speed USB 2.0 data transfers.
+
+	  It has three configurable endpoints, as well as endpoint zero
+	  (for control transfer).
+	  Say "y" to link the driver statically, or "m" to build a
+	  dynamically linked module called "net2272" and force all
+	  gadget drivers to also be dynamically linked.
+
+config USB_NET2272_DMA
+	boolean "Support external DMA controller"
+	depends on USB_NET2272
+	help
+	  The NET2272 part can optionally support an external DMA
+	  controller, but your board has to have support in the
+	  driver itself.
 
 
-config USB_GADGET_NET2280
-	boolean "NetChip 228x"
+	  If unsure, say "N" here.  The driver works fine in PIO mode.
+
+config USB_NET2280
+	tristate "NetChip 228x"
 	depends on PCI
 	depends on PCI
 	select USB_GADGET_DUALSPEED
 	select USB_GADGET_DUALSPEED
 	help
 	help
@@ -496,14 +411,8 @@ config USB_GADGET_NET2280
 	   dynamically linked module called "net2280" and force all
 	   dynamically linked module called "net2280" and force all
 	   gadget drivers to also be dynamically linked.
 	   gadget drivers to also be dynamically linked.
 
 
-config USB_NET2280
-	tristate
-	depends on USB_GADGET_NET2280
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_GOKU
-	boolean "Toshiba TC86C001 'Goku-S'"
+config USB_GOKU
+	tristate "Toshiba TC86C001 'Goku-S'"
 	depends on PCI
 	depends on PCI
 	help
 	help
 	   The Toshiba TC86C001 is a PCI device which includes controllers
 	   The Toshiba TC86C001 is a PCI device which includes controllers
@@ -516,15 +425,10 @@ config USB_GADGET_GOKU
 	   dynamically linked module called "goku_udc" and to force all
 	   dynamically linked module called "goku_udc" and to force all
 	   gadget drivers to also be dynamically linked.
 	   gadget drivers to also be dynamically linked.
 
 
-config USB_GOKU
-	tristate
-	depends on USB_GADGET_GOKU
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_LANGWELL
-	boolean "Intel Langwell USB Device Controller"
+config USB_LANGWELL
+	tristate "Intel Langwell USB Device Controller"
 	depends on PCI
 	depends on PCI
+	depends on !PHYS_ADDR_T_64BIT
 	select USB_GADGET_DUALSPEED
 	select USB_GADGET_DUALSPEED
 	help
 	help
 	   Intel Langwell USB Device Controller is a High-Speed USB
 	   Intel Langwell USB Device Controller is a High-Speed USB
@@ -537,14 +441,8 @@ config USB_GADGET_LANGWELL
 	   dynamically linked module called "langwell_udc" and force all
 	   dynamically linked module called "langwell_udc" and force all
 	   gadget drivers to also be dynamically linked.
 	   gadget drivers to also be dynamically linked.
 
 
-config USB_LANGWELL
-	tristate
-	depends on USB_GADGET_LANGWELL
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_EG20T
-	boolean "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH UDC"
+config USB_EG20T
+	tristate "Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH UDC"
 	depends on PCI
 	depends on PCI
 	select USB_GADGET_DUALSPEED
 	select USB_GADGET_DUALSPEED
 	help
 	help
@@ -565,14 +463,8 @@ config USB_GADGET_EG20T
 	  ML7213 is companion chip for Intel Atom E6xx series.
 	  ML7213 is companion chip for Intel Atom E6xx series.
 	  ML7213 is completely compatible for Intel EG20T PCH.
 	  ML7213 is completely compatible for Intel EG20T PCH.
 
 
-config USB_EG20T
-	tristate
-	depends on USB_GADGET_EG20T
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
-config USB_GADGET_CI13XXX_MSM
-	boolean "MIPS USB CI13xxx for MSM"
+config USB_CI13XXX_MSM
+	tristate "MIPS USB CI13xxx for MSM"
 	depends on ARCH_MSM
 	depends on ARCH_MSM
 	select USB_GADGET_DUALSPEED
 	select USB_GADGET_DUALSPEED
 	select USB_MSM_OTG
 	select USB_MSM_OTG
@@ -588,31 +480,26 @@ config USB_GADGET_CI13XXX_MSM
 	  dynamically linked module called "ci13xxx_msm" and force all
 	  dynamically linked module called "ci13xxx_msm" and force all
 	  gadget drivers to also be dynamically linked.
 	  gadget drivers to also be dynamically linked.
 
 
-config USB_CI13XXX_MSM
-	tristate
-	depends on USB_GADGET_CI13XXX_MSM
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
 #
 #
 # LAST -- dummy/emulated controller
 # LAST -- dummy/emulated controller
 #
 #
 
 
-config USB_GADGET_DUMMY_HCD
-	boolean "Dummy HCD (DEVELOPMENT)"
+config USB_DUMMY_HCD
+	tristate "Dummy HCD (DEVELOPMENT)"
 	depends on USB=y || (USB=m && USB_GADGET=m)
 	depends on USB=y || (USB=m && USB_GADGET=m)
 	select USB_GADGET_DUALSPEED
 	select USB_GADGET_DUALSPEED
+	select USB_GADGET_SUPERSPEED
 	help
 	help
 	  This host controller driver emulates USB, looping all data transfer
 	  This host controller driver emulates USB, looping all data transfer
 	  requests back to a USB "gadget driver" in the same host.  The host
 	  requests back to a USB "gadget driver" in the same host.  The host
 	  side is the master; the gadget side is the slave.  Gadget drivers
 	  side is the master; the gadget side is the slave.  Gadget drivers
 	  can be high, full, or low speed; and they have access to endpoints
 	  can be high, full, or low speed; and they have access to endpoints
 	  like those from NET2280, PXA2xx, or SA1100 hardware.
 	  like those from NET2280, PXA2xx, or SA1100 hardware.
-	  
+
 	  This may help in some stages of creating a driver to embed in a
 	  This may help in some stages of creating a driver to embed in a
 	  Linux device, since it lets you debug several parts of the gadget
 	  Linux device, since it lets you debug several parts of the gadget
 	  driver without its hardware or drivers being involved.
 	  driver without its hardware or drivers being involved.
-	  
+
 	  Since such a gadget side driver needs to interoperate with a host
 	  Since such a gadget side driver needs to interoperate with a host
 	  side Linux-USB device driver, this may help to debug both sides
 	  side Linux-USB device driver, this may help to debug both sides
 	  of a USB protocol stack.
 	  of a USB protocol stack.
@@ -621,12 +508,6 @@ config USB_GADGET_DUMMY_HCD
 	  dynamically linked module called "dummy_hcd" and force all
 	  dynamically linked module called "dummy_hcd" and force all
 	  gadget drivers to also be dynamically linked.
 	  gadget drivers to also be dynamically linked.
 
 
-config USB_DUMMY_HCD
-	tristate
-	depends on USB_GADGET_DUMMY_HCD
-	default USB_GADGET
-	select USB_GADGET_SELECTED
-
 # NOTE:  Please keep dummy_hcd LAST so that "real hardware" appears
 # NOTE:  Please keep dummy_hcd LAST so that "real hardware" appears
 # first and will be selected by default.
 # first and will be selected by default.
 
 
@@ -637,12 +518,18 @@ config USB_GADGET_DUALSPEED
 	bool
 	bool
 	depends on USB_GADGET
 	depends on USB_GADGET
 
 
+# Selected by UDC drivers that support super-speed opperation
+config USB_GADGET_SUPERSPEED
+	bool
+	depends on USB_GADGET
+	depends on USB_GADGET_DUALSPEED
+
 #
 #
 # USB Gadget Drivers
 # USB Gadget Drivers
 #
 #
 choice
 choice
 	tristate "USB Gadget Drivers"
 	tristate "USB Gadget Drivers"
-	depends on USB_GADGET && USB_GADGET_SELECTED
+	depends on USB_GADGET
 	default USB_ETH
 	default USB_ETH
 	help
 	help
 	  A Linux "Gadget Driver" talks to the USB Peripheral Controller
 	  A Linux "Gadget Driver" talks to the USB Peripheral Controller
@@ -848,7 +735,7 @@ config USB_FUNCTIONFS_GENERIC
 	  no Ethernet interface.
 	  no Ethernet interface.
 
 
 config USB_FILE_STORAGE
 config USB_FILE_STORAGE
-	tristate "File-backed Storage Gadget"
+	tristate "File-backed Storage Gadget (DEPRECATED)"
 	depends on BLOCK
 	depends on BLOCK
 	help
 	help
 	  The File-backed Storage Gadget acts as a USB Mass Storage
 	  The File-backed Storage Gadget acts as a USB Mass Storage
@@ -859,6 +746,9 @@ config USB_FILE_STORAGE
 	  Say "y" to link the driver statically, or "m" to build a
 	  Say "y" to link the driver statically, or "m" to build a
 	  dynamically linked module called "g_file_storage".
 	  dynamically linked module called "g_file_storage".
 
 
+	  NOTE: This driver is deprecated.  Its replacement is the
+	  Mass Storage Gadget.
+
 config USB_FILE_STORAGE_TEST
 config USB_FILE_STORAGE_TEST
 	bool "File-backed Storage Gadget testing version"
 	bool "File-backed Storage Gadget testing version"
 	depends on USB_FILE_STORAGE
 	depends on USB_FILE_STORAGE
@@ -878,14 +768,11 @@ config USB_MASS_STORAGE
 	  device (in much the same way as the "loop" device driver),
 	  device (in much the same way as the "loop" device driver),
 	  specified as a module parameter or sysfs option.
 	  specified as a module parameter or sysfs option.
 
 
-	  This is heavily based on File-backed Storage Gadget and in most
-	  cases you will want to use FSG instead.  This gadget is mostly
-	  here to test the functionality of the Mass Storage Function
-	  which may be used with composite framework.
+	  This driver is an updated replacement for the deprecated
+	  File-backed Storage Gadget (g_file_storage).
 
 
 	  Say "y" to link the driver statically, or "m" to build
 	  Say "y" to link the driver statically, or "m" to build
-	  a dynamically linked module called "g_mass_storage".  If unsure,
-	  consider File-backed Storage Gadget.
+	  a dynamically linked module called "g_mass_storage".
 
 
 config USB_G_SERIAL
 config USB_G_SERIAL
 	tristate "Serial Gadget (with CDC ACM and CDC OBEX support)"
 	tristate "Serial Gadget (with CDC ACM and CDC OBEX support)"

+ 2 - 0
drivers/usb/gadget/Makefile

@@ -3,7 +3,9 @@
 #
 #
 ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
 ccflags-$(CONFIG_USB_GADGET_DEBUG) := -DDEBUG
 
 
+obj-$(CONFIG_USB_GADGET)	+= udc-core.o
 obj-$(CONFIG_USB_DUMMY_HCD)	+= dummy_hcd.o
 obj-$(CONFIG_USB_DUMMY_HCD)	+= dummy_hcd.o
+obj-$(CONFIG_USB_NET2272)	+= net2272.o
 obj-$(CONFIG_USB_NET2280)	+= net2280.o
 obj-$(CONFIG_USB_NET2280)	+= net2280.o
 obj-$(CONFIG_USB_AMD5536UDC)	+= amd5536udc.o
 obj-$(CONFIG_USB_AMD5536UDC)	+= amd5536udc.o
 obj-$(CONFIG_USB_PXA25X)	+= pxa25x_udc.o
 obj-$(CONFIG_USB_PXA25X)	+= pxa25x_udc.o

+ 13 - 5
drivers/usb/gadget/amd5536udc.c

@@ -1438,10 +1438,15 @@ static int udc_wakeup(struct usb_gadget *gadget)
 	return 0;
 	return 0;
 }
 }
 
 
+static int amd5536_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int amd5536_stop(struct usb_gadget_driver *driver);
 /* gadget operations */
 /* gadget operations */
 static const struct usb_gadget_ops udc_ops = {
 static const struct usb_gadget_ops udc_ops = {
 	.wakeup		= udc_wakeup,
 	.wakeup		= udc_wakeup,
 	.get_frame	= udc_get_frame,
 	.get_frame	= udc_get_frame,
+	.start		= amd5536_start,
+	.stop		= amd5536_stop,
 };
 };
 
 
 /* Setups endpoint parameters, adds endpoints to linked list */
 /* Setups endpoint parameters, adds endpoints to linked list */
@@ -1955,7 +1960,7 @@ static int setup_ep0(struct udc *dev)
 }
 }
 
 
 /* Called by gadget driver to register itself */
 /* Called by gadget driver to register itself */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int amd5536_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 		int (*bind)(struct usb_gadget *))
 {
 {
 	struct udc		*dev = udc;
 	struct udc		*dev = udc;
@@ -2002,7 +2007,6 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 
 
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 
 /* shutdown requests and disconnect from gadget */
 /* shutdown requests and disconnect from gadget */
 static void
 static void
@@ -2027,7 +2031,7 @@ __acquires(dev->lock)
 }
 }
 
 
 /* Called by gadget driver to unregister itself */
 /* Called by gadget driver to unregister itself */
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int amd5536_stop(struct usb_gadget_driver *driver)
 {
 {
 	struct udc	*dev = udc;
 	struct udc	*dev = udc;
 	unsigned long	flags;
 	unsigned long	flags;
@@ -2057,8 +2061,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 
 
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
 
 
 /* Clear pending NAK bits */
 /* Clear pending NAK bits */
 static void udc_process_cnak_queue(struct udc *dev)
 static void udc_process_cnak_queue(struct udc *dev)
@@ -3134,6 +3136,7 @@ static void udc_pci_remove(struct pci_dev *pdev)
 
 
 	dev = pci_get_drvdata(pdev);
 	dev = pci_get_drvdata(pdev);
 
 
+	usb_del_gadget_udc(&udc->gadget);
 	/* gadget driver must not be registered */
 	/* gadget driver must not be registered */
 	BUG_ON(dev->driver != NULL);
 	BUG_ON(dev->driver != NULL);
 
 
@@ -3382,8 +3385,13 @@ static int udc_probe(struct udc *dev)
 		"driver version: %s(for Geode5536 B1)\n", tmp);
 		"driver version: %s(for Geode5536 B1)\n", tmp);
 	udc = dev;
 	udc = dev;
 
 
+	retval = usb_add_gadget_udc(&udc->pdev->dev, &dev->gadget);
+	if (retval)
+		goto finished;
+
 	retval = device_register(&dev->gadget.dev);
 	retval = device_register(&dev->gadget.dev);
 	if (retval) {
 	if (retval) {
+		usb_del_gadget_udc(&dev->gadget);
 		put_device(&dev->gadget.dev);
 		put_device(&dev->gadget.dev);
 		goto finished;
 		goto finished;
 	}
 	}

+ 15 - 5
drivers/usb/gadget/at91_udc.c

@@ -985,12 +985,18 @@ static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on)
 	return 0;
 	return 0;
 }
 }
 
 
+static int at91_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int at91_stop(struct usb_gadget_driver *driver);
+
 static const struct usb_gadget_ops at91_udc_ops = {
 static const struct usb_gadget_ops at91_udc_ops = {
 	.get_frame		= at91_get_frame,
 	.get_frame		= at91_get_frame,
 	.wakeup			= at91_wakeup,
 	.wakeup			= at91_wakeup,
 	.set_selfpowered	= at91_set_selfpowered,
 	.set_selfpowered	= at91_set_selfpowered,
 	.vbus_session		= at91_vbus_session,
 	.vbus_session		= at91_vbus_session,
 	.pullup			= at91_pullup,
 	.pullup			= at91_pullup,
+	.start			= at91_start,
+	.stop			= at91_stop,
 
 
 	/*
 	/*
 	 * VBUS-powered devices may also also want to support bigger
 	 * VBUS-powered devices may also also want to support bigger
@@ -1628,7 +1634,7 @@ static void at91_vbus_timer(unsigned long data)
 		schedule_work(&udc->vbus_timer_work);
 		schedule_work(&udc->vbus_timer_work);
 }
 }
 
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int at91_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 		int (*bind)(struct usb_gadget *))
 {
 {
 	struct at91_udc	*udc = &controller;
 	struct at91_udc	*udc = &controller;
@@ -1672,9 +1678,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 	DBG("bound to %s\n", driver->driver.name);
 	DBG("bound to %s\n", driver->driver.name);
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 
-int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+static int at91_stop(struct usb_gadget_driver *driver)
 {
 {
 	struct at91_udc *udc = &controller;
 	struct at91_udc *udc = &controller;
 	unsigned long	flags;
 	unsigned long	flags;
@@ -1696,7 +1701,6 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 	DBG("unbound from %s\n", driver->driver.name);
 	DBG("unbound from %s\n", driver->driver.name);
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL (usb_gadget_unregister_driver);
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
@@ -1854,13 +1858,18 @@ static int __init at91udc_probe(struct platform_device *pdev)
 		DBG("no VBUS detection, assuming always-on\n");
 		DBG("no VBUS detection, assuming always-on\n");
 		udc->vbus = 1;
 		udc->vbus = 1;
 	}
 	}
+	retval = usb_add_gadget_udc(dev, &udc->gadget);
+	if (retval)
+		goto fail4;
 	dev_set_drvdata(dev, udc);
 	dev_set_drvdata(dev, udc);
 	device_init_wakeup(dev, 1);
 	device_init_wakeup(dev, 1);
 	create_debug_file(udc);
 	create_debug_file(udc);
 
 
 	INFO("%s version %s\n", driver_name, DRIVER_VERSION);
 	INFO("%s version %s\n", driver_name, DRIVER_VERSION);
 	return 0;
 	return 0;
-
+fail4:
+	if (udc->board.vbus_pin > 0 && !udc->board.vbus_polled)
+		free_irq(udc->board.vbus_pin, udc);
 fail3:
 fail3:
 	if (udc->board.vbus_pin > 0)
 	if (udc->board.vbus_pin > 0)
 		gpio_free(udc->board.vbus_pin);
 		gpio_free(udc->board.vbus_pin);
@@ -1887,6 +1896,7 @@ static int __exit at91udc_remove(struct platform_device *pdev)
 
 
 	DBG("remove\n");
 	DBG("remove\n");
 
 
+	usb_del_gadget_udc(&udc->gadget);
 	if (udc->driver)
 	if (udc->driver)
 		return -EBUSY;
 		return -EBUSY;
 
 

+ 22 - 4
drivers/usb/gadget/atmel_usba_udc.c

@@ -1007,10 +1007,16 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
 	return 0;
 	return 0;
 }
 }
 
 
+static int atmel_usba_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int atmel_usba_stop(struct usb_gadget_driver *driver);
+
 static const struct usb_gadget_ops usba_udc_ops = {
 static const struct usb_gadget_ops usba_udc_ops = {
 	.get_frame		= usba_udc_get_frame,
 	.get_frame		= usba_udc_get_frame,
 	.wakeup			= usba_udc_wakeup,
 	.wakeup			= usba_udc_wakeup,
 	.set_selfpowered	= usba_udc_set_selfpowered,
 	.set_selfpowered	= usba_udc_set_selfpowered,
+	.start			= atmel_usba_start,
+	.stop			= atmel_usba_stop,
 };
 };
 
 
 static struct usb_endpoint_descriptor usba_ep0_desc = {
 static struct usb_endpoint_descriptor usba_ep0_desc = {
@@ -1789,7 +1795,7 @@ out:
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }
 
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int atmel_usba_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 		int (*bind)(struct usb_gadget *))
 {
 {
 	struct usba_udc *udc = &the_udc;
 	struct usba_udc *udc = &the_udc;
@@ -1842,9 +1848,8 @@ err_driver_bind:
 	udc->gadget.dev.driver = NULL;
 	udc->gadget.dev.driver = NULL;
 	return ret;
 	return ret;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int atmel_usba_stop(struct usb_gadget_driver *driver)
 {
 {
 	struct usba_udc *udc = &the_udc;
 	struct usba_udc *udc = &the_udc;
 	unsigned long flags;
 	unsigned long flags;
@@ -1880,7 +1885,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 
 
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 
 static int __init usba_udc_probe(struct platform_device *pdev)
 static int __init usba_udc_probe(struct platform_device *pdev)
 {
 {
@@ -2021,12 +2025,24 @@ static int __init usba_udc_probe(struct platform_device *pdev)
 		}
 		}
 	}
 	}
 
 
+	ret = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
+	if (ret)
+		goto err_add_udc;
+
 	usba_init_debugfs(udc);
 	usba_init_debugfs(udc);
 	for (i = 1; i < pdata->num_ep; i++)
 	for (i = 1; i < pdata->num_ep; i++)
 		usba_ep_init_debugfs(udc, &usba_ep[i]);
 		usba_ep_init_debugfs(udc, &usba_ep[i]);
 
 
 	return 0;
 	return 0;
 
 
+err_add_udc:
+	if (gpio_is_valid(pdata->vbus_pin)) {
+		free_irq(gpio_to_irq(udc->vbus_pin), udc);
+		gpio_free(udc->vbus_pin);
+	}
+
+	device_unregister(&udc->gadget.dev);
+
 err_device_add:
 err_device_add:
 	free_irq(irq, udc);
 	free_irq(irq, udc);
 err_request_irq:
 err_request_irq:
@@ -2053,6 +2069,8 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
 
 
 	udc = platform_get_drvdata(pdev);
 	udc = platform_get_drvdata(pdev);
 
 
+	usb_del_gadget_udc(&udc->gadget);
+
 	for (i = 1; i < pdata->num_ep; i++)
 	for (i = 1; i < pdata->num_ep; i++)
 		usba_ep_cleanup_debugfs(&usba_ep[i]);
 		usba_ep_cleanup_debugfs(&usba_ep[i]);
 	usba_cleanup_debugfs(udc);
 	usba_cleanup_debugfs(udc);

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

@@ -165,6 +165,7 @@ static struct usb_composite_driver audio_driver = {
 	.name		= "g_audio",
 	.name		= "g_audio",
 	.dev		= &device_desc,
 	.dev		= &device_desc,
 	.strings	= audio_strings,
 	.strings	= audio_strings,
+	.max_speed	= USB_SPEED_HIGH,
 	.unbind		= __exit_p(audio_unbind),
 	.unbind		= __exit_p(audio_unbind),
 };
 };
 
 

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

@@ -244,6 +244,7 @@ static struct usb_composite_driver cdc_driver = {
 	.name		= "g_cdc",
 	.name		= "g_cdc",
 	.dev		= &device_desc,
 	.dev		= &device_desc,
 	.strings	= dev_strings,
 	.strings	= dev_strings,
+	.max_speed	= USB_SPEED_HIGH,
 	.unbind		= __exit_p(cdc_unbind),
 	.unbind		= __exit_p(cdc_unbind),
 };
 };
 
 

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

@@ -126,6 +126,7 @@ static struct platform_driver ci13xxx_msm_driver = {
 	.probe = ci13xxx_msm_probe,
 	.probe = ci13xxx_msm_probe,
 	.driver = { .name = "msm_hsusb", },
 	.driver = { .name = "msm_hsusb", },
 };
 };
+MODULE_ALIAS("platform:msm_hsusb");
 
 
 static int __init ci13xxx_msm_init(void)
 static int __init ci13xxx_msm_init(void)
 {
 {

+ 44 - 18
drivers/usb/gadget/ci13xxx_udc.c

@@ -857,7 +857,7 @@ static void dbg_print(u8 addr, const char *name, int status, const char *extra)
 	stamp = stamp * 1000000 + tval.tv_usec;
 	stamp = stamp * 1000000 + tval.tv_usec;
 
 
 	scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
 	scnprintf(dbg_data.buf[dbg_data.idx], DBG_DATA_MSG,
-		  "%04X\t» %02X %-7.7s %4i «\t%s\n",
+		  "%04X\t? %02X %-7.7s %4i ?\t%s\n",
 		  stamp, addr, name, status, extra);
 		  stamp, addr, name, status, extra);
 
 
 	dbg_inc(&dbg_data.idx);
 	dbg_inc(&dbg_data.idx);
@@ -865,7 +865,7 @@ static void dbg_print(u8 addr, const char *name, int status, const char *extra)
 	write_unlock_irqrestore(&dbg_data.lck, flags);
 	write_unlock_irqrestore(&dbg_data.lck, flags);
 
 
 	if (dbg_data.tty != 0)
 	if (dbg_data.tty != 0)
-		pr_notice("%04X\t» %02X %-7.7s %4i «\t%s\n",
+		pr_notice("%04X\t? %02X %-7.7s %4i ?\t%s\n",
 			  stamp, addr, name, status, extra);
 			  stamp, addr, name, status, extra);
 }
 }
 
 
@@ -1025,15 +1025,15 @@ static ssize_t show_inters(struct device *dev, struct device_attribute *attr,
 
 
 	n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
 	n += scnprintf(buf + n, PAGE_SIZE - n, "*test = %d\n",
 		       isr_statistics.test);
 		       isr_statistics.test);
-	n += scnprintf(buf + n, PAGE_SIZE - n, "» ui  = %d\n",
+	n += scnprintf(buf + n, PAGE_SIZE - n, "? ui  = %d\n",
 		       isr_statistics.ui);
 		       isr_statistics.ui);
-	n += scnprintf(buf + n, PAGE_SIZE - n, "» uei = %d\n",
+	n += scnprintf(buf + n, PAGE_SIZE - n, "? uei = %d\n",
 		       isr_statistics.uei);
 		       isr_statistics.uei);
-	n += scnprintf(buf + n, PAGE_SIZE - n, "» pci = %d\n",
+	n += scnprintf(buf + n, PAGE_SIZE - n, "? pci = %d\n",
 		       isr_statistics.pci);
 		       isr_statistics.pci);
-	n += scnprintf(buf + n, PAGE_SIZE - n, "» uri = %d\n",
+	n += scnprintf(buf + n, PAGE_SIZE - n, "? uri = %d\n",
 		       isr_statistics.uri);
 		       isr_statistics.uri);
-	n += scnprintf(buf + n, PAGE_SIZE - n, "» sli = %d\n",
+	n += scnprintf(buf + n, PAGE_SIZE - n, "? sli = %d\n",
 		       isr_statistics.sli);
 		       isr_statistics.sli);
 	n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",
 	n += scnprintf(buf + n, PAGE_SIZE - n, "*none = %d\n",
 		       isr_statistics.none);
 		       isr_statistics.none);
@@ -1214,12 +1214,13 @@ static DEVICE_ATTR(qheads, S_IRUSR, show_qheads, NULL);
  *
  *
  * Check "device.h" for details
  * Check "device.h" for details
  */
  */
+#define DUMP_ENTRIES	512
 static ssize_t show_registers(struct device *dev,
 static ssize_t show_registers(struct device *dev,
 			      struct device_attribute *attr, char *buf)
 			      struct device_attribute *attr, char *buf)
 {
 {
 	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
 	struct ci13xxx *udc = container_of(dev, struct ci13xxx, gadget.dev);
 	unsigned long flags;
 	unsigned long flags;
-	u32 dump[512];
+	u32 *dump;
 	unsigned i, k, n = 0;
 	unsigned i, k, n = 0;
 
 
 	dbg_trace("[%s] %p\n", __func__, buf);
 	dbg_trace("[%s] %p\n", __func__, buf);
@@ -1228,8 +1229,14 @@ static ssize_t show_registers(struct device *dev,
 		return 0;
 		return 0;
 	}
 	}
 
 
+	dump = kmalloc(sizeof(u32) * DUMP_ENTRIES, GFP_KERNEL);
+	if (!dump) {
+		dev_err(dev, "%s: out of memory\n", __func__);
+		return 0;
+	}
+
 	spin_lock_irqsave(udc->lock, flags);
 	spin_lock_irqsave(udc->lock, flags);
-	k = hw_register_read(dump, sizeof(dump)/sizeof(u32));
+	k = hw_register_read(dump, DUMP_ENTRIES);
 	spin_unlock_irqrestore(udc->lock, flags);
 	spin_unlock_irqrestore(udc->lock, flags);
 
 
 	for (i = 0; i < k; i++) {
 	for (i = 0; i < k; i++) {
@@ -1237,6 +1244,7 @@ static ssize_t show_registers(struct device *dev,
 			       "reg[0x%04X] = 0x%08X\n",
 			       "reg[0x%04X] = 0x%08X\n",
 			       i * (unsigned)sizeof(u32), dump[i]);
 			       i * (unsigned)sizeof(u32), dump[i]);
 	}
 	}
+	kfree(dump);
 
 
 	return n;
 	return n;
 }
 }
@@ -2515,6 +2523,9 @@ static int ci13xxx_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
 	return -ENOTSUPP;
 	return -ENOTSUPP;
 }
 }
 
 
+static int ci13xxx_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int ci13xxx_stop(struct usb_gadget_driver *driver);
 /**
 /**
  * Device operations part of the API to the USB controller hardware,
  * Device operations part of the API to the USB controller hardware,
  * which don't involve endpoints (or i/o)
  * which don't involve endpoints (or i/o)
@@ -2524,17 +2535,19 @@ static const struct usb_gadget_ops usb_gadget_ops = {
 	.vbus_session	= ci13xxx_vbus_session,
 	.vbus_session	= ci13xxx_vbus_session,
 	.wakeup		= ci13xxx_wakeup,
 	.wakeup		= ci13xxx_wakeup,
 	.vbus_draw	= ci13xxx_vbus_draw,
 	.vbus_draw	= ci13xxx_vbus_draw,
+	.start		= ci13xxx_start,
+	.stop		= ci13xxx_stop,
 };
 };
 
 
 /**
 /**
- * usb_gadget_probe_driver: register a gadget driver
+ * ci13xxx_start: register a gadget driver
  * @driver: the driver being registered
  * @driver: the driver being registered
  * @bind: the driver's bind callback
  * @bind: the driver's bind callback
  *
  *
- * Check usb_gadget_probe_driver() at <linux/usb/gadget.h> for details.
+ * Check ci13xxx_start() at <linux/usb/gadget.h> for details.
  * Interrupts are enabled here.
  * Interrupts are enabled here.
  */
  */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int ci13xxx_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 		int (*bind)(struct usb_gadget *))
 {
 {
 	struct ci13xxx *udc = _udc;
 	struct ci13xxx *udc = _udc;
@@ -2615,10 +2628,13 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 	if (retval)
 	if (retval)
 		goto done;
 		goto done;
 	spin_unlock_irqrestore(udc->lock, flags);
 	spin_unlock_irqrestore(udc->lock, flags);
-	retval = usb_ep_enable(&udc->ep0out.ep, &ctrl_endpt_out_desc);
+	udc->ep0out.ep.desc = &ctrl_endpt_out_desc;
+	retval = usb_ep_enable(&udc->ep0out.ep);
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
-	retval = usb_ep_enable(&udc->ep0in.ep, &ctrl_endpt_in_desc);
+
+	udc->ep0in.ep.desc = &ctrl_endpt_in_desc;
+	retval = usb_ep_enable(&udc->ep0in.ep);
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
 	spin_lock_irqsave(udc->lock, flags);
 	spin_lock_irqsave(udc->lock, flags);
@@ -2657,14 +2673,13 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 	spin_unlock_irqrestore(udc->lock, flags);
 	spin_unlock_irqrestore(udc->lock, flags);
 	return retval;
 	return retval;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 
 /**
 /**
- * usb_gadget_unregister_driver: unregister a gadget driver
+ * ci13xxx_stop: unregister a gadget driver
  *
  *
  * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details
  * Check usb_gadget_unregister_driver() at "usb_gadget.h" for details
  */
  */
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int ci13xxx_stop(struct usb_gadget_driver *driver)
 {
 {
 	struct ci13xxx *udc = _udc;
 	struct ci13xxx *udc = _udc;
 	unsigned long i, flags;
 	unsigned long i, flags;
@@ -2726,7 +2741,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 
 
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 
 /******************************************************************************
 /******************************************************************************
  * BUS block
  * BUS block
@@ -2901,12 +2915,23 @@ static int udc_probe(struct ci13xxx_udc_driver *driver, struct device *dev,
 		if (retval)
 		if (retval)
 			goto remove_dbg;
 			goto remove_dbg;
 	}
 	}
+
+	retval = usb_add_gadget_udc(dev, &udc->gadget);
+	if (retval)
+		goto remove_trans;
+
 	pm_runtime_no_callbacks(&udc->gadget.dev);
 	pm_runtime_no_callbacks(&udc->gadget.dev);
 	pm_runtime_enable(&udc->gadget.dev);
 	pm_runtime_enable(&udc->gadget.dev);
 
 
 	_udc = udc;
 	_udc = udc;
 	return retval;
 	return retval;
 
 
+remove_trans:
+	if (udc->transceiver) {
+		otg_set_peripheral(udc->transceiver, &udc->gadget);
+		otg_put_transceiver(udc->transceiver);
+	}
+
 	err("error = %i", retval);
 	err("error = %i", retval);
 remove_dbg:
 remove_dbg:
 #ifdef CONFIG_USB_GADGET_DEBUG_FILES
 #ifdef CONFIG_USB_GADGET_DEBUG_FILES
@@ -2936,6 +2961,7 @@ static void udc_remove(void)
 		err("EINVAL");
 		err("EINVAL");
 		return;
 		return;
 	}
 	}
+	usb_del_gadget_udc(&udc->gadget);
 
 
 	if (udc->transceiver) {
 	if (udc->transceiver) {
 		otg_set_peripheral(udc->transceiver, &udc->gadget);
 		otg_set_peripheral(udc->transceiver, &udc->gadget);

+ 339 - 24
drivers/usb/gadget/composite.c

@@ -27,7 +27,7 @@
 #include <linux/utsname.h>
 #include <linux/utsname.h>
 
 
 #include <linux/usb/composite.h>
 #include <linux/usb/composite.h>
-
+#include <asm/unaligned.h>
 
 
 /*
 /*
  * The code in this file is utility code, used to build a gadget driver
  * The code in this file is utility code, used to build a gadget driver
@@ -74,6 +74,130 @@ MODULE_PARM_DESC(iSerialNumber, "SerialNumber string");
 static char composite_manufacturer[50];
 static char composite_manufacturer[50];
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
+/**
+ * next_ep_desc() - advance to the next EP descriptor
+ * @t: currect pointer within descriptor array
+ *
+ * Return: next EP descriptor or NULL
+ *
+ * Iterate over @t until either EP descriptor found or
+ * NULL (that indicates end of list) encountered
+ */
+static struct usb_descriptor_header**
+next_ep_desc(struct usb_descriptor_header **t)
+{
+	for (; *t; t++) {
+		if ((*t)->bDescriptorType == USB_DT_ENDPOINT)
+			return t;
+	}
+	return NULL;
+}
+
+/*
+ * for_each_ep_desc()- iterate over endpoint descriptors in the
+ *		descriptors list
+ * @start:	pointer within descriptor array.
+ * @ep_desc:	endpoint descriptor to use as the loop cursor
+ */
+#define for_each_ep_desc(start, ep_desc) \
+	for (ep_desc = next_ep_desc(start); \
+	      ep_desc; ep_desc = next_ep_desc(ep_desc+1))
+
+/**
+ * config_ep_by_speed() - configures the given endpoint
+ * according to gadget speed.
+ * @g: pointer to the gadget
+ * @f: usb function
+ * @_ep: the endpoint to configure
+ *
+ * Return: error code, 0 on success
+ *
+ * This function chooses the right descriptors for a given
+ * endpoint according to gadget speed and saves it in the
+ * endpoint desc field. If the endpoint already has a descriptor
+ * assigned to it - overwrites it with currently corresponding
+ * descriptor. The endpoint maxpacket field is updated according
+ * to the chosen descriptor.
+ * Note: the supplied function should hold all the descriptors
+ * for supported speeds
+ */
+int config_ep_by_speed(struct usb_gadget *g,
+			struct usb_function *f,
+			struct usb_ep *_ep)
+{
+	struct usb_endpoint_descriptor *chosen_desc = NULL;
+	struct usb_descriptor_header **speed_desc = NULL;
+
+	struct usb_ss_ep_comp_descriptor *comp_desc = NULL;
+	int want_comp_desc = 0;
+
+	struct usb_descriptor_header **d_spd; /* cursor for speed desc */
+
+	if (!g || !f || !_ep)
+		return -EIO;
+
+	/* select desired speed */
+	switch (g->speed) {
+	case USB_SPEED_SUPER:
+		if (gadget_is_superspeed(g)) {
+			speed_desc = f->ss_descriptors;
+			want_comp_desc = 1;
+			break;
+		}
+		/* else: Fall trough */
+	case USB_SPEED_HIGH:
+		if (gadget_is_dualspeed(g)) {
+			speed_desc = f->hs_descriptors;
+			break;
+		}
+		/* else: fall through */
+	default:
+		speed_desc = f->descriptors;
+	}
+	/* find descriptors */
+	for_each_ep_desc(speed_desc, d_spd) {
+		chosen_desc = (struct usb_endpoint_descriptor *)*d_spd;
+		if (chosen_desc->bEndpointAddress == _ep->address)
+			goto ep_found;
+	}
+	return -EIO;
+
+ep_found:
+	/* commit results */
+	_ep->maxpacket = le16_to_cpu(chosen_desc->wMaxPacketSize);
+	_ep->desc = chosen_desc;
+	_ep->comp_desc = NULL;
+	_ep->maxburst = 0;
+	_ep->mult = 0;
+	if (!want_comp_desc)
+		return 0;
+
+	/*
+	 * Companion descriptor should follow EP descriptor
+	 * USB 3.0 spec, #9.6.7
+	 */
+	comp_desc = (struct usb_ss_ep_comp_descriptor *)*(++d_spd);
+	if (!comp_desc ||
+	    (comp_desc->bDescriptorType != USB_DT_SS_ENDPOINT_COMP))
+		return -EIO;
+	_ep->comp_desc = comp_desc;
+	if (g->speed == USB_SPEED_SUPER) {
+		switch (usb_endpoint_type(_ep->desc)) {
+		case USB_ENDPOINT_XFER_BULK:
+		case USB_ENDPOINT_XFER_INT:
+			_ep->maxburst = comp_desc->bMaxBurst;
+			break;
+		case USB_ENDPOINT_XFER_ISOC:
+			/* mult: bits 1:0 of bmAttributes */
+			_ep->mult = comp_desc->bmAttributes & 0x3;
+			break;
+		default:
+			/* Do nothing for control endpoints */
+			break;
+		}
+	}
+	return 0;
+}
 
 
 /**
 /**
  * usb_add_function() - add a function to a configuration
  * usb_add_function() - add a function to a configuration
@@ -123,6 +247,8 @@ int usb_add_function(struct usb_configuration *config,
 		config->fullspeed = true;
 		config->fullspeed = true;
 	if (!config->highspeed && function->hs_descriptors)
 	if (!config->highspeed && function->hs_descriptors)
 		config->highspeed = true;
 		config->highspeed = true;
+	if (!config->superspeed && function->ss_descriptors)
+		config->superspeed = true;
 
 
 done:
 done:
 	if (value)
 	if (value)
@@ -266,10 +392,17 @@ static int config_buf(struct usb_configuration *config,
 	list_for_each_entry(f, &config->functions, list) {
 	list_for_each_entry(f, &config->functions, list) {
 		struct usb_descriptor_header **descriptors;
 		struct usb_descriptor_header **descriptors;
 
 
-		if (speed == USB_SPEED_HIGH)
+		switch (speed) {
+		case USB_SPEED_SUPER:
+			descriptors = f->ss_descriptors;
+			break;
+		case USB_SPEED_HIGH:
 			descriptors = f->hs_descriptors;
 			descriptors = f->hs_descriptors;
-		else
+			break;
+		default:
 			descriptors = f->descriptors;
 			descriptors = f->descriptors;
+		}
+
 		if (!descriptors)
 		if (!descriptors)
 			continue;
 			continue;
 		status = usb_descriptor_fillbuf(next, len,
 		status = usb_descriptor_fillbuf(next, len,
@@ -292,9 +425,10 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
 	u8				type = w_value >> 8;
 	u8				type = w_value >> 8;
 	enum usb_device_speed		speed = USB_SPEED_UNKNOWN;
 	enum usb_device_speed		speed = USB_SPEED_UNKNOWN;
 
 
-	if (gadget_is_dualspeed(gadget)) {
-		int			hs = 0;
-
+	if (gadget->speed == USB_SPEED_SUPER)
+		speed = gadget->speed;
+	else if (gadget_is_dualspeed(gadget)) {
+		int	hs = 0;
 		if (gadget->speed == USB_SPEED_HIGH)
 		if (gadget->speed == USB_SPEED_HIGH)
 			hs = 1;
 			hs = 1;
 		if (type == USB_DT_OTHER_SPEED_CONFIG)
 		if (type == USB_DT_OTHER_SPEED_CONFIG)
@@ -308,13 +442,20 @@ static int config_desc(struct usb_composite_dev *cdev, unsigned w_value)
 	w_value &= 0xff;
 	w_value &= 0xff;
 	list_for_each_entry(c, &cdev->configs, list) {
 	list_for_each_entry(c, &cdev->configs, list) {
 		/* ignore configs that won't work at this speed */
 		/* ignore configs that won't work at this speed */
-		if (speed == USB_SPEED_HIGH) {
+		switch (speed) {
+		case USB_SPEED_SUPER:
+			if (!c->superspeed)
+				continue;
+			break;
+		case USB_SPEED_HIGH:
 			if (!c->highspeed)
 			if (!c->highspeed)
 				continue;
 				continue;
-		} else {
+			break;
+		default:
 			if (!c->fullspeed)
 			if (!c->fullspeed)
 				continue;
 				continue;
 		}
 		}
+
 		if (w_value == 0)
 		if (w_value == 0)
 			return config_buf(c, speed, cdev->req->buf, type);
 			return config_buf(c, speed, cdev->req->buf, type);
 		w_value--;
 		w_value--;
@@ -328,16 +469,22 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type)
 	struct usb_configuration	*c;
 	struct usb_configuration	*c;
 	unsigned			count = 0;
 	unsigned			count = 0;
 	int				hs = 0;
 	int				hs = 0;
+	int				ss = 0;
 
 
 	if (gadget_is_dualspeed(gadget)) {
 	if (gadget_is_dualspeed(gadget)) {
 		if (gadget->speed == USB_SPEED_HIGH)
 		if (gadget->speed == USB_SPEED_HIGH)
 			hs = 1;
 			hs = 1;
+		if (gadget->speed == USB_SPEED_SUPER)
+			ss = 1;
 		if (type == USB_DT_DEVICE_QUALIFIER)
 		if (type == USB_DT_DEVICE_QUALIFIER)
 			hs = !hs;
 			hs = !hs;
 	}
 	}
 	list_for_each_entry(c, &cdev->configs, list) {
 	list_for_each_entry(c, &cdev->configs, list) {
 		/* ignore configs that won't work at this speed */
 		/* ignore configs that won't work at this speed */
-		if (hs) {
+		if (ss) {
+			if (!c->superspeed)
+				continue;
+		} else if (hs) {
 			if (!c->highspeed)
 			if (!c->highspeed)
 				continue;
 				continue;
 		} else {
 		} else {
@@ -349,6 +496,71 @@ static int count_configs(struct usb_composite_dev *cdev, unsigned type)
 	return count;
 	return count;
 }
 }
 
 
+/**
+ * bos_desc() - prepares the BOS descriptor.
+ * @cdev: pointer to usb_composite device to generate the bos
+ *	descriptor for
+ *
+ * This function generates the BOS (Binary Device Object)
+ * descriptor and its device capabilities descriptors. The BOS
+ * descriptor should be supported by a SuperSpeed device.
+ */
+static int bos_desc(struct usb_composite_dev *cdev)
+{
+	struct usb_ext_cap_descriptor	*usb_ext;
+	struct usb_ss_cap_descriptor	*ss_cap;
+	struct usb_dcd_config_params	dcd_config_params;
+	struct usb_bos_descriptor	*bos = cdev->req->buf;
+
+	bos->bLength = USB_DT_BOS_SIZE;
+	bos->bDescriptorType = USB_DT_BOS;
+
+	bos->wTotalLength = cpu_to_le16(USB_DT_BOS_SIZE);
+	bos->bNumDeviceCaps = 0;
+
+	/*
+	 * A SuperSpeed device shall include the USB2.0 extension descriptor
+	 * and shall support LPM when operating in USB2.0 HS mode.
+	 */
+	usb_ext = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+	bos->bNumDeviceCaps++;
+	le16_add_cpu(&bos->wTotalLength, USB_DT_USB_EXT_CAP_SIZE);
+	usb_ext->bLength = USB_DT_USB_EXT_CAP_SIZE;
+	usb_ext->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+	usb_ext->bDevCapabilityType = USB_CAP_TYPE_EXT;
+	usb_ext->bmAttributes = cpu_to_le32(USB_LPM_SUPPORT);
+
+	/*
+	 * The Superspeed USB Capability descriptor shall be implemented by all
+	 * SuperSpeed devices.
+	 */
+	ss_cap = cdev->req->buf + le16_to_cpu(bos->wTotalLength);
+	bos->bNumDeviceCaps++;
+	le16_add_cpu(&bos->wTotalLength, USB_DT_USB_SS_CAP_SIZE);
+	ss_cap->bLength = USB_DT_USB_SS_CAP_SIZE;
+	ss_cap->bDescriptorType = USB_DT_DEVICE_CAPABILITY;
+	ss_cap->bDevCapabilityType = USB_SS_CAP_TYPE;
+	ss_cap->bmAttributes = 0; /* LTM is not supported yet */
+	ss_cap->wSpeedSupported = cpu_to_le16(USB_LOW_SPEED_OPERATION |
+				USB_FULL_SPEED_OPERATION |
+				USB_HIGH_SPEED_OPERATION |
+				USB_5GBPS_OPERATION);
+	ss_cap->bFunctionalitySupport = USB_LOW_SPEED_OPERATION;
+
+	/* Get Controller configuration */
+	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.bU2DevExitLat =
+			cpu_to_le16(USB_DEFULT_U2_DEV_EXIT_LAT);
+	}
+	ss_cap->bU1devExitLat = dcd_config_params.bU1devExitLat;
+	ss_cap->bU2DevExitLat = dcd_config_params.bU2DevExitLat;
+
+	return le16_to_cpu(bos->wTotalLength);
+}
+
 static void device_qual(struct usb_composite_dev *cdev)
 static void device_qual(struct usb_composite_dev *cdev)
 {
 {
 	struct usb_qualifier_descriptor	*qual = cdev->req->buf;
 	struct usb_qualifier_descriptor	*qual = cdev->req->buf;
@@ -361,7 +573,7 @@ static void device_qual(struct usb_composite_dev *cdev)
 	qual->bDeviceSubClass = cdev->desc.bDeviceSubClass;
 	qual->bDeviceSubClass = cdev->desc.bDeviceSubClass;
 	qual->bDeviceProtocol = cdev->desc.bDeviceProtocol;
 	qual->bDeviceProtocol = cdev->desc.bDeviceProtocol;
 	/* ASSUME same EP0 fifo size at both speeds */
 	/* ASSUME same EP0 fifo size at both speeds */
-	qual->bMaxPacketSize0 = cdev->desc.bMaxPacketSize0;
+	qual->bMaxPacketSize0 = cdev->gadget->ep0->maxpacket;
 	qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER);
 	qual->bNumConfigurations = count_configs(cdev, USB_DT_DEVICE_QUALIFIER);
 	qual->bRESERVED = 0;
 	qual->bRESERVED = 0;
 }
 }
@@ -392,28 +604,46 @@ static int set_config(struct usb_composite_dev *cdev,
 	unsigned		power = gadget_is_otg(gadget) ? 8 : 100;
 	unsigned		power = gadget_is_otg(gadget) ? 8 : 100;
 	int			tmp;
 	int			tmp;
 
 
-	if (cdev->config)
-		reset_config(cdev);
-
 	if (number) {
 	if (number) {
 		list_for_each_entry(c, &cdev->configs, list) {
 		list_for_each_entry(c, &cdev->configs, list) {
 			if (c->bConfigurationValue == number) {
 			if (c->bConfigurationValue == number) {
+				/*
+				 * We disable the FDs of the previous
+				 * configuration only if the new configuration
+				 * is a valid one
+				 */
+				if (cdev->config)
+					reset_config(cdev);
 				result = 0;
 				result = 0;
 				break;
 				break;
 			}
 			}
 		}
 		}
 		if (result < 0)
 		if (result < 0)
 			goto done;
 			goto done;
-	} else
+	} else { /* Zero configuration value - need to reset the config */
+		if (cdev->config)
+			reset_config(cdev);
 		result = 0;
 		result = 0;
+	}
 
 
 	INFO(cdev, "%s speed config #%d: %s\n",
 	INFO(cdev, "%s speed config #%d: %s\n",
 		({ char *speed;
 		({ char *speed;
 		switch (gadget->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;
+		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");
 		} ; speed; }), number, c ? c->label : "unconfigured");
 
 
 	if (!c)
 	if (!c)
@@ -435,10 +665,16 @@ static int set_config(struct usb_composite_dev *cdev,
 		 * function's setup callback instead of the current
 		 * function's setup callback instead of the current
 		 * configuration's setup callback.
 		 * configuration's setup callback.
 		 */
 		 */
-		if (gadget->speed == USB_SPEED_HIGH)
+		switch (gadget->speed) {
+		case USB_SPEED_SUPER:
+			descriptors = f->ss_descriptors;
+			break;
+		case USB_SPEED_HIGH:
 			descriptors = f->hs_descriptors;
 			descriptors = f->hs_descriptors;
-		else
+			break;
+		default:
 			descriptors = f->descriptors;
 			descriptors = f->descriptors;
+		}
 
 
 		for (; *descriptors; ++descriptors) {
 		for (; *descriptors; ++descriptors) {
 			struct usb_endpoint_descriptor *ep;
 			struct usb_endpoint_descriptor *ep;
@@ -531,8 +767,9 @@ int usb_add_config(struct usb_composite_dev *cdev,
 	} else {
 	} else {
 		unsigned	i;
 		unsigned	i;
 
 
-		DBG(cdev, "cfg %d/%p speeds:%s%s\n",
+		DBG(cdev, "cfg %d/%p speeds:%s%s%s\n",
 			config->bConfigurationValue, config,
 			config->bConfigurationValue, config,
+			config->superspeed ? " super" : "",
 			config->highspeed ? " high" : "",
 			config->highspeed ? " high" : "",
 			config->fullspeed
 			config->fullspeed
 				? (gadget_is_dualspeed(cdev->gadget)
 				? (gadget_is_dualspeed(cdev->gadget)
@@ -811,6 +1048,7 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
 	struct usb_composite_dev	*cdev = get_gadget_data(gadget);
 	struct usb_request		*req = cdev->req;
 	struct usb_request		*req = cdev->req;
 	int				value = -EOPNOTSUPP;
 	int				value = -EOPNOTSUPP;
+	int				status = 0;
 	u16				w_index = le16_to_cpu(ctrl->wIndex);
 	u16				w_index = le16_to_cpu(ctrl->wIndex);
 	u8				intf = w_index & 0xFF;
 	u8				intf = w_index & 0xFF;
 	u16				w_value = le16_to_cpu(ctrl->wValue);
 	u16				w_value = le16_to_cpu(ctrl->wValue);
@@ -838,18 +1076,29 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 		case USB_DT_DEVICE:
 		case USB_DT_DEVICE:
 			cdev->desc.bNumConfigurations =
 			cdev->desc.bNumConfigurations =
 				count_configs(cdev, USB_DT_DEVICE);
 				count_configs(cdev, USB_DT_DEVICE);
+			cdev->desc.bMaxPacketSize0 =
+				cdev->gadget->ep0->maxpacket;
+			if (gadget_is_superspeed(gadget)) {
+				if (gadget->speed >= USB_SPEED_SUPER)
+					cdev->desc.bcdUSB = cpu_to_le16(0x0300);
+				else
+					cdev->desc.bcdUSB = cpu_to_le16(0x0210);
+			}
+
 			value = min(w_length, (u16) sizeof cdev->desc);
 			value = min(w_length, (u16) sizeof cdev->desc);
 			memcpy(req->buf, &cdev->desc, value);
 			memcpy(req->buf, &cdev->desc, value);
 			break;
 			break;
 		case USB_DT_DEVICE_QUALIFIER:
 		case USB_DT_DEVICE_QUALIFIER:
-			if (!gadget_is_dualspeed(gadget))
+			if (!gadget_is_dualspeed(gadget) ||
+			    gadget->speed >= USB_SPEED_SUPER)
 				break;
 				break;
 			device_qual(cdev);
 			device_qual(cdev);
 			value = min_t(int, w_length,
 			value = min_t(int, w_length,
 				sizeof(struct usb_qualifier_descriptor));
 				sizeof(struct usb_qualifier_descriptor));
 			break;
 			break;
 		case USB_DT_OTHER_SPEED_CONFIG:
 		case USB_DT_OTHER_SPEED_CONFIG:
-			if (!gadget_is_dualspeed(gadget))
+			if (!gadget_is_dualspeed(gadget) ||
+			    gadget->speed >= USB_SPEED_SUPER)
 				break;
 				break;
 			/* FALLTHROUGH */
 			/* FALLTHROUGH */
 		case USB_DT_CONFIG:
 		case USB_DT_CONFIG:
@@ -863,6 +1112,12 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 			if (value >= 0)
 			if (value >= 0)
 				value = min(w_length, (u16) value);
 				value = min(w_length, (u16) value);
 			break;
 			break;
+		case USB_DT_BOS:
+			if (gadget_is_superspeed(gadget)) {
+				value = bos_desc(cdev);
+				value = min(w_length, (u16) value);
+			}
+			break;
 		}
 		}
 		break;
 		break;
 
 
@@ -930,6 +1185,61 @@ composite_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 		*((u8 *)req->buf) = value;
 		*((u8 *)req->buf) = value;
 		value = min(w_length, (u16) 1);
 		value = min(w_length, (u16) 1);
 		break;
 		break;
+
+	/*
+	 * USB 3.0 additions:
+	 * Function driver should handle get_status request. If such cb
+	 * wasn't supplied we respond with default value = 0
+	 * Note: function driver should supply such cb only for the first
+	 * interface of the function
+	 */
+	case USB_REQ_GET_STATUS:
+		if (!gadget_is_superspeed(gadget))
+			goto unknown;
+		if (ctrl->bRequestType != (USB_DIR_IN | USB_RECIP_INTERFACE))
+			goto unknown;
+		value = 2;	/* This is the length of the get_status reply */
+		put_unaligned_le16(0, req->buf);
+		if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
+			break;
+		f = cdev->config->interface[intf];
+		if (!f)
+			break;
+		status = f->get_status ? f->get_status(f) : 0;
+		if (status < 0)
+			break;
+		put_unaligned_le16(status & 0x0000ffff, req->buf);
+		break;
+	/*
+	 * Function drivers should handle SetFeature/ClearFeature
+	 * (FUNCTION_SUSPEND) request. function_suspend cb should be supplied
+	 * only for the first interface of the function
+	 */
+	case USB_REQ_CLEAR_FEATURE:
+	case USB_REQ_SET_FEATURE:
+		if (!gadget_is_superspeed(gadget))
+			goto unknown;
+		if (ctrl->bRequestType != (USB_DIR_OUT | USB_RECIP_INTERFACE))
+			goto unknown;
+		switch (w_value) {
+		case USB_INTRF_FUNC_SUSPEND:
+			if (!cdev->config || intf >= MAX_CONFIG_INTERFACES)
+				break;
+			f = cdev->config->interface[intf];
+			if (!f)
+				break;
+			value = 0;
+			if (f->func_suspend)
+				value = f->func_suspend(f, w_index >> 8);
+			if (value < 0) {
+				ERROR(cdev,
+				      "func_suspend() returned error %d\n",
+				      value);
+				value = 0;
+			}
+			break;
+		}
+		break;
 	default:
 	default:
 unknown:
 unknown:
 		VDBG(cdev,
 		VDBG(cdev,
@@ -1140,7 +1450,6 @@ static int composite_bind(struct usb_gadget *gadget)
 		goto fail;
 		goto fail;
 
 
 	cdev->desc = *composite->dev;
 	cdev->desc = *composite->dev;
-	cdev->desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 
 
 	/* standardized runtime overrides for device ID data */
 	/* standardized runtime overrides for device ID data */
 	if (idVendor)
 	if (idVendor)
@@ -1247,7 +1556,11 @@ composite_resume(struct usb_gadget *gadget)
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 static struct usb_gadget_driver composite_driver = {
 static struct usb_gadget_driver composite_driver = {
+#ifdef CONFIG_USB_GADGET_SUPERSPEED
+	.speed		= USB_SPEED_SUPER,
+#else
 	.speed		= USB_SPEED_HIGH,
 	.speed		= USB_SPEED_HIGH,
+#endif
 
 
 	.unbind		= composite_unbind,
 	.unbind		= composite_unbind,
 
 
@@ -1293,6 +1606,8 @@ int usb_composite_probe(struct usb_composite_driver *driver,
 		driver->iProduct = driver->name;
 		driver->iProduct = driver->name;
 	composite_driver.function =  (char *) driver->name;
 	composite_driver.function =  (char *) driver->name;
 	composite_driver.driver.name = driver->name;
 	composite_driver.driver.name = driver->name;
+	composite_driver.speed = min((u8)composite_driver.speed,
+				     (u8)driver->max_speed);
 	composite = driver;
 	composite = driver;
 	composite_gadget_bind = bind;
 	composite_gadget_bind = bind;
 
 

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

@@ -165,28 +165,3 @@ usb_copy_descriptors(struct usb_descriptor_header **src)
 	return ret;
 	return ret;
 }
 }
 
 
-/**
- * usb_find_endpoint - find a copy of an endpoint descriptor
- * @src: original vector of descriptors
- * @copy: copy of @src
- * @match: endpoint descriptor found in @src
- *
- * This returns the copy of the @match descriptor made for @copy.  Its
- * intended use is to help remembering the endpoint descriptor to use
- * when enabling a given endpoint.
- */
-struct usb_endpoint_descriptor *
-usb_find_endpoint(
-	struct usb_descriptor_header **src,
-	struct usb_descriptor_header **copy,
-	struct usb_endpoint_descriptor *match
-)
-{
-	while (*src) {
-		if (*src == (void *) match)
-			return (void *)*copy;
-		src++;
-		copy++;
-	}
-	return NULL;
-}

+ 6 - 4
drivers/usb/gadget/dbgp.c

@@ -173,7 +173,9 @@ fail_1:
 
 
 static int __enable_ep(struct usb_ep *ep, struct usb_endpoint_descriptor *desc)
 static int __enable_ep(struct usb_ep *ep, struct usb_endpoint_descriptor *desc)
 {
 {
-	int err = usb_ep_enable(ep, desc);
+	int err;
+	ep->desc = desc;
+	err = usb_ep_enable(ep);
 	ep->driver_data = dbgp.gadget;
 	ep->driver_data = dbgp.gadget;
 	return err;
 	return err;
 }
 }
@@ -268,8 +270,8 @@ static int __init dbgp_configure_endpoints(struct usb_gadget *gadget)
 	dbgp.serial->in = dbgp.i_ep;
 	dbgp.serial->in = dbgp.i_ep;
 	dbgp.serial->out = dbgp.o_ep;
 	dbgp.serial->out = dbgp.o_ep;
 
 
-	dbgp.serial->in_desc = &i_desc;
-	dbgp.serial->out_desc = &o_desc;
+	dbgp.serial->in->desc = &i_desc;
+	dbgp.serial->out->desc = &o_desc;
 
 
 	if (gserial_setup(gadget, 1) < 0) {
 	if (gserial_setup(gadget, 1) < 0) {
 		stp = 3;
 		stp = 3;
@@ -312,7 +314,6 @@ static int __init dbgp_bind(struct usb_gadget *gadget)
 
 
 	dbgp.req->length = DBGP_REQ_EP0_LEN;
 	dbgp.req->length = DBGP_REQ_EP0_LEN;
 	gadget->ep0->driver_data = gadget;
 	gadget->ep0->driver_data = gadget;
-	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 
 
 #ifdef CONFIG_USB_G_DBGP_SERIAL
 #ifdef CONFIG_USB_G_DBGP_SERIAL
 	dbgp.serial = kzalloc(sizeof(struct gserial), GFP_KERNEL);
 	dbgp.serial = kzalloc(sizeof(struct gserial), GFP_KERNEL);
@@ -363,6 +364,7 @@ static int dbgp_setup(struct usb_gadget *gadget,
 			dev_dbg(&dbgp.gadget->dev, "setup: desc device\n");
 			dev_dbg(&dbgp.gadget->dev, "setup: desc device\n");
 			len = sizeof device_desc;
 			len = sizeof device_desc;
 			data = &device_desc;
 			data = &device_desc;
+			device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 			break;
 			break;
 		case USB_DT_DEBUG:
 		case USB_DT_DEBUG:
 			dev_dbg(&dbgp.gadget->dev, "setup: desc debug\n");
 			dev_dbg(&dbgp.gadget->dev, "setup: desc debug\n");

+ 794 - 368
drivers/usb/gadget/dummy_hcd.c

@@ -70,6 +70,19 @@ MODULE_DESCRIPTION (DRIVER_DESC);
 MODULE_AUTHOR ("David Brownell");
 MODULE_AUTHOR ("David Brownell");
 MODULE_LICENSE ("GPL");
 MODULE_LICENSE ("GPL");
 
 
+struct dummy_hcd_module_parameters {
+	bool is_super_speed;
+	bool is_high_speed;
+};
+
+static struct dummy_hcd_module_parameters mod_data = {
+	.is_super_speed = false,
+	.is_high_speed = true,
+};
+module_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO);
+MODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection");
+module_param_named(is_high_speed, mod_data.is_high_speed, bool, S_IRUGO);
+MODULE_PARM_DESC(is_high_speed, "true to simulate HighSpeed connection");
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 /* gadget side driver data structres */
 /* gadget side driver data structres */
@@ -152,6 +165,22 @@ enum dummy_rh_state {
 	DUMMY_RH_RUNNING
 	DUMMY_RH_RUNNING
 };
 };
 
 
+struct dummy_hcd {
+	struct dummy			*dum;
+	enum dummy_rh_state		rh_state;
+	struct timer_list		timer;
+	u32				port_status;
+	u32				old_status;
+	unsigned long			re_timeout;
+
+	struct usb_device		*udev;
+	struct list_head		urbp_list;
+
+	unsigned			active:1;
+	unsigned			old_active:1;
+	unsigned			resuming:1;
+};
+
 struct dummy {
 struct dummy {
 	spinlock_t			lock;
 	spinlock_t			lock;
 
 
@@ -167,36 +196,27 @@ struct dummy {
 	u16				devstatus;
 	u16				devstatus;
 	unsigned			udc_suspended:1;
 	unsigned			udc_suspended:1;
 	unsigned			pullup:1;
 	unsigned			pullup:1;
-	unsigned			active:1;
-	unsigned			old_active:1;
 
 
 	/*
 	/*
 	 * MASTER/HOST side support
 	 * MASTER/HOST side support
 	 */
 	 */
-	enum dummy_rh_state		rh_state;
-	struct timer_list		timer;
-	u32				port_status;
-	u32				old_status;
-	unsigned			resuming:1;
-	unsigned long			re_timeout;
-
-	struct usb_device		*udev;
-	struct list_head		urbp_list;
+	struct dummy_hcd		*hs_hcd;
+	struct dummy_hcd		*ss_hcd;
 };
 };
 
 
-static inline struct dummy *hcd_to_dummy (struct usb_hcd *hcd)
+static inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd)
 {
 {
-	return (struct dummy *) (hcd->hcd_priv);
+	return (struct dummy_hcd *) (hcd->hcd_priv);
 }
 }
 
 
-static inline struct usb_hcd *dummy_to_hcd (struct dummy *dum)
+static inline struct usb_hcd *dummy_hcd_to_hcd(struct dummy_hcd *dum)
 {
 {
 	return container_of((void *) dum, struct usb_hcd, hcd_priv);
 	return container_of((void *) dum, struct usb_hcd, hcd_priv);
 }
 }
 
 
-static inline struct device *dummy_dev (struct dummy *dum)
+static inline struct device *dummy_dev(struct dummy_hcd *dum)
 {
 {
-	return dummy_to_hcd(dum)->self.controller;
+	return dummy_hcd_to_hcd(dum)->self.controller;
 }
 }
 
 
 static inline struct device *udc_dev (struct dummy *dum)
 static inline struct device *udc_dev (struct dummy *dum)
@@ -209,9 +229,13 @@ static inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
 	return container_of (ep->gadget, struct dummy, gadget);
 	return container_of (ep->gadget, struct dummy, gadget);
 }
 }
 
 
-static inline struct dummy *gadget_to_dummy (struct usb_gadget *gadget)
+static inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)
 {
 {
-	return container_of (gadget, struct dummy, gadget);
+	struct dummy *dum = container_of(gadget, struct dummy, gadget);
+	if (dum->gadget.speed == USB_SPEED_SUPER)
+		return dum->ss_hcd;
+	else
+		return dum->hs_hcd;
 }
 }
 
 
 static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
 static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
@@ -219,7 +243,7 @@ static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
 	return container_of (dev, struct dummy, gadget.dev);
 	return container_of (dev, struct dummy, gadget.dev);
 }
 }
 
 
-static struct dummy			*the_controller;
+static struct dummy			the_controller;
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
@@ -259,61 +283,122 @@ stop_activity (struct dummy *dum)
 	/* driver now does any non-usb quiescing necessary */
 	/* driver now does any non-usb quiescing necessary */
 }
 }
 
 
-/* caller must hold lock */
-static void
-set_link_state (struct dummy *dum)
-{
-	dum->active = 0;
-	if ((dum->port_status & USB_PORT_STAT_POWER) == 0)
-		dum->port_status = 0;
-
-	/* UDC suspend must cause a disconnect */
-	else if (!dum->pullup || dum->udc_suspended) {
-		dum->port_status &= ~(USB_PORT_STAT_CONNECTION |
-					USB_PORT_STAT_ENABLE |
-					USB_PORT_STAT_LOW_SPEED |
-					USB_PORT_STAT_HIGH_SPEED |
-					USB_PORT_STAT_SUSPEND);
-		if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0)
-			dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
+/**
+ * set_link_state_by_speed() - Sets the current state of the link according to
+ *	the hcd speed
+ * @dum_hcd: pointer to the dummy_hcd structure to update the link state for
+ *
+ * This function updates the port_status according to the link state and the
+ * speed of the hcd.
+ */
+static void set_link_state_by_speed(struct dummy_hcd *dum_hcd)
+{
+	struct dummy *dum = dum_hcd->dum;
+
+	if (dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3) {
+		if ((dum_hcd->port_status & USB_SS_PORT_STAT_POWER) == 0) {
+			dum_hcd->port_status = 0;
+		} else if (!dum->pullup || dum->udc_suspended) {
+			/* UDC suspend must cause a disconnect */
+			dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
+						USB_PORT_STAT_ENABLE);
+			if ((dum_hcd->old_status &
+			     USB_PORT_STAT_CONNECTION) != 0)
+				dum_hcd->port_status |=
+					(USB_PORT_STAT_C_CONNECTION << 16);
+		} else {
+			/* device is connected and not suspended */
+			dum_hcd->port_status |= (USB_PORT_STAT_CONNECTION |
+						 USB_PORT_STAT_SPEED_5GBPS) ;
+			if ((dum_hcd->old_status &
+			     USB_PORT_STAT_CONNECTION) == 0)
+				dum_hcd->port_status |=
+					(USB_PORT_STAT_C_CONNECTION << 16);
+			if ((dum_hcd->port_status &
+			     USB_PORT_STAT_ENABLE) == 1 &&
+				(dum_hcd->port_status &
+				 USB_SS_PORT_LS_U0) == 1 &&
+				dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
+				dum_hcd->active = 1;
+		}
 	} else {
 	} else {
-		dum->port_status |= USB_PORT_STAT_CONNECTION;
-		if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0)
-			dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
-		if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0)
-			dum->port_status &= ~USB_PORT_STAT_SUSPEND;
-		else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
-				dum->rh_state != DUMMY_RH_SUSPENDED)
-			dum->active = 1;
+		if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0) {
+			dum_hcd->port_status = 0;
+		} else if (!dum->pullup || dum->udc_suspended) {
+			/* UDC suspend must cause a disconnect */
+			dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
+						USB_PORT_STAT_ENABLE |
+						USB_PORT_STAT_LOW_SPEED |
+						USB_PORT_STAT_HIGH_SPEED |
+						USB_PORT_STAT_SUSPEND);
+			if ((dum_hcd->old_status &
+			     USB_PORT_STAT_CONNECTION) != 0)
+				dum_hcd->port_status |=
+					(USB_PORT_STAT_C_CONNECTION << 16);
+		} else {
+			dum_hcd->port_status |= USB_PORT_STAT_CONNECTION;
+			if ((dum_hcd->old_status &
+			     USB_PORT_STAT_CONNECTION) == 0)
+				dum_hcd->port_status |=
+					(USB_PORT_STAT_C_CONNECTION << 16);
+			if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0)
+				dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
+			else if ((dum_hcd->port_status &
+				  USB_PORT_STAT_SUSPEND) == 0 &&
+					dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
+				dum_hcd->active = 1;
+		}
 	}
 	}
+}
+
+/* caller must hold lock */
+static void set_link_state(struct dummy_hcd *dum_hcd)
+{
+	struct dummy *dum = dum_hcd->dum;
 
 
-	if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active)
-		dum->resuming = 0;
+	dum_hcd->active = 0;
+	if (dum->pullup)
+		if ((dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3 &&
+		     dum->gadget.speed != USB_SPEED_SUPER) ||
+		    (dummy_hcd_to_hcd(dum_hcd)->speed != HCD_USB3 &&
+		     dum->gadget.speed == USB_SPEED_SUPER))
+			return;
 
 
-	if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
-			(dum->port_status & USB_PORT_STAT_RESET) != 0) {
-		if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
-				(dum->old_status & USB_PORT_STAT_RESET) == 0 &&
-				dum->driver) {
-			stop_activity (dum);
-			spin_unlock (&dum->lock);
-			dum->driver->disconnect (&dum->gadget);
-			spin_lock (&dum->lock);
+	set_link_state_by_speed(dum_hcd);
+
+	if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
+	     dum_hcd->active)
+		dum_hcd->resuming = 0;
+
+	/* if !connected or reset */
+	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
+			(dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
+		/*
+		 * We're connected and not reset (reset occurred now),
+		 * and driver attached - disconnect!
+		 */
+		if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
+		    (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 &&
+		    dum->driver) {
+			stop_activity(dum);
+			spin_unlock(&dum->lock);
+			dum->driver->disconnect(&dum->gadget);
+			spin_lock(&dum->lock);
 		}
 		}
-	} else if (dum->active != dum->old_active) {
-		if (dum->old_active && dum->driver->suspend) {
-			spin_unlock (&dum->lock);
-			dum->driver->suspend (&dum->gadget);
-			spin_lock (&dum->lock);
-		} else if (!dum->old_active && dum->driver->resume) {
-			spin_unlock (&dum->lock);
-			dum->driver->resume (&dum->gadget);
-			spin_lock (&dum->lock);
+	} else if (dum_hcd->active != dum_hcd->old_active) {
+		if (dum_hcd->old_active && dum->driver->suspend) {
+			spin_unlock(&dum->lock);
+			dum->driver->suspend(&dum->gadget);
+			spin_lock(&dum->lock);
+		} else if (!dum_hcd->old_active &&  dum->driver->resume) {
+			spin_unlock(&dum->lock);
+			dum->driver->resume(&dum->gadget);
+			spin_lock(&dum->lock);
 		}
 		}
 	}
 	}
 
 
-	dum->old_status = dum->port_status;
-	dum->old_active = dum->active;
+	dum_hcd->old_status = dum_hcd->port_status;
+	dum_hcd->old_active = dum_hcd->active;
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -332,6 +417,7 @@ static int
 dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 {
 {
 	struct dummy		*dum;
 	struct dummy		*dum;
+	struct dummy_hcd	*dum_hcd;
 	struct dummy_ep		*ep;
 	struct dummy_ep		*ep;
 	unsigned		max;
 	unsigned		max;
 	int			retval;
 	int			retval;
@@ -341,9 +427,19 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 			|| desc->bDescriptorType != USB_DT_ENDPOINT)
 			|| desc->bDescriptorType != USB_DT_ENDPOINT)
 		return -EINVAL;
 		return -EINVAL;
 	dum = ep_to_dummy (ep);
 	dum = ep_to_dummy (ep);
-	if (!dum->driver || !is_enabled (dum))
+	if (!dum->driver)
+		return -ESHUTDOWN;
+
+	dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
+	if (!is_enabled(dum_hcd))
 		return -ESHUTDOWN;
 		return -ESHUTDOWN;
-	max = le16_to_cpu(desc->wMaxPacketSize) & 0x3ff;
+
+	/*
+	 * For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the
+	 * maximum packet size.
+	 * For SS devices the wMaxPacketSize is limited by 1024.
+	 */
+	max = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
 
 
 	/* drivers must not request bad settings, since lower levels
 	/* drivers must not request bad settings, since lower levels
 	 * (hardware or its drivers) may not check.  some endpoints
 	 * (hardware or its drivers) may not check.  some endpoints
@@ -361,6 +457,10 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 			goto done;
 			goto done;
 		}
 		}
 		switch (dum->gadget.speed) {
 		switch (dum->gadget.speed) {
+		case USB_SPEED_SUPER:
+			if (max == 1024)
+				break;
+			goto done;
 		case USB_SPEED_HIGH:
 		case USB_SPEED_HIGH:
 			if (max == 512)
 			if (max == 512)
 				break;
 				break;
@@ -379,6 +479,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 			goto done;
 			goto done;
 		/* real hardware might not handle all packet sizes */
 		/* real hardware might not handle all packet sizes */
 		switch (dum->gadget.speed) {
 		switch (dum->gadget.speed) {
+		case USB_SPEED_SUPER:
 		case USB_SPEED_HIGH:
 		case USB_SPEED_HIGH:
 			if (max <= 1024)
 			if (max <= 1024)
 				break;
 				break;
@@ -399,6 +500,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 			goto done;
 			goto done;
 		/* real hardware might not handle all packet sizes */
 		/* real hardware might not handle all packet sizes */
 		switch (dum->gadget.speed) {
 		switch (dum->gadget.speed) {
+		case USB_SPEED_SUPER:
 		case USB_SPEED_HIGH:
 		case USB_SPEED_HIGH:
 			if (max <= 1024)
 			if (max <= 1024)
 				break;
 				break;
@@ -425,10 +527,18 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
 		(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
 		(desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
 		({ char *val;
 		({ char *val;
 		 switch (desc->bmAttributes & 0x03) {
 		 switch (desc->bmAttributes & 0x03) {
-		 case USB_ENDPOINT_XFER_BULK: val = "bulk"; break;
-		 case USB_ENDPOINT_XFER_ISOC: val = "iso"; break;
-		 case USB_ENDPOINT_XFER_INT: val = "intr"; break;
-		 default: val = "ctrl"; break;
+		 case USB_ENDPOINT_XFER_BULK:
+			 val = "bulk";
+			 break;
+		 case USB_ENDPOINT_XFER_ISOC:
+			 val = "iso";
+			 break;
+		 case USB_ENDPOINT_XFER_INT:
+			 val = "intr";
+			 break;
+		 default:
+			 val = "ctrl";
+			 break;
 		 }; val; }),
 		 }; val; }),
 		max);
 		max);
 
 
@@ -507,6 +617,7 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
 	struct dummy_ep		*ep;
 	struct dummy_ep		*ep;
 	struct dummy_request	*req;
 	struct dummy_request	*req;
 	struct dummy		*dum;
 	struct dummy		*dum;
+	struct dummy_hcd	*dum_hcd;
 	unsigned long		flags;
 	unsigned long		flags;
 
 
 	req = usb_request_to_dummy_request (_req);
 	req = usb_request_to_dummy_request (_req);
@@ -518,7 +629,8 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
 		return -EINVAL;
 		return -EINVAL;
 
 
 	dum = ep_to_dummy (ep);
 	dum = ep_to_dummy (ep);
-	if (!dum->driver || !is_enabled (dum))
+	dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
+	if (!dum->driver || !is_enabled(dum_hcd))
 		return -ESHUTDOWN;
 		return -ESHUTDOWN;
 
 
 #if 0
 #if 0
@@ -662,24 +774,24 @@ static int dummy_g_get_frame (struct usb_gadget *_gadget)
 
 
 static int dummy_wakeup (struct usb_gadget *_gadget)
 static int dummy_wakeup (struct usb_gadget *_gadget)
 {
 {
-	struct dummy	*dum;
+	struct dummy_hcd *dum_hcd;
 
 
-	dum = gadget_to_dummy (_gadget);
-	if (!(dum->devstatus &	( (1 << USB_DEVICE_B_HNP_ENABLE)
+	dum_hcd = gadget_to_dummy_hcd(_gadget);
+	if (!(dum_hcd->dum->devstatus & ((1 << USB_DEVICE_B_HNP_ENABLE)
 				| (1 << USB_DEVICE_REMOTE_WAKEUP))))
 				| (1 << USB_DEVICE_REMOTE_WAKEUP))))
 		return -EINVAL;
 		return -EINVAL;
-	if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0)
+	if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0)
 		return -ENOLINK;
 		return -ENOLINK;
-	if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
-			 dum->rh_state != DUMMY_RH_SUSPENDED)
+	if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
+			 dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
 		return -EIO;
 		return -EIO;
 
 
 	/* FIXME: What if the root hub is suspended but the port isn't? */
 	/* FIXME: What if the root hub is suspended but the port isn't? */
 
 
 	/* hub notices our request, issues downstream resume, etc */
 	/* hub notices our request, issues downstream resume, etc */
-	dum->resuming = 1;
-	dum->re_timeout = jiffies + msecs_to_jiffies(20);
-	mod_timer (&dummy_to_hcd (dum)->rh_timer, dum->re_timeout);
+	dum_hcd->resuming = 1;
+	dum_hcd->re_timeout = jiffies + msecs_to_jiffies(20);
+	mod_timer(&dummy_hcd_to_hcd(dum_hcd)->rh_timer, dum_hcd->re_timeout);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -687,7 +799,7 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
 {
 {
 	struct dummy	*dum;
 	struct dummy	*dum;
 
 
-	dum = gadget_to_dummy (_gadget);
+	dum = (gadget_to_dummy_hcd(_gadget))->dum;
 	if (value)
 	if (value)
 		dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
 		dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
 	else
 	else
@@ -695,26 +807,68 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
 	return 0;
 	return 0;
 }
 }
 
 
+static void dummy_udc_udpate_ep0(struct dummy *dum)
+{
+	u32 i;
+
+	if (dum->gadget.speed == USB_SPEED_SUPER) {
+		for (i = 0; i < DUMMY_ENDPOINTS; i++)
+			dum->ep[i].ep.max_streams = 0x10;
+		dum->ep[0].ep.maxpacket = 9;
+	} else {
+		for (i = 0; i < DUMMY_ENDPOINTS; i++)
+			dum->ep[i].ep.max_streams = 0;
+		dum->ep[0].ep.maxpacket = 64;
+	}
+}
+
 static int dummy_pullup (struct usb_gadget *_gadget, int value)
 static int dummy_pullup (struct usb_gadget *_gadget, int value)
 {
 {
+	struct dummy_hcd *dum_hcd;
 	struct dummy	*dum;
 	struct dummy	*dum;
 	unsigned long	flags;
 	unsigned long	flags;
 
 
-	dum = gadget_to_dummy (_gadget);
+	dum = gadget_dev_to_dummy(&_gadget->dev);
+
+	if (value && dum->driver) {
+		if (mod_data.is_super_speed)
+			dum->gadget.speed = dum->driver->speed;
+		else if (mod_data.is_high_speed)
+			dum->gadget.speed = min_t(u8, USB_SPEED_HIGH,
+					dum->driver->speed);
+		else
+			dum->gadget.speed = USB_SPEED_FULL;
+		dummy_udc_udpate_ep0(dum);
+
+		if (dum->gadget.speed < dum->driver->speed)
+			dev_dbg(udc_dev(dum), "This device can perform faster"
+					" if you connect it to a %s port...\n",
+					(dum->driver->speed == USB_SPEED_SUPER ?
+					 "SuperSpeed" : "HighSpeed"));
+	}
+	dum_hcd = gadget_to_dummy_hcd(_gadget);
+
 	spin_lock_irqsave (&dum->lock, flags);
 	spin_lock_irqsave (&dum->lock, flags);
 	dum->pullup = (value != 0);
 	dum->pullup = (value != 0);
-	set_link_state (dum);
+	set_link_state(dum_hcd);
 	spin_unlock_irqrestore (&dum->lock, flags);
 	spin_unlock_irqrestore (&dum->lock, flags);
 
 
-	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
 	return 0;
 	return 0;
 }
 }
 
 
+static int dummy_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver);
+static int dummy_udc_stop(struct usb_gadget *g,
+		struct usb_gadget_driver *driver);
+
 static const struct usb_gadget_ops dummy_ops = {
 static const struct usb_gadget_ops dummy_ops = {
 	.get_frame	= dummy_g_get_frame,
 	.get_frame	= dummy_g_get_frame,
 	.wakeup		= dummy_wakeup,
 	.wakeup		= dummy_wakeup,
 	.set_selfpowered = dummy_set_selfpowered,
 	.set_selfpowered = dummy_set_selfpowered,
 	.pullup		= dummy_pullup,
 	.pullup		= dummy_pullup,
+	.udc_start	= dummy_udc_start,
+	.udc_stop	= dummy_udc_stop,
 };
 };
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -747,18 +901,13 @@ static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
  * for each driver that registers:  just add to a big root hub.
  * for each driver that registers:  just add to a big root hub.
  */
  */
 
 
-int
-usb_gadget_probe_driver(struct usb_gadget_driver *driver,
-		int (*bind)(struct usb_gadget *))
+static int dummy_udc_start(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
-	struct dummy	*dum = the_controller;
-	int		retval, i;
+	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(g);
+	struct dummy		*dum = dum_hcd->dum;
 
 
-	if (!dum)
-		return -EINVAL;
-	if (dum->driver)
-		return -EBUSY;
-	if (!bind || !driver->setup || driver->speed == USB_SPEED_UNKNOWN)
+	if (driver->speed == USB_SPEED_UNKNOWN)
 		return -EINVAL;
 		return -EINVAL;
 
 
 	/*
 	/*
@@ -768,121 +917,77 @@ usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 
 
 	dum->devstatus = 0;
 	dum->devstatus = 0;
 
 
-	INIT_LIST_HEAD (&dum->gadget.ep_list);
-	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
-		struct dummy_ep	*ep = &dum->ep [i];
-
-		if (!ep_name [i])
-			break;
-		ep->ep.name = ep_name [i];
-		ep->ep.ops = &dummy_ep_ops;
-		list_add_tail (&ep->ep.ep_list, &dum->gadget.ep_list);
-		ep->halted = ep->wedged = ep->already_seen =
-				ep->setup_stage = 0;
-		ep->ep.maxpacket = ~0;
-		ep->last_io = jiffies;
-		ep->gadget = &dum->gadget;
-		ep->desc = NULL;
-		INIT_LIST_HEAD (&ep->queue);
-	}
-
-	dum->gadget.ep0 = &dum->ep [0].ep;
-	dum->ep [0].ep.maxpacket = 64;
-	list_del_init (&dum->ep [0].ep.ep_list);
-	INIT_LIST_HEAD(&dum->fifo_req.queue);
-
-	driver->driver.bus = NULL;
 	dum->driver = driver;
 	dum->driver = driver;
-	dum->gadget.dev.driver = &driver->driver;
 	dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
 	dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
 			driver->driver.name);
 			driver->driver.name);
-	retval = bind(&dum->gadget);
-	if (retval) {
-		dum->driver = NULL;
-		dum->gadget.dev.driver = NULL;
-		return retval;
-	}
-
-	/* khubd will enumerate this in a while */
-	spin_lock_irq (&dum->lock);
-	dum->pullup = 1;
-	set_link_state (dum);
-	spin_unlock_irq (&dum->lock);
-
-	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 
-int
-usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+static int dummy_udc_stop(struct usb_gadget *g,
+		struct usb_gadget_driver *driver)
 {
 {
-	struct dummy	*dum = the_controller;
-	unsigned long	flags;
-
-	if (!dum)
-		return -ENODEV;
-	if (!driver || driver != dum->driver || !driver->unbind)
-		return -EINVAL;
+	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(g);
+	struct dummy		*dum = dum_hcd->dum;
 
 
 	dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
 	dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
 			driver->driver.name);
 			driver->driver.name);
 
 
-	spin_lock_irqsave (&dum->lock, flags);
-	dum->pullup = 0;
-	set_link_state (dum);
-	spin_unlock_irqrestore (&dum->lock, flags);
-
-	driver->unbind (&dum->gadget);
-	dum->gadget.dev.driver = NULL;
 	dum->driver = NULL;
 	dum->driver = NULL;
 
 
-	spin_lock_irqsave (&dum->lock, flags);
-	dum->pullup = 0;
-	set_link_state (dum);
-	spin_unlock_irqrestore (&dum->lock, flags);
-
-	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+	dummy_pullup(&dum->gadget, 0);
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL (usb_gadget_unregister_driver);
 
 
 #undef is_enabled
 #undef is_enabled
 
 
-/* just declare this in any driver that really need it */
-extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
-
-int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode)
-{
-	return -ENOSYS;
-}
-EXPORT_SYMBOL (net2280_set_fifo_mode);
-
-
 /* The gadget structure is stored inside the hcd structure and will be
 /* The gadget structure is stored inside the hcd structure and will be
  * released along with it. */
  * released along with it. */
 static void
 static void
 dummy_gadget_release (struct device *dev)
 dummy_gadget_release (struct device *dev)
 {
 {
-	struct dummy	*dum = gadget_dev_to_dummy (dev);
+	return;
+}
+
+static void init_dummy_udc_hw(struct dummy *dum)
+{
+	int i;
+
+	INIT_LIST_HEAD(&dum->gadget.ep_list);
+	for (i = 0; i < DUMMY_ENDPOINTS; i++) {
+		struct dummy_ep	*ep = &dum->ep[i];
+
+		if (!ep_name[i])
+			break;
+		ep->ep.name = ep_name[i];
+		ep->ep.ops = &dummy_ep_ops;
+		list_add_tail(&ep->ep.ep_list, &dum->gadget.ep_list);
+		ep->halted = ep->wedged = ep->already_seen =
+				ep->setup_stage = 0;
+		ep->ep.maxpacket = ~0;
+		ep->last_io = jiffies;
+		ep->gadget = &dum->gadget;
+		ep->desc = NULL;
+		INIT_LIST_HEAD(&ep->queue);
+	}
+
+	dum->gadget.ep0 = &dum->ep[0].ep;
+	list_del_init(&dum->ep[0].ep.ep_list);
+	INIT_LIST_HEAD(&dum->fifo_req.queue);
 
 
-	usb_put_hcd (dummy_to_hcd (dum));
+#ifdef CONFIG_USB_OTG
+	dum->gadget.is_otg = 1;
+#endif
 }
 }
 
 
 static int dummy_udc_probe (struct platform_device *pdev)
 static int dummy_udc_probe (struct platform_device *pdev)
 {
 {
-	struct dummy	*dum = the_controller;
+	struct dummy	*dum = &the_controller;
 	int		rc;
 	int		rc;
 
 
-	usb_get_hcd(dummy_to_hcd(dum));
-
 	dum->gadget.name = gadget_name;
 	dum->gadget.name = gadget_name;
 	dum->gadget.ops = &dummy_ops;
 	dum->gadget.ops = &dummy_ops;
 	dum->gadget.is_dualspeed = 1;
 	dum->gadget.is_dualspeed = 1;
 
 
-	/* maybe claim OTG support, though we won't complete HNP */
-	dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0);
-
 	dev_set_name(&dum->gadget.dev, "gadget");
 	dev_set_name(&dum->gadget.dev, "gadget");
 	dum->gadget.dev.parent = &pdev->dev;
 	dum->gadget.dev.parent = &pdev->dev;
 	dum->gadget.dev.release = dummy_gadget_release;
 	dum->gadget.dev.release = dummy_gadget_release;
@@ -892,11 +997,22 @@ static int dummy_udc_probe (struct platform_device *pdev)
 		return rc;
 		return rc;
 	}
 	}
 
 
+	init_dummy_udc_hw(dum);
+
+	rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget);
+	if (rc < 0)
+		goto err_udc;
+
 	rc = device_create_file (&dum->gadget.dev, &dev_attr_function);
 	rc = device_create_file (&dum->gadget.dev, &dev_attr_function);
 	if (rc < 0)
 	if (rc < 0)
-		device_unregister (&dum->gadget.dev);
-	else
-		platform_set_drvdata(pdev, dum);
+		goto err_dev;
+	platform_set_drvdata(pdev, dum);
+	return rc;
+
+err_dev:
+	usb_del_gadget_udc(&dum->gadget);
+err_udc:
+	device_unregister(&dum->gadget.dev);
 	return rc;
 	return rc;
 }
 }
 
 
@@ -904,37 +1020,41 @@ static int dummy_udc_remove (struct platform_device *pdev)
 {
 {
 	struct dummy	*dum = platform_get_drvdata (pdev);
 	struct dummy	*dum = platform_get_drvdata (pdev);
 
 
+	usb_del_gadget_udc(&dum->gadget);
 	platform_set_drvdata (pdev, NULL);
 	platform_set_drvdata (pdev, NULL);
 	device_remove_file (&dum->gadget.dev, &dev_attr_function);
 	device_remove_file (&dum->gadget.dev, &dev_attr_function);
 	device_unregister (&dum->gadget.dev);
 	device_unregister (&dum->gadget.dev);
 	return 0;
 	return 0;
 }
 }
 
 
-static int dummy_udc_suspend (struct platform_device *pdev, pm_message_t state)
+static void dummy_udc_pm(struct dummy *dum, struct dummy_hcd *dum_hcd,
+		int suspend)
 {
 {
-	struct dummy	*dum = platform_get_drvdata(pdev);
+	spin_lock_irq(&dum->lock);
+	dum->udc_suspended = suspend;
+	set_link_state(dum_hcd);
+	spin_unlock_irq(&dum->lock);
+}
 
 
-	dev_dbg (&pdev->dev, "%s\n", __func__);
-	spin_lock_irq (&dum->lock);
-	dum->udc_suspended = 1;
-	set_link_state (dum);
-	spin_unlock_irq (&dum->lock);
+static int dummy_udc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct dummy		*dum = platform_get_drvdata(pdev);
+	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
 
 
-	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+	dev_dbg(&pdev->dev, "%s\n", __func__);
+	dummy_udc_pm(dum, dum_hcd, 1);
+	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
 	return 0;
 	return 0;
 }
 }
 
 
-static int dummy_udc_resume (struct platform_device *pdev)
+static int dummy_udc_resume(struct platform_device *pdev)
 {
 {
-	struct dummy	*dum = platform_get_drvdata(pdev);
+	struct dummy		*dum = platform_get_drvdata(pdev);
+	struct dummy_hcd	*dum_hcd = gadget_to_dummy_hcd(&dum->gadget);
 
 
-	dev_dbg (&pdev->dev, "%s\n", __func__);
-	spin_lock_irq (&dum->lock);
-	dum->udc_suspended = 0;
-	set_link_state (dum);
-	spin_unlock_irq (&dum->lock);
-
-	usb_hcd_poll_rh_status (dummy_to_hcd (dum));
+	dev_dbg(&pdev->dev, "%s\n", __func__);
+	dummy_udc_pm(dum, dum_hcd, 0);
+	usb_hcd_poll_rh_status(dummy_hcd_to_hcd(dum_hcd));
 	return 0;
 	return 0;
 }
 }
 
 
@@ -968,7 +1088,7 @@ static int dummy_urb_enqueue (
 	struct urb			*urb,
 	struct urb			*urb,
 	gfp_t				mem_flags
 	gfp_t				mem_flags
 ) {
 ) {
-	struct dummy	*dum;
+	struct dummy_hcd *dum_hcd;
 	struct urbp	*urbp;
 	struct urbp	*urbp;
 	unsigned long	flags;
 	unsigned long	flags;
 	int		rc;
 	int		rc;
@@ -981,51 +1101,51 @@ static int dummy_urb_enqueue (
 		return -ENOMEM;
 		return -ENOMEM;
 	urbp->urb = urb;
 	urbp->urb = urb;
 
 
-	dum = hcd_to_dummy (hcd);
-	spin_lock_irqsave (&dum->lock, flags);
+	dum_hcd = hcd_to_dummy_hcd(hcd);
+	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
 	rc = usb_hcd_link_urb_to_ep(hcd, urb);
 	rc = usb_hcd_link_urb_to_ep(hcd, urb);
 	if (rc) {
 	if (rc) {
 		kfree(urbp);
 		kfree(urbp);
 		goto done;
 		goto done;
 	}
 	}
 
 
-	if (!dum->udev) {
-		dum->udev = urb->dev;
-		usb_get_dev (dum->udev);
-	} else if (unlikely (dum->udev != urb->dev))
-		dev_err (dummy_dev(dum), "usb_device address has changed!\n");
+	if (!dum_hcd->udev) {
+		dum_hcd->udev = urb->dev;
+		usb_get_dev(dum_hcd->udev);
+	} else if (unlikely(dum_hcd->udev != urb->dev))
+		dev_err(dummy_dev(dum_hcd), "usb_device address has changed!\n");
 
 
-	list_add_tail (&urbp->urbp_list, &dum->urbp_list);
+	list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
 	urb->hcpriv = urbp;
 	urb->hcpriv = urbp;
 	if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
 	if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
 		urb->error_count = 1;		/* mark as a new urb */
 		urb->error_count = 1;		/* mark as a new urb */
 
 
 	/* kick the scheduler, it'll do the rest */
 	/* kick the scheduler, it'll do the rest */
-	if (!timer_pending (&dum->timer))
-		mod_timer (&dum->timer, jiffies + 1);
+	if (!timer_pending(&dum_hcd->timer))
+		mod_timer(&dum_hcd->timer, jiffies + 1);
 
 
  done:
  done:
-	spin_unlock_irqrestore(&dum->lock, flags);
+	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
 	return rc;
 	return rc;
 }
 }
 
 
 static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 {
 {
-	struct dummy	*dum;
+	struct dummy_hcd *dum_hcd;
 	unsigned long	flags;
 	unsigned long	flags;
 	int		rc;
 	int		rc;
 
 
 	/* giveback happens automatically in timer callback,
 	/* giveback happens automatically in timer callback,
 	 * so make sure the callback happens */
 	 * so make sure the callback happens */
-	dum = hcd_to_dummy (hcd);
-	spin_lock_irqsave (&dum->lock, flags);
+	dum_hcd = hcd_to_dummy_hcd(hcd);
+	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
 
 
 	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
 	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
-	if (!rc && dum->rh_state != DUMMY_RH_RUNNING &&
-			!list_empty(&dum->urbp_list))
-		mod_timer (&dum->timer, jiffies);
+	if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING &&
+			!list_empty(&dum_hcd->urbp_list))
+		mod_timer(&dum_hcd->timer, jiffies);
 
 
-	spin_unlock_irqrestore (&dum->lock, flags);
+	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
 	return rc;
 	return rc;
 }
 }
 
 
@@ -1162,10 +1282,25 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
 		tmp *= 8 /* applies to entire frame */;
 		tmp *= 8 /* applies to entire frame */;
 		limit += limit * tmp;
 		limit += limit * tmp;
 	}
 	}
+	if (dum->gadget.speed == USB_SPEED_SUPER) {
+		switch (ep->desc->bmAttributes & 0x03) {
+		case USB_ENDPOINT_XFER_ISOC:
+			/* Sec. 4.4.8.2 USB3.0 Spec */
+			limit = 3 * 16 * 1024 * 8;
+			break;
+		case USB_ENDPOINT_XFER_INT:
+			/* Sec. 4.4.7.2 USB3.0 Spec */
+			limit = 3 * 1024 * 8;
+			break;
+		case USB_ENDPOINT_XFER_BULK:
+		default:
+			break;
+		}
+	}
 	return limit;
 	return limit;
 }
 }
 
 
-#define is_active(dum)	((dum->port_status & \
+#define is_active(dum_hcd)	((dum_hcd->port_status & \
 		(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \
 		(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \
 			USB_PORT_STAT_SUSPEND)) \
 			USB_PORT_STAT_SUSPEND)) \
 		== (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
 		== (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
@@ -1174,7 +1309,8 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
 {
 {
 	int		i;
 	int		i;
 
 
-	if (!is_active (dum))
+	if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ?
+			dum->ss_hcd : dum->hs_hcd)))
 		return NULL;
 		return NULL;
 	if ((address & ~USB_DIR_IN) == 0)
 	if ((address & ~USB_DIR_IN) == 0)
 		return &dum->ep [0];
 		return &dum->ep [0];
@@ -1211,11 +1347,12 @@ static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
  *	  1 - if the request wasn't handles
  *	  1 - if the request wasn't handles
  *	  error code on error
  *	  error code on error
  */
  */
-static int handle_control_request(struct dummy *dum, struct urb *urb,
+static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
 				  struct usb_ctrlrequest *setup,
 				  struct usb_ctrlrequest *setup,
 				  int *status)
 				  int *status)
 {
 {
 	struct dummy_ep		*ep2;
 	struct dummy_ep		*ep2;
+	struct dummy		*dum = dum_hcd->dum;
 	int			ret_val = 1;
 	int			ret_val = 1;
 	unsigned	w_index;
 	unsigned	w_index;
 	unsigned	w_value;
 	unsigned	w_value;
@@ -1247,6 +1384,27 @@ static int handle_control_request(struct dummy *dum, struct urb *urb,
 			case USB_DEVICE_A_ALT_HNP_SUPPORT:
 			case USB_DEVICE_A_ALT_HNP_SUPPORT:
 				dum->gadget.a_alt_hnp_support = 1;
 				dum->gadget.a_alt_hnp_support = 1;
 				break;
 				break;
+			case USB_DEVICE_U1_ENABLE:
+				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
+				    HCD_USB3)
+					w_value = USB_DEV_STAT_U1_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
+			case USB_DEVICE_U2_ENABLE:
+				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
+				    HCD_USB3)
+					w_value = USB_DEV_STAT_U2_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
+			case USB_DEVICE_LTM_ENABLE:
+				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
+				    HCD_USB3)
+					w_value = USB_DEV_STAT_LTM_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
 			default:
 			default:
 				ret_val = -EOPNOTSUPP;
 				ret_val = -EOPNOTSUPP;
 			}
 			}
@@ -1273,6 +1431,27 @@ static int handle_control_request(struct dummy *dum, struct urb *urb,
 			case USB_DEVICE_REMOTE_WAKEUP:
 			case USB_DEVICE_REMOTE_WAKEUP:
 				w_value = USB_DEVICE_REMOTE_WAKEUP;
 				w_value = USB_DEVICE_REMOTE_WAKEUP;
 				break;
 				break;
+			case USB_DEVICE_U1_ENABLE:
+				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
+				    HCD_USB3)
+					w_value = USB_DEV_STAT_U1_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
+			case USB_DEVICE_U2_ENABLE:
+				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
+				    HCD_USB3)
+					w_value = USB_DEV_STAT_U2_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
+			case USB_DEVICE_LTM_ENABLE:
+				if (dummy_hcd_to_hcd(dum_hcd)->speed ==
+				    HCD_USB3)
+					w_value = USB_DEV_STAT_LTM_ENABLED;
+				else
+					ret_val = -EOPNOTSUPP;
+				break;
 			default:
 			default:
 				ret_val = -EOPNOTSUPP;
 				ret_val = -EOPNOTSUPP;
 				break;
 				break;
@@ -1334,9 +1513,10 @@ static int handle_control_request(struct dummy *dum, struct urb *urb,
 /* drive both sides of the transfers; looks like irq handlers to
 /* drive both sides of the transfers; looks like irq handlers to
  * both drivers except the callbacks aren't in_irq().
  * both drivers except the callbacks aren't in_irq().
  */
  */
-static void dummy_timer (unsigned long _dum)
+static void dummy_timer(unsigned long _dum_hcd)
 {
 {
-	struct dummy		*dum = (struct dummy *) _dum;
+	struct dummy_hcd	*dum_hcd = (struct dummy_hcd *) _dum_hcd;
+	struct dummy		*dum = dum_hcd->dum;
 	struct urbp		*urbp, *tmp;
 	struct urbp		*urbp, *tmp;
 	unsigned long		flags;
 	unsigned long		flags;
 	int			limit, total;
 	int			limit, total;
@@ -1353,8 +1533,12 @@ static void dummy_timer (unsigned long _dum)
 	case USB_SPEED_HIGH:
 	case USB_SPEED_HIGH:
 		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
 		total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
 		break;
 		break;
+	case USB_SPEED_SUPER:
+		/* Bus speed is 500000 bytes/ms, so use a little less */
+		total = 490000;
+		break;
 	default:
 	default:
-		dev_err (dummy_dev(dum), "bogus device speed\n");
+		dev_err(dummy_dev(dum_hcd), "bogus device speed\n");
 		return;
 		return;
 	}
 	}
 
 
@@ -1363,8 +1547,8 @@ static void dummy_timer (unsigned long _dum)
 	/* look at each urb queued by the host side driver */
 	/* look at each urb queued by the host side driver */
 	spin_lock_irqsave (&dum->lock, flags);
 	spin_lock_irqsave (&dum->lock, flags);
 
 
-	if (!dum->udev) {
-		dev_err (dummy_dev(dum),
+	if (!dum_hcd->udev) {
+		dev_err(dummy_dev(dum_hcd),
 				"timer fired with no URBs pending?\n");
 				"timer fired with no URBs pending?\n");
 		spin_unlock_irqrestore (&dum->lock, flags);
 		spin_unlock_irqrestore (&dum->lock, flags);
 		return;
 		return;
@@ -1377,7 +1561,7 @@ static void dummy_timer (unsigned long _dum)
 	}
 	}
 
 
 restart:
 restart:
-	list_for_each_entry_safe (urbp, tmp, &dum->urbp_list, urbp_list) {
+	list_for_each_entry_safe(urbp, tmp, &dum_hcd->urbp_list, urbp_list) {
 		struct urb		*urb;
 		struct urb		*urb;
 		struct dummy_request	*req;
 		struct dummy_request	*req;
 		u8			address;
 		u8			address;
@@ -1388,7 +1572,7 @@ restart:
 		urb = urbp->urb;
 		urb = urbp->urb;
 		if (urb->unlinked)
 		if (urb->unlinked)
 			goto return_urb;
 			goto return_urb;
-		else if (dum->rh_state != DUMMY_RH_RUNNING)
+		else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)
 			continue;
 			continue;
 		type = usb_pipetype (urb->pipe);
 		type = usb_pipetype (urb->pipe);
 
 
@@ -1406,7 +1590,7 @@ restart:
 		ep = find_endpoint(dum, address);
 		ep = find_endpoint(dum, address);
 		if (!ep) {
 		if (!ep) {
 			/* set_configuration() disagreement */
 			/* set_configuration() disagreement */
-			dev_dbg (dummy_dev(dum),
+			dev_dbg(dummy_dev(dum_hcd),
 				"no ep configured for urb %p\n",
 				"no ep configured for urb %p\n",
 				urb);
 				urb);
 			status = -EPROTO;
 			status = -EPROTO;
@@ -1422,7 +1606,7 @@ restart:
 		}
 		}
 		if (ep->halted && !ep->setup_stage) {
 		if (ep->halted && !ep->setup_stage) {
 			/* NOTE: must not be iso! */
 			/* NOTE: must not be iso! */
-			dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n",
+			dev_dbg(dummy_dev(dum_hcd), "ep %s halted, urb %p\n",
 					ep->ep.name, urb);
 					ep->ep.name, urb);
 			status = -EPIPE;
 			status = -EPIPE;
 			goto return_urb;
 			goto return_urb;
@@ -1457,7 +1641,7 @@ restart:
 			ep->setup_stage = 0;
 			ep->setup_stage = 0;
 			ep->halted = 0;
 			ep->halted = 0;
 
 
-			value = handle_control_request(dum, urb, &setup,
+			value = handle_control_request(dum_hcd, urb, &setup,
 						       &status);
 						       &status);
 
 
 			/* gadget driver handles all other requests.  block
 			/* gadget driver handles all other requests.  block
@@ -1527,20 +1711,20 @@ return_urb:
 		if (ep)
 		if (ep)
 			ep->already_seen = ep->setup_stage = 0;
 			ep->already_seen = ep->setup_stage = 0;
 
 
-		usb_hcd_unlink_urb_from_ep(dummy_to_hcd(dum), urb);
+		usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb);
 		spin_unlock (&dum->lock);
 		spin_unlock (&dum->lock);
-		usb_hcd_giveback_urb(dummy_to_hcd(dum), urb, status);
+		usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status);
 		spin_lock (&dum->lock);
 		spin_lock (&dum->lock);
 
 
 		goto restart;
 		goto restart;
 	}
 	}
 
 
-	if (list_empty (&dum->urbp_list)) {
-		usb_put_dev (dum->udev);
-		dum->udev = NULL;
-	} else if (dum->rh_state == DUMMY_RH_RUNNING) {
+	if (list_empty(&dum_hcd->urbp_list)) {
+		usb_put_dev(dum_hcd->udev);
+		dum_hcd->udev = NULL;
+	} else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
 		/* want a 1 msec delay here */
 		/* want a 1 msec delay here */
-		mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1));
+		mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1));
 	}
 	}
 
 
 	spin_unlock_irqrestore (&dum->lock, flags);
 	spin_unlock_irqrestore (&dum->lock, flags);
@@ -1557,35 +1741,47 @@ return_urb:
 
 
 static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
 static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
 {
 {
-	struct dummy		*dum;
+	struct dummy_hcd	*dum_hcd;
 	unsigned long		flags;
 	unsigned long		flags;
 	int			retval = 0;
 	int			retval = 0;
 
 
-	dum = hcd_to_dummy (hcd);
+	dum_hcd = hcd_to_dummy_hcd(hcd);
 
 
-	spin_lock_irqsave (&dum->lock, flags);
+	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
 	if (!HCD_HW_ACCESSIBLE(hcd))
 	if (!HCD_HW_ACCESSIBLE(hcd))
 		goto done;
 		goto done;
 
 
-	if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) {
-		dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
-		dum->port_status &= ~USB_PORT_STAT_SUSPEND;
-		set_link_state (dum);
+	if (dum_hcd->resuming && time_after_eq(jiffies, dum_hcd->re_timeout)) {
+		dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
+		dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
+		set_link_state(dum_hcd);
 	}
 	}
 
 
-	if ((dum->port_status & PORT_C_MASK) != 0) {
+	if ((dum_hcd->port_status & PORT_C_MASK) != 0) {
 		*buf = (1 << 1);
 		*buf = (1 << 1);
-		dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n",
-				dum->port_status);
+		dev_dbg(dummy_dev(dum_hcd), "port status 0x%08x has changes\n",
+				dum_hcd->port_status);
 		retval = 1;
 		retval = 1;
-		if (dum->rh_state == DUMMY_RH_SUSPENDED)
+		if (dum_hcd->rh_state == DUMMY_RH_SUSPENDED)
 			usb_hcd_resume_root_hub (hcd);
 			usb_hcd_resume_root_hub (hcd);
 	}
 	}
 done:
 done:
-	spin_unlock_irqrestore (&dum->lock, flags);
+	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
 	return retval;
 	return retval;
 }
 }
 
 
+static inline void
+ss_hub_descriptor(struct usb_hub_descriptor *desc)
+{
+	memset(desc, 0, sizeof *desc);
+	desc->bDescriptorType = 0x2a;
+	desc->bDescLength = 12;
+	desc->wHubCharacteristics = cpu_to_le16(0x0001);
+	desc->bNbrPorts = 1;
+	desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/
+	desc->u.ss.DeviceRemovable = 0xffff;
+}
+
 static inline void
 static inline void
 hub_descriptor (struct usb_hub_descriptor *desc)
 hub_descriptor (struct usb_hub_descriptor *desc)
 {
 {
@@ -1606,39 +1802,64 @@ static int dummy_hub_control (
 	char		*buf,
 	char		*buf,
 	u16		wLength
 	u16		wLength
 ) {
 ) {
-	struct dummy	*dum;
+	struct dummy_hcd *dum_hcd;
 	int		retval = 0;
 	int		retval = 0;
 	unsigned long	flags;
 	unsigned long	flags;
 
 
 	if (!HCD_HW_ACCESSIBLE(hcd))
 	if (!HCD_HW_ACCESSIBLE(hcd))
 		return -ETIMEDOUT;
 		return -ETIMEDOUT;
 
 
-	dum = hcd_to_dummy (hcd);
-	spin_lock_irqsave (&dum->lock, flags);
+	dum_hcd = hcd_to_dummy_hcd(hcd);
+
+	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
 	switch (typeReq) {
 	switch (typeReq) {
 	case ClearHubFeature:
 	case ClearHubFeature:
 		break;
 		break;
 	case ClearPortFeature:
 	case ClearPortFeature:
 		switch (wValue) {
 		switch (wValue) {
 		case USB_PORT_FEAT_SUSPEND:
 		case USB_PORT_FEAT_SUSPEND:
-			if (dum->port_status & USB_PORT_STAT_SUSPEND) {
+			if (hcd->speed == HCD_USB3) {
+				dev_dbg(dummy_dev(dum_hcd),
+					 "USB_PORT_FEAT_SUSPEND req not "
+					 "supported for USB 3.0 roothub\n");
+				goto error;
+			}
+			if (dum_hcd->port_status & USB_PORT_STAT_SUSPEND) {
 				/* 20msec resume signaling */
 				/* 20msec resume signaling */
-				dum->resuming = 1;
-				dum->re_timeout = jiffies +
+				dum_hcd->resuming = 1;
+				dum_hcd->re_timeout = jiffies +
 						msecs_to_jiffies(20);
 						msecs_to_jiffies(20);
 			}
 			}
 			break;
 			break;
 		case USB_PORT_FEAT_POWER:
 		case USB_PORT_FEAT_POWER:
-			if (dum->port_status & USB_PORT_STAT_POWER)
-				dev_dbg (dummy_dev(dum), "power-off\n");
+			if (hcd->speed == HCD_USB3) {
+				if (dum_hcd->port_status & USB_PORT_STAT_POWER)
+					dev_dbg(dummy_dev(dum_hcd),
+						"power-off\n");
+			} else
+				if (dum_hcd->port_status &
+							USB_SS_PORT_STAT_POWER)
+					dev_dbg(dummy_dev(dum_hcd),
+						"power-off\n");
 			/* FALLS THROUGH */
 			/* FALLS THROUGH */
 		default:
 		default:
-			dum->port_status &= ~(1 << wValue);
-			set_link_state (dum);
+			dum_hcd->port_status &= ~(1 << wValue);
+			set_link_state(dum_hcd);
 		}
 		}
 		break;
 		break;
 	case GetHubDescriptor:
 	case GetHubDescriptor:
-		hub_descriptor ((struct usb_hub_descriptor *) buf);
+		if (hcd->speed == HCD_USB3 &&
+				(wLength < USB_DT_SS_HUB_SIZE ||
+				 wValue != (USB_DT_SS_HUB << 8))) {
+			dev_dbg(dummy_dev(dum_hcd),
+				"Wrong hub descriptor type for "
+				"USB 3.0 roothub.\n");
+			goto error;
+		}
+		if (hcd->speed == HCD_USB3)
+			ss_hub_descriptor((struct usb_hub_descriptor *) buf);
+		else
+			hub_descriptor((struct usb_hub_descriptor *) buf);
 		break;
 		break;
 	case GetHubStatus:
 	case GetHubStatus:
 		*(__le32 *) buf = cpu_to_le32 (0);
 		*(__le32 *) buf = cpu_to_le32 (0);
@@ -1650,127 +1871,210 @@ static int dummy_hub_control (
 		/* whoever resets or resumes must GetPortStatus to
 		/* whoever resets or resumes must GetPortStatus to
 		 * complete it!!
 		 * complete it!!
 		 */
 		 */
-		if (dum->resuming &&
-				time_after_eq (jiffies, dum->re_timeout)) {
-			dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
-			dum->port_status &= ~USB_PORT_STAT_SUSPEND;
+		if (dum_hcd->resuming &&
+				time_after_eq(jiffies, dum_hcd->re_timeout)) {
+			dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
+			dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
 		}
 		}
-		if ((dum->port_status & USB_PORT_STAT_RESET) != 0 &&
-				time_after_eq (jiffies, dum->re_timeout)) {
-			dum->port_status |= (USB_PORT_STAT_C_RESET << 16);
-			dum->port_status &= ~USB_PORT_STAT_RESET;
-			if (dum->pullup) {
-				dum->port_status |= USB_PORT_STAT_ENABLE;
-				/* give it the best speed we agree on */
-				dum->gadget.speed = dum->driver->speed;
-				dum->gadget.ep0->maxpacket = 64;
-				switch (dum->gadget.speed) {
-				case USB_SPEED_HIGH:
-					dum->port_status |=
-						USB_PORT_STAT_HIGH_SPEED;
-					break;
-				case USB_SPEED_LOW:
-					dum->gadget.ep0->maxpacket = 8;
-					dum->port_status |=
-						USB_PORT_STAT_LOW_SPEED;
-					break;
-				default:
-					dum->gadget.speed = USB_SPEED_FULL;
-					break;
+		if ((dum_hcd->port_status & USB_PORT_STAT_RESET) != 0 &&
+				time_after_eq(jiffies, dum_hcd->re_timeout)) {
+			dum_hcd->port_status |= (USB_PORT_STAT_C_RESET << 16);
+			dum_hcd->port_status &= ~USB_PORT_STAT_RESET;
+			if (dum_hcd->dum->pullup) {
+				dum_hcd->port_status |= USB_PORT_STAT_ENABLE;
+
+				if (hcd->speed < HCD_USB3) {
+					switch (dum_hcd->dum->gadget.speed) {
+					case USB_SPEED_HIGH:
+						dum_hcd->port_status |=
+						      USB_PORT_STAT_HIGH_SPEED;
+						break;
+					case USB_SPEED_LOW:
+						dum_hcd->dum->gadget.ep0->
+							maxpacket = 8;
+						dum_hcd->port_status |=
+							USB_PORT_STAT_LOW_SPEED;
+						break;
+					default:
+						dum_hcd->dum->gadget.speed =
+							USB_SPEED_FULL;
+						break;
+					}
 				}
 				}
 			}
 			}
 		}
 		}
-		set_link_state (dum);
-		((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status);
-		((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
+		set_link_state(dum_hcd);
+		((__le16 *) buf)[0] = cpu_to_le16 (dum_hcd->port_status);
+		((__le16 *) buf)[1] = cpu_to_le16 (dum_hcd->port_status >> 16);
 		break;
 		break;
 	case SetHubFeature:
 	case SetHubFeature:
 		retval = -EPIPE;
 		retval = -EPIPE;
 		break;
 		break;
 	case SetPortFeature:
 	case SetPortFeature:
 		switch (wValue) {
 		switch (wValue) {
+		case USB_PORT_FEAT_LINK_STATE:
+			if (hcd->speed != HCD_USB3) {
+				dev_dbg(dummy_dev(dum_hcd),
+					 "USB_PORT_FEAT_LINK_STATE req not "
+					 "supported for USB 2.0 roothub\n");
+				goto error;
+			}
+			/*
+			 * Since this is dummy we don't have an actual link so
+			 * there is nothing to do for the SET_LINK_STATE cmd
+			 */
+			break;
+		case USB_PORT_FEAT_U1_TIMEOUT:
+		case USB_PORT_FEAT_U2_TIMEOUT:
+			/* TODO: add suspend/resume support! */
+			if (hcd->speed != HCD_USB3) {
+				dev_dbg(dummy_dev(dum_hcd),
+					 "USB_PORT_FEAT_U1/2_TIMEOUT req not "
+					 "supported for USB 2.0 roothub\n");
+				goto error;
+			}
+			break;
 		case USB_PORT_FEAT_SUSPEND:
 		case USB_PORT_FEAT_SUSPEND:
-			if (dum->active) {
-				dum->port_status |= USB_PORT_STAT_SUSPEND;
+			/* Applicable only for USB2.0 hub */
+			if (hcd->speed == HCD_USB3) {
+				dev_dbg(dummy_dev(dum_hcd),
+					 "USB_PORT_FEAT_SUSPEND req not "
+					 "supported for USB 3.0 roothub\n");
+				goto error;
+			}
+			if (dum_hcd->active) {
+				dum_hcd->port_status |= USB_PORT_STAT_SUSPEND;
 
 
 				/* HNP would happen here; for now we
 				/* HNP would happen here; for now we
 				 * assume b_bus_req is always true.
 				 * assume b_bus_req is always true.
 				 */
 				 */
-				set_link_state (dum);
+				set_link_state(dum_hcd);
 				if (((1 << USB_DEVICE_B_HNP_ENABLE)
 				if (((1 << USB_DEVICE_B_HNP_ENABLE)
-						& dum->devstatus) != 0)
-					dev_dbg (dummy_dev(dum),
+						& dum_hcd->dum->devstatus) != 0)
+					dev_dbg(dummy_dev(dum_hcd),
 							"no HNP yet!\n");
 							"no HNP yet!\n");
 			}
 			}
 			break;
 			break;
 		case USB_PORT_FEAT_POWER:
 		case USB_PORT_FEAT_POWER:
-			dum->port_status |= USB_PORT_STAT_POWER;
-			set_link_state (dum);
+			if (hcd->speed == HCD_USB3)
+				dum_hcd->port_status |= USB_SS_PORT_STAT_POWER;
+			else
+				dum_hcd->port_status |= USB_PORT_STAT_POWER;
+			set_link_state(dum_hcd);
 			break;
 			break;
+		case USB_PORT_FEAT_BH_PORT_RESET:
+			/* Applicable only for USB3.0 hub */
+			if (hcd->speed != HCD_USB3) {
+				dev_dbg(dummy_dev(dum_hcd),
+					 "USB_PORT_FEAT_BH_PORT_RESET req not "
+					 "supported for USB 2.0 roothub\n");
+				goto error;
+			}
+			/* FALLS THROUGH */
 		case USB_PORT_FEAT_RESET:
 		case USB_PORT_FEAT_RESET:
 			/* if it's already enabled, disable */
 			/* if it's already enabled, disable */
-			dum->port_status &= ~(USB_PORT_STAT_ENABLE
+			if (hcd->speed == HCD_USB3) {
+				dum_hcd->port_status = 0;
+				dum_hcd->port_status =
+					(USB_SS_PORT_STAT_POWER |
+					 USB_PORT_STAT_CONNECTION |
+					 USB_PORT_STAT_RESET);
+			} else
+				dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE
 					| USB_PORT_STAT_LOW_SPEED
 					| USB_PORT_STAT_LOW_SPEED
 					| USB_PORT_STAT_HIGH_SPEED);
 					| USB_PORT_STAT_HIGH_SPEED);
-			dum->devstatus = 0;
-			/* 50msec reset signaling */
-			dum->re_timeout = jiffies + msecs_to_jiffies(50);
+			/*
+			 * We want to reset device status. All but the
+			 * Self powered feature
+			 */
+			dum_hcd->dum->devstatus &=
+				(1 << USB_DEVICE_SELF_POWERED);
+			/*
+			 * FIXME USB3.0: what is the correct reset signaling
+			 * interval? Is it still 50msec as for HS?
+			 */
+			dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50);
 			/* FALLS THROUGH */
 			/* FALLS THROUGH */
 		default:
 		default:
-			if ((dum->port_status & USB_PORT_STAT_POWER) != 0) {
-				dum->port_status |= (1 << wValue);
-				set_link_state (dum);
-			}
+			if (hcd->speed == HCD_USB3) {
+				if ((dum_hcd->port_status &
+				     USB_SS_PORT_STAT_POWER) != 0) {
+					dum_hcd->port_status |= (1 << wValue);
+					set_link_state(dum_hcd);
+				}
+			} else
+				if ((dum_hcd->port_status &
+				     USB_PORT_STAT_POWER) != 0) {
+					dum_hcd->port_status |= (1 << wValue);
+					set_link_state(dum_hcd);
+				}
+		}
+		break;
+	case GetPortErrorCount:
+		if (hcd->speed != HCD_USB3) {
+			dev_dbg(dummy_dev(dum_hcd),
+				 "GetPortErrorCount req not "
+				 "supported for USB 2.0 roothub\n");
+			goto error;
+		}
+		/* We'll always return 0 since this is a dummy hub */
+		*(__le32 *) buf = cpu_to_le32(0);
+		break;
+	case SetHubDepth:
+		if (hcd->speed != HCD_USB3) {
+			dev_dbg(dummy_dev(dum_hcd),
+				 "SetHubDepth req not supported for "
+				 "USB 2.0 roothub\n");
+			goto error;
 		}
 		}
 		break;
 		break;
-
 	default:
 	default:
-		dev_dbg (dummy_dev(dum),
+		dev_dbg(dummy_dev(dum_hcd),
 			"hub control req%04x v%04x i%04x l%d\n",
 			"hub control req%04x v%04x i%04x l%d\n",
 			typeReq, wValue, wIndex, wLength);
 			typeReq, wValue, wIndex, wLength);
-
+error:
 		/* "protocol stall" on error */
 		/* "protocol stall" on error */
 		retval = -EPIPE;
 		retval = -EPIPE;
 	}
 	}
-	spin_unlock_irqrestore (&dum->lock, flags);
+	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
 
 
-	if ((dum->port_status & PORT_C_MASK) != 0)
+	if ((dum_hcd->port_status & PORT_C_MASK) != 0)
 		usb_hcd_poll_rh_status (hcd);
 		usb_hcd_poll_rh_status (hcd);
 	return retval;
 	return retval;
 }
 }
 
 
 static int dummy_bus_suspend (struct usb_hcd *hcd)
 static int dummy_bus_suspend (struct usb_hcd *hcd)
 {
 {
-	struct dummy *dum = hcd_to_dummy (hcd);
+	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
 
 
 	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
 	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
 
 
-	spin_lock_irq (&dum->lock);
-	dum->rh_state = DUMMY_RH_SUSPENDED;
-	set_link_state (dum);
+	spin_lock_irq(&dum_hcd->dum->lock);
+	dum_hcd->rh_state = DUMMY_RH_SUSPENDED;
+	set_link_state(dum_hcd);
 	hcd->state = HC_STATE_SUSPENDED;
 	hcd->state = HC_STATE_SUSPENDED;
-	spin_unlock_irq (&dum->lock);
+	spin_unlock_irq(&dum_hcd->dum->lock);
 	return 0;
 	return 0;
 }
 }
 
 
 static int dummy_bus_resume (struct usb_hcd *hcd)
 static int dummy_bus_resume (struct usb_hcd *hcd)
 {
 {
-	struct dummy *dum = hcd_to_dummy (hcd);
+	struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
 	int rc = 0;
 	int rc = 0;
 
 
 	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
 	dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
 
 
-	spin_lock_irq (&dum->lock);
+	spin_lock_irq(&dum_hcd->dum->lock);
 	if (!HCD_HW_ACCESSIBLE(hcd)) {
 	if (!HCD_HW_ACCESSIBLE(hcd)) {
 		rc = -ESHUTDOWN;
 		rc = -ESHUTDOWN;
 	} else {
 	} else {
-		dum->rh_state = DUMMY_RH_RUNNING;
-		set_link_state (dum);
-		if (!list_empty(&dum->urbp_list))
-			mod_timer (&dum->timer, jiffies);
+		dum_hcd->rh_state = DUMMY_RH_RUNNING;
+		set_link_state(dum_hcd);
+		if (!list_empty(&dum_hcd->urbp_list))
+			mod_timer(&dum_hcd->timer, jiffies);
 		hcd->state = HC_STATE_RUNNING;
 		hcd->state = HC_STATE_RUNNING;
 	}
 	}
-	spin_unlock_irq (&dum->lock);
+	spin_unlock_irq(&dum_hcd->dum->lock);
 	return rc;
 	return rc;
 }
 }
 
 
@@ -1786,18 +2090,37 @@ show_urb (char *buf, size_t size, struct urb *urb)
 		urb,
 		urb,
 		({ char *s;
 		({ char *s;
 		 switch (urb->dev->speed) {
 		 switch (urb->dev->speed) {
-		 case USB_SPEED_LOW:	s = "ls"; break;
-		 case USB_SPEED_FULL:	s = "fs"; break;
-		 case USB_SPEED_HIGH:	s = "hs"; break;
-		 default:		s = "?"; break;
+		 case USB_SPEED_LOW:
+			s = "ls";
+			break;
+		 case USB_SPEED_FULL:
+			s = "fs";
+			break;
+		 case USB_SPEED_HIGH:
+			s = "hs";
+			break;
+		 case USB_SPEED_SUPER:
+			s = "ss";
+			break;
+		 default:
+			s = "?";
+			break;
 		 }; s; }),
 		 }; s; }),
 		ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
 		ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
 		({ char *s; \
 		({ char *s; \
 		 switch (usb_pipetype (urb->pipe)) { \
 		 switch (usb_pipetype (urb->pipe)) { \
-		 case PIPE_CONTROL:	s = ""; break; \
-		 case PIPE_BULK:	s = "-bulk"; break; \
-		 case PIPE_INTERRUPT:	s = "-int"; break; \
-		 default: 		s = "-iso"; break; \
+		 case PIPE_CONTROL: \
+			s = ""; \
+			break; \
+		 case PIPE_BULK: \
+			s = "-bulk"; \
+			break; \
+		 case PIPE_INTERRUPT: \
+			s = "-int"; \
+			break; \
+		 default: \
+			s = "-iso"; \
+			break; \
 		}; s;}),
 		}; s;}),
 		urb->actual_length, urb->transfer_buffer_length);
 		urb->actual_length, urb->transfer_buffer_length);
 }
 }
@@ -1806,43 +2129,63 @@ static ssize_t
 show_urbs (struct device *dev, struct device_attribute *attr, char *buf)
 show_urbs (struct device *dev, struct device_attribute *attr, char *buf)
 {
 {
 	struct usb_hcd		*hcd = dev_get_drvdata (dev);
 	struct usb_hcd		*hcd = dev_get_drvdata (dev);
-	struct dummy		*dum = hcd_to_dummy (hcd);
+	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
 	struct urbp		*urbp;
 	struct urbp		*urbp;
 	size_t			size = 0;
 	size_t			size = 0;
 	unsigned long		flags;
 	unsigned long		flags;
 
 
-	spin_lock_irqsave (&dum->lock, flags);
-	list_for_each_entry (urbp, &dum->urbp_list, urbp_list) {
+	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
+	list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) {
 		size_t		temp;
 		size_t		temp;
 
 
 		temp = show_urb (buf, PAGE_SIZE - size, urbp->urb);
 		temp = show_urb (buf, PAGE_SIZE - size, urbp->urb);
 		buf += temp;
 		buf += temp;
 		size += temp;
 		size += temp;
 	}
 	}
-	spin_unlock_irqrestore (&dum->lock, flags);
+	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
 
 
 	return size;
 	return size;
 }
 }
 static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
 static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
 
 
-static int dummy_start (struct usb_hcd *hcd)
+static int dummy_start_ss(struct dummy_hcd *dum_hcd)
 {
 {
-	struct dummy		*dum;
+	init_timer(&dum_hcd->timer);
+	dum_hcd->timer.function = dummy_timer;
+	dum_hcd->timer.data = (unsigned long)dum_hcd;
+	dum_hcd->rh_state = DUMMY_RH_RUNNING;
+	INIT_LIST_HEAD(&dum_hcd->urbp_list);
+	dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET;
+	dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING;
+	dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1;
+#ifdef CONFIG_USB_OTG
+	dummy_hcd_to_hcd(dum_hcd)->self.otg_port = 1;
+#endif
+	return 0;
+
+	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
+	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
+}
 
 
-	dum = hcd_to_dummy (hcd);
+static int dummy_start(struct usb_hcd *hcd)
+{
+	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
 
 
 	/*
 	/*
 	 * MASTER side init ... we emulate a root hub that'll only ever
 	 * MASTER side init ... we emulate a root hub that'll only ever
 	 * talk to one device (the slave side).  Also appears in sysfs,
 	 * talk to one device (the slave side).  Also appears in sysfs,
 	 * just like more familiar pci-based HCDs.
 	 * just like more familiar pci-based HCDs.
 	 */
 	 */
-	spin_lock_init (&dum->lock);
-	init_timer (&dum->timer);
-	dum->timer.function = dummy_timer;
-	dum->timer.data = (unsigned long) dum;
-	dum->rh_state = DUMMY_RH_RUNNING;
+	if (!usb_hcd_is_primary_hcd(hcd))
+		return dummy_start_ss(dum_hcd);
 
 
-	INIT_LIST_HEAD (&dum->urbp_list);
+	spin_lock_init(&dum_hcd->dum->lock);
+	init_timer(&dum_hcd->timer);
+	dum_hcd->timer.function = dummy_timer;
+	dum_hcd->timer.data = (unsigned long)dum_hcd;
+	dum_hcd->rh_state = DUMMY_RH_RUNNING;
+
+	INIT_LIST_HEAD(&dum_hcd->urbp_list);
 
 
 	hcd->power_budget = POWER_BUDGET;
 	hcd->power_budget = POWER_BUDGET;
 	hcd->state = HC_STATE_RUNNING;
 	hcd->state = HC_STATE_RUNNING;
@@ -1853,18 +2196,17 @@ static int dummy_start (struct usb_hcd *hcd)
 #endif
 #endif
 
 
 	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
 	/* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
-	return device_create_file (dummy_dev(dum), &dev_attr_urbs);
+	return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
 }
 }
 
 
 static void dummy_stop (struct usb_hcd *hcd)
 static void dummy_stop (struct usb_hcd *hcd)
 {
 {
 	struct dummy		*dum;
 	struct dummy		*dum;
 
 
-	dum = hcd_to_dummy (hcd);
-
-	device_remove_file (dummy_dev(dum), &dev_attr_urbs);
-	usb_gadget_unregister_driver (dum->driver);
-	dev_info (dummy_dev(dum), "stopped\n");
+	dum = (hcd_to_dummy_hcd(hcd))->dum;
+	device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs);
+	usb_gadget_unregister_driver(dum->driver);
+	dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -1874,13 +2216,59 @@ static int dummy_h_get_frame (struct usb_hcd *hcd)
 	return dummy_g_get_frame (NULL);
 	return dummy_g_get_frame (NULL);
 }
 }
 
 
-static const struct hc_driver dummy_hcd = {
+static int dummy_setup(struct usb_hcd *hcd)
+{
+	if (usb_hcd_is_primary_hcd(hcd)) {
+		the_controller.hs_hcd = hcd_to_dummy_hcd(hcd);
+		the_controller.hs_hcd->dum = &the_controller;
+		/*
+		 * Mark the first roothub as being USB 2.0.
+		 * The USB 3.0 roothub will be registered later by
+		 * dummy_hcd_probe()
+		 */
+		hcd->speed = HCD_USB2;
+		hcd->self.root_hub->speed = USB_SPEED_HIGH;
+	} else {
+		the_controller.ss_hcd = hcd_to_dummy_hcd(hcd);
+		the_controller.ss_hcd->dum = &the_controller;
+		hcd->speed = HCD_USB3;
+		hcd->self.root_hub->speed = USB_SPEED_SUPER;
+	}
+	return 0;
+}
+
+/* Change a group of bulk endpoints to support multiple stream IDs */
+int dummy_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
+	struct usb_host_endpoint **eps, unsigned int num_eps,
+	unsigned int num_streams, gfp_t mem_flags)
+{
+	if (hcd->speed != HCD_USB3)
+		dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)),
+			"%s() - ERROR! Not supported for USB2.0 roothub\n",
+			__func__);
+	return 0;
+}
+
+/* Reverts a group of bulk endpoints back to not using stream IDs. */
+int dummy_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
+	struct usb_host_endpoint **eps, unsigned int num_eps,
+	gfp_t mem_flags)
+{
+	if (hcd->speed != HCD_USB3)
+		dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)),
+			"%s() - ERROR! Not supported for USB2.0 roothub\n",
+			__func__);
+	return 0;
+}
+
+static struct hc_driver dummy_hcd = {
 	.description =		(char *) driver_name,
 	.description =		(char *) driver_name,
 	.product_desc =		"Dummy host controller",
 	.product_desc =		"Dummy host controller",
-	.hcd_priv_size =	sizeof(struct dummy),
+	.hcd_priv_size =	sizeof(struct dummy_hcd),
 
 
-	.flags =		HCD_USB2,
+	.flags =		HCD_USB3 | HCD_SHARED,
 
 
+	.reset =		dummy_setup,
 	.start =		dummy_start,
 	.start =		dummy_start,
 	.stop =			dummy_stop,
 	.stop =			dummy_stop,
 
 
@@ -1893,51 +2281,85 @@ static const struct hc_driver dummy_hcd = {
 	.hub_control = 		dummy_hub_control,
 	.hub_control = 		dummy_hub_control,
 	.bus_suspend =		dummy_bus_suspend,
 	.bus_suspend =		dummy_bus_suspend,
 	.bus_resume =		dummy_bus_resume,
 	.bus_resume =		dummy_bus_resume,
+
+	.alloc_streams =	dummy_alloc_streams,
+	.free_streams =		dummy_free_streams,
 };
 };
 
 
 static int dummy_hcd_probe(struct platform_device *pdev)
 static int dummy_hcd_probe(struct platform_device *pdev)
 {
 {
-	struct usb_hcd		*hcd;
+	struct usb_hcd		*hs_hcd;
+	struct usb_hcd		*ss_hcd;
 	int			retval;
 	int			retval;
 
 
 	dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
 	dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
 
 
-	hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
-	if (!hcd)
+	if (!mod_data.is_super_speed)
+		dummy_hcd.flags = HCD_USB2;
+	hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
+	if (!hs_hcd)
 		return -ENOMEM;
 		return -ENOMEM;
-	the_controller = hcd_to_dummy (hcd);
-	hcd->has_tt = 1;
+	hs_hcd->has_tt = 1;
 
 
-	retval = usb_add_hcd(hcd, 0, 0);
+	retval = usb_add_hcd(hs_hcd, 0, 0);
 	if (retval != 0) {
 	if (retval != 0) {
-		usb_put_hcd (hcd);
-		the_controller = NULL;
+		usb_put_hcd(hs_hcd);
+		return retval;
+	}
+
+	if (mod_data.is_super_speed) {
+		ss_hcd = usb_create_shared_hcd(&dummy_hcd, &pdev->dev,
+					dev_name(&pdev->dev), hs_hcd);
+		if (!ss_hcd) {
+			retval = -ENOMEM;
+			goto dealloc_usb2_hcd;
+		}
+
+		retval = usb_add_hcd(ss_hcd, 0, 0);
+		if (retval)
+			goto put_usb3_hcd;
 	}
 	}
+	return 0;
+
+put_usb3_hcd:
+	usb_put_hcd(ss_hcd);
+dealloc_usb2_hcd:
+	usb_put_hcd(hs_hcd);
+	the_controller.hs_hcd = the_controller.ss_hcd = NULL;
 	return retval;
 	return retval;
 }
 }
 
 
-static int dummy_hcd_remove (struct platform_device *pdev)
+static int dummy_hcd_remove(struct platform_device *pdev)
 {
 {
-	struct usb_hcd		*hcd;
+	struct dummy		*dum;
+
+	dum = (hcd_to_dummy_hcd(platform_get_drvdata(pdev)))->dum;
+
+	if (dum->ss_hcd) {
+		usb_remove_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
+		usb_put_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
+	}
+
+	usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
+	usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
+
+	the_controller.hs_hcd = NULL;
+	the_controller.ss_hcd = NULL;
 
 
-	hcd = platform_get_drvdata (pdev);
-	usb_remove_hcd (hcd);
-	usb_put_hcd (hcd);
-	the_controller = NULL;
 	return 0;
 	return 0;
 }
 }
 
 
 static int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
 static int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
 {
 {
 	struct usb_hcd		*hcd;
 	struct usb_hcd		*hcd;
-	struct dummy		*dum;
+	struct dummy_hcd	*dum_hcd;
 	int			rc = 0;
 	int			rc = 0;
 
 
 	dev_dbg (&pdev->dev, "%s\n", __func__);
 	dev_dbg (&pdev->dev, "%s\n", __func__);
 
 
 	hcd = platform_get_drvdata (pdev);
 	hcd = platform_get_drvdata (pdev);
-	dum = hcd_to_dummy (hcd);
-	if (dum->rh_state == DUMMY_RH_RUNNING) {
+	dum_hcd = hcd_to_dummy_hcd(hcd);
+	if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
 		dev_warn(&pdev->dev, "Root hub isn't suspended!\n");
 		dev_warn(&pdev->dev, "Root hub isn't suspended!\n");
 		rc = -EBUSY;
 		rc = -EBUSY;
 	} else
 	} else
@@ -1980,6 +2402,9 @@ static int __init init (void)
 	if (usb_disabled ())
 	if (usb_disabled ())
 		return -ENODEV;
 		return -ENODEV;
 
 
+	if (!mod_data.is_high_speed && mod_data.is_super_speed)
+		return -EINVAL;
+
 	the_hcd_pdev = platform_device_alloc(driver_name, -1);
 	the_hcd_pdev = platform_device_alloc(driver_name, -1);
 	if (!the_hcd_pdev)
 	if (!the_hcd_pdev)
 		return retval;
 		return retval;
@@ -1997,7 +2422,8 @@ static int __init init (void)
 	retval = platform_device_add(the_hcd_pdev);
 	retval = platform_device_add(the_hcd_pdev);
 	if (retval < 0)
 	if (retval < 0)
 		goto err_add_hcd;
 		goto err_add_hcd;
-	if (!the_controller) {
+	if (!the_controller.hs_hcd ||
+	    (!the_controller.ss_hcd && mod_data.is_super_speed)) {
 		/*
 		/*
 		 * The hcd was added successfully but its probe function failed
 		 * The hcd was added successfully but its probe function failed
 		 * for some reason.
 		 * for some reason.

+ 104 - 28
drivers/usb/gadget/epautoconf.c

@@ -63,13 +63,16 @@ static int
 ep_matches (
 ep_matches (
 	struct usb_gadget		*gadget,
 	struct usb_gadget		*gadget,
 	struct usb_ep			*ep,
 	struct usb_ep			*ep,
-	struct usb_endpoint_descriptor	*desc
+	struct usb_endpoint_descriptor	*desc,
+	struct usb_ss_ep_comp_descriptor *ep_comp
 )
 )
 {
 {
 	u8		type;
 	u8		type;
 	const char	*tmp;
 	const char	*tmp;
 	u16		max;
 	u16		max;
 
 
+	int		num_req_streams = 0;
+
 	/* endpoint already claimed? */
 	/* endpoint already claimed? */
 	if (NULL != ep->driver_data)
 	if (NULL != ep->driver_data)
 		return 0;
 		return 0;
@@ -128,6 +131,22 @@ ep_matches (
 		}
 		}
 	}
 	}
 
 
+	/*
+	 * Get the number of required streams from the EP companion
+	 * descriptor and see if the EP matches it
+	 */
+	if (usb_endpoint_xfer_bulk(desc)) {
+		if (ep_comp) {
+			num_req_streams = ep_comp->bmAttributes & 0x1f;
+			if (num_req_streams > ep->max_streams)
+				return 0;
+			/* Update the ep_comp descriptor if needed */
+			if (num_req_streams != ep->max_streams)
+				ep_comp->bmAttributes = ep->max_streams;
+		}
+
+	}
+
 	/*
 	/*
 	 * If the protocol driver hasn't yet decided on wMaxPacketSize
 	 * If the protocol driver hasn't yet decided on wMaxPacketSize
 	 * and wants to know the maximum possible, provide the info.
 	 * and wants to know the maximum possible, provide the info.
@@ -142,13 +161,13 @@ ep_matches (
 	max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);
 	max = 0x7ff & le16_to_cpu(desc->wMaxPacketSize);
 	switch (type) {
 	switch (type) {
 	case USB_ENDPOINT_XFER_INT:
 	case USB_ENDPOINT_XFER_INT:
-		/* INT:  limit 64 bytes full speed, 1024 high speed */
+		/* INT:  limit 64 bytes full speed, 1024 high/super speed */
 		if (!gadget->is_dualspeed && max > 64)
 		if (!gadget->is_dualspeed && max > 64)
 			return 0;
 			return 0;
 		/* FALLTHROUGH */
 		/* FALLTHROUGH */
 
 
 	case USB_ENDPOINT_XFER_ISOC:
 	case USB_ENDPOINT_XFER_ISOC:
-		/* ISO:  limit 1023 bytes full speed, 1024 high speed */
+		/* ISO:  limit 1023 bytes full speed, 1024 high/super speed */
 		if (ep->maxpacket < max)
 		if (ep->maxpacket < max)
 			return 0;
 			return 0;
 		if (!gadget->is_dualspeed && max > 1023)
 		if (!gadget->is_dualspeed && max > 1023)
@@ -183,7 +202,7 @@ ep_matches (
 	}
 	}
 
 
 	/* report (variable) full speed bulk maxpacket */
 	/* report (variable) full speed bulk maxpacket */
-	if (USB_ENDPOINT_XFER_BULK == type) {
+	if ((USB_ENDPOINT_XFER_BULK == type) && !ep_comp) {
 		int size = ep->maxpacket;
 		int size = ep->maxpacket;
 
 
 		/* min() doesn't work on bitfields with gcc-3.5 */
 		/* min() doesn't work on bitfields with gcc-3.5 */
@@ -191,6 +210,7 @@ ep_matches (
 			size = 64;
 			size = 64;
 		desc->wMaxPacketSize = cpu_to_le16(size);
 		desc->wMaxPacketSize = cpu_to_le16(size);
 	}
 	}
+	ep->address = desc->bEndpointAddress;
 	return 1;
 	return 1;
 }
 }
 
 
@@ -207,38 +227,53 @@ find_ep (struct usb_gadget *gadget, const char *name)
 }
 }
 
 
 /**
 /**
- * usb_ep_autoconfig - choose an endpoint matching the descriptor
+ * usb_ep_autoconfig_ss() - choose an endpoint matching the ep
+ * descriptor and ep companion descriptor
  * @gadget: The device to which the endpoint must belong.
  * @gadget: The device to which the endpoint must belong.
  * @desc: Endpoint descriptor, with endpoint direction and transfer mode
  * @desc: Endpoint descriptor, with endpoint direction and transfer mode
- *	initialized.  For periodic transfers, the maximum packet
- *	size must also be initialized.  This is modified on success.
+ *    initialized.  For periodic transfers, the maximum packet
+ *    size must also be initialized.  This is modified on
+ *    success.
+ * @ep_comp: Endpoint companion descriptor, with the required
+ *    number of streams. Will be modified when the chosen EP
+ *    supports a different number of streams.
  *
  *
- * By choosing an endpoint to use with the specified descriptor, this
- * routine simplifies writing gadget drivers that work with multiple
- * USB device controllers.  The endpoint would be passed later to
- * usb_ep_enable(), along with some descriptor.
+ * This routine replaces the usb_ep_autoconfig when needed
+ * superspeed enhancments. If such enhancemnets are required,
+ * the FD should call usb_ep_autoconfig_ss directly and provide
+ * the additional ep_comp parameter.
+ *
+ * By choosing an endpoint to use with the specified descriptor,
+ * this routine simplifies writing gadget drivers that work with
+ * multiple USB device controllers.  The endpoint would be
+ * passed later to usb_ep_enable(), along with some descriptor.
  *
  *
  * That second descriptor won't always be the same as the first one.
  * That second descriptor won't always be the same as the first one.
  * For example, isochronous endpoints can be autoconfigured for high
  * For example, isochronous endpoints can be autoconfigured for high
  * bandwidth, and then used in several lower bandwidth altsettings.
  * bandwidth, and then used in several lower bandwidth altsettings.
  * Also, high and full speed descriptors will be different.
  * Also, high and full speed descriptors will be different.
  *
  *
- * Be sure to examine and test the results of autoconfiguration on your
- * hardware.  This code may not make the best choices about how to use the
- * USB controller, and it can't know all the restrictions that may apply.
- * Some combinations of driver and hardware won't be able to autoconfigure.
+ * Be sure to examine and test the results of autoconfiguration
+ * on your hardware.  This code may not make the best choices
+ * about how to use the USB controller, and it can't know all
+ * the restrictions that may apply. Some combinations of driver
+ * and hardware won't be able to autoconfigure.
  *
  *
  * On success, this returns an un-claimed usb_ep, and modifies the endpoint
  * On success, this returns an un-claimed usb_ep, and modifies the endpoint
  * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value
  * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value
- * is initialized as if the endpoint were used at full speed.  To prevent
- * the endpoint from being returned by a later autoconfig call, claim it
- * by assigning ep->driver_data to some non-null value.
+ * is initialized as if the endpoint were used at full speed and
+ * the bmAttribute field in the ep companion descriptor is
+ * updated with the assigned number of streams if it is
+ * different from the original value. To prevent the endpoint
+ * from being returned by a later autoconfig call, claim it by
+ * assigning ep->driver_data to some non-null value.
  *
  *
  * On failure, this returns a null endpoint descriptor.
  * On failure, this returns a null endpoint descriptor.
  */
  */
-struct usb_ep *usb_ep_autoconfig (
+struct usb_ep *usb_ep_autoconfig_ss(
 	struct usb_gadget		*gadget,
 	struct usb_gadget		*gadget,
-	struct usb_endpoint_descriptor	*desc
+	struct usb_endpoint_descriptor	*desc,
+	struct usb_ss_ep_comp_descriptor *ep_comp
 )
 )
 {
 {
 	struct usb_ep	*ep;
 	struct usb_ep	*ep;
@@ -252,23 +287,24 @@ struct usb_ep *usb_ep_autoconfig (
 	if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {
 	if (gadget_is_net2280 (gadget) && type == USB_ENDPOINT_XFER_INT) {
 		/* ep-e, ep-f are PIO with only 64 byte fifos */
 		/* ep-e, ep-f are PIO with only 64 byte fifos */
 		ep = find_ep (gadget, "ep-e");
 		ep = find_ep (gadget, "ep-e");
-		if (ep && ep_matches (gadget, ep, desc))
+		if (ep && ep_matches(gadget, ep, desc, ep_comp))
 			return ep;
 			return ep;
 		ep = find_ep (gadget, "ep-f");
 		ep = find_ep (gadget, "ep-f");
-		if (ep && ep_matches (gadget, ep, desc))
+		if (ep && ep_matches(gadget, ep, desc, ep_comp))
 			return ep;
 			return ep;
 
 
 	} else if (gadget_is_goku (gadget)) {
 	} else if (gadget_is_goku (gadget)) {
 		if (USB_ENDPOINT_XFER_INT == type) {
 		if (USB_ENDPOINT_XFER_INT == type) {
 			/* single buffering is enough */
 			/* single buffering is enough */
-			ep = find_ep (gadget, "ep3-bulk");
-			if (ep && ep_matches (gadget, ep, desc))
+			ep = find_ep(gadget, "ep3-bulk");
+			if (ep && ep_matches(gadget, ep, desc, ep_comp))
 				return ep;
 				return ep;
 		} else if (USB_ENDPOINT_XFER_BULK == type
 		} else if (USB_ENDPOINT_XFER_BULK == type
 				&& (USB_DIR_IN & desc->bEndpointAddress)) {
 				&& (USB_DIR_IN & desc->bEndpointAddress)) {
 			/* DMA may be available */
 			/* DMA may be available */
-			ep = find_ep (gadget, "ep2-bulk");
-			if (ep && ep_matches (gadget, ep, desc))
+			ep = find_ep(gadget, "ep2-bulk");
+			if (ep && ep_matches(gadget, ep, desc,
+					      ep_comp))
 				return ep;
 				return ep;
 		}
 		}
 
 
@@ -287,14 +323,14 @@ struct usb_ep *usb_ep_autoconfig (
 				ep = find_ep(gadget, "ep2out");
 				ep = find_ep(gadget, "ep2out");
 		} else
 		} else
 			ep = NULL;
 			ep = NULL;
-		if (ep && ep_matches (gadget, ep, desc))
+		if (ep && ep_matches(gadget, ep, desc, ep_comp))
 			return ep;
 			return ep;
 #endif
 #endif
 	}
 	}
 
 
 	/* Second, look at endpoints until an unclaimed one looks usable */
 	/* Second, look at endpoints until an unclaimed one looks usable */
 	list_for_each_entry (ep, &gadget->ep_list, ep_list) {
 	list_for_each_entry (ep, &gadget->ep_list, ep_list) {
-		if (ep_matches (gadget, ep, desc))
+		if (ep_matches(gadget, ep, desc, ep_comp))
 			return ep;
 			return ep;
 	}
 	}
 
 
@@ -302,6 +338,46 @@ struct usb_ep *usb_ep_autoconfig (
 	return NULL;
 	return NULL;
 }
 }
 
 
+/**
+ * usb_ep_autoconfig() - choose an endpoint matching the
+ * descriptor
+ * @gadget: The device to which the endpoint must belong.
+ * @desc: Endpoint descriptor, with endpoint direction and transfer mode
+ *	initialized.  For periodic transfers, the maximum packet
+ *	size must also be initialized.  This is modified on success.
+ *
+ * By choosing an endpoint to use with the specified descriptor, this
+ * routine simplifies writing gadget drivers that work with multiple
+ * USB device controllers.  The endpoint would be passed later to
+ * usb_ep_enable(), along with some descriptor.
+ *
+ * That second descriptor won't always be the same as the first one.
+ * For example, isochronous endpoints can be autoconfigured for high
+ * bandwidth, and then used in several lower bandwidth altsettings.
+ * Also, high and full speed descriptors will be different.
+ *
+ * Be sure to examine and test the results of autoconfiguration on your
+ * hardware.  This code may not make the best choices about how to use the
+ * USB controller, and it can't know all the restrictions that may apply.
+ * Some combinations of driver and hardware won't be able to autoconfigure.
+ *
+ * On success, this returns an un-claimed usb_ep, and modifies the endpoint
+ * descriptor bEndpointAddress.  For bulk endpoints, the wMaxPacket value
+ * is initialized as if the endpoint were used at full speed.  To prevent
+ * the endpoint from being returned by a later autoconfig call, claim it
+ * by assigning ep->driver_data to some non-null value.
+ *
+ * On failure, this returns a null endpoint descriptor.
+ */
+struct usb_ep *usb_ep_autoconfig(
+	struct usb_gadget		*gadget,
+	struct usb_endpoint_descriptor	*desc
+)
+{
+	return usb_ep_autoconfig_ss(gadget, desc, NULL);
+}
+
+
 /**
 /**
  * usb_ep_autoconfig_reset - reset endpoint autoconfig state
  * usb_ep_autoconfig_reset - reset endpoint autoconfig state
  * @gadget: device for which autoconfig state will be reset
  * @gadget: device for which autoconfig state will be reset

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

@@ -401,6 +401,7 @@ static struct usb_composite_driver eth_driver = {
 	.name		= "g_ether",
 	.name		= "g_ether",
 	.dev		= &device_desc,
 	.dev		= &device_desc,
 	.strings	= dev_strings,
 	.strings	= dev_strings,
+	.max_speed	= USB_SPEED_SUPER,
 	.unbind		= __exit_p(eth_unbind),
 	.unbind		= __exit_p(eth_unbind),
 };
 };
 
 

+ 15 - 35
drivers/usb/gadget/f_acm.c

@@ -39,12 +39,6 @@
  * descriptors (roughly equivalent to CDC Unions) may sometimes help.
  * descriptors (roughly equivalent to CDC Unions) may sometimes help.
  */
  */
 
 
-struct acm_ep_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-	struct usb_endpoint_descriptor	*notify;
-};
-
 struct f_acm {
 struct f_acm {
 	struct gserial			port;
 	struct gserial			port;
 	u8				ctrl_id, data_id;
 	u8				ctrl_id, data_id;
@@ -58,11 +52,7 @@ struct f_acm {
 	 */
 	 */
 	spinlock_t			lock;
 	spinlock_t			lock;
 
 
-	struct acm_ep_descs		fs;
-	struct acm_ep_descs		hs;
-
 	struct usb_ep			*notify;
 	struct usb_ep			*notify;
-	struct usb_endpoint_descriptor	*notify_desc;
 	struct usb_request		*notify_req;
 	struct usb_request		*notify_req;
 
 
 	struct usb_cdc_line_coding	port_line_coding;	/* 8-N-1 etc */
 	struct usb_cdc_line_coding	port_line_coding;	/* 8-N-1 etc */
@@ -405,23 +395,27 @@ static int acm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			usb_ep_disable(acm->notify);
 			usb_ep_disable(acm->notify);
 		} else {
 		} else {
 			VDBG(cdev, "init acm ctrl interface %d\n", intf);
 			VDBG(cdev, "init acm ctrl interface %d\n", intf);
-			acm->notify_desc = ep_choose(cdev->gadget,
-					acm->hs.notify,
-					acm->fs.notify);
+			if (config_ep_by_speed(cdev->gadget, f, acm->notify))
+				return -EINVAL;
 		}
 		}
-		usb_ep_enable(acm->notify, acm->notify_desc);
+		usb_ep_enable(acm->notify);
 		acm->notify->driver_data = acm;
 		acm->notify->driver_data = acm;
 
 
 	} else if (intf == acm->data_id) {
 	} else if (intf == acm->data_id) {
 		if (acm->port.in->driver_data) {
 		if (acm->port.in->driver_data) {
 			DBG(cdev, "reset acm ttyGS%d\n", acm->port_num);
 			DBG(cdev, "reset acm ttyGS%d\n", acm->port_num);
 			gserial_disconnect(&acm->port);
 			gserial_disconnect(&acm->port);
-		} else {
+		}
+		if (!acm->port.in->desc || !acm->port.out->desc) {
 			DBG(cdev, "activate acm ttyGS%d\n", acm->port_num);
 			DBG(cdev, "activate acm ttyGS%d\n", acm->port_num);
-			acm->port.in_desc = ep_choose(cdev->gadget,
-					acm->hs.in, acm->fs.in);
-			acm->port.out_desc = ep_choose(cdev->gadget,
-					acm->hs.out, acm->fs.out);
+			if (config_ep_by_speed(cdev->gadget, f,
+					       acm->port.in) ||
+			    config_ep_by_speed(cdev->gadget, f,
+					       acm->port.out)) {
+				acm->port.in->desc = NULL;
+				acm->port.out->desc = NULL;
+				return -EINVAL;
+			}
 		}
 		}
 		gserial_connect(&acm->port, acm->port_num);
 		gserial_connect(&acm->port, acm->port_num);
 
 
@@ -629,18 +623,11 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
 	acm->notify_req->complete = acm_cdc_notify_complete;
 	acm->notify_req->complete = acm_cdc_notify_complete;
 	acm->notify_req->context = acm;
 	acm->notify_req->context = acm;
 
 
-	/* copy descriptors, and track endpoint copies */
+	/* copy descriptors */
 	f->descriptors = usb_copy_descriptors(acm_fs_function);
 	f->descriptors = usb_copy_descriptors(acm_fs_function);
 	if (!f->descriptors)
 	if (!f->descriptors)
 		goto fail;
 		goto fail;
 
 
-	acm->fs.in = usb_find_endpoint(acm_fs_function,
-			f->descriptors, &acm_fs_in_desc);
-	acm->fs.out = usb_find_endpoint(acm_fs_function,
-			f->descriptors, &acm_fs_out_desc);
-	acm->fs.notify = usb_find_endpoint(acm_fs_function,
-			f->descriptors, &acm_fs_notify_desc);
-
 	/* support all relevant hardware speeds... we expect that when
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
 	 * both speeds
@@ -653,15 +640,8 @@ acm_bind(struct usb_configuration *c, struct usb_function *f)
 		acm_hs_notify_desc.bEndpointAddress =
 		acm_hs_notify_desc.bEndpointAddress =
 				acm_fs_notify_desc.bEndpointAddress;
 				acm_fs_notify_desc.bEndpointAddress;
 
 
-		/* copy descriptors, and track endpoint copies */
+		/* copy descriptors */
 		f->hs_descriptors = usb_copy_descriptors(acm_hs_function);
 		f->hs_descriptors = usb_copy_descriptors(acm_hs_function);
-
-		acm->hs.in = usb_find_endpoint(acm_hs_function,
-				f->hs_descriptors, &acm_hs_in_desc);
-		acm->hs.out = usb_find_endpoint(acm_hs_function,
-				f->hs_descriptors, &acm_hs_out_desc);
-		acm->hs.notify = usb_find_endpoint(acm_hs_function,
-				f->hs_descriptors, &acm_hs_notify_desc);
 	}
 	}
 
 
 	DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",
 	DBG(cdev, "acm ttyGS%d: %s speed IN/%s OUT/%s NOTIFY/%s\n",

+ 2 - 3
drivers/usb/gadget/f_audio.c

@@ -279,7 +279,6 @@ struct f_audio {
 
 
 	/* endpoints handle full and/or high speeds */
 	/* endpoints handle full and/or high speeds */
 	struct usb_ep			*out_ep;
 	struct usb_ep			*out_ep;
-	struct usb_endpoint_descriptor	*out_desc;
 
 
 	spinlock_t			lock;
 	spinlock_t			lock;
 	struct f_audio_buf *copy_buf;
 	struct f_audio_buf *copy_buf;
@@ -575,7 +574,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 
 
 	if (intf == 1) {
 	if (intf == 1) {
 		if (alt == 1) {
 		if (alt == 1) {
-			usb_ep_enable(out_ep, audio->out_desc);
+			usb_ep_enable(out_ep);
 			out_ep->driver_data = audio;
 			out_ep->driver_data = audio;
 			audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
 			audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
 			if (IS_ERR(audio->copy_buf))
 			if (IS_ERR(audio->copy_buf))
@@ -677,6 +676,7 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
 	if (!ep)
 	if (!ep)
 		goto fail;
 		goto fail;
 	audio->out_ep = ep;
 	audio->out_ep = ep;
+	audio->out_ep->desc = &as_out_ep_desc;
 	ep->driver_data = cdev;	/* claim */
 	ep->driver_data = cdev;	/* claim */
 
 
 	status = -ENOMEM;
 	status = -ENOMEM;
@@ -776,7 +776,6 @@ int __init audio_bind_config(struct usb_configuration *c)
 	audio->card.func.set_alt = f_audio_set_alt;
 	audio->card.func.set_alt = f_audio_set_alt;
 	audio->card.func.setup = f_audio_setup;
 	audio->card.func.setup = f_audio_setup;
 	audio->card.func.disable = f_audio_disable;
 	audio->card.func.disable = f_audio_disable;
-	audio->out_desc = &as_out_ep_desc;
 
 
 	control_selector_init(audio);
 	control_selector_init(audio);
 
 

+ 115 - 37
drivers/usb/gadget/f_ecm.c

@@ -46,11 +46,6 @@
  * and also means that a get_alt() method is required.
  * and also means that a get_alt() method is required.
  */
  */
 
 
-struct ecm_ep_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-	struct usb_endpoint_descriptor	*notify;
-};
 
 
 enum ecm_notify_state {
 enum ecm_notify_state {
 	ECM_NOTIFY_NONE,		/* don't notify */
 	ECM_NOTIFY_NONE,		/* don't notify */
@@ -64,11 +59,7 @@ struct f_ecm {
 
 
 	char				ethaddr[14];
 	char				ethaddr[14];
 
 
-	struct ecm_ep_descs		fs;
-	struct ecm_ep_descs		hs;
-
 	struct usb_ep			*notify;
 	struct usb_ep			*notify;
-	struct usb_endpoint_descriptor	*notify_desc;
 	struct usb_request		*notify_req;
 	struct usb_request		*notify_req;
 	u8				notify_state;
 	u8				notify_state;
 	bool				is_open;
 	bool				is_open;
@@ -86,10 +77,12 @@ static inline struct f_ecm *func_to_ecm(struct usb_function *f)
 /* peak (theoretical) bulk transfer rate in bits-per-second */
 /* peak (theoretical) bulk transfer rate in bits-per-second */
 static inline unsigned ecm_bitrate(struct usb_gadget *g)
 static inline unsigned ecm_bitrate(struct usb_gadget *g)
 {
 {
-	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+	if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
+		return 13 * 1024 * 8 * 1000 * 8;
+	else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
 		return 13 * 512 * 8 * 1000 * 8;
 		return 13 * 512 * 8 * 1000 * 8;
 	else
 	else
-		return 19 *  64 * 1 * 1000 * 8;
+		return 19 * 64 * 1 * 1000 * 8;
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -219,8 +212,10 @@ static struct usb_descriptor_header *ecm_fs_function[] = {
 	(struct usb_descriptor_header *) &ecm_header_desc,
 	(struct usb_descriptor_header *) &ecm_header_desc,
 	(struct usb_descriptor_header *) &ecm_union_desc,
 	(struct usb_descriptor_header *) &ecm_union_desc,
 	(struct usb_descriptor_header *) &ecm_desc,
 	(struct usb_descriptor_header *) &ecm_desc,
+
 	/* NOTE: status endpoint might need to be removed */
 	/* NOTE: status endpoint might need to be removed */
 	(struct usb_descriptor_header *) &fs_ecm_notify_desc,
 	(struct usb_descriptor_header *) &fs_ecm_notify_desc,
+
 	/* data interface, altsettings 0 and 1 */
 	/* data interface, altsettings 0 and 1 */
 	(struct usb_descriptor_header *) &ecm_data_nop_intf,
 	(struct usb_descriptor_header *) &ecm_data_nop_intf,
 	(struct usb_descriptor_header *) &ecm_data_intf,
 	(struct usb_descriptor_header *) &ecm_data_intf,
@@ -240,6 +235,7 @@ static struct usb_endpoint_descriptor hs_ecm_notify_desc = {
 	.wMaxPacketSize =	cpu_to_le16(ECM_STATUS_BYTECOUNT),
 	.wMaxPacketSize =	cpu_to_le16(ECM_STATUS_BYTECOUNT),
 	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4,
 	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4,
 };
 };
+
 static struct usb_endpoint_descriptor hs_ecm_in_desc = {
 static struct usb_endpoint_descriptor hs_ecm_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 	.bDescriptorType =	USB_DT_ENDPOINT,
@@ -264,8 +260,10 @@ static struct usb_descriptor_header *ecm_hs_function[] = {
 	(struct usb_descriptor_header *) &ecm_header_desc,
 	(struct usb_descriptor_header *) &ecm_header_desc,
 	(struct usb_descriptor_header *) &ecm_union_desc,
 	(struct usb_descriptor_header *) &ecm_union_desc,
 	(struct usb_descriptor_header *) &ecm_desc,
 	(struct usb_descriptor_header *) &ecm_desc,
+
 	/* NOTE: status endpoint might need to be removed */
 	/* NOTE: status endpoint might need to be removed */
 	(struct usb_descriptor_header *) &hs_ecm_notify_desc,
 	(struct usb_descriptor_header *) &hs_ecm_notify_desc,
+
 	/* data interface, altsettings 0 and 1 */
 	/* data interface, altsettings 0 and 1 */
 	(struct usb_descriptor_header *) &ecm_data_nop_intf,
 	(struct usb_descriptor_header *) &ecm_data_nop_intf,
 	(struct usb_descriptor_header *) &ecm_data_intf,
 	(struct usb_descriptor_header *) &ecm_data_intf,
@@ -274,6 +272,76 @@ static struct usb_descriptor_header *ecm_hs_function[] = {
 	NULL,
 	NULL,
 };
 };
 
 
+/* super speed support: */
+
+static struct usb_endpoint_descriptor ss_ecm_notify_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(ECM_STATUS_BYTECOUNT),
+	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4,
+};
+
+static struct usb_ss_ep_comp_descriptor ss_ecm_intr_comp_desc = {
+	.bLength =		sizeof ss_ecm_intr_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 3 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+	.wBytesPerInterval =	cpu_to_le16(ECM_STATUS_BYTECOUNT),
+};
+
+static struct usb_endpoint_descriptor ss_ecm_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor ss_ecm_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor ss_ecm_bulk_comp_desc = {
+	.bLength =		sizeof ss_ecm_bulk_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 2 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+};
+
+static struct usb_descriptor_header *ecm_ss_function[] = {
+	/* CDC ECM control descriptors */
+	(struct usb_descriptor_header *) &ecm_control_intf,
+	(struct usb_descriptor_header *) &ecm_header_desc,
+	(struct usb_descriptor_header *) &ecm_union_desc,
+	(struct usb_descriptor_header *) &ecm_desc,
+
+	/* NOTE: status endpoint might need to be removed */
+	(struct usb_descriptor_header *) &ss_ecm_notify_desc,
+	(struct usb_descriptor_header *) &ss_ecm_intr_comp_desc,
+
+	/* data interface, altsettings 0 and 1 */
+	(struct usb_descriptor_header *) &ecm_data_nop_intf,
+	(struct usb_descriptor_header *) &ecm_data_intf,
+	(struct usb_descriptor_header *) &ss_ecm_in_desc,
+	(struct usb_descriptor_header *) &ss_ecm_bulk_comp_desc,
+	(struct usb_descriptor_header *) &ss_ecm_out_desc,
+	(struct usb_descriptor_header *) &ss_ecm_bulk_comp_desc,
+	NULL,
+};
+
 /* string descriptors: */
 /* string descriptors: */
 
 
 static struct usb_string ecm_string_defs[] = {
 static struct usb_string ecm_string_defs[] = {
@@ -464,13 +532,13 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (ecm->notify->driver_data) {
 		if (ecm->notify->driver_data) {
 			VDBG(cdev, "reset ecm control %d\n", intf);
 			VDBG(cdev, "reset ecm control %d\n", intf);
 			usb_ep_disable(ecm->notify);
 			usb_ep_disable(ecm->notify);
-		} else {
+		}
+		if (!(ecm->notify->desc)) {
 			VDBG(cdev, "init ecm ctrl %d\n", intf);
 			VDBG(cdev, "init ecm ctrl %d\n", intf);
-			ecm->notify_desc = ep_choose(cdev->gadget,
-					ecm->hs.notify,
-					ecm->fs.notify);
+			if (config_ep_by_speed(cdev->gadget, f, ecm->notify))
+				goto fail;
 		}
 		}
-		usb_ep_enable(ecm->notify, ecm->notify_desc);
+		usb_ep_enable(ecm->notify);
 		ecm->notify->driver_data = ecm;
 		ecm->notify->driver_data = ecm;
 
 
 	/* Data interface has two altsettings, 0 and 1 */
 	/* Data interface has two altsettings, 0 and 1 */
@@ -483,12 +551,17 @@ static int ecm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gether_disconnect(&ecm->port);
 			gether_disconnect(&ecm->port);
 		}
 		}
 
 
-		if (!ecm->port.in) {
+		if (!ecm->port.in_ep->desc ||
+		    !ecm->port.out_ep->desc) {
 			DBG(cdev, "init ecm\n");
 			DBG(cdev, "init ecm\n");
-			ecm->port.in = ep_choose(cdev->gadget,
-					ecm->hs.in, ecm->fs.in);
-			ecm->port.out = ep_choose(cdev->gadget,
-					ecm->hs.out, ecm->fs.out);
+			if (config_ep_by_speed(cdev->gadget, f,
+					       ecm->port.in_ep) ||
+			    config_ep_by_speed(cdev->gadget, f,
+					       ecm->port.out_ep)) {
+				ecm->port.in_ep->desc = NULL;
+				ecm->port.out_ep->desc = NULL;
+				goto fail;
+			}
 		}
 		}
 
 
 		/* CDC Ethernet only sends data in non-default altsettings.
 		/* CDC Ethernet only sends data in non-default altsettings.
@@ -549,7 +622,7 @@ static void ecm_disable(struct usb_function *f)
 	if (ecm->notify->driver_data) {
 	if (ecm->notify->driver_data) {
 		usb_ep_disable(ecm->notify);
 		usb_ep_disable(ecm->notify);
 		ecm->notify->driver_data = NULL;
 		ecm->notify->driver_data = NULL;
-		ecm->notify_desc = NULL;
+		ecm->notify->desc = NULL;
 	}
 	}
 }
 }
 
 
@@ -665,13 +738,6 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
 	if (!f->descriptors)
 	if (!f->descriptors)
 		goto fail;
 		goto fail;
 
 
-	ecm->fs.in = usb_find_endpoint(ecm_fs_function,
-			f->descriptors, &fs_ecm_in_desc);
-	ecm->fs.out = usb_find_endpoint(ecm_fs_function,
-			f->descriptors, &fs_ecm_out_desc);
-	ecm->fs.notify = usb_find_endpoint(ecm_fs_function,
-			f->descriptors, &fs_ecm_notify_desc);
-
 	/* support all relevant hardware speeds... we expect that when
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
 	 * both speeds
@@ -688,13 +754,20 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
 		f->hs_descriptors = usb_copy_descriptors(ecm_hs_function);
 		f->hs_descriptors = usb_copy_descriptors(ecm_hs_function);
 		if (!f->hs_descriptors)
 		if (!f->hs_descriptors)
 			goto fail;
 			goto fail;
+	}
 
 
-		ecm->hs.in = usb_find_endpoint(ecm_hs_function,
-				f->hs_descriptors, &hs_ecm_in_desc);
-		ecm->hs.out = usb_find_endpoint(ecm_hs_function,
-				f->hs_descriptors, &hs_ecm_out_desc);
-		ecm->hs.notify = usb_find_endpoint(ecm_hs_function,
-				f->hs_descriptors, &hs_ecm_notify_desc);
+	if (gadget_is_superspeed(c->cdev->gadget)) {
+		ss_ecm_in_desc.bEndpointAddress =
+				fs_ecm_in_desc.bEndpointAddress;
+		ss_ecm_out_desc.bEndpointAddress =
+				fs_ecm_out_desc.bEndpointAddress;
+		ss_ecm_notify_desc.bEndpointAddress =
+				fs_ecm_notify_desc.bEndpointAddress;
+
+		/* copy descriptors, and track endpoint copies */
+		f->ss_descriptors = usb_copy_descriptors(ecm_ss_function);
+		if (!f->ss_descriptors)
+			goto fail;
 	}
 	}
 
 
 	/* NOTE:  all that is done without knowing or caring about
 	/* NOTE:  all that is done without knowing or caring about
@@ -706,6 +779,7 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
 	ecm->port.close = ecm_close;
 	ecm->port.close = ecm_close;
 
 
 	DBG(cdev, "CDC Ethernet: %s speed IN/%s OUT/%s NOTIFY/%s\n",
 	DBG(cdev, "CDC Ethernet: %s speed IN/%s OUT/%s NOTIFY/%s\n",
+			gadget_is_superspeed(c->cdev->gadget) ? "super" :
 			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
 			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
 			ecm->port.in_ep->name, ecm->port.out_ep->name,
 			ecm->port.in_ep->name, ecm->port.out_ep->name,
 			ecm->notify->name);
 			ecm->notify->name);
@@ -714,6 +788,8 @@ ecm_bind(struct usb_configuration *c, struct usb_function *f)
 fail:
 fail:
 	if (f->descriptors)
 	if (f->descriptors)
 		usb_free_descriptors(f->descriptors);
 		usb_free_descriptors(f->descriptors);
+	if (f->hs_descriptors)
+		usb_free_descriptors(f->hs_descriptors);
 
 
 	if (ecm->notify_req) {
 	if (ecm->notify_req) {
 		kfree(ecm->notify_req->buf);
 		kfree(ecm->notify_req->buf);
@@ -723,9 +799,9 @@ fail:
 	/* we might as well release our claims on endpoints */
 	/* we might as well release our claims on endpoints */
 	if (ecm->notify)
 	if (ecm->notify)
 		ecm->notify->driver_data = NULL;
 		ecm->notify->driver_data = NULL;
-	if (ecm->port.out)
+	if (ecm->port.out_ep->desc)
 		ecm->port.out_ep->driver_data = NULL;
 		ecm->port.out_ep->driver_data = NULL;
-	if (ecm->port.in)
+	if (ecm->port.in_ep->desc)
 		ecm->port.in_ep->driver_data = NULL;
 		ecm->port.in_ep->driver_data = NULL;
 
 
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
@@ -740,6 +816,8 @@ ecm_unbind(struct usb_configuration *c, struct usb_function *f)
 
 
 	DBG(c->cdev, "ecm unbind\n");
 	DBG(c->cdev, "ecm unbind\n");
 
 
+	if (gadget_is_superspeed(c->cdev->gadget))
+		usb_free_descriptors(f->ss_descriptors);
 	if (gadget_is_dualspeed(c->cdev->gadget))
 	if (gadget_is_dualspeed(c->cdev->gadget))
 		usb_free_descriptors(f->hs_descriptors);
 		usb_free_descriptors(f->hs_descriptors);
 	usb_free_descriptors(f->descriptors);
 	usb_free_descriptors(f->descriptors);

+ 66 - 24
drivers/usb/gadget/f_eem.c

@@ -35,17 +35,9 @@
  * Ethernet link.
  * Ethernet link.
  */
  */
 
 
-struct eem_ep_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-};
-
 struct f_eem {
 struct f_eem {
 	struct gether			port;
 	struct gether			port;
 	u8				ctrl_id;
 	u8				ctrl_id;
-
-	struct eem_ep_descs		fs;
-	struct eem_ep_descs		hs;
 };
 };
 
 
 static inline struct f_eem *func_to_eem(struct usb_function *f)
 static inline struct f_eem *func_to_eem(struct usb_function *f)
@@ -123,6 +115,45 @@ static struct usb_descriptor_header *eem_hs_function[] __initdata = {
 	NULL,
 	NULL,
 };
 };
 
 
+/* super speed support: */
+
+static struct usb_endpoint_descriptor eem_ss_in_desc __initdata = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor eem_ss_out_desc __initdata = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor eem_ss_bulk_comp_desc __initdata = {
+	.bLength =		sizeof eem_ss_bulk_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 2 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+};
+
+static struct usb_descriptor_header *eem_ss_function[] __initdata = {
+	/* CDC EEM control descriptors */
+	(struct usb_descriptor_header *) &eem_intf,
+	(struct usb_descriptor_header *) &eem_ss_in_desc,
+	(struct usb_descriptor_header *) &eem_ss_bulk_comp_desc,
+	(struct usb_descriptor_header *) &eem_ss_out_desc,
+	(struct usb_descriptor_header *) &eem_ss_bulk_comp_desc,
+	NULL,
+};
+
 /* string descriptors: */
 /* string descriptors: */
 
 
 static struct usb_string eem_string_defs[] = {
 static struct usb_string eem_string_defs[] = {
@@ -176,12 +207,16 @@ static int eem_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gether_disconnect(&eem->port);
 			gether_disconnect(&eem->port);
 		}
 		}
 
 
-		if (!eem->port.in) {
+		if (!eem->port.in_ep->desc || !eem->port.out_ep->desc) {
 			DBG(cdev, "init eem\n");
 			DBG(cdev, "init eem\n");
-			eem->port.in = ep_choose(cdev->gadget,
-					eem->hs.in, eem->fs.in);
-			eem->port.out = ep_choose(cdev->gadget,
-					eem->hs.out, eem->fs.out);
+			if (config_ep_by_speed(cdev->gadget, f,
+					       eem->port.in_ep) ||
+			    config_ep_by_speed(cdev->gadget, f,
+					       eem->port.out_ep)) {
+				eem->port.in_ep->desc = NULL;
+				eem->port.out_ep->desc = NULL;
+				goto fail;
+			}
 		}
 		}
 
 
 		/* zlps should not occur because zero-length EEM packets
 		/* zlps should not occur because zero-length EEM packets
@@ -253,11 +288,6 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
 	if (!f->descriptors)
 	if (!f->descriptors)
 		goto fail;
 		goto fail;
 
 
-	eem->fs.in = usb_find_endpoint(eem_fs_function,
-			f->descriptors, &eem_fs_in_desc);
-	eem->fs.out = usb_find_endpoint(eem_fs_function,
-			f->descriptors, &eem_fs_out_desc);
-
 	/* support all relevant hardware speeds... we expect that when
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
 	 * both speeds
@@ -272,14 +302,22 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
 		f->hs_descriptors = usb_copy_descriptors(eem_hs_function);
 		f->hs_descriptors = usb_copy_descriptors(eem_hs_function);
 		if (!f->hs_descriptors)
 		if (!f->hs_descriptors)
 			goto fail;
 			goto fail;
+	}
+
+	if (gadget_is_superspeed(c->cdev->gadget)) {
+		eem_ss_in_desc.bEndpointAddress =
+				eem_fs_in_desc.bEndpointAddress;
+		eem_ss_out_desc.bEndpointAddress =
+				eem_fs_out_desc.bEndpointAddress;
 
 
-		eem->hs.in = usb_find_endpoint(eem_hs_function,
-				f->hs_descriptors, &eem_hs_in_desc);
-		eem->hs.out = usb_find_endpoint(eem_hs_function,
-				f->hs_descriptors, &eem_hs_out_desc);
+		/* copy descriptors, and track endpoint copies */
+		f->ss_descriptors = usb_copy_descriptors(eem_ss_function);
+		if (!f->ss_descriptors)
+			goto fail;
 	}
 	}
 
 
 	DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n",
 	DBG(cdev, "CDC Ethernet (EEM): %s speed IN/%s OUT/%s\n",
+			gadget_is_superspeed(c->cdev->gadget) ? "super" :
 			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
 			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
 			eem->port.in_ep->name, eem->port.out_ep->name);
 			eem->port.in_ep->name, eem->port.out_ep->name);
 	return 0;
 	return 0;
@@ -287,11 +325,13 @@ eem_bind(struct usb_configuration *c, struct usb_function *f)
 fail:
 fail:
 	if (f->descriptors)
 	if (f->descriptors)
 		usb_free_descriptors(f->descriptors);
 		usb_free_descriptors(f->descriptors);
+	if (f->hs_descriptors)
+		usb_free_descriptors(f->hs_descriptors);
 
 
 	/* we might as well release our claims on endpoints */
 	/* we might as well release our claims on endpoints */
-	if (eem->port.out)
+	if (eem->port.out_ep->desc)
 		eem->port.out_ep->driver_data = NULL;
 		eem->port.out_ep->driver_data = NULL;
-	if (eem->port.in)
+	if (eem->port.in_ep->desc)
 		eem->port.in_ep->driver_data = NULL;
 		eem->port.in_ep->driver_data = NULL;
 
 
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
@@ -306,6 +346,8 @@ eem_unbind(struct usb_configuration *c, struct usb_function *f)
 
 
 	DBG(c->cdev, "eem unbind\n");
 	DBG(c->cdev, "eem unbind\n");
 
 
+	if (gadget_is_superspeed(c->cdev->gadget))
+		usb_free_descriptors(f->ss_descriptors);
 	if (gadget_is_dualspeed(c->cdev->gadget))
 	if (gadget_is_dualspeed(c->cdev->gadget))
 		usb_free_descriptors(f->hs_descriptors);
 		usb_free_descriptors(f->hs_descriptors);
 	usb_free_descriptors(f->descriptors);
 	usb_free_descriptors(f->descriptors);

+ 2 - 1
drivers/usb/gadget/f_fs.c

@@ -1544,7 +1544,8 @@ static int ffs_func_eps_enable(struct ffs_function *func)
 		ds = ep->descs[ep->descs[1] ? 1 : 0];
 		ds = ep->descs[ep->descs[1] ? 1 : 0];
 
 
 		ep->ep->driver_data = ep;
 		ep->ep->driver_data = ep;
-		ret = usb_ep_enable(ep->ep, ds);
+		ep->ep->desc = ds;
+		ret = usb_ep_enable(ep->ep);
 		if (likely(!ret)) {
 		if (likely(!ret)) {
 			epfile->ep = ep;
 			epfile->ep = ep;
 			epfile->in = usb_endpoint_dir_in(ds);
 			epfile->in = usb_endpoint_dir_in(ds);

+ 7 - 15
drivers/usb/gadget/f_hid.c

@@ -59,8 +59,6 @@ struct f_hidg {
 	struct cdev			cdev;
 	struct cdev			cdev;
 	struct usb_function		func;
 	struct usb_function		func;
 	struct usb_ep			*in_ep;
 	struct usb_ep			*in_ep;
-	struct usb_endpoint_descriptor	*fs_in_ep_desc;
-	struct usb_endpoint_descriptor	*hs_in_ep_desc;
 };
 };
 
 
 static inline struct f_hidg *func_to_hidg(struct usb_function *f)
 static inline struct f_hidg *func_to_hidg(struct usb_function *f)
@@ -416,7 +414,6 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 {
 {
 	struct usb_composite_dev		*cdev = f->config->cdev;
 	struct usb_composite_dev		*cdev = f->config->cdev;
 	struct f_hidg				*hidg = func_to_hidg(f);
 	struct f_hidg				*hidg = func_to_hidg(f);
-	const struct usb_endpoint_descriptor	*ep_desc;
 	int status = 0;
 	int status = 0;
 
 
 	VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt);
 	VDBG(cdev, "hidg_set_alt intf:%d alt:%d\n", intf, alt);
@@ -426,9 +423,13 @@ static int hidg_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (hidg->in_ep->driver_data != NULL)
 		if (hidg->in_ep->driver_data != NULL)
 			usb_ep_disable(hidg->in_ep);
 			usb_ep_disable(hidg->in_ep);
 
 
-		ep_desc = ep_choose(f->config->cdev->gadget,
-				hidg->hs_in_ep_desc, hidg->fs_in_ep_desc);
-		status = usb_ep_enable(hidg->in_ep, ep_desc);
+		status = config_ep_by_speed(f->config->cdev->gadget, f,
+					    hidg->in_ep);
+		if (status) {
+			ERROR(cdev, "config_ep_by_speed FAILED!\n");
+			goto fail;
+		}
+		status = usb_ep_enable(hidg->in_ep);
 		if (status < 0) {
 		if (status < 0) {
 			ERROR(cdev, "Enable endpoint FAILED!\n");
 			ERROR(cdev, "Enable endpoint FAILED!\n");
 			goto fail;
 			goto fail;
@@ -498,21 +499,12 @@ static int __init hidg_bind(struct usb_configuration *c, struct usb_function *f)
 	if (!f->descriptors)
 	if (!f->descriptors)
 		goto fail;
 		goto fail;
 
 
-	hidg->fs_in_ep_desc = usb_find_endpoint(hidg_fs_descriptors,
-						f->descriptors,
-						&hidg_fs_in_ep_desc);
-
 	if (gadget_is_dualspeed(c->cdev->gadget)) {
 	if (gadget_is_dualspeed(c->cdev->gadget)) {
 		hidg_hs_in_ep_desc.bEndpointAddress =
 		hidg_hs_in_ep_desc.bEndpointAddress =
 			hidg_fs_in_ep_desc.bEndpointAddress;
 			hidg_fs_in_ep_desc.bEndpointAddress;
 		f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors);
 		f->hs_descriptors = usb_copy_descriptors(hidg_hs_descriptors);
 		if (!f->hs_descriptors)
 		if (!f->hs_descriptors)
 			goto fail;
 			goto fail;
-		hidg->hs_in_ep_desc = usb_find_endpoint(hidg_hs_descriptors,
-							f->hs_descriptors,
-							&hidg_hs_in_ep_desc);
-	} else {
-		hidg->hs_in_ep_desc = NULL;
 	}
 	}
 
 
 	mutex_init(&hidg->lock);
 	mutex_init(&hidg->lock);

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

@@ -118,6 +118,49 @@ static struct usb_descriptor_header *hs_loopback_descs[] = {
 	NULL,
 	NULL,
 };
 };
 
 
+/* super speed support: */
+
+static struct usb_endpoint_descriptor ss_loop_source_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+struct usb_ss_ep_comp_descriptor ss_loop_source_comp_desc = {
+	.bLength =		USB_DT_SS_EP_COMP_SIZE,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+	.bMaxBurst =		0,
+	.bmAttributes =		0,
+	.wBytesPerInterval =	0,
+};
+
+static struct usb_endpoint_descriptor ss_loop_sink_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+struct usb_ss_ep_comp_descriptor ss_loop_sink_comp_desc = {
+	.bLength =		USB_DT_SS_EP_COMP_SIZE,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+	.bMaxBurst =		0,
+	.bmAttributes =		0,
+	.wBytesPerInterval =	0,
+};
+
+static struct usb_descriptor_header *ss_loopback_descs[] = {
+	(struct usb_descriptor_header *) &loopback_intf,
+	(struct usb_descriptor_header *) &ss_loop_source_desc,
+	(struct usb_descriptor_header *) &ss_loop_source_comp_desc,
+	(struct usb_descriptor_header *) &ss_loop_sink_desc,
+	(struct usb_descriptor_header *) &ss_loop_sink_comp_desc,
+	NULL,
+};
+
 /* function-specific strings: */
 /* function-specific strings: */
 
 
 static struct usb_string strings_loopback[] = {
 static struct usb_string strings_loopback[] = {
@@ -175,8 +218,18 @@ autoconf_fail:
 		f->hs_descriptors = hs_loopback_descs;
 		f->hs_descriptors = hs_loopback_descs;
 	}
 	}
 
 
+	/* support super speed hardware */
+	if (gadget_is_superspeed(c->cdev->gadget)) {
+		ss_loop_source_desc.bEndpointAddress =
+				fs_loop_source_desc.bEndpointAddress;
+		ss_loop_sink_desc.bEndpointAddress =
+				fs_loop_sink_desc.bEndpointAddress;
+		f->ss_descriptors = ss_loopback_descs;
+	}
+
 	DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
 	DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
-			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
+	    (gadget_is_superspeed(c->cdev->gadget) ? "super" :
+	     (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
 			f->name, loop->in_ep->name, loop->out_ep->name);
 			f->name, loop->in_ep->name, loop->out_ep->name);
 	return 0;
 	return 0;
 }
 }
@@ -250,26 +303,27 @@ static int
 enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
 enable_loopback(struct usb_composite_dev *cdev, struct f_loopback *loop)
 {
 {
 	int					result = 0;
 	int					result = 0;
-	const struct usb_endpoint_descriptor	*src, *sink;
 	struct usb_ep				*ep;
 	struct usb_ep				*ep;
 	struct usb_request			*req;
 	struct usb_request			*req;
 	unsigned				i;
 	unsigned				i;
 
 
-	src = ep_choose(cdev->gadget,
-			&hs_loop_source_desc, &fs_loop_source_desc);
-	sink = ep_choose(cdev->gadget,
-			&hs_loop_sink_desc, &fs_loop_sink_desc);
-
 	/* one endpoint writes data back IN to the host */
 	/* one endpoint writes data back IN to the host */
 	ep = loop->in_ep;
 	ep = loop->in_ep;
-	result = usb_ep_enable(ep, src);
+	result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
+	if (result)
+		return result;
+	result = usb_ep_enable(ep);
 	if (result < 0)
 	if (result < 0)
 		return result;
 		return result;
 	ep->driver_data = loop;
 	ep->driver_data = loop;
 
 
 	/* one endpoint just reads OUT packets */
 	/* one endpoint just reads OUT packets */
 	ep = loop->out_ep;
 	ep = loop->out_ep;
-	result = usb_ep_enable(ep, sink);
+	result = config_ep_by_speed(cdev->gadget, &(loop->function), ep);
+	if (result)
+		goto fail0;
+
+	result = usb_ep_enable(ep);
 	if (result < 0) {
 	if (result < 0) {
 fail0:
 fail0:
 		ep = loop->in_ep;
 		ep = loop->in_ep;

+ 13 - 20
drivers/usb/gadget/f_mass_storage.c

@@ -2324,18 +2324,6 @@ static int get_next_command(struct fsg_common *common)
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-static int enable_endpoint(struct fsg_common *common, struct usb_ep *ep,
-		const struct usb_endpoint_descriptor *d)
-{
-	int	rc;
-
-	ep->driver_data = common;
-	rc = usb_ep_enable(ep, d);
-	if (rc)
-		ERROR(common, "can't enable %s, result %d\n", ep->name, rc);
-	return rc;
-}
-
 static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
 static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
 		struct usb_request **preq)
 		struct usb_request **preq)
 {
 {
@@ -2349,7 +2337,6 @@ static int alloc_request(struct fsg_common *common, struct usb_ep *ep,
 /* Reset interface setting and re-init endpoint state (toggle etc). */
 /* Reset interface setting and re-init endpoint state (toggle etc). */
 static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg)
 static int do_set_interface(struct fsg_common *common, struct fsg_dev *new_fsg)
 {
 {
-	const struct usb_endpoint_descriptor *d;
 	struct fsg_dev *fsg;
 	struct fsg_dev *fsg;
 	int i, rc = 0;
 	int i, rc = 0;
 
 
@@ -2396,20 +2383,26 @@ reset:
 	fsg = common->fsg;
 	fsg = common->fsg;
 
 
 	/* Enable the endpoints */
 	/* Enable the endpoints */
-	d = fsg_ep_desc(common->gadget,
-			&fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc);
-	rc = enable_endpoint(common, fsg->bulk_in, d);
+	rc = config_ep_by_speed(common->gadget, &(fsg->function), fsg->bulk_in);
+	if (rc)
+		goto reset;
+	rc = usb_ep_enable(fsg->bulk_in);
 	if (rc)
 	if (rc)
 		goto reset;
 		goto reset;
+	fsg->bulk_in->driver_data = common;
 	fsg->bulk_in_enabled = 1;
 	fsg->bulk_in_enabled = 1;
 
 
-	d = fsg_ep_desc(common->gadget,
-			&fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc);
-	rc = enable_endpoint(common, fsg->bulk_out, d);
+	rc = config_ep_by_speed(common->gadget, &(fsg->function),
+				fsg->bulk_out);
+	if (rc)
+		goto reset;
+	rc = usb_ep_enable(fsg->bulk_out);
 	if (rc)
 	if (rc)
 		goto reset;
 		goto reset;
+	fsg->bulk_out->driver_data = common;
 	fsg->bulk_out_enabled = 1;
 	fsg->bulk_out_enabled = 1;
-	common->bulk_out_maxpacket = le16_to_cpu(d->wMaxPacketSize);
+	common->bulk_out_maxpacket =
+		le16_to_cpu(fsg->bulk_out->desc->wMaxPacketSize);
 	clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
 	clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags);
 
 
 	/* Allocate the requests */
 	/* Allocate the requests */

+ 19 - 39
drivers/usb/gadget/f_ncm.c

@@ -48,12 +48,6 @@
 #define NCM_NDP_HDR_CRC		0x01000000
 #define NCM_NDP_HDR_CRC		0x01000000
 #define NCM_NDP_HDR_NOCRC	0x00000000
 #define NCM_NDP_HDR_NOCRC	0x00000000
 
 
-struct ncm_ep_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-	struct usb_endpoint_descriptor	*notify;
-};
-
 enum ncm_notify_state {
 enum ncm_notify_state {
 	NCM_NOTIFY_NONE,		/* don't notify */
 	NCM_NOTIFY_NONE,		/* don't notify */
 	NCM_NOTIFY_CONNECT,		/* issue CONNECT next */
 	NCM_NOTIFY_CONNECT,		/* issue CONNECT next */
@@ -66,11 +60,7 @@ struct f_ncm {
 
 
 	char				ethaddr[14];
 	char				ethaddr[14];
 
 
-	struct ncm_ep_descs		fs;
-	struct ncm_ep_descs		hs;
-
 	struct usb_ep			*notify;
 	struct usb_ep			*notify;
-	struct usb_endpoint_descriptor	*notify_desc;
 	struct usb_request		*notify_req;
 	struct usb_request		*notify_req;
 	u8				notify_state;
 	u8				notify_state;
 	bool				is_open;
 	bool				is_open;
@@ -802,13 +792,14 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (ncm->notify->driver_data) {
 		if (ncm->notify->driver_data) {
 			DBG(cdev, "reset ncm control %d\n", intf);
 			DBG(cdev, "reset ncm control %d\n", intf);
 			usb_ep_disable(ncm->notify);
 			usb_ep_disable(ncm->notify);
-		} else {
+		}
+
+		if (!(ncm->notify->desc)) {
 			DBG(cdev, "init ncm ctrl %d\n", intf);
 			DBG(cdev, "init ncm ctrl %d\n", intf);
-			ncm->notify_desc = ep_choose(cdev->gadget,
-					ncm->hs.notify,
-					ncm->fs.notify);
+			if (config_ep_by_speed(cdev->gadget, f, ncm->notify))
+				goto fail;
 		}
 		}
-		usb_ep_enable(ncm->notify, ncm->notify_desc);
+		usb_ep_enable(ncm->notify);
 		ncm->notify->driver_data = ncm;
 		ncm->notify->driver_data = ncm;
 
 
 	/* Data interface has two altsettings, 0 and 1 */
 	/* Data interface has two altsettings, 0 and 1 */
@@ -829,14 +820,17 @@ static int ncm_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (alt == 1) {
 		if (alt == 1) {
 			struct net_device	*net;
 			struct net_device	*net;
 
 
-			if (!ncm->port.in) {
+			if (!ncm->port.in_ep->desc ||
+			    !ncm->port.out_ep->desc) {
 				DBG(cdev, "init ncm\n");
 				DBG(cdev, "init ncm\n");
-				ncm->port.in = ep_choose(cdev->gadget,
-							 ncm->hs.in,
-							 ncm->fs.in);
-				ncm->port.out = ep_choose(cdev->gadget,
-							  ncm->hs.out,
-							  ncm->fs.out);
+				if (config_ep_by_speed(cdev->gadget, f,
+						       ncm->port.in_ep) ||
+				    config_ep_by_speed(cdev->gadget, f,
+						       ncm->port.out_ep)) {
+					ncm->port.in_ep->desc = NULL;
+					ncm->port.out_ep->desc = NULL;
+					goto fail;
+				}
 			}
 			}
 
 
 			/* TODO */
 			/* TODO */
@@ -1111,7 +1105,7 @@ static void ncm_disable(struct usb_function *f)
 	if (ncm->notify->driver_data) {
 	if (ncm->notify->driver_data) {
 		usb_ep_disable(ncm->notify);
 		usb_ep_disable(ncm->notify);
 		ncm->notify->driver_data = NULL;
 		ncm->notify->driver_data = NULL;
-		ncm->notify_desc = NULL;
+		ncm->notify->desc = NULL;
 	}
 	}
 }
 }
 
 
@@ -1228,13 +1222,6 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f)
 	if (!f->descriptors)
 	if (!f->descriptors)
 		goto fail;
 		goto fail;
 
 
-	ncm->fs.in = usb_find_endpoint(ncm_fs_function,
-			f->descriptors, &fs_ncm_in_desc);
-	ncm->fs.out = usb_find_endpoint(ncm_fs_function,
-			f->descriptors, &fs_ncm_out_desc);
-	ncm->fs.notify = usb_find_endpoint(ncm_fs_function,
-			f->descriptors, &fs_ncm_notify_desc);
-
 	/*
 	/*
 	 * support all relevant hardware speeds... we expect that when
 	 * support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * hardware is dual speed, all bulk-capable endpoints work at
@@ -1252,13 +1239,6 @@ ncm_bind(struct usb_configuration *c, struct usb_function *f)
 		f->hs_descriptors = usb_copy_descriptors(ncm_hs_function);
 		f->hs_descriptors = usb_copy_descriptors(ncm_hs_function);
 		if (!f->hs_descriptors)
 		if (!f->hs_descriptors)
 			goto fail;
 			goto fail;
-
-		ncm->hs.in = usb_find_endpoint(ncm_hs_function,
-				f->hs_descriptors, &hs_ncm_in_desc);
-		ncm->hs.out = usb_find_endpoint(ncm_hs_function,
-				f->hs_descriptors, &hs_ncm_out_desc);
-		ncm->hs.notify = usb_find_endpoint(ncm_hs_function,
-				f->hs_descriptors, &hs_ncm_notify_desc);
 	}
 	}
 
 
 	/*
 	/*
@@ -1288,9 +1268,9 @@ fail:
 	/* we might as well release our claims on endpoints */
 	/* we might as well release our claims on endpoints */
 	if (ncm->notify)
 	if (ncm->notify)
 		ncm->notify->driver_data = NULL;
 		ncm->notify->driver_data = NULL;
-	if (ncm->port.out)
+	if (ncm->port.out_ep->desc)
 		ncm->port.out_ep->driver_data = NULL;
 		ncm->port.out_ep->driver_data = NULL;
-	if (ncm->port.in)
+	if (ncm->port.in_ep->desc)
 		ncm->port.in_ep->driver_data = NULL;
 		ncm->port.in_ep->driver_data = NULL;
 
 
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);

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

@@ -39,20 +39,12 @@
  * ready to handle the commands.
  * ready to handle the commands.
  */
  */
 
 
-struct obex_ep_descs {
-	struct usb_endpoint_descriptor	*obex_in;
-	struct usb_endpoint_descriptor	*obex_out;
-};
-
 struct f_obex {
 struct f_obex {
 	struct gserial			port;
 	struct gserial			port;
 	u8				ctrl_id;
 	u8				ctrl_id;
 	u8				data_id;
 	u8				data_id;
 	u8				port_num;
 	u8				port_num;
 	u8				can_activate;
 	u8				can_activate;
-
-	struct obex_ep_descs		fs;
-	struct obex_ep_descs		hs;
 };
 };
 
 
 static inline struct f_obex *func_to_obex(struct usb_function *f)
 static inline struct f_obex *func_to_obex(struct usb_function *f)
@@ -227,12 +219,16 @@ static int obex_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gserial_disconnect(&obex->port);
 			gserial_disconnect(&obex->port);
 		}
 		}
 
 
-		if (!obex->port.in_desc) {
+		if (!obex->port.in->desc || !obex->port.out->desc) {
 			DBG(cdev, "init obex ttyGS%d\n", obex->port_num);
 			DBG(cdev, "init obex ttyGS%d\n", obex->port_num);
-			obex->port.in_desc = ep_choose(cdev->gadget,
-					obex->hs.obex_in, obex->fs.obex_in);
-			obex->port.out_desc = ep_choose(cdev->gadget,
-					obex->hs.obex_out, obex->fs.obex_out);
+			if (config_ep_by_speed(cdev->gadget, f,
+					       obex->port.in) ||
+			    config_ep_by_speed(cdev->gadget, f,
+					       obex->port.out)) {
+				obex->port.out->desc = NULL;
+				obex->port.in->desc = NULL;
+				goto fail;
+			}
 		}
 		}
 
 
 		if (alt == 1) {
 		if (alt == 1) {
@@ -346,11 +342,6 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
 	/* copy descriptors, and track endpoint copies */
 	/* copy descriptors, and track endpoint copies */
 	f->descriptors = usb_copy_descriptors(fs_function);
 	f->descriptors = usb_copy_descriptors(fs_function);
 
 
-	obex->fs.obex_in = usb_find_endpoint(fs_function,
-			f->descriptors, &obex_fs_ep_in_desc);
-	obex->fs.obex_out = usb_find_endpoint(fs_function,
-			f->descriptors, &obex_fs_ep_out_desc);
-
 	/* support all relevant hardware speeds... we expect that when
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
 	 * both speeds
@@ -364,11 +355,6 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
 
 
 		/* copy descriptors, and track endpoint copies */
 		/* copy descriptors, and track endpoint copies */
 		f->hs_descriptors = usb_copy_descriptors(hs_function);
 		f->hs_descriptors = usb_copy_descriptors(hs_function);
-
-		obex->hs.obex_in = usb_find_endpoint(hs_function,
-				f->hs_descriptors, &obex_hs_ep_in_desc);
-		obex->hs.obex_out = usb_find_endpoint(hs_function,
-				f->hs_descriptors, &obex_hs_ep_out_desc);
 	}
 	}
 
 
 	/* Avoid letting this gadget enumerate until the userspace
 	/* Avoid letting this gadget enumerate until the userspace

+ 8 - 9
drivers/usb/gadget/f_phonet.c

@@ -428,17 +428,16 @@ static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		spin_lock(&port->lock);
 		spin_lock(&port->lock);
 		__pn_reset(f);
 		__pn_reset(f);
 		if (alt == 1) {
 		if (alt == 1) {
-			struct usb_endpoint_descriptor *out, *in;
 			int i;
 			int i;
 
 
-			out = ep_choose(gadget,
-					&pn_hs_sink_desc,
-					&pn_fs_sink_desc);
-			in = ep_choose(gadget,
-					&pn_hs_source_desc,
-					&pn_fs_source_desc);
-			usb_ep_enable(fp->out_ep, out);
-			usb_ep_enable(fp->in_ep, in);
+			if (config_ep_by_speed(gadget, f, fp->in_ep) ||
+			    config_ep_by_speed(gadget, f, fp->out_ep)) {
+				fp->in_ep->desc = NULL;
+				fp->out_ep->desc = NULL;
+				return -EINVAL;
+			}
+			usb_ep_enable(fp->out_ep);
+			usb_ep_enable(fp->in_ep);
 
 
 			port->usb = fp;
 			port->usb = fp;
 			fp->out_ep->driver_data = fp;
 			fp->out_ep->driver_data = fp;

+ 113 - 38
drivers/usb/gadget/f_rndis.c

@@ -76,23 +76,13 @@
  *   - MS-Windows drivers sometimes emit undocumented requests.
  *   - MS-Windows drivers sometimes emit undocumented requests.
  */
  */
 
 
-struct rndis_ep_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-	struct usb_endpoint_descriptor	*notify;
-};
-
 struct f_rndis {
 struct f_rndis {
 	struct gether			port;
 	struct gether			port;
 	u8				ctrl_id, data_id;
 	u8				ctrl_id, data_id;
 	u8				ethaddr[ETH_ALEN];
 	u8				ethaddr[ETH_ALEN];
 	int				config;
 	int				config;
 
 
-	struct rndis_ep_descs		fs;
-	struct rndis_ep_descs		hs;
-
 	struct usb_ep			*notify;
 	struct usb_ep			*notify;
-	struct usb_endpoint_descriptor	*notify_desc;
 	struct usb_request		*notify_req;
 	struct usb_request		*notify_req;
 	atomic_t			notify_count;
 	atomic_t			notify_count;
 };
 };
@@ -105,10 +95,12 @@ static inline struct f_rndis *func_to_rndis(struct usb_function *f)
 /* peak (theoretical) bulk transfer rate in bits-per-second */
 /* peak (theoretical) bulk transfer rate in bits-per-second */
 static unsigned int bitrate(struct usb_gadget *g)
 static unsigned int bitrate(struct usb_gadget *g)
 {
 {
-	if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
+	if (gadget_is_superspeed(g) && g->speed == USB_SPEED_SUPER)
+		return 13 * 1024 * 8 * 1000 * 8;
+	else if (gadget_is_dualspeed(g) && g->speed == USB_SPEED_HIGH)
 		return 13 * 512 * 8 * 1000 * 8;
 		return 13 * 512 * 8 * 1000 * 8;
 	else
 	else
-		return 19 *  64 * 1 * 1000 * 8;
+		return 19 * 64 * 1 * 1000 * 8;
 }
 }
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -226,6 +218,7 @@ static struct usb_endpoint_descriptor fs_out_desc = {
 
 
 static struct usb_descriptor_header *eth_fs_function[] = {
 static struct usb_descriptor_header *eth_fs_function[] = {
 	(struct usb_descriptor_header *) &rndis_iad_descriptor,
 	(struct usb_descriptor_header *) &rndis_iad_descriptor,
+
 	/* control interface matches ACM, not Ethernet */
 	/* control interface matches ACM, not Ethernet */
 	(struct usb_descriptor_header *) &rndis_control_intf,
 	(struct usb_descriptor_header *) &rndis_control_intf,
 	(struct usb_descriptor_header *) &header_desc,
 	(struct usb_descriptor_header *) &header_desc,
@@ -233,6 +226,7 @@ static struct usb_descriptor_header *eth_fs_function[] = {
 	(struct usb_descriptor_header *) &rndis_acm_descriptor,
 	(struct usb_descriptor_header *) &rndis_acm_descriptor,
 	(struct usb_descriptor_header *) &rndis_union_desc,
 	(struct usb_descriptor_header *) &rndis_union_desc,
 	(struct usb_descriptor_header *) &fs_notify_desc,
 	(struct usb_descriptor_header *) &fs_notify_desc,
+
 	/* data interface has no altsetting */
 	/* data interface has no altsetting */
 	(struct usb_descriptor_header *) &rndis_data_intf,
 	(struct usb_descriptor_header *) &rndis_data_intf,
 	(struct usb_descriptor_header *) &fs_in_desc,
 	(struct usb_descriptor_header *) &fs_in_desc,
@@ -251,6 +245,7 @@ static struct usb_endpoint_descriptor hs_notify_desc = {
 	.wMaxPacketSize =	cpu_to_le16(STATUS_BYTECOUNT),
 	.wMaxPacketSize =	cpu_to_le16(STATUS_BYTECOUNT),
 	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4,
 	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4,
 };
 };
+
 static struct usb_endpoint_descriptor hs_in_desc = {
 static struct usb_endpoint_descriptor hs_in_desc = {
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bLength =		USB_DT_ENDPOINT_SIZE,
 	.bDescriptorType =	USB_DT_ENDPOINT,
 	.bDescriptorType =	USB_DT_ENDPOINT,
@@ -271,6 +266,7 @@ static struct usb_endpoint_descriptor hs_out_desc = {
 
 
 static struct usb_descriptor_header *eth_hs_function[] = {
 static struct usb_descriptor_header *eth_hs_function[] = {
 	(struct usb_descriptor_header *) &rndis_iad_descriptor,
 	(struct usb_descriptor_header *) &rndis_iad_descriptor,
+
 	/* control interface matches ACM, not Ethernet */
 	/* control interface matches ACM, not Ethernet */
 	(struct usb_descriptor_header *) &rndis_control_intf,
 	(struct usb_descriptor_header *) &rndis_control_intf,
 	(struct usb_descriptor_header *) &header_desc,
 	(struct usb_descriptor_header *) &header_desc,
@@ -278,6 +274,7 @@ static struct usb_descriptor_header *eth_hs_function[] = {
 	(struct usb_descriptor_header *) &rndis_acm_descriptor,
 	(struct usb_descriptor_header *) &rndis_acm_descriptor,
 	(struct usb_descriptor_header *) &rndis_union_desc,
 	(struct usb_descriptor_header *) &rndis_union_desc,
 	(struct usb_descriptor_header *) &hs_notify_desc,
 	(struct usb_descriptor_header *) &hs_notify_desc,
+
 	/* data interface has no altsetting */
 	/* data interface has no altsetting */
 	(struct usb_descriptor_header *) &rndis_data_intf,
 	(struct usb_descriptor_header *) &rndis_data_intf,
 	(struct usb_descriptor_header *) &hs_in_desc,
 	(struct usb_descriptor_header *) &hs_in_desc,
@@ -285,6 +282,76 @@ static struct usb_descriptor_header *eth_hs_function[] = {
 	NULL,
 	NULL,
 };
 };
 
 
+/* super speed support: */
+
+static struct usb_endpoint_descriptor ss_notify_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_INT,
+	.wMaxPacketSize =	cpu_to_le16(STATUS_BYTECOUNT),
+	.bInterval =		LOG2_STATUS_INTERVAL_MSEC + 4,
+};
+
+static struct usb_ss_ep_comp_descriptor ss_intr_comp_desc = {
+	.bLength =		sizeof ss_intr_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 3 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+	.wBytesPerInterval =	cpu_to_le16(STATUS_BYTECOUNT),
+};
+
+static struct usb_endpoint_descriptor ss_in_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_IN,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor ss_out_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bEndpointAddress =	USB_DIR_OUT,
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor ss_bulk_comp_desc = {
+	.bLength =		sizeof ss_bulk_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 2 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+};
+
+static struct usb_descriptor_header *eth_ss_function[] = {
+	(struct usb_descriptor_header *) &rndis_iad_descriptor,
+
+	/* control interface matches ACM, not Ethernet */
+	(struct usb_descriptor_header *) &rndis_control_intf,
+	(struct usb_descriptor_header *) &header_desc,
+	(struct usb_descriptor_header *) &call_mgmt_descriptor,
+	(struct usb_descriptor_header *) &rndis_acm_descriptor,
+	(struct usb_descriptor_header *) &rndis_union_desc,
+	(struct usb_descriptor_header *) &ss_notify_desc,
+	(struct usb_descriptor_header *) &ss_intr_comp_desc,
+
+	/* data interface has no altsetting */
+	(struct usb_descriptor_header *) &rndis_data_intf,
+	(struct usb_descriptor_header *) &ss_in_desc,
+	(struct usb_descriptor_header *) &ss_bulk_comp_desc,
+	(struct usb_descriptor_header *) &ss_out_desc,
+	(struct usb_descriptor_header *) &ss_bulk_comp_desc,
+	NULL,
+};
+
 /* string descriptors: */
 /* string descriptors: */
 
 
 static struct usb_string rndis_string_defs[] = {
 static struct usb_string rndis_string_defs[] = {
@@ -484,13 +551,13 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 		if (rndis->notify->driver_data) {
 		if (rndis->notify->driver_data) {
 			VDBG(cdev, "reset rndis control %d\n", intf);
 			VDBG(cdev, "reset rndis control %d\n", intf);
 			usb_ep_disable(rndis->notify);
 			usb_ep_disable(rndis->notify);
-		} else {
+		}
+		if (!rndis->notify->desc) {
 			VDBG(cdev, "init rndis ctrl %d\n", intf);
 			VDBG(cdev, "init rndis ctrl %d\n", intf);
-			rndis->notify_desc = ep_choose(cdev->gadget,
-					rndis->hs.notify,
-					rndis->fs.notify);
+			if (config_ep_by_speed(cdev->gadget, f, rndis->notify))
+				goto fail;
 		}
 		}
-		usb_ep_enable(rndis->notify, rndis->notify_desc);
+		usb_ep_enable(rndis->notify);
 		rndis->notify->driver_data = rndis;
 		rndis->notify->driver_data = rndis;
 
 
 	} else if (intf == rndis->data_id) {
 	} else if (intf == rndis->data_id) {
@@ -501,12 +568,16 @@ static int rndis_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 			gether_disconnect(&rndis->port);
 			gether_disconnect(&rndis->port);
 		}
 		}
 
 
-		if (!rndis->port.in) {
+		if (!rndis->port.in_ep->desc || !rndis->port.out_ep->desc) {
 			DBG(cdev, "init rndis\n");
 			DBG(cdev, "init rndis\n");
-			rndis->port.in = ep_choose(cdev->gadget,
-					rndis->hs.in, rndis->fs.in);
-			rndis->port.out = ep_choose(cdev->gadget,
-					rndis->hs.out, rndis->fs.out);
+			if (config_ep_by_speed(cdev->gadget, f,
+					       rndis->port.in_ep) ||
+			    config_ep_by_speed(cdev->gadget, f,
+					       rndis->port.out_ep)) {
+				rndis->port.in_ep->desc = NULL;
+				rndis->port.out_ep->desc = NULL;
+				goto fail;
+			}
 		}
 		}
 
 
 		/* Avoid ZLPs; they can be troublesome. */
 		/* Avoid ZLPs; they can be troublesome. */
@@ -662,13 +733,6 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
 	if (!f->descriptors)
 	if (!f->descriptors)
 		goto fail;
 		goto fail;
 
 
-	rndis->fs.in = usb_find_endpoint(eth_fs_function,
-			f->descriptors, &fs_in_desc);
-	rndis->fs.out = usb_find_endpoint(eth_fs_function,
-			f->descriptors, &fs_out_desc);
-	rndis->fs.notify = usb_find_endpoint(eth_fs_function,
-			f->descriptors, &fs_notify_desc);
-
 	/* support all relevant hardware speeds... we expect that when
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
 	 * both speeds
@@ -683,16 +747,22 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
 
 
 		/* copy descriptors, and track endpoint copies */
 		/* copy descriptors, and track endpoint copies */
 		f->hs_descriptors = usb_copy_descriptors(eth_hs_function);
 		f->hs_descriptors = usb_copy_descriptors(eth_hs_function);
-
 		if (!f->hs_descriptors)
 		if (!f->hs_descriptors)
 			goto fail;
 			goto fail;
+	}
 
 
-		rndis->hs.in = usb_find_endpoint(eth_hs_function,
-				f->hs_descriptors, &hs_in_desc);
-		rndis->hs.out = usb_find_endpoint(eth_hs_function,
-				f->hs_descriptors, &hs_out_desc);
-		rndis->hs.notify = usb_find_endpoint(eth_hs_function,
-				f->hs_descriptors, &hs_notify_desc);
+	if (gadget_is_superspeed(c->cdev->gadget)) {
+		ss_in_desc.bEndpointAddress =
+				fs_in_desc.bEndpointAddress;
+		ss_out_desc.bEndpointAddress =
+				fs_out_desc.bEndpointAddress;
+		ss_notify_desc.bEndpointAddress =
+				fs_notify_desc.bEndpointAddress;
+
+		/* copy descriptors, and track endpoint copies */
+		f->ss_descriptors = usb_copy_descriptors(eth_ss_function);
+		if (!f->ss_descriptors)
+			goto fail;
 	}
 	}
 
 
 	rndis->port.open = rndis_open;
 	rndis->port.open = rndis_open;
@@ -719,12 +789,15 @@ rndis_bind(struct usb_configuration *c, struct usb_function *f)
 	 */
 	 */
 
 
 	DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n",
 	DBG(cdev, "RNDIS: %s speed IN/%s OUT/%s NOTIFY/%s\n",
+			gadget_is_superspeed(c->cdev->gadget) ? "super" :
 			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
 			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
 			rndis->port.in_ep->name, rndis->port.out_ep->name,
 			rndis->port.in_ep->name, rndis->port.out_ep->name,
 			rndis->notify->name);
 			rndis->notify->name);
 	return 0;
 	return 0;
 
 
 fail:
 fail:
+	if (gadget_is_superspeed(c->cdev->gadget) && f->ss_descriptors)
+		usb_free_descriptors(f->ss_descriptors);
 	if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors)
 	if (gadget_is_dualspeed(c->cdev->gadget) && f->hs_descriptors)
 		usb_free_descriptors(f->hs_descriptors);
 		usb_free_descriptors(f->hs_descriptors);
 	if (f->descriptors)
 	if (f->descriptors)
@@ -738,9 +811,9 @@ fail:
 	/* we might as well release our claims on endpoints */
 	/* we might as well release our claims on endpoints */
 	if (rndis->notify)
 	if (rndis->notify)
 		rndis->notify->driver_data = NULL;
 		rndis->notify->driver_data = NULL;
-	if (rndis->port.out)
+	if (rndis->port.out_ep->desc)
 		rndis->port.out_ep->driver_data = NULL;
 		rndis->port.out_ep->driver_data = NULL;
-	if (rndis->port.in)
+	if (rndis->port.in_ep->desc)
 		rndis->port.in_ep->driver_data = NULL;
 		rndis->port.in_ep->driver_data = NULL;
 
 
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
@@ -756,6 +829,8 @@ rndis_unbind(struct usb_configuration *c, struct usb_function *f)
 	rndis_deregister(rndis->config);
 	rndis_deregister(rndis->config);
 	rndis_exit();
 	rndis_exit();
 
 
+	if (gadget_is_superspeed(c->cdev->gadget))
+		usb_free_descriptors(f->ss_descriptors);
 	if (gadget_is_dualspeed(c->cdev->gadget))
 	if (gadget_is_dualspeed(c->cdev->gadget))
 		usb_free_descriptors(f->hs_descriptors);
 		usb_free_descriptors(f->hs_descriptors);
 	usb_free_descriptors(f->descriptors);
 	usb_free_descriptors(f->descriptors);

+ 8 - 24
drivers/usb/gadget/f_serial.c

@@ -27,18 +27,10 @@
  * if you can arrange appropriate host side drivers.
  * if you can arrange appropriate host side drivers.
  */
  */
 
 
-struct gser_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-};
-
 struct f_gser {
 struct f_gser {
 	struct gserial			port;
 	struct gserial			port;
 	u8				data_id;
 	u8				data_id;
 	u8				port_num;
 	u8				port_num;
-
-	struct gser_descs		fs;
-	struct gser_descs		hs;
 };
 };
 
 
 static inline struct f_gser *func_to_gser(struct usb_function *f)
 static inline struct f_gser *func_to_gser(struct usb_function *f)
@@ -136,12 +128,15 @@ static int gser_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 	if (gser->port.in->driver_data) {
 	if (gser->port.in->driver_data) {
 		DBG(cdev, "reset generic ttyGS%d\n", gser->port_num);
 		DBG(cdev, "reset generic ttyGS%d\n", gser->port_num);
 		gserial_disconnect(&gser->port);
 		gserial_disconnect(&gser->port);
-	} else {
+	}
+	if (!gser->port.in->desc || !gser->port.out->desc) {
 		DBG(cdev, "activate generic ttyGS%d\n", gser->port_num);
 		DBG(cdev, "activate generic ttyGS%d\n", gser->port_num);
-		gser->port.in_desc = ep_choose(cdev->gadget,
-				gser->hs.in, gser->fs.in);
-		gser->port.out_desc = ep_choose(cdev->gadget,
-				gser->hs.out, gser->fs.out);
+		if (!config_ep_by_speed(cdev->gadget, f, gser->port.in) ||
+		    !config_ep_by_speed(cdev->gadget, f, gser->port.out)) {
+			gser->port.in->desc = NULL;
+			gser->port.out->desc = NULL;
+			return -EINVAL;
+		}
 	}
 	}
 	gserial_connect(&gser->port, gser->port_num);
 	gserial_connect(&gser->port, gser->port_num);
 	return 0;
 	return 0;
@@ -193,12 +188,6 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
 	/* copy descriptors, and track endpoint copies */
 	/* copy descriptors, and track endpoint copies */
 	f->descriptors = usb_copy_descriptors(gser_fs_function);
 	f->descriptors = usb_copy_descriptors(gser_fs_function);
 
 
-	gser->fs.in = usb_find_endpoint(gser_fs_function,
-			f->descriptors, &gser_fs_in_desc);
-	gser->fs.out = usb_find_endpoint(gser_fs_function,
-			f->descriptors, &gser_fs_out_desc);
-
-
 	/* support all relevant hardware speeds... we expect that when
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * both speeds
 	 * both speeds
@@ -211,11 +200,6 @@ gser_bind(struct usb_configuration *c, struct usb_function *f)
 
 
 		/* copy descriptors, and track endpoint copies */
 		/* copy descriptors, and track endpoint copies */
 		f->hs_descriptors = usb_copy_descriptors(gser_hs_function);
 		f->hs_descriptors = usb_copy_descriptors(gser_hs_function);
-
-		gser->hs.in = usb_find_endpoint(gser_hs_function,
-				f->hs_descriptors, &gser_hs_in_desc);
-		gser->hs.out = usb_find_endpoint(gser_hs_function,
-				f->hs_descriptors, &gser_hs_out_desc);
 	}
 	}
 
 
 	DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",
 	DBG(cdev, "generic ttyGS%d: %s speed IN/%s OUT/%s\n",

+ 64 - 7
drivers/usb/gadget/f_sourcesink.c

@@ -131,6 +131,49 @@ static struct usb_descriptor_header *hs_source_sink_descs[] = {
 	NULL,
 	NULL,
 };
 };
 
 
+/* super speed support: */
+
+static struct usb_endpoint_descriptor ss_source_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+struct usb_ss_ep_comp_descriptor ss_source_comp_desc = {
+	.bLength =		USB_DT_SS_EP_COMP_SIZE,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+	.bMaxBurst =		0,
+	.bmAttributes =		0,
+	.wBytesPerInterval =	0,
+};
+
+static struct usb_endpoint_descriptor ss_sink_desc = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+struct usb_ss_ep_comp_descriptor ss_sink_comp_desc = {
+	.bLength =		USB_DT_SS_EP_COMP_SIZE,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+	.bMaxBurst =		0,
+	.bmAttributes =		0,
+	.wBytesPerInterval =	0,
+};
+
+static struct usb_descriptor_header *ss_source_sink_descs[] = {
+	(struct usb_descriptor_header *) &source_sink_intf,
+	(struct usb_descriptor_header *) &ss_source_desc,
+	(struct usb_descriptor_header *) &ss_source_comp_desc,
+	(struct usb_descriptor_header *) &ss_sink_desc,
+	(struct usb_descriptor_header *) &ss_sink_comp_desc,
+	NULL,
+};
+
 /* function-specific strings: */
 /* function-specific strings: */
 
 
 static struct usb_string strings_sourcesink[] = {
 static struct usb_string strings_sourcesink[] = {
@@ -187,8 +230,18 @@ autoconf_fail:
 		f->hs_descriptors = hs_source_sink_descs;
 		f->hs_descriptors = hs_source_sink_descs;
 	}
 	}
 
 
+	/* support super speed hardware */
+	if (gadget_is_superspeed(c->cdev->gadget)) {
+		ss_source_desc.bEndpointAddress =
+				fs_source_desc.bEndpointAddress;
+		ss_sink_desc.bEndpointAddress =
+				fs_sink_desc.bEndpointAddress;
+		f->ss_descriptors = ss_source_sink_descs;
+	}
+
 	DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
 	DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
-			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
+	    (gadget_is_superspeed(c->cdev->gadget) ? "super" :
+	     (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full")),
 			f->name, ss->in_ep->name, ss->out_ep->name);
 			f->name, ss->in_ep->name, ss->out_ep->name);
 	return 0;
 	return 0;
 }
 }
@@ -343,15 +396,14 @@ static int
 enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss)
 enable_source_sink(struct usb_composite_dev *cdev, struct f_sourcesink *ss)
 {
 {
 	int					result = 0;
 	int					result = 0;
-	const struct usb_endpoint_descriptor	*src, *sink;
 	struct usb_ep				*ep;
 	struct usb_ep				*ep;
 
 
-	src = ep_choose(cdev->gadget, &hs_source_desc, &fs_source_desc);
-	sink = ep_choose(cdev->gadget, &hs_sink_desc, &fs_sink_desc);
-
 	/* one endpoint writes (sources) zeroes IN (to the host) */
 	/* one endpoint writes (sources) zeroes IN (to the host) */
 	ep = ss->in_ep;
 	ep = ss->in_ep;
-	result = usb_ep_enable(ep, src);
+	result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
+	if (result)
+		return result;
+	result = usb_ep_enable(ep);
 	if (result < 0)
 	if (result < 0)
 		return result;
 		return result;
 	ep->driver_data = ss;
 	ep->driver_data = ss;
@@ -367,7 +419,10 @@ fail:
 
 
 	/* one endpoint reads (sinks) anything OUT (from the host) */
 	/* one endpoint reads (sinks) anything OUT (from the host) */
 	ep = ss->out_ep;
 	ep = ss->out_ep;
-	result = usb_ep_enable(ep, sink);
+	result = config_ep_by_speed(cdev->gadget, &(ss->function), ep);
+	if (result)
+		goto fail;
+	result = usb_ep_enable(ep);
 	if (result < 0)
 	if (result < 0)
 		goto fail;
 		goto fail;
 	ep->driver_data = ss;
 	ep->driver_data = ss;
@@ -435,6 +490,8 @@ static int sourcesink_setup(struct usb_configuration *c,
 	u16			w_value = le16_to_cpu(ctrl->wValue);
 	u16			w_value = le16_to_cpu(ctrl->wValue);
 	u16			w_length = le16_to_cpu(ctrl->wLength);
 	u16			w_length = le16_to_cpu(ctrl->wLength);
 
 
+	req->length = USB_BUFSIZ;
+
 	/* composite driver infrastructure handles everything except
 	/* composite driver infrastructure handles everything except
 	 * the two control test requests.
 	 * the two control test requests.
 	 */
 	 */

+ 71 - 24
drivers/usb/gadget/f_subset.c

@@ -57,18 +57,10 @@
  * caring about specific product and vendor IDs.
  * caring about specific product and vendor IDs.
  */
  */
 
 
-struct geth_descs {
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-};
-
 struct f_gether {
 struct f_gether {
 	struct gether			port;
 	struct gether			port;
 
 
 	char				ethaddr[14];
 	char				ethaddr[14];
-
-	struct geth_descs		fs;
-	struct geth_descs		hs;
 };
 };
 
 
 static inline struct f_gether *func_to_geth(struct usb_function *f)
 static inline struct f_gether *func_to_geth(struct usb_function *f)
@@ -209,6 +201,46 @@ static struct usb_descriptor_header *hs_eth_function[] __initdata = {
 	NULL,
 	NULL,
 };
 };
 
 
+/* super speed support: */
+
+static struct usb_endpoint_descriptor ss_subset_in_desc __initdata = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_endpoint_descriptor ss_subset_out_desc __initdata = {
+	.bLength =		USB_DT_ENDPOINT_SIZE,
+	.bDescriptorType =	USB_DT_ENDPOINT,
+
+	.bmAttributes =		USB_ENDPOINT_XFER_BULK,
+	.wMaxPacketSize =	cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor ss_subset_bulk_comp_desc __initdata = {
+	.bLength =		sizeof ss_subset_bulk_comp_desc,
+	.bDescriptorType =	USB_DT_SS_ENDPOINT_COMP,
+
+	/* the following 2 values can be tweaked if necessary */
+	/* .bMaxBurst =		0, */
+	/* .bmAttributes =	0, */
+};
+
+static struct usb_descriptor_header *ss_eth_function[] __initdata = {
+	(struct usb_descriptor_header *) &subset_data_intf,
+	(struct usb_descriptor_header *) &mdlm_header_desc,
+	(struct usb_descriptor_header *) &mdlm_desc,
+	(struct usb_descriptor_header *) &mdlm_detail_desc,
+	(struct usb_descriptor_header *) &ether_desc,
+	(struct usb_descriptor_header *) &ss_subset_in_desc,
+	(struct usb_descriptor_header *) &ss_subset_bulk_comp_desc,
+	(struct usb_descriptor_header *) &ss_subset_out_desc,
+	(struct usb_descriptor_header *) &ss_subset_bulk_comp_desc,
+	NULL,
+};
+
 /* string descriptors: */
 /* string descriptors: */
 
 
 static struct usb_string geth_string_defs[] = {
 static struct usb_string geth_string_defs[] = {
@@ -243,10 +275,12 @@ static int geth_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
 	}
 	}
 
 
 	DBG(cdev, "init + activate cdc subset\n");
 	DBG(cdev, "init + activate cdc subset\n");
-	geth->port.in = ep_choose(cdev->gadget,
-			geth->hs.in, geth->fs.in);
-	geth->port.out = ep_choose(cdev->gadget,
-			geth->hs.out, geth->fs.out);
+	if (config_ep_by_speed(cdev->gadget, f, geth->port.in_ep) ||
+	    config_ep_by_speed(cdev->gadget, f, geth->port.out_ep)) {
+		geth->port.in_ep->desc = NULL;
+		geth->port.out_ep->desc = NULL;
+		return -EINVAL;
+	}
 
 
 	net = gether_connect(&geth->port);
 	net = gether_connect(&geth->port);
 	return IS_ERR(net) ? PTR_ERR(net) : 0;
 	return IS_ERR(net) ? PTR_ERR(net) : 0;
@@ -296,12 +330,8 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
 
 
 	/* copy descriptors, and track endpoint copies */
 	/* copy descriptors, and track endpoint copies */
 	f->descriptors = usb_copy_descriptors(fs_eth_function);
 	f->descriptors = usb_copy_descriptors(fs_eth_function);
-
-	geth->fs.in = usb_find_endpoint(fs_eth_function,
-			f->descriptors, &fs_subset_in_desc);
-	geth->fs.out = usb_find_endpoint(fs_eth_function,
-			f->descriptors, &fs_subset_out_desc);
-
+	if (!f->descriptors)
+		goto fail;
 
 
 	/* support all relevant hardware speeds... we expect that when
 	/* support all relevant hardware speeds... we expect that when
 	 * hardware is dual speed, all bulk-capable endpoints work at
 	 * hardware is dual speed, all bulk-capable endpoints work at
@@ -315,11 +345,20 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
 
 
 		/* copy descriptors, and track endpoint copies */
 		/* copy descriptors, and track endpoint copies */
 		f->hs_descriptors = usb_copy_descriptors(hs_eth_function);
 		f->hs_descriptors = usb_copy_descriptors(hs_eth_function);
+		if (!f->hs_descriptors)
+			goto fail;
+	}
 
 
-		geth->hs.in = usb_find_endpoint(hs_eth_function,
-				f->hs_descriptors, &hs_subset_in_desc);
-		geth->hs.out = usb_find_endpoint(hs_eth_function,
-				f->hs_descriptors, &hs_subset_out_desc);
+	if (gadget_is_superspeed(c->cdev->gadget)) {
+		ss_subset_in_desc.bEndpointAddress =
+				fs_subset_in_desc.bEndpointAddress;
+		ss_subset_out_desc.bEndpointAddress =
+				fs_subset_out_desc.bEndpointAddress;
+
+		/* copy descriptors, and track endpoint copies */
+		f->ss_descriptors = usb_copy_descriptors(ss_eth_function);
+		if (!f->ss_descriptors)
+			goto fail;
 	}
 	}
 
 
 	/* NOTE:  all that is done without knowing or caring about
 	/* NOTE:  all that is done without knowing or caring about
@@ -328,15 +367,21 @@ geth_bind(struct usb_configuration *c, struct usb_function *f)
 	 */
 	 */
 
 
 	DBG(cdev, "CDC Subset: %s speed IN/%s OUT/%s\n",
 	DBG(cdev, "CDC Subset: %s speed IN/%s OUT/%s\n",
+			gadget_is_superspeed(c->cdev->gadget) ? "super" :
 			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
 			gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
 			geth->port.in_ep->name, geth->port.out_ep->name);
 			geth->port.in_ep->name, geth->port.out_ep->name);
 	return 0;
 	return 0;
 
 
 fail:
 fail:
+	if (f->descriptors)
+		usb_free_descriptors(f->descriptors);
+	if (f->hs_descriptors)
+		usb_free_descriptors(f->hs_descriptors);
+
 	/* we might as well release our claims on endpoints */
 	/* we might as well release our claims on endpoints */
-	if (geth->port.out)
+	if (geth->port.out_ep->desc)
 		geth->port.out_ep->driver_data = NULL;
 		geth->port.out_ep->driver_data = NULL;
-	if (geth->port.in)
+	if (geth->port.in_ep->desc)
 		geth->port.in_ep->driver_data = NULL;
 		geth->port.in_ep->driver_data = NULL;
 
 
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
 	ERROR(cdev, "%s: can't bind, err %d\n", f->name, status);
@@ -347,6 +392,8 @@ fail:
 static void
 static void
 geth_unbind(struct usb_configuration *c, struct usb_function *f)
 geth_unbind(struct usb_configuration *c, struct usb_function *f)
 {
 {
+	if (gadget_is_superspeed(c->cdev->gadget))
+		usb_free_descriptors(f->ss_descriptors);
 	if (gadget_is_dualspeed(c->cdev->gadget))
 	if (gadget_is_dualspeed(c->cdev->gadget))
 		usb_free_descriptors(f->hs_descriptors);
 		usb_free_descriptors(f->hs_descriptors);
 	usb_free_descriptors(f->descriptors);
 	usb_free_descriptors(f->descriptors);

+ 5 - 3
drivers/usb/gadget/f_uvc.c

@@ -262,8 +262,10 @@ uvc_function_set_alt(struct usb_function *f, unsigned interface, unsigned alt)
 		if (uvc->state != UVC_STATE_CONNECTED)
 		if (uvc->state != UVC_STATE_CONNECTED)
 			return 0;
 			return 0;
 
 
-		if (uvc->video.ep)
-			usb_ep_enable(uvc->video.ep, &uvc_streaming_ep);
+		if (uvc->video.ep) {
+			uvc->video.ep->desc = &uvc_streaming_ep;
+			usb_ep_enable(uvc->video.ep);
+		}
 
 
 		memset(&v4l2_event, 0, sizeof(v4l2_event));
 		memset(&v4l2_event, 0, sizeof(v4l2_event));
 		v4l2_event.type = UVC_EVENT_STREAMON;
 		v4l2_event.type = UVC_EVENT_STREAMON;
@@ -649,7 +651,7 @@ uvc_bind_config(struct usb_configuration *c,
 	if (ret)
 	if (ret)
 		kfree(uvc);
 		kfree(uvc);
 
 
-	return 0;
+	return ret;
 
 
 error:
 error:
 	kfree(uvc);
 	kfree(uvc);

+ 10 - 5
drivers/usb/gadget/file_storage.c

@@ -929,6 +929,7 @@ static int standard_setup_req(struct fsg_dev *fsg,
 
 
 		case USB_DT_DEVICE:
 		case USB_DT_DEVICE:
 			VDBG(fsg, "get device descriptor\n");
 			VDBG(fsg, "get device descriptor\n");
+			device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
 			value = sizeof device_desc;
 			value = sizeof device_desc;
 			memcpy(req->buf, &device_desc, value);
 			memcpy(req->buf, &device_desc, value);
 			break;
 			break;
@@ -936,6 +937,11 @@ static int standard_setup_req(struct fsg_dev *fsg,
 			VDBG(fsg, "get device qualifier\n");
 			VDBG(fsg, "get device qualifier\n");
 			if (!gadget_is_dualspeed(fsg->gadget))
 			if (!gadget_is_dualspeed(fsg->gadget))
 				break;
 				break;
+			/*
+			 * Assume ep0 uses the same maxpacket value for both
+			 * speeds
+			 */
+			dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
 			value = sizeof dev_qualifier;
 			value = sizeof dev_qualifier;
 			memcpy(req->buf, &dev_qualifier, value);
 			memcpy(req->buf, &dev_qualifier, value);
 			break;
 			break;
@@ -2713,7 +2719,8 @@ static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep,
 	int	rc;
 	int	rc;
 
 
 	ep->driver_data = fsg;
 	ep->driver_data = fsg;
-	rc = usb_ep_enable(ep, d);
+	ep->desc = d;
+	rc = usb_ep_enable(ep);
 	if (rc)
 	if (rc)
 		ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc);
 		ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc);
 	return rc;
 	return rc;
@@ -3416,7 +3423,6 @@ static int __init fsg_bind(struct usb_gadget *gadget)
 	}
 	}
 
 
 	/* Fix up the descriptors */
 	/* Fix up the descriptors */
-	device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket;
 	device_desc.idVendor = cpu_to_le16(mod_data.vendor);
 	device_desc.idVendor = cpu_to_le16(mod_data.vendor);
 	device_desc.idProduct = cpu_to_le16(mod_data.product);
 	device_desc.idProduct = cpu_to_le16(mod_data.product);
 	device_desc.bcdDevice = cpu_to_le16(mod_data.release);
 	device_desc.bcdDevice = cpu_to_le16(mod_data.release);
@@ -3430,9 +3436,6 @@ static int __init fsg_bind(struct usb_gadget *gadget)
 	if (gadget_is_dualspeed(gadget)) {
 	if (gadget_is_dualspeed(gadget)) {
 		fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
 		fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL;
 
 
-		/* Assume ep0 uses the same maxpacket value for both speeds */
-		dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket;
-
 		/* Assume endpoint addresses are the same for both speeds */
 		/* Assume endpoint addresses are the same for both speeds */
 		fsg_hs_bulk_in_desc.bEndpointAddress =
 		fsg_hs_bulk_in_desc.bEndpointAddress =
 			fsg_fs_bulk_in_desc.bEndpointAddress;
 			fsg_fs_bulk_in_desc.bEndpointAddress;
@@ -3486,6 +3489,8 @@ static int __init fsg_bind(struct usb_gadget *gadget)
 	}
 	}
 
 
 	INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
 	INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n");
+	INFO(fsg, "NOTE: This driver is deprecated.  "
+			"Consider using g_mass_storage instead.\n");
 	INFO(fsg, "Number of LUNs=%d\n", fsg->nluns);
 	INFO(fsg, "Number of LUNs=%d\n", fsg->nluns);
 
 
 	pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);
 	pathbuf = kmalloc(PATH_MAX, GFP_KERNEL);

+ 16 - 4
drivers/usb/gadget/fsl_qe_udc.c

@@ -1927,6 +1927,10 @@ static int qe_pullup(struct usb_gadget *gadget, int is_on)
 	return -ENOTSUPP;
 	return -ENOTSUPP;
 }
 }
 
 
+static int fsl_qe_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int fsl_qe_stop(struct usb_gadget_driver *driver);
+
 /* defined in usb_gadget.h */
 /* defined in usb_gadget.h */
 static struct usb_gadget_ops qe_gadget_ops = {
 static struct usb_gadget_ops qe_gadget_ops = {
 	.get_frame = qe_get_frame,
 	.get_frame = qe_get_frame,
@@ -1935,6 +1939,8 @@ static struct usb_gadget_ops qe_gadget_ops = {
 	.vbus_session = qe_vbus_session,
 	.vbus_session = qe_vbus_session,
 	.vbus_draw = qe_vbus_draw,
 	.vbus_draw = qe_vbus_draw,
 	.pullup = qe_pullup,
 	.pullup = qe_pullup,
+	.start = fsl_qe_start,
+	.stop = fsl_qe_stop,
 };
 };
 
 
 /*-------------------------------------------------------------------------
 /*-------------------------------------------------------------------------
@@ -2320,7 +2326,7 @@ static irqreturn_t qe_udc_irq(int irq, void *_udc)
 /*-------------------------------------------------------------------------
 /*-------------------------------------------------------------------------
 	Gadget driver probe and unregister.
 	Gadget driver probe and unregister.
  --------------------------------------------------------------------------*/
  --------------------------------------------------------------------------*/
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int fsl_qe_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 		int (*bind)(struct usb_gadget *))
 {
 {
 	int retval;
 	int retval;
@@ -2369,9 +2375,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 		udc_controller->gadget.name, driver->driver.name);
 		udc_controller->gadget.name, driver->driver.name);
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int fsl_qe_stop(struct usb_gadget_driver *driver)
 {
 {
 	struct qe_ep *loop_ep;
 	struct qe_ep *loop_ep;
 	unsigned long flags;
 	unsigned long flags;
@@ -2411,7 +2416,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 			driver->driver.name);
 			driver->driver.name);
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 
 /* udc structure's alloc and setup, include ep-param alloc */
 /* udc structure's alloc and setup, include ep-param alloc */
 static struct qe_udc __devinit *qe_udc_config(struct platform_device *ofdev)
 static struct qe_udc __devinit *qe_udc_config(struct platform_device *ofdev)
@@ -2662,11 +2666,17 @@ static int __devinit qe_udc_probe(struct platform_device *ofdev)
 	if (ret)
 	if (ret)
 		goto err6;
 		goto err6;
 
 
+	ret = usb_add_gadget_udc(&ofdev->dev, &udc_controller->gadget);
+	if (ret)
+		goto err7;
+
 	dev_info(udc_controller->dev,
 	dev_info(udc_controller->dev,
 			"%s USB controller initialized as device\n",
 			"%s USB controller initialized as device\n",
 			(udc_controller->soc_type == PORT_QE) ? "QE" : "CPM");
 			(udc_controller->soc_type == PORT_QE) ? "QE" : "CPM");
 	return 0;
 	return 0;
 
 
+err7:
+	device_unregister(&udc_controller->gadget.dev);
 err6:
 err6:
 	free_irq(udc_controller->usb_irq, udc_controller);
 	free_irq(udc_controller->usb_irq, udc_controller);
 err5:
 err5:
@@ -2721,6 +2731,8 @@ static int __devexit qe_udc_remove(struct platform_device *ofdev)
 	if (!udc_controller)
 	if (!udc_controller)
 		return -ENODEV;
 		return -ENODEV;
 
 
+	usb_del_gadget_udc(&udc_controller->gadget);
+
 	udc_controller->done = &done;
 	udc_controller->done = &done;
 	tasklet_disable(&udc_controller->rx_tasklet);
 	tasklet_disable(&udc_controller->rx_tasklet);
 
 

+ 16 - 4
drivers/usb/gadget/fsl_udc_core.c

@@ -1244,6 +1244,9 @@ static int fsl_pullup(struct usb_gadget *gadget, int is_on)
 	return 0;
 	return 0;
 }
 }
 
 
+static int fsl_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int fsl_stop(struct usb_gadget_driver *driver);
 /* defined in gadget.h */
 /* defined in gadget.h */
 static struct usb_gadget_ops fsl_gadget_ops = {
 static struct usb_gadget_ops fsl_gadget_ops = {
 	.get_frame = fsl_get_frame,
 	.get_frame = fsl_get_frame,
@@ -1252,6 +1255,8 @@ static struct usb_gadget_ops fsl_gadget_ops = {
 	.vbus_session = fsl_vbus_session,
 	.vbus_session = fsl_vbus_session,
 	.vbus_draw = fsl_vbus_draw,
 	.vbus_draw = fsl_vbus_draw,
 	.pullup = fsl_pullup,
 	.pullup = fsl_pullup,
+	.start = fsl_start,
+	.stop = fsl_stop,
 };
 };
 
 
 /* Set protocol stall on ep0, protocol stall will automatically be cleared
 /* Set protocol stall on ep0, protocol stall will automatically be cleared
@@ -1927,7 +1932,7 @@ static irqreturn_t fsl_udc_irq(int irq, void *_udc)
  * Hook to gadget drivers
  * Hook to gadget drivers
  * Called by initialization code of gadget drivers
  * Called by initialization code of gadget drivers
 *----------------------------------------------------------------*/
 *----------------------------------------------------------------*/
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int fsl_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 		int (*bind)(struct usb_gadget *))
 {
 {
 	int retval = -ENODEV;
 	int retval = -ENODEV;
@@ -1995,10 +2000,9 @@ out:
 		       retval);
 		       retval);
 	return retval;
 	return retval;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 
 /* Disconnect from gadget driver */
 /* Disconnect from gadget driver */
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int fsl_stop(struct usb_gadget_driver *driver)
 {
 {
 	struct fsl_ep *loop_ep;
 	struct fsl_ep *loop_ep;
 	unsigned long flags;
 	unsigned long flags;
@@ -2041,7 +2045,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 	       driver->driver.name);
 	       driver->driver.name);
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 
 /*-------------------------------------------------------------------------
 /*-------------------------------------------------------------------------
 		PROC File System Support
 		PROC File System Support
@@ -2590,9 +2593,16 @@ static int __init fsl_udc_probe(struct platform_device *pdev)
 		ret = -ENOMEM;
 		ret = -ENOMEM;
 		goto err_unregister;
 		goto err_unregister;
 	}
 	}
+
+	ret = usb_add_gadget_udc(&pdev->dev, &udc_controller->gadget);
+	if (ret)
+		goto err_del_udc;
+
 	create_proc_file();
 	create_proc_file();
 	return 0;
 	return 0;
 
 
+err_del_udc:
+	dma_pool_destroy(udc_controller->td_pool);
 err_unregister:
 err_unregister:
 	device_unregister(&udc_controller->gadget.dev);
 	device_unregister(&udc_controller->gadget.dev);
 err_free_irq:
 err_free_irq:
@@ -2624,6 +2634,8 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
 
 
 	if (!udc_controller)
 	if (!udc_controller)
 		return -ENODEV;
 		return -ENODEV;
+
+	usb_del_gadget_udc(&udc_controller->gadget);
 	udc_controller->done = &done;
 	udc_controller->done = &done;
 
 
 	fsl_udc_clk_release();
 	fsl_udc_clk_release();

+ 19 - 92
drivers/usb/gadget/fusb300_udc.c

@@ -767,56 +767,6 @@ static void fusb300_rdfifo(struct fusb300_ep *ep,
 	} while (!reg);
 	} while (!reg);
 }
 }
 
 
-/* write data to fifo */
-static void fusb300_wrfifo(struct fusb300_ep *ep,
-			   struct fusb300_request *req)
-{
-	int i = 0;
-	u8 *tmp;
-	u32 data, reg;
-	struct fusb300 *fusb300 = ep->fusb300;
-
-	tmp = req->req.buf;
-	req->req.actual = req->req.length;
-
-	for (i = (req->req.length >> 2); i > 0; i--) {
-		data = *tmp | *(tmp + 1) << 8 |
-			*(tmp + 2) << 16 | *(tmp + 3) << 24;
-
-		iowrite32(data, fusb300->reg +
-			FUSB300_OFFSET_EPPORT(ep->epnum));
-		tmp += 4;
-	}
-
-	switch (req->req.length % 4) {
-	case 1:
-		data = *tmp;
-		iowrite32(data, fusb300->reg +
-			FUSB300_OFFSET_EPPORT(ep->epnum));
-		break;
-	case 2:
-		data = *tmp | *(tmp + 1) << 8;
-		iowrite32(data, fusb300->reg +
-			FUSB300_OFFSET_EPPORT(ep->epnum));
-		break;
-	case 3:
-		data = *tmp | *(tmp + 1) << 8 | *(tmp + 2) << 16;
-		iowrite32(data, fusb300->reg +
-			FUSB300_OFFSET_EPPORT(ep->epnum));
-		break;
-	default:
-		break;
-	}
-
-	do {
-		reg = ioread32(fusb300->reg + FUSB300_OFFSET_IGR1);
-		reg &= FUSB300_IGR1_SYNF0_EMPTY_INT;
-		if (i)
-			printk(KERN_INFO"sync fifo is not empty!\n");
-		i++;
-	} while (!reg);
-}
-
 static u8 fusb300_get_epnstall(struct fusb300 *fusb300, u8 ep)
 static u8 fusb300_get_epnstall(struct fusb300 *fusb300, u8 ep)
 {
 {
 	u8 value;
 	u8 value;
@@ -980,11 +930,6 @@ static void set_address(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
 		} \
 		} \
 	} while (0)
 	} while (0)
 
 
-static void fusb300_ep0_complete(struct usb_ep *ep,
-				struct usb_request *req)
-{
-}
-
 static int setup_packet(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
 static int setup_packet(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
 {
 {
 	u8 *p = (u8 *)ctrl;
 	u8 *p = (u8 *)ctrl;
@@ -1029,17 +974,6 @@ static int setup_packet(struct fusb300 *fusb300, struct usb_ctrlrequest *ctrl)
 	return ret;
 	return ret;
 }
 }
 
 
-static void fusb300_set_ep_bycnt(struct fusb300_ep *ep, u32 bycnt)
-{
-	struct fusb300 *fusb300 = ep->fusb300;
-	u32 reg = ioread32(fusb300->reg + FUSB300_OFFSET_EPFFR(ep->epnum));
-
-	reg &= ~FUSB300_FFR_BYCNT;
-	reg |= bycnt & FUSB300_FFR_BYCNT;
-
-	iowrite32(reg, fusb300->reg + FUSB300_OFFSET_EPFFR(ep->epnum));
-}
-
 static void done(struct fusb300_ep *ep, struct fusb300_request *req,
 static void done(struct fusb300_ep *ep, struct fusb300_request *req,
 		 int status)
 		 int status)
 {
 {
@@ -1063,8 +997,8 @@ static void done(struct fusb300_ep *ep, struct fusb300_request *req,
 		fusb300_set_cxdone(ep->fusb300);
 		fusb300_set_cxdone(ep->fusb300);
 }
 }
 
 
-void fusb300_fill_idma_prdtbl(struct fusb300_ep *ep,
-			struct fusb300_request *req)
+static void fusb300_fill_idma_prdtbl(struct fusb300_ep *ep, dma_addr_t d,
+		u32 len)
 {
 {
 	u32 value;
 	u32 value;
 	u32 reg;
 	u32 reg;
@@ -1076,10 +1010,9 @@ void fusb300_fill_idma_prdtbl(struct fusb300_ep *ep,
 		reg &= FUSB300_EPPRD0_H;
 		reg &= FUSB300_EPPRD0_H;
 	} while (reg);
 	} while (reg);
 
 
-	iowrite32((u32) req->req.buf, ep->fusb300->reg +
-		FUSB300_OFFSET_EPPRD_W1(ep->epnum));
+	iowrite32(d, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W1(ep->epnum));
 
 
-	value = FUSB300_EPPRD0_BTC(req->req.length) | FUSB300_EPPRD0_H |
+	value = FUSB300_EPPRD0_BTC(len) | FUSB300_EPPRD0_H |
 		FUSB300_EPPRD0_F | FUSB300_EPPRD0_L | FUSB300_EPPRD0_I;
 		FUSB300_EPPRD0_F | FUSB300_EPPRD0_L | FUSB300_EPPRD0_I;
 	iowrite32(value, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W0(ep->epnum));
 	iowrite32(value, ep->fusb300->reg + FUSB300_OFFSET_EPPRD_W0(ep->epnum));
 
 
@@ -1116,13 +1049,12 @@ static void  fusb300_set_idma(struct fusb300_ep *ep,
 			struct fusb300_request *req)
 			struct fusb300_request *req)
 {
 {
 	dma_addr_t d;
 	dma_addr_t d;
-	u8 *tmp = NULL;
 
 
 	d = dma_map_single(NULL, req->req.buf, req->req.length, DMA_TO_DEVICE);
 	d = dma_map_single(NULL, req->req.buf, req->req.length, DMA_TO_DEVICE);
 
 
 	if (dma_mapping_error(NULL, d)) {
 	if (dma_mapping_error(NULL, d)) {
-		kfree(req->req.buf);
 		printk(KERN_DEBUG "dma_mapping_error\n");
 		printk(KERN_DEBUG "dma_mapping_error\n");
+		return;
 	}
 	}
 
 
 	dma_sync_single_for_device(NULL, d, req->req.length, DMA_TO_DEVICE);
 	dma_sync_single_for_device(NULL, d, req->req.length, DMA_TO_DEVICE);
@@ -1130,17 +1062,11 @@ static void  fusb300_set_idma(struct fusb300_ep *ep,
 	fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER0,
 	fusb300_enable_bit(ep->fusb300, FUSB300_OFFSET_IGER0,
 		FUSB300_IGER0_EEPn_PRD_INT(ep->epnum));
 		FUSB300_IGER0_EEPn_PRD_INT(ep->epnum));
 
 
-	tmp = req->req.buf;
-	req->req.buf = (u8 *)d;
-
-	fusb300_fill_idma_prdtbl(ep, req);
+	fusb300_fill_idma_prdtbl(ep, d, req->req.length);
 	/* check idma is done */
 	/* check idma is done */
 	fusb300_wait_idma_finished(ep);
 	fusb300_wait_idma_finished(ep);
 
 
-	req->req.buf = tmp;
-
-	if (d)
-		dma_unmap_single(NULL, d, req->req.length, DMA_TO_DEVICE);
+	dma_unmap_single(NULL, d, req->req.length, DMA_TO_DEVICE);
 }
 }
 
 
 static void in_ep_fifo_handler(struct fusb300_ep *ep)
 static void in_ep_fifo_handler(struct fusb300_ep *ep)
@@ -1148,14 +1074,8 @@ static void in_ep_fifo_handler(struct fusb300_ep *ep)
 	struct fusb300_request *req = list_entry(ep->queue.next,
 	struct fusb300_request *req = list_entry(ep->queue.next,
 					struct fusb300_request, queue);
 					struct fusb300_request, queue);
 
 
-	if (req->req.length) {
-#if 0
-		fusb300_set_ep_bycnt(ep, req->req.length);
-		fusb300_wrfifo(ep, req);
-#else
+	if (req->req.length)
 		fusb300_set_idma(ep, req);
 		fusb300_set_idma(ep, req);
-#endif
-	}
 	done(ep, req, 0);
 	done(ep, req, 0);
 }
 }
 
 
@@ -1500,7 +1420,7 @@ static void init_controller(struct fusb300 *fusb300)
 /*------------------------------------------------------------------------*/
 /*------------------------------------------------------------------------*/
 static struct fusb300 *the_controller;
 static struct fusb300 *the_controller;
 
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int fusb300_udc_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 		int (*bind)(struct usb_gadget *))
 {
 {
 	struct fusb300 *fusb300 = the_controller;
 	struct fusb300 *fusb300 = the_controller;
@@ -1544,9 +1464,8 @@ error:
 
 
 	return retval;
 	return retval;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int fusb300_udc_stop(struct usb_gadget_driver *driver)
 {
 {
 	struct fusb300 *fusb300 = the_controller;
 	struct fusb300 *fusb300 = the_controller;
 
 
@@ -1562,7 +1481,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 
 
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 /*--------------------------------------------------------------------------*/
 /*--------------------------------------------------------------------------*/
 
 
 static int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active)
 static int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active)
@@ -1572,12 +1490,15 @@ static int fusb300_udc_pullup(struct usb_gadget *_gadget, int is_active)
 
 
 static struct usb_gadget_ops fusb300_gadget_ops = {
 static struct usb_gadget_ops fusb300_gadget_ops = {
 	.pullup		= fusb300_udc_pullup,
 	.pullup		= fusb300_udc_pullup,
+	.start		= fusb300_udc_start,
+	.stop		= fusb300_udc_stop,
 };
 };
 
 
 static int __exit fusb300_remove(struct platform_device *pdev)
 static int __exit fusb300_remove(struct platform_device *pdev)
 {
 {
 	struct fusb300 *fusb300 = dev_get_drvdata(&pdev->dev);
 	struct fusb300 *fusb300 = dev_get_drvdata(&pdev->dev);
 
 
+	usb_del_gadget_udc(&fusb300->gadget);
 	iounmap(fusb300->reg);
 	iounmap(fusb300->reg);
 	free_irq(platform_get_irq(pdev, 0), fusb300);
 	free_irq(platform_get_irq(pdev, 0), fusb300);
 
 
@@ -1702,9 +1623,15 @@ static int __init fusb300_probe(struct platform_device *pdev)
 		goto clean_up3;
 		goto clean_up3;
 
 
 	init_controller(fusb300);
 	init_controller(fusb300);
+	ret = usb_add_gadget_udc(&pdev->dev, &fusb300->gadget);
+	if (ret)
+		goto err_add_udc;
+
 	dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
 	dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
 
 
 	return 0;
 	return 0;
+err_add_udc:
+	fusb300_free_request(&fusb300->ep[0]->ep, fusb300->ep0_req);
 
 
 clean_up3:
 clean_up3:
 	free_irq(ires->start, fusb300);
 	free_irq(ires->start, fusb300);

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

@@ -162,6 +162,7 @@ static struct usb_composite_driver gfs_driver = {
 	.name		= DRIVER_NAME,
 	.name		= DRIVER_NAME,
 	.dev		= &gfs_dev_desc,
 	.dev		= &gfs_dev_desc,
 	.strings	= gfs_dev_strings,
 	.strings	= gfs_dev_strings,
+	.max_speed	= USB_SPEED_HIGH,
 	.unbind		= gfs_unbind,
 	.unbind		= gfs_unbind,
 	.iProduct	= DRIVER_DESC,
 	.iProduct	= DRIVER_DESC,
 };
 };

+ 35 - 143
drivers/usb/gadget/gadget_chips.h

@@ -15,150 +15,40 @@
 #ifndef __GADGET_CHIPS_H
 #ifndef __GADGET_CHIPS_H
 #define __GADGET_CHIPS_H
 #define __GADGET_CHIPS_H
 
 
-#ifdef CONFIG_USB_GADGET_NET2280
-#define	gadget_is_net2280(g)	!strcmp("net2280", (g)->name)
-#else
-#define	gadget_is_net2280(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_AMD5536UDC
-#define	gadget_is_amd5536udc(g)	!strcmp("amd5536udc", (g)->name)
-#else
-#define	gadget_is_amd5536udc(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_DUMMY_HCD
-#define	gadget_is_dummy(g)	!strcmp("dummy_udc", (g)->name)
-#else
-#define	gadget_is_dummy(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_PXA25X
-#define	gadget_is_pxa(g)	!strcmp("pxa25x_udc", (g)->name)
-#else
-#define	gadget_is_pxa(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_GOKU
-#define	gadget_is_goku(g)	!strcmp("goku_udc", (g)->name)
-#else
-#define	gadget_is_goku(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_OMAP
-#define	gadget_is_omap(g)	!strcmp("omap_udc", (g)->name)
-#else
-#define	gadget_is_omap(g)	0
-#endif
-
-/* various unstable versions available */
-#ifdef CONFIG_USB_GADGET_PXA27X
-#define	gadget_is_pxa27x(g)	!strcmp("pxa27x_udc", (g)->name)
-#else
-#define	gadget_is_pxa27x(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_ATMEL_USBA
-#define gadget_is_atmel_usba(g)	!strcmp("atmel_usba_udc", (g)->name)
-#else
-#define gadget_is_atmel_usba(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_S3C2410
-#define gadget_is_s3c2410(g)    !strcmp("s3c2410_udc", (g)->name)
-#else
-#define gadget_is_s3c2410(g)    0
-#endif
-
-#ifdef CONFIG_USB_GADGET_AT91
-#define gadget_is_at91(g)	!strcmp("at91_udc", (g)->name)
-#else
-#define gadget_is_at91(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_IMX
-#define gadget_is_imx(g)	!strcmp("imx_udc", (g)->name)
-#else
-#define gadget_is_imx(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_FSL_USB2
-#define gadget_is_fsl_usb2(g)	!strcmp("fsl-usb2-udc", (g)->name)
-#else
-#define gadget_is_fsl_usb2(g)	0
-#endif
-
-/* Mentor high speed "dual role" controller, in peripheral role */
-#ifdef CONFIG_USB_GADGET_MUSB_HDRC
-#define gadget_is_musbhdrc(g)	!strcmp("musb-hdrc", (g)->name)
-#else
-#define gadget_is_musbhdrc(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_LANGWELL
-#define gadget_is_langwell(g)	(!strcmp("langwell_udc", (g)->name))
-#else
-#define gadget_is_langwell(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_M66592
-#define	gadget_is_m66592(g)	!strcmp("m66592_udc", (g)->name)
-#else
-#define	gadget_is_m66592(g)	0
-#endif
-
-/* Freescale CPM/QE UDC SUPPORT */
-#ifdef CONFIG_USB_GADGET_FSL_QE
-#define gadget_is_fsl_qe(g)	!strcmp("fsl_qe_udc", (g)->name)
-#else
-#define gadget_is_fsl_qe(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_CI13XXX_PCI
-#define gadget_is_ci13xxx_pci(g)	(!strcmp("ci13xxx_pci", (g)->name))
-#else
-#define gadget_is_ci13xxx_pci(g)	0
-#endif
-
-// CONFIG_USB_GADGET_SX2
-// CONFIG_USB_GADGET_AU1X00
-// ...
-
-#ifdef CONFIG_USB_GADGET_R8A66597
-#define	gadget_is_r8a66597(g)	!strcmp("r8a66597_udc", (g)->name)
-#else
-#define	gadget_is_r8a66597(g)	0
-#endif
-
-#ifdef CONFIG_USB_S3C_HSOTG
-#define gadget_is_s3c_hsotg(g)    (!strcmp("s3c-hsotg", (g)->name))
-#else
-#define gadget_is_s3c_hsotg(g)    0
-#endif
-
-#ifdef CONFIG_USB_S3C_HSUDC
-#define gadget_is_s3c_hsudc(g) (!strcmp("s3c-hsudc", (g)->name))
-#else
-#define gadget_is_s3c_hsudc(g) 0
-#endif
-
-#ifdef CONFIG_USB_GADGET_EG20T
-#define	gadget_is_pch(g)	(!strcmp("pch_udc", (g)->name))
-#else
-#define	gadget_is_pch(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_CI13XXX_MSM
+/*
+ * NOTICE: the entries below are alphabetical and should be kept
+ * that way.
+ *
+ * Always be sure to add new entries to the correct position or
+ * accept the bashing later.
+ *
+ * If you have forgotten the alphabetical order let VIM/EMACS
+ * do that for you.
+ */
+#define gadget_is_amd5536udc(g)		(!strcmp("amd5536udc", (g)->name))
+#define gadget_is_at91(g)		(!strcmp("at91_udc", (g)->name))
+#define gadget_is_atmel_usba(g)		(!strcmp("atmel_usba_udc", (g)->name))
 #define gadget_is_ci13xxx_msm(g)	(!strcmp("ci13xxx_msm", (g)->name))
 #define gadget_is_ci13xxx_msm(g)	(!strcmp("ci13xxx_msm", (g)->name))
-#else
-#define gadget_is_ci13xxx_msm(g)	0
-#endif
-
-#ifdef CONFIG_USB_GADGET_RENESAS_USBHS
-#define	gadget_is_renesas_usbhs(g) (!strcmp("renesas_usbhs_udc", (g)->name))
-#else
-#define	gadget_is_renesas_usbhs(g) 0
-#endif
+#define gadget_is_ci13xxx_pci(g)	(!strcmp("ci13xxx_pci", (g)->name))
+#define gadget_is_dummy(g)		(!strcmp("dummy_udc", (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))
+#define gadget_is_imx(g)		(!strcmp("imx_udc", (g)->name))
+#define gadget_is_langwell(g)		(!strcmp("langwell_udc", (g)->name))
+#define gadget_is_m66592(g)		(!strcmp("m66592_udc", (g)->name))
+#define gadget_is_musbhdrc(g)		(!strcmp("musb-hdrc", (g)->name))
+#define gadget_is_net2272(g)		(!strcmp("net2272", (g)->name))
+#define gadget_is_net2280(g)		(!strcmp("net2280", (g)->name))
+#define gadget_is_omap(g)		(!strcmp("omap_udc", (g)->name))
+#define gadget_is_pch(g)		(!strcmp("pch_udc", (g)->name))
+#define gadget_is_pxa(g)		(!strcmp("pxa25x_udc", (g)->name))
+#define gadget_is_pxa27x(g)		(!strcmp("pxa27x_udc", (g)->name))
+#define gadget_is_r8a66597(g)		(!strcmp("r8a66597_udc", (g)->name))
+#define gadget_is_renesas_usbhs(g)	(!strcmp("renesas_usbhs_udc", (g)->name))
+#define gadget_is_s3c2410(g)		(!strcmp("s3c2410_udc", (g)->name))
+#define gadget_is_s3c_hsotg(g)		(!strcmp("s3c-hsotg", (g)->name))
+#define gadget_is_s3c_hsudc(g)		(!strcmp("s3c-hsudc", (g)->name))
 
 
 /**
 /**
  * usb_gadget_controller_number - support bcdDevice id convention
  * usb_gadget_controller_number - support bcdDevice id convention
@@ -223,6 +113,8 @@ static inline int usb_gadget_controller_number(struct usb_gadget *gadget)
 		return 0x29;
 		return 0x29;
 	else if (gadget_is_s3c_hsudc(gadget))
 	else if (gadget_is_s3c_hsudc(gadget))
 		return 0x30;
 		return 0x30;
+	else if (gadget_is_net2272(gadget))
+		return 0x31;
 
 
 	return -ENOENT;
 	return -ENOENT;
 }
 }

+ 5 - 4
drivers/usb/gadget/gmidi.c

@@ -537,14 +537,16 @@ static int set_gmidi_config(struct gmidi_device *dev, gfp_t gfp_flags)
 	struct usb_ep *ep;
 	struct usb_ep *ep;
 	unsigned i;
 	unsigned i;
 
 
-	err = usb_ep_enable(dev->in_ep, &bulk_in_desc);
+	dev->in_ep->desc = &bulk_in_desc;
+	err = usb_ep_enable(dev->in_ep);
 	if (err) {
 	if (err) {
 		ERROR(dev, "can't start %s: %d\n", dev->in_ep->name, err);
 		ERROR(dev, "can't start %s: %d\n", dev->in_ep->name, err);
 		goto fail;
 		goto fail;
 	}
 	}
 	dev->in_ep->driver_data = dev;
 	dev->in_ep->driver_data = dev;
 
 
-	err = usb_ep_enable(dev->out_ep, &bulk_out_desc);
+	dev->out_ep->desc = &bulk_out_desc;
+	err = usb_ep_enable(dev->out_ep);
 	if (err) {
 	if (err) {
 		ERROR(dev, "can't start %s: %d\n", dev->out_ep->name, err);
 		ERROR(dev, "can't start %s: %d\n", dev->out_ep->name, err);
 		goto fail;
 		goto fail;
@@ -693,6 +695,7 @@ static int gmidi_setup(struct usb_gadget *gadget,
 		switch (w_value >> 8) {
 		switch (w_value >> 8) {
 
 
 		case USB_DT_DEVICE:
 		case USB_DT_DEVICE:
+			device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 			value = min(w_length, (u16) sizeof(device_desc));
 			value = min(w_length, (u16) sizeof(device_desc));
 			memcpy(req->buf, &device_desc, value);
 			memcpy(req->buf, &device_desc, value);
 			break;
 			break;
@@ -1247,8 +1250,6 @@ autoconf_fail:
 
 
 	dev->req->complete = gmidi_setup_complete;
 	dev->req->complete = gmidi_setup_complete;
 
 
-	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
-
 	gadget->ep0->driver_data = dev;
 	gadget->ep0->driver_data = dev;
 
 
 	INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname);
 	INFO(dev, "%s, version: " DRIVER_VERSION "\n", longname);

+ 14 - 5
drivers/usb/gadget/goku_udc.c

@@ -996,8 +996,14 @@ static int goku_get_frame(struct usb_gadget *_gadget)
 	return -EOPNOTSUPP;
 	return -EOPNOTSUPP;
 }
 }
 
 
+static int goku_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int goku_stop(struct usb_gadget_driver *driver);
+
 static const struct usb_gadget_ops goku_ops = {
 static const struct usb_gadget_ops goku_ops = {
 	.get_frame	= goku_get_frame,
 	.get_frame	= goku_get_frame,
+	.start		= goku_start,
+	.stop		= goku_stop,
 	// no remote wakeup
 	// no remote wakeup
 	// not selfpowered
 	// not selfpowered
 };
 };
@@ -1344,7 +1350,7 @@ static struct goku_udc	*the_controller;
  * disconnect is reported.  then a host may connect again, or
  * disconnect is reported.  then a host may connect again, or
  * the driver might get unbound.
  * the driver might get unbound.
  */
  */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int goku_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 		int (*bind)(struct usb_gadget *))
 {
 {
 	struct goku_udc	*dev = the_controller;
 	struct goku_udc	*dev = the_controller;
@@ -1382,7 +1388,6 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 	DBG(dev, "registered gadget driver '%s'\n", driver->driver.name);
 	DBG(dev, "registered gadget driver '%s'\n", driver->driver.name);
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 
 static void
 static void
 stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver)
 stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver)
@@ -1408,7 +1413,7 @@ stop_activity(struct goku_udc *dev, struct usb_gadget_driver *driver)
 		udc_enable(dev);
 		udc_enable(dev);
 }
 }
 
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int goku_stop(struct usb_gadget_driver *driver)
 {
 {
 	struct goku_udc	*dev = the_controller;
 	struct goku_udc	*dev = the_controller;
 	unsigned long	flags;
 	unsigned long	flags;
@@ -1429,8 +1434,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 	DBG(dev, "unregistered driver '%s'\n", driver->driver.name);
 	DBG(dev, "unregistered driver '%s'\n", driver->driver.name);
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
@@ -1730,6 +1733,8 @@ static void goku_remove(struct pci_dev *pdev)
 
 
 	DBG(dev, "%s\n", __func__);
 	DBG(dev, "%s\n", __func__);
 
 
+	usb_del_gadget_udc(&dev->gadget);
+
 	BUG_ON(dev->driver);
 	BUG_ON(dev->driver);
 
 
 #ifdef CONFIG_USB_GADGET_DEBUG_FILES
 #ifdef CONFIG_USB_GADGET_DEBUG_FILES
@@ -1854,6 +1859,10 @@ static int goku_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 		goto err;
 		goto err;
 	}
 	}
 	dev->registered = 1;
 	dev->registered = 1;
+	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+	if (retval)
+		goto err;
+
 	return 0;
 	return 0;
 
 
 err:
 err:

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

@@ -255,6 +255,7 @@ static struct usb_composite_driver hidg_driver = {
 	.name		= "g_hid",
 	.name		= "g_hid",
 	.dev		= &device_desc,
 	.dev		= &device_desc,
 	.strings	= dev_strings,
 	.strings	= dev_strings,
+	.max_speed	= USB_SPEED_HIGH,
 	.unbind		= __exit_p(hid_unbind),
 	.unbind		= __exit_p(hid_unbind),
 };
 };
 
 

+ 15 - 5
drivers/usb/gadget/imx_udc.c

@@ -1237,9 +1237,14 @@ irq_handler_t intr_handler(int i)
  *******************************************************************************
  *******************************************************************************
  */
  */
 
 
+static int imx_udc_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int imx_udc_stop(struct usb_gadget_driver *driver);
 static const struct usb_gadget_ops imx_udc_ops = {
 static const struct usb_gadget_ops imx_udc_ops = {
 	.get_frame	 = imx_udc_get_frame,
 	.get_frame	 = imx_udc_get_frame,
 	.wakeup		 = imx_udc_wakeup,
 	.wakeup		 = imx_udc_wakeup,
+	.start		= imx_udc_start,
+	.stop		= imx_udc_stop,
 };
 };
 
 
 static struct imx_udc_struct controller = {
 static struct imx_udc_struct controller = {
@@ -1324,7 +1329,7 @@ static struct imx_udc_struct controller = {
  * USB gadget driver functions
  * USB gadget driver functions
  *******************************************************************************
  *******************************************************************************
  */
  */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int imx_udc_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 		int (*bind)(struct usb_gadget *))
 {
 {
 	struct imx_udc_struct *imx_usb = &controller;
 	struct imx_udc_struct *imx_usb = &controller;
@@ -1368,9 +1373,8 @@ fail:
 	imx_usb->gadget.dev.driver = NULL;
 	imx_usb->gadget.dev.driver = NULL;
 	return retval;
 	return retval;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int imx_udc_stop(struct usb_gadget_driver *driver)
 {
 {
 	struct imx_udc_struct *imx_usb = &controller;
 	struct imx_udc_struct *imx_usb = &controller;
 
 
@@ -1394,7 +1398,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 
 
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 
 /*******************************************************************************
 /*******************************************************************************
  * Module functions
  * Module functions
@@ -1504,8 +1507,14 @@ static int __init imx_udc_probe(struct platform_device *pdev)
 	imx_usb->timer.function = handle_config;
 	imx_usb->timer.function = handle_config;
 	imx_usb->timer.data = (unsigned long)imx_usb;
 	imx_usb->timer.data = (unsigned long)imx_usb;
 
 
-	return 0;
+	ret = usb_add_gadget_udc(&pdev->dev, &imx_usb->gadget);
+	if (ret)
+		goto fail4;
 
 
+	return 0;
+fail4:
+	for (i = 0; i < IMX_USB_NB_EP + 1; i++)
+		free_irq(imx_usb->usbd_int[i], imx_usb);
 fail3:
 fail3:
 	clk_put(clk);
 	clk_put(clk);
 	clk_disable(clk);
 	clk_disable(clk);
@@ -1525,6 +1534,7 @@ static int __exit imx_udc_remove(struct platform_device *pdev)
 	struct imxusb_platform_data *pdata = pdev->dev.platform_data;
 	struct imxusb_platform_data *pdata = pdev->dev.platform_data;
 	int i;
 	int i;
 
 
+	usb_del_gadget_udc(&imx_usb->gadget);
 	imx_udc_disable(imx_usb);
 	imx_udc_disable(imx_usb);
 	del_timer(&imx_usb->timer);
 	del_timer(&imx_usb->timer);
 
 

+ 6 - 5
drivers/usb/gadget/inode.c

@@ -832,14 +832,16 @@ ep_config (struct file *fd, const char __user *buf, size_t len, loff_t *ptr)
 	switch (data->dev->gadget->speed) {
 	switch (data->dev->gadget->speed) {
 	case USB_SPEED_LOW:
 	case USB_SPEED_LOW:
 	case USB_SPEED_FULL:
 	case USB_SPEED_FULL:
-		value = usb_ep_enable (ep, &data->desc);
+		ep->desc = &data->desc;
+		value = usb_ep_enable(ep);
 		if (value == 0)
 		if (value == 0)
 			data->state = STATE_EP_ENABLED;
 			data->state = STATE_EP_ENABLED;
 		break;
 		break;
 #ifdef	CONFIG_USB_GADGET_DUALSPEED
 #ifdef	CONFIG_USB_GADGET_DUALSPEED
 	case USB_SPEED_HIGH:
 	case USB_SPEED_HIGH:
 		/* fails if caller didn't provide that descriptor... */
 		/* fails if caller didn't provide that descriptor... */
-		value = usb_ep_enable (ep, &data->hs_desc);
+		ep->desc = &data->hs_desc;
+		value = usb_ep_enable(ep);
 		if (value == 0)
 		if (value == 0)
 			data->state = STATE_EP_ENABLED;
 			data->state = STATE_EP_ENABLED;
 		break;
 		break;
@@ -1345,7 +1347,7 @@ static void make_qualifier (struct dev_data *dev)
 	qual.bDeviceProtocol = desc->bDeviceProtocol;
 	qual.bDeviceProtocol = desc->bDeviceProtocol;
 
 
 	/* assumes ep0 uses the same value for both speeds ... */
 	/* assumes ep0 uses the same value for both speeds ... */
-	qual.bMaxPacketSize0 = desc->bMaxPacketSize0;
+	qual.bMaxPacketSize0 = dev->gadget->ep0->maxpacket;
 
 
 	qual.bNumConfigurations = 1;
 	qual.bNumConfigurations = 1;
 	qual.bRESERVED = 0;
 	qual.bRESERVED = 0;
@@ -1402,7 +1404,6 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 		}
 		}
 
 
 		dev->state = STATE_DEV_CONNECTED;
 		dev->state = STATE_DEV_CONNECTED;
-		dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
 
 
 		INFO (dev, "connected\n");
 		INFO (dev, "connected\n");
 		event = next_event (dev, GADGETFS_CONNECT);
 		event = next_event (dev, GADGETFS_CONNECT);
@@ -1430,6 +1431,7 @@ gadgetfs_setup (struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 
 
 		case USB_DT_DEVICE:
 		case USB_DT_DEVICE:
 			value = min (w_length, (u16) sizeof *dev->dev);
 			value = min (w_length, (u16) sizeof *dev->dev);
+			dev->dev->bMaxPacketSize0 = dev->gadget->ep0->maxpacket;
 			req->buf = dev->dev;
 			req->buf = dev->dev;
 			break;
 			break;
 #ifdef	CONFIG_USB_GADGET_DUALSPEED
 #ifdef	CONFIG_USB_GADGET_DUALSPEED
@@ -1710,7 +1712,6 @@ gadgetfs_bind (struct usb_gadget *gadget)
 	set_gadget_data (gadget, dev);
 	set_gadget_data (gadget, dev);
 	dev->gadget = gadget;
 	dev->gadget = gadget;
 	gadget->ep0->driver_data = dev;
 	gadget->ep0->driver_data = dev;
-	dev->dev->bMaxPacketSize0 = gadget->ep0->maxpacket;
 
 
 	/* preallocate control response and buffer */
 	/* preallocate control response and buffer */
 	dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);
 	dev->req = usb_ep_alloc_request (gadget->ep0, GFP_KERNEL);

+ 19 - 13
drivers/usb/gadget/langwell_udc.c

@@ -593,8 +593,8 @@ static int queue_dtd(struct langwell_ep *ep, struct langwell_request *req)
 		/* ep0 */
 		/* ep0 */
 		dev_vdbg(&dev->pdev->dev, "%s-%s\n", ep->name, DIR_STRING(ep));
 		dev_vdbg(&dev->pdev->dev, "%s-%s\n", ep->name, DIR_STRING(ep));
 
 
-	dev_vdbg(&dev->pdev->dev, "ep_dqh[%d] addr: 0x%08x\n",
-			i, (u32)&(dev->ep_dqh[i]));
+	dev_vdbg(&dev->pdev->dev, "ep_dqh[%d] addr: 0x%p\n",
+			i, &(dev->ep_dqh[i]));
 
 
 	bit_mask = is_in(ep) ?
 	bit_mask = is_in(ep) ?
 		(1 << (ep->ep_num + 16)) : (1 << (ep->ep_num));
 		(1 << (ep->ep_num + 16)) : (1 << (ep->ep_num));
@@ -1321,7 +1321,9 @@ static int langwell_pullup(struct usb_gadget *_gadget, int is_on)
 	return 0;
 	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);
 /* device controller usb_gadget_ops structure */
 /* device controller usb_gadget_ops structure */
 static const struct usb_gadget_ops langwell_ops = {
 static const struct usb_gadget_ops langwell_ops = {
 
 
@@ -1342,6 +1344,9 @@ static const struct usb_gadget_ops langwell_ops = {
 
 
 	/* D+ pullup, software-controlled connect/disconnect to USB host */
 	/* D+ pullup, software-controlled connect/disconnect to USB host */
 	.pullup		= langwell_pullup,
 	.pullup		= langwell_pullup,
+
+	.start		= langwell_start,
+	.stop		= langwell_stop,
 };
 };
 
 
 
 
@@ -1852,7 +1857,7 @@ static DEVICE_ATTR(remote_wakeup, S_IWUSR, NULL, store_remote_wakeup);
  * the driver might get unbound.
  * the driver might get unbound.
  */
  */
 
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int langwell_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 		int (*bind)(struct usb_gadget *))
 {
 {
 	struct langwell_udc	*dev = the_controller;
 	struct langwell_udc	*dev = the_controller;
@@ -1914,11 +1919,9 @@ err_unbind:
 	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
 	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
 	return retval;
 	return retval;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-
 
 
 /* unregister gadget driver */
 /* unregister gadget driver */
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int langwell_stop(struct usb_gadget_driver *driver)
 {
 {
 	struct langwell_udc	*dev = the_controller;
 	struct langwell_udc	*dev = the_controller;
 	unsigned long		flags;
 	unsigned long		flags;
@@ -1965,8 +1968,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
 	dev_dbg(&dev->pdev->dev, "<--- %s()\n", __func__);
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
@@ -3270,7 +3271,7 @@ static int langwell_udc_probe(struct pci_dev *pdev,
 
 
 	/* allocate device dQH memory */
 	/* allocate device dQH memory */
 	size = dev->ep_max * sizeof(struct langwell_dqh);
 	size = dev->ep_max * sizeof(struct langwell_dqh);
-	dev_vdbg(&dev->pdev->dev, "orig size = %d\n", size);
+	dev_vdbg(&dev->pdev->dev, "orig size = %zd\n", size);
 	if (size < DQH_ALIGNMENT)
 	if (size < DQH_ALIGNMENT)
 		size = DQH_ALIGNMENT;
 		size = DQH_ALIGNMENT;
 	else if ((size % DQH_ALIGNMENT) != 0) {
 	else if ((size % DQH_ALIGNMENT) != 0) {
@@ -3285,7 +3286,7 @@ static int langwell_udc_probe(struct pci_dev *pdev,
 		goto error;
 		goto error;
 	}
 	}
 	dev->ep_dqh_size = size;
 	dev->ep_dqh_size = size;
-	dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %d\n", dev->ep_dqh_size);
+	dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %zd\n", dev->ep_dqh_size);
 
 
 	/* initialize ep0 status request structure */
 	/* initialize ep0 status request structure */
 	dev->status_req = kzalloc(sizeof(struct langwell_request), GFP_KERNEL);
 	dev->status_req = kzalloc(sizeof(struct langwell_request), GFP_KERNEL);
@@ -3373,6 +3374,10 @@ static int langwell_udc_probe(struct pci_dev *pdev,
 	if (retval)
 	if (retval)
 		goto error;
 		goto error;
 
 
+	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+	if (retval)
+		goto error;
+
 	retval = device_create_file(&pdev->dev, &dev_attr_langwell_udc);
 	retval = device_create_file(&pdev->dev, &dev_attr_langwell_udc);
 	if (retval)
 	if (retval)
 		goto error;
 		goto error;
@@ -3403,6 +3408,7 @@ static int langwell_udc_suspend(struct pci_dev *pdev, pm_message_t state)
 
 
 	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
 	dev_dbg(&dev->pdev->dev, "---> %s()\n", __func__);
 
 
+	usb_del_gadget_udc(&dev->gadget);
 	/* disable interrupt and set controller to stop state */
 	/* disable interrupt and set controller to stop state */
 	langwell_udc_stop(dev);
 	langwell_udc_stop(dev);
 
 
@@ -3464,7 +3470,7 @@ static int langwell_udc_resume(struct pci_dev *pdev)
 
 
 	/* allocate device dQH memory */
 	/* allocate device dQH memory */
 	size = dev->ep_max * sizeof(struct langwell_dqh);
 	size = dev->ep_max * sizeof(struct langwell_dqh);
-	dev_vdbg(&dev->pdev->dev, "orig size = %d\n", size);
+	dev_vdbg(&dev->pdev->dev, "orig size = %zd\n", size);
 	if (size < DQH_ALIGNMENT)
 	if (size < DQH_ALIGNMENT)
 		size = DQH_ALIGNMENT;
 		size = DQH_ALIGNMENT;
 	else if ((size % DQH_ALIGNMENT) != 0) {
 	else if ((size % DQH_ALIGNMENT) != 0) {
@@ -3478,7 +3484,7 @@ static int langwell_udc_resume(struct pci_dev *pdev)
 		return -ENOMEM;
 		return -ENOMEM;
 	}
 	}
 	dev->ep_dqh_size = size;
 	dev->ep_dqh_size = size;
-	dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %d\n", dev->ep_dqh_size);
+	dev_vdbg(&dev->pdev->dev, "ep_dqh_size = %zd\n", dev->ep_dqh_size);
 
 
 	/* create dTD dma_pool resource */
 	/* create dTD dma_pool resource */
 	dev->dtd_pool = dma_pool_create("langwell_dtd",
 	dev->dtd_pool = dma_pool_create("langwell_dtd",

+ 54 - 8
drivers/usb/gadget/m66592-udc.c

@@ -3,7 +3,7 @@
  *
  *
  * Copyright (C) 2006-2007 Renesas Solutions Corp.
  * Copyright (C) 2006-2007 Renesas Solutions Corp.
  *
  *
- * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ * Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by
@@ -691,6 +691,7 @@ static void init_controller(struct m66592 *m66592)
 
 
 static void disable_controller(struct m66592 *m66592)
 static void disable_controller(struct m66592 *m66592)
 {
 {
+	m66592_bclr(m66592, M66592_UTST, M66592_TESTMODE);
 	if (!m66592->pdata->on_chip) {
 	if (!m66592->pdata->on_chip) {
 		m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG);
 		m66592_bclr(m66592, M66592_SCKE, M66592_SYSCFG);
 		udelay(1);
 		udelay(1);
@@ -780,7 +781,7 @@ static void irq_ep0_write(struct m66592_ep *ep, struct m66592_request *req)
 	/* write fifo */
 	/* write fifo */
 	if (req->req.buf) {
 	if (req->req.buf) {
 		if (size > 0)
 		if (size > 0)
-			m66592_write_fifo(m66592, ep->fifoaddr, buf, size);
+			m66592_write_fifo(m66592, ep, buf, size);
 		if ((size == 0) || ((size % ep->ep.maxpacket) != 0))
 		if ((size == 0) || ((size % ep->ep.maxpacket) != 0))
 			m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
 			m66592_bset(m66592, M66592_BVAL, ep->fifoctr);
 	}
 	}
@@ -826,7 +827,7 @@ static void irq_packet_write(struct m66592_ep *ep, struct m66592_request *req)
 
 
 	/* write fifo */
 	/* write fifo */
 	if (req->req.buf) {
 	if (req->req.buf) {
-		m66592_write_fifo(m66592, ep->fifoaddr, buf, size);
+		m66592_write_fifo(m66592, ep, buf, size);
 		if ((size == 0)
 		if ((size == 0)
 				|| ((size % ep->ep.maxpacket) != 0)
 				|| ((size % ep->ep.maxpacket) != 0)
 				|| ((bufsize != ep->ep.maxpacket)
 				|| ((bufsize != ep->ep.maxpacket)
@@ -1048,10 +1049,30 @@ static void clear_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
 
 
 static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
 static void set_feature(struct m66592 *m66592, struct usb_ctrlrequest *ctrl)
 {
 {
+	u16 tmp;
+	int timeout = 3000;
 
 
 	switch (ctrl->bRequestType & USB_RECIP_MASK) {
 	switch (ctrl->bRequestType & USB_RECIP_MASK) {
 	case USB_RECIP_DEVICE:
 	case USB_RECIP_DEVICE:
-		control_end(m66592, 1);
+		switch (le16_to_cpu(ctrl->wValue)) {
+		case USB_DEVICE_TEST_MODE:
+			control_end(m66592, 1);
+			/* Wait for the completion of status stage */
+			do {
+				tmp = m66592_read(m66592, M66592_INTSTS0) &
+								M66592_CTSQ;
+				udelay(1);
+			} while (tmp != M66592_CS_IDST || timeout-- > 0);
+
+			if (tmp == M66592_CS_IDST)
+				m66592_bset(m66592,
+					    le16_to_cpu(ctrl->wIndex >> 8),
+					    M66592_TESTMODE);
+			break;
+		default:
+			pipe_stall(m66592, 0);
+			break;
+		}
 		break;
 		break;
 	case USB_RECIP_INTERFACE:
 	case USB_RECIP_INTERFACE:
 		control_end(m66592, 1);
 		control_end(m66592, 1);
@@ -1454,7 +1475,7 @@ static struct usb_ep_ops m66592_ep_ops = {
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 static struct m66592 *the_controller;
 static struct m66592 *the_controller;
 
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int m66592_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 		int (*bind)(struct usb_gadget *))
 {
 {
 	struct m66592 *m66592 = the_controller;
 	struct m66592 *m66592 = the_controller;
@@ -1506,9 +1527,8 @@ error:
 
 
 	return retval;
 	return retval;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int m66592_stop(struct usb_gadget_driver *driver)
 {
 {
 	struct m66592 *m66592 = the_controller;
 	struct m66592 *m66592 = the_controller;
 	unsigned long flags;
 	unsigned long flags;
@@ -1533,7 +1553,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 	m66592->driver = NULL;
 	m66592->driver = NULL;
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 static int m66592_get_frame(struct usb_gadget *_gadget)
 static int m66592_get_frame(struct usb_gadget *_gadget)
@@ -1542,14 +1561,34 @@ static int m66592_get_frame(struct usb_gadget *_gadget)
 	return m66592_read(m66592, M66592_FRMNUM) & 0x03FF;
 	return m66592_read(m66592, M66592_FRMNUM) & 0x03FF;
 }
 }
 
 
+static int m66592_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct m66592 *m66592 = gadget_to_m66592(gadget);
+	unsigned long flags;
+
+	spin_lock_irqsave(&m66592->lock, flags);
+	if (is_on)
+		m66592_bset(m66592, M66592_DPRPU, M66592_SYSCFG);
+	else
+		m66592_bclr(m66592, M66592_DPRPU, M66592_SYSCFG);
+	spin_unlock_irqrestore(&m66592->lock, flags);
+
+	return 0;
+}
+
 static struct usb_gadget_ops m66592_gadget_ops = {
 static struct usb_gadget_ops m66592_gadget_ops = {
 	.get_frame		= m66592_get_frame,
 	.get_frame		= m66592_get_frame,
+	.start			= m66592_start,
+	.stop			= m66592_stop,
+	.pullup			= m66592_pullup,
 };
 };
 
 
 static int __exit m66592_remove(struct platform_device *pdev)
 static int __exit m66592_remove(struct platform_device *pdev)
 {
 {
 	struct m66592		*m66592 = dev_get_drvdata(&pdev->dev);
 	struct m66592		*m66592 = dev_get_drvdata(&pdev->dev);
 
 
+	usb_del_gadget_udc(&m66592->gadget);
+
 	del_timer_sync(&m66592->timer);
 	del_timer_sync(&m66592->timer);
 	iounmap(m66592->reg);
 	iounmap(m66592->reg);
 	free_irq(platform_get_irq(pdev, 0), m66592);
 	free_irq(platform_get_irq(pdev, 0), m66592);
@@ -1691,9 +1730,16 @@ static int __init m66592_probe(struct platform_device *pdev)
 
 
 	init_controller(m66592);
 	init_controller(m66592);
 
 
+	ret = usb_add_gadget_udc(&pdev->dev, &m66592->gadget);
+	if (ret)
+		goto err_add_udc;
+
 	dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
 	dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
 	return 0;
 	return 0;
 
 
+err_add_udc:
+	m66592_free_request(&m66592->ep[0].ep, m66592->ep0_req);
+
 clean_up3:
 clean_up3:
 #ifdef CONFIG_HAVE_CLK
 #ifdef CONFIG_HAVE_CLK
 	if (m66592->pdata->on_chip) {
 	if (m66592->pdata->on_chip) {

+ 22 - 18
drivers/usb/gadget/m66592-udc.h

@@ -3,7 +3,7 @@
  *
  *
  * Copyright (C) 2006-2007 Renesas Solutions Corp.
  * Copyright (C) 2006-2007 Renesas Solutions Corp.
  *
  *
- * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ * Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by
@@ -561,11 +561,26 @@ static inline void m66592_write(struct m66592 *m66592, u16 val,
 	iowrite16(val, m66592->reg + offset);
 	iowrite16(val, m66592->reg + offset);
 }
 }
 
 
+static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
+		unsigned long offset)
+{
+	u16 tmp;
+	tmp = m66592_read(m66592, offset);
+	tmp = tmp & (~pat);
+	tmp = tmp | val;
+	m66592_write(m66592, tmp, offset);
+}
+
+#define m66592_bclr(m66592, val, offset)	\
+			m66592_mdfy(m66592, 0, val, offset)
+#define m66592_bset(m66592, val, offset)	\
+			m66592_mdfy(m66592, val, 0, offset)
+
 static inline void m66592_write_fifo(struct m66592 *m66592,
 static inline void m66592_write_fifo(struct m66592 *m66592,
-		unsigned long offset,
+		struct m66592_ep *ep,
 		void *buf, unsigned long len)
 		void *buf, unsigned long len)
 {
 {
-	void __iomem *fifoaddr = m66592->reg + offset;
+	void __iomem *fifoaddr = m66592->reg + ep->fifoaddr;
 
 
 	if (m66592->pdata->on_chip) {
 	if (m66592->pdata->on_chip) {
 		unsigned long count;
 		unsigned long count;
@@ -591,26 +606,15 @@ static inline void m66592_write_fifo(struct m66592 *m66592,
 		iowrite16_rep(fifoaddr, buf, len);
 		iowrite16_rep(fifoaddr, buf, len);
 		if (odd) {
 		if (odd) {
 			unsigned char *p = buf + len*2;
 			unsigned char *p = buf + len*2;
+			if (m66592->pdata->wr0_shorted_to_wr1)
+				m66592_bclr(m66592, M66592_MBW_16, ep->fifosel);
 			iowrite8(*p, fifoaddr);
 			iowrite8(*p, fifoaddr);
+			if (m66592->pdata->wr0_shorted_to_wr1)
+				m66592_bset(m66592, M66592_MBW_16, ep->fifosel);
 		}
 		}
 	}
 	}
 }
 }
 
 
-static inline void m66592_mdfy(struct m66592 *m66592, u16 val, u16 pat,
-		unsigned long offset)
-{
-	u16 tmp;
-	tmp = m66592_read(m66592, offset);
-	tmp = tmp & (~pat);
-	tmp = tmp | val;
-	m66592_write(m66592, tmp, offset);
-}
-
-#define m66592_bclr(m66592, val, offset)	\
-			m66592_mdfy(m66592, 0, val, offset)
-#define m66592_bset(m66592, val, offset)	\
-			m66592_mdfy(m66592, val, 0, offset)
-
 #endif	/* ifndef __M66592_UDC_H__ */
 #endif	/* ifndef __M66592_UDC_H__ */
 
 
 
 

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

@@ -169,6 +169,7 @@ static struct usb_composite_driver msg_driver = {
 	.name		= "g_mass_storage",
 	.name		= "g_mass_storage",
 	.dev		= &msg_device_desc,
 	.dev		= &msg_device_desc,
 	.iProduct	= DRIVER_DESC,
 	.iProduct	= DRIVER_DESC,
+	.max_speed	= USB_SPEED_HIGH,
 	.needs_serial	= 1,
 	.needs_serial	= 1,
 };
 };
 
 

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

@@ -351,6 +351,7 @@ static struct usb_composite_driver multi_driver = {
 	.name		= "g_multi",
 	.name		= "g_multi",
 	.dev		= &device_desc,
 	.dev		= &device_desc,
 	.strings	= dev_strings,
 	.strings	= dev_strings,
+	.max_speed	= USB_SPEED_HIGH,
 	.unbind		= __exit_p(multi_unbind),
 	.unbind		= __exit_p(multi_unbind),
 	.iProduct	= DRIVER_DESC,
 	.iProduct	= DRIVER_DESC,
 	.needs_serial	= 1,
 	.needs_serial	= 1,

+ 13 - 8
drivers/usb/gadget/mv_udc_core.c

@@ -1128,6 +1128,9 @@ static int mv_udc_pullup(struct usb_gadget *gadget, int is_on)
 	return 0;
 	return 0;
 }
 }
 
 
+static int mv_udc_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int mv_udc_stop(struct usb_gadget_driver *driver);
 /* device controller usb_gadget_ops structure */
 /* device controller usb_gadget_ops structure */
 static const struct usb_gadget_ops mv_ops = {
 static const struct usb_gadget_ops mv_ops = {
 
 
@@ -1139,6 +1142,8 @@ static const struct usb_gadget_ops mv_ops = {
 
 
 	/* D+ pullup, software-controlled connect/disconnect to USB host */
 	/* D+ pullup, software-controlled connect/disconnect to USB host */
 	.pullup		= mv_udc_pullup,
 	.pullup		= mv_udc_pullup,
+	.start		= mv_udc_start,
+	.stop		= mv_udc_stop,
 };
 };
 
 
 static void mv_udc_testmode(struct mv_udc *udc, u16 index, bool enter)
 static void mv_udc_testmode(struct mv_udc *udc, u16 index, bool enter)
@@ -1230,7 +1235,7 @@ static void stop_activity(struct mv_udc *udc, struct usb_gadget_driver *driver)
 	}
 	}
 }
 }
 
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int mv_udc_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 		int (*bind)(struct usb_gadget *))
 {
 {
 	struct mv_udc *udc = the_controller;
 	struct mv_udc *udc = the_controller;
@@ -1270,9 +1275,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 
 
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int mv_udc_stop(struct usb_gadget_driver *driver)
 {
 {
 	struct mv_udc *udc = the_controller;
 	struct mv_udc *udc = the_controller;
 	unsigned long flags;
 	unsigned long flags;
@@ -1296,7 +1300,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 
 
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 
 static int
 static int
 udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty)
 udc_prime_status(struct mv_udc *udc, u8 direction, u16 status, bool empty)
@@ -1880,9 +1883,10 @@ static void gadget_release(struct device *_dev)
 static int mv_udc_remove(struct platform_device *dev)
 static int mv_udc_remove(struct platform_device *dev)
 {
 {
 	struct mv_udc *udc = the_controller;
 	struct mv_udc *udc = the_controller;
-
 	DECLARE_COMPLETION(done);
 	DECLARE_COMPLETION(done);
 
 
+	usb_del_gadget_udc(&udc->gadget);
+
 	udc->done = &done;
 	udc->done = &done;
 
 
 	/* free memory allocated in probe */
 	/* free memory allocated in probe */
@@ -2074,11 +2078,12 @@ int mv_udc_probe(struct platform_device *dev)
 
 
 	the_controller = udc;
 	the_controller = udc;
 
 
-	goto out;
+	retval = usb_add_gadget_udc(&dev->dev, &udc->gadget);
+	if (!retval)
+		return retval;
 error:
 error:
 	if (udc)
 	if (udc)
 		mv_udc_remove(udc->dev);
 		mv_udc_remove(udc->dev);
-out:
 	return retval;
 	return retval;
 }
 }
 
 
@@ -2126,7 +2131,7 @@ static struct platform_driver udc_driver = {
 #endif
 #endif
 	},
 	},
 };
 };
-
+MODULE_ALIAS("platform:pxa-u2o");
 
 
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>");
 MODULE_AUTHOR("Chao Xie <chao.xie@marvell.com>");

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

@@ -228,6 +228,7 @@ static struct usb_composite_driver ncm_driver = {
 	.name		= "g_ncm",
 	.name		= "g_ncm",
 	.dev		= &device_desc,
 	.dev		= &device_desc,
 	.strings	= dev_strings,
 	.strings	= dev_strings,
+	.max_speed	= USB_SPEED_HIGH,
 	.unbind		= __exit_p(gncm_unbind),
 	.unbind		= __exit_p(gncm_unbind),
 };
 };
 
 

+ 2752 - 0
drivers/usb/gadget/net2272.c

@@ -0,0 +1,2752 @@
+/*
+ * Driver for PLX NET2272 USB device controller
+ *
+ * Copyright (C) 2005-2006 PLX Technology, Inc.
+ * Copyright (C) 2006-2011 Analog Devices, Inc.
+ *
+ * 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.
+ *
+ * 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/delay.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/usb.h>
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+#include <asm/byteorder.h>
+#include <asm/system.h>
+#include <asm/unaligned.h>
+
+#include "net2272.h"
+
+#define DRIVER_DESC "PLX NET2272 USB Peripheral Controller"
+
+static const char driver_name[] = "net2272";
+static const char driver_vers[] = "2006 October 17/mainline";
+static const char driver_desc[] = DRIVER_DESC;
+
+static const char ep0name[] = "ep0";
+static const char * const ep_name[] = {
+	ep0name,
+	"ep-a", "ep-b", "ep-c",
+};
+
+#define DMA_ADDR_INVALID	(~(dma_addr_t)0)
+#ifdef CONFIG_USB_GADGET_NET2272_DMA
+/*
+ * use_dma: the NET2272 can use an external DMA controller.
+ * Note that since there is no generic DMA api, some functions,
+ * notably request_dma, start_dma, and cancel_dma will need to be
+ * modified for your platform's particular dma controller.
+ *
+ * If use_dma is disabled, pio will be used instead.
+ */
+static int use_dma = 0;
+module_param(use_dma, bool, 0644);
+
+/*
+ * dma_ep: selects the endpoint for use with dma (1=ep-a, 2=ep-b)
+ * The NET2272 can only use dma for a single endpoint at a time.
+ * At some point this could be modified to allow either endpoint
+ * to take control of dma as it becomes available.
+ *
+ * Note that DMA should not be used on OUT endpoints unless it can
+ * be guaranteed that no short packets will arrive on an IN endpoint
+ * while the DMA operation is pending.  Otherwise the OUT DMA will
+ * terminate prematurely (See NET2272 Errata 630-0213-0101)
+ */
+static ushort dma_ep = 1;
+module_param(dma_ep, ushort, 0644);
+
+/*
+ * dma_mode: net2272 dma mode setting (see LOCCTL1 definiton):
+ *	mode 0 == Slow DREQ mode
+ *	mode 1 == Fast DREQ mode
+ *	mode 2 == Burst mode
+ */
+static ushort dma_mode = 2;
+module_param(dma_mode, ushort, 0644);
+#else
+#define use_dma 0
+#define dma_ep 1
+#define dma_mode 2
+#endif
+
+/*
+ * fifo_mode: net2272 buffer configuration:
+ *      mode 0 == ep-{a,b,c} 512db each
+ *      mode 1 == ep-a 1k, ep-{b,c} 512db
+ *      mode 2 == ep-a 1k, ep-b 1k, ep-c 512db
+ *      mode 3 == ep-a 1k, ep-b disabled, ep-c 512db
+ */
+static ushort fifo_mode = 0;
+module_param(fifo_mode, ushort, 0644);
+
+/*
+ * enable_suspend: When enabled, the driver will respond to
+ * USB suspend requests by powering down the NET2272.  Otherwise,
+ * USB suspend requests will be ignored.  This is acceptible for
+ * self-powered devices.  For bus powered devices set this to 1.
+ */
+static ushort enable_suspend = 0;
+module_param(enable_suspend, ushort, 0644);
+
+static void assert_out_naking(struct net2272_ep *ep, const char *where)
+{
+	u8 tmp;
+
+#ifndef DEBUG
+	return;
+#endif
+
+	tmp = net2272_ep_read(ep, EP_STAT0);
+	if ((tmp & (1 << NAK_OUT_PACKETS)) == 0) {
+		dev_dbg(ep->dev->dev, "%s %s %02x !NAK\n",
+			ep->ep.name, where, tmp);
+		net2272_ep_write(ep, EP_RSPSET, 1 << ALT_NAK_OUT_PACKETS);
+	}
+}
+#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep, __func__)
+
+static void stop_out_naking(struct net2272_ep *ep)
+{
+	u8 tmp = net2272_ep_read(ep, EP_STAT0);
+
+	if ((tmp & (1 << NAK_OUT_PACKETS)) != 0)
+		net2272_ep_write(ep, EP_RSPCLR, 1 << ALT_NAK_OUT_PACKETS);
+}
+
+#define PIPEDIR(bAddress) (usb_pipein(bAddress) ? "in" : "out")
+
+static char *type_string(u8 bmAttributes)
+{
+	switch ((bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) {
+	case USB_ENDPOINT_XFER_BULK: return "bulk";
+	case USB_ENDPOINT_XFER_ISOC: return "iso";
+	case USB_ENDPOINT_XFER_INT:  return "intr";
+	default:                     return "control";
+	}
+}
+
+static char *buf_state_string(unsigned state)
+{
+	switch (state) {
+	case BUFF_FREE:  return "free";
+	case BUFF_VALID: return "valid";
+	case BUFF_LCL:   return "local";
+	case BUFF_USB:   return "usb";
+	default:         return "unknown";
+	}
+}
+
+static char *dma_mode_string(void)
+{
+	if (!use_dma)
+		return "PIO";
+	switch (dma_mode) {
+	case 0:  return "SLOW DREQ";
+	case 1:  return "FAST DREQ";
+	case 2:  return "BURST";
+	default: return "invalid";
+	}
+}
+
+static void net2272_dequeue_all(struct net2272_ep *);
+static int net2272_kick_dma(struct net2272_ep *, struct net2272_request *);
+static int net2272_fifo_status(struct usb_ep *);
+
+static struct usb_ep_ops net2272_ep_ops;
+
+/*---------------------------------------------------------------------------*/
+
+static int
+net2272_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
+{
+	struct net2272 *dev;
+	struct net2272_ep *ep;
+	u32 max;
+	u8 tmp;
+	unsigned long flags;
+
+	ep = container_of(_ep, struct net2272_ep, ep);
+	if (!_ep || !desc || ep->desc || _ep->name == ep0name
+			|| desc->bDescriptorType != USB_DT_ENDPOINT)
+		return -EINVAL;
+	dev = ep->dev;
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	max = le16_to_cpu(desc->wMaxPacketSize) & 0x1fff;
+
+	spin_lock_irqsave(&dev->lock, flags);
+	_ep->maxpacket = max & 0x7fff;
+	ep->desc = desc;
+
+	/* net2272_ep_reset() has already been called */
+	ep->stopped = 0;
+	ep->wedged = 0;
+
+	/* set speed-dependent max packet */
+	net2272_ep_write(ep, EP_MAXPKT0, max & 0xff);
+	net2272_ep_write(ep, EP_MAXPKT1, (max & 0xff00) >> 8);
+
+	/* set type, direction, address; reset fifo counters */
+	net2272_ep_write(ep, EP_STAT1, 1 << BUFFER_FLUSH);
+	tmp = usb_endpoint_type(desc);
+	if (usb_endpoint_xfer_bulk(desc)) {
+		/* catch some particularly blatant driver bugs */
+		if ((dev->gadget.speed == USB_SPEED_HIGH && max != 512) ||
+		    (dev->gadget.speed == USB_SPEED_FULL && max > 64)) {
+			spin_unlock_irqrestore(&dev->lock, flags);
+			return -ERANGE;
+		}
+	}
+	ep->is_iso = usb_endpoint_xfer_isoc(desc) ? 1 : 0;
+	tmp <<= ENDPOINT_TYPE;
+	tmp |= ((desc->bEndpointAddress & 0x0f) << ENDPOINT_NUMBER);
+	tmp |= usb_endpoint_dir_in(desc) << ENDPOINT_DIRECTION;
+	tmp |= (1 << ENDPOINT_ENABLE);
+
+	/* for OUT transfers, block the rx fifo until a read is posted */
+	ep->is_in = usb_endpoint_dir_in(desc);
+	if (!ep->is_in)
+		net2272_ep_write(ep, EP_RSPSET, 1 << ALT_NAK_OUT_PACKETS);
+
+	net2272_ep_write(ep, EP_CFG, tmp);
+
+	/* enable irqs */
+	tmp = (1 << ep->num) | net2272_read(dev, IRQENB0);
+	net2272_write(dev, IRQENB0, tmp);
+
+	tmp = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE)
+		| (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE)
+		| net2272_ep_read(ep, EP_IRQENB);
+	net2272_ep_write(ep, EP_IRQENB, tmp);
+
+	tmp = desc->bEndpointAddress;
+	dev_dbg(dev->dev, "enabled %s (ep%d%s-%s) max %04x cfg %02x\n",
+		_ep->name, tmp & 0x0f, PIPEDIR(tmp),
+		type_string(desc->bmAttributes), max,
+		net2272_ep_read(ep, EP_CFG));
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+	return 0;
+}
+
+static void net2272_ep_reset(struct net2272_ep *ep)
+{
+	u8 tmp;
+
+	ep->desc = NULL;
+	INIT_LIST_HEAD(&ep->queue);
+
+	ep->ep.maxpacket = ~0;
+	ep->ep.ops = &net2272_ep_ops;
+
+	/* disable irqs, endpoint */
+	net2272_ep_write(ep, EP_IRQENB, 0);
+
+	/* init to our chosen defaults, notably so that we NAK OUT
+	 * packets until the driver queues a read.
+	 */
+	tmp = (1 << NAK_OUT_PACKETS_MODE) | (1 << ALT_NAK_OUT_PACKETS);
+	net2272_ep_write(ep, EP_RSPSET, tmp);
+
+	tmp = (1 << INTERRUPT_MODE) | (1 << HIDE_STATUS_PHASE);
+	if (ep->num != 0)
+		tmp |= (1 << ENDPOINT_TOGGLE) | (1 << ENDPOINT_HALT);
+
+	net2272_ep_write(ep, EP_RSPCLR, tmp);
+
+	/* scrub most status bits, and flush any fifo state */
+	net2272_ep_write(ep, EP_STAT0,
+			  (1 << DATA_IN_TOKEN_INTERRUPT)
+			| (1 << DATA_OUT_TOKEN_INTERRUPT)
+			| (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)
+			| (1 << DATA_PACKET_RECEIVED_INTERRUPT)
+			| (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT));
+
+	net2272_ep_write(ep, EP_STAT1,
+			    (1 << TIMEOUT)
+			  | (1 << USB_OUT_ACK_SENT)
+			  | (1 << USB_OUT_NAK_SENT)
+			  | (1 << USB_IN_ACK_RCVD)
+			  | (1 << USB_IN_NAK_SENT)
+			  | (1 << USB_STALL_SENT)
+			  | (1 << LOCAL_OUT_ZLP)
+			  | (1 << BUFFER_FLUSH));
+
+	/* fifo size is handled seperately */
+}
+
+static int net2272_disable(struct usb_ep *_ep)
+{
+	struct net2272_ep *ep;
+	unsigned long flags;
+
+	ep = container_of(_ep, struct net2272_ep, ep);
+	if (!_ep || !ep->desc || _ep->name == ep0name)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ep->dev->lock, flags);
+	net2272_dequeue_all(ep);
+	net2272_ep_reset(ep);
+
+	dev_vdbg(ep->dev->dev, "disabled %s\n", _ep->name);
+
+	spin_unlock_irqrestore(&ep->dev->lock, flags);
+	return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static struct usb_request *
+net2272_alloc_request(struct usb_ep *_ep, gfp_t gfp_flags)
+{
+	struct net2272_ep *ep;
+	struct net2272_request *req;
+
+	if (!_ep)
+		return NULL;
+	ep = container_of(_ep, struct net2272_ep, ep);
+
+	req = kzalloc(sizeof(*req), gfp_flags);
+	if (!req)
+		return NULL;
+
+	req->req.dma = DMA_ADDR_INVALID;
+	INIT_LIST_HEAD(&req->queue);
+
+	return &req->req;
+}
+
+static void
+net2272_free_request(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct net2272_ep *ep;
+	struct net2272_request *req;
+
+	ep = container_of(_ep, struct net2272_ep, ep);
+	if (!_ep || !_req)
+		return;
+
+	req = container_of(_req, struct net2272_request, req);
+	WARN_ON(!list_empty(&req->queue));
+	kfree(req);
+}
+
+static void
+net2272_done(struct net2272_ep *ep, struct net2272_request *req, int status)
+{
+	struct net2272 *dev;
+	unsigned stopped = ep->stopped;
+
+	if (ep->num == 0) {
+		if (ep->dev->protocol_stall) {
+			ep->stopped = 1;
+			set_halt(ep);
+		}
+		allow_status(ep);
+	}
+
+	list_del_init(&req->queue);
+
+	if (req->req.status == -EINPROGRESS)
+		req->req.status = status;
+	else
+		status = req->req.status;
+
+	dev = ep->dev;
+	if (use_dma && req->mapped) {
+		dma_unmap_single(dev->dev, req->req.dma, req->req.length,
+			ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		req->req.dma = DMA_ADDR_INVALID;
+		req->mapped = 0;
+	}
+
+	if (status && status != -ESHUTDOWN)
+		dev_vdbg(dev->dev, "complete %s req %p stat %d len %u/%u buf %p\n",
+			ep->ep.name, &req->req, status,
+			req->req.actual, req->req.length, req->req.buf);
+
+	/* don't modify queue heads during completion callback */
+	ep->stopped = 1;
+	spin_unlock(&dev->lock);
+	req->req.complete(&ep->ep, &req->req);
+	spin_lock(&dev->lock);
+	ep->stopped = stopped;
+}
+
+static int
+net2272_write_packet(struct net2272_ep *ep, u8 *buf,
+	struct net2272_request *req, unsigned max)
+{
+	u16 __iomem *ep_data = net2272_reg_addr(ep->dev, EP_DATA);
+	u16 *bufp;
+	unsigned length, count;
+	u8 tmp;
+
+	length = min(req->req.length - req->req.actual, max);
+	req->req.actual += length;
+
+	dev_vdbg(ep->dev->dev, "write packet %s req %p max %u len %u avail %u\n",
+		ep->ep.name, req, max, length,
+		(net2272_ep_read(ep, EP_AVAIL1) << 8) | net2272_ep_read(ep, EP_AVAIL0));
+
+	count = length;
+	bufp = (u16 *)buf;
+
+	while (likely(count >= 2)) {
+		/* no byte-swap required; chip endian set during init */
+		writew(*bufp++, ep_data);
+		count -= 2;
+	}
+	buf = (u8 *)bufp;
+
+	/* write final byte by placing the NET2272 into 8-bit mode */
+	if (unlikely(count)) {
+		tmp = net2272_read(ep->dev, LOCCTL);
+		net2272_write(ep->dev, LOCCTL, tmp & ~(1 << DATA_WIDTH));
+		writeb(*buf, ep_data);
+		net2272_write(ep->dev, LOCCTL, tmp);
+	}
+	return length;
+}
+
+/* returns: 0: still running, 1: completed, negative: errno */
+static int
+net2272_write_fifo(struct net2272_ep *ep, struct net2272_request *req)
+{
+	u8 *buf;
+	unsigned count, max;
+	int status;
+
+	dev_vdbg(ep->dev->dev, "write_fifo %s actual %d len %d\n",
+		ep->ep.name, req->req.actual, req->req.length);
+
+	/*
+	 * Keep loading the endpoint until the final packet is loaded,
+	 * or the endpoint buffer is full.
+	 */
+ top:
+	/*
+	 * Clear interrupt status
+	 *  - Packet Transmitted interrupt will become set again when the
+	 *    host successfully takes another packet
+	 */
+	net2272_ep_write(ep, EP_STAT0, (1 << DATA_PACKET_TRANSMITTED_INTERRUPT));
+	while (!(net2272_ep_read(ep, EP_STAT0) & (1 << BUFFER_FULL))) {
+		buf = req->req.buf + req->req.actual;
+		prefetch(buf);
+
+		/* force pagesel */
+		net2272_ep_read(ep, EP_STAT0);
+
+		max = (net2272_ep_read(ep, EP_AVAIL1) << 8) |
+			(net2272_ep_read(ep, EP_AVAIL0));
+
+		if (max < ep->ep.maxpacket)
+			max = (net2272_ep_read(ep, EP_AVAIL1) << 8)
+				| (net2272_ep_read(ep, EP_AVAIL0));
+
+		count = net2272_write_packet(ep, buf, req, max);
+		/* see if we are done */
+		if (req->req.length == req->req.actual) {
+			/* validate short or zlp packet */
+			if (count < ep->ep.maxpacket)
+				set_fifo_bytecount(ep, 0);
+			net2272_done(ep, req, 0);
+
+			if (!list_empty(&ep->queue)) {
+				req = list_entry(ep->queue.next,
+						struct net2272_request,
+						queue);
+				status = net2272_kick_dma(ep, req);
+
+				if (status < 0)
+					if ((net2272_ep_read(ep, EP_STAT0)
+							& (1 << BUFFER_EMPTY)))
+						goto top;
+			}
+			return 1;
+		}
+		net2272_ep_write(ep, EP_STAT0, (1 << DATA_PACKET_TRANSMITTED_INTERRUPT));
+	}
+	return 0;
+}
+
+static void
+net2272_out_flush(struct net2272_ep *ep)
+{
+	ASSERT_OUT_NAKING(ep);
+
+	net2272_ep_write(ep, EP_STAT0, (1 << DATA_OUT_TOKEN_INTERRUPT)
+			| (1 << DATA_PACKET_RECEIVED_INTERRUPT));
+	net2272_ep_write(ep, EP_STAT1, 1 << BUFFER_FLUSH);
+}
+
+static int
+net2272_read_packet(struct net2272_ep *ep, u8 *buf,
+	struct net2272_request *req, unsigned avail)
+{
+	u16 __iomem *ep_data = net2272_reg_addr(ep->dev, EP_DATA);
+	unsigned is_short;
+	u16 *bufp;
+
+	req->req.actual += avail;
+
+	dev_vdbg(ep->dev->dev, "read packet %s req %p len %u avail %u\n",
+		ep->ep.name, req, avail,
+		(net2272_ep_read(ep, EP_AVAIL1) << 8) | net2272_ep_read(ep, EP_AVAIL0));
+
+	is_short = (avail < ep->ep.maxpacket);
+
+	if (unlikely(avail == 0)) {
+		/* remove any zlp from the buffer */
+		(void)readw(ep_data);
+		return is_short;
+	}
+
+	/* Ensure we get the final byte */
+	if (unlikely(avail % 2))
+		avail++;
+	bufp = (u16 *)buf;
+
+	do {
+		*bufp++ = readw(ep_data);
+		avail -= 2;
+	} while (avail);
+
+	/*
+	 * To avoid false endpoint available race condition must read
+	 * ep stat0 twice in the case of a short transfer
+	 */
+	if (net2272_ep_read(ep, EP_STAT0) & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT))
+		net2272_ep_read(ep, EP_STAT0);
+
+	return is_short;
+}
+
+static int
+net2272_read_fifo(struct net2272_ep *ep, struct net2272_request *req)
+{
+	u8 *buf;
+	unsigned is_short;
+	int count;
+	int tmp;
+	int cleanup = 0;
+	int status = -1;
+
+	dev_vdbg(ep->dev->dev, "read_fifo %s actual %d len %d\n",
+		ep->ep.name, req->req.actual, req->req.length);
+
+ top:
+	do {
+		buf = req->req.buf + req->req.actual;
+		prefetchw(buf);
+
+		count = (net2272_ep_read(ep, EP_AVAIL1) << 8)
+			| net2272_ep_read(ep, EP_AVAIL0);
+
+		net2272_ep_write(ep, EP_STAT0,
+			(1 << SHORT_PACKET_TRANSFERRED_INTERRUPT) |
+			(1 << DATA_PACKET_RECEIVED_INTERRUPT));
+
+		tmp = req->req.length - req->req.actual;
+
+		if (count > tmp) {
+			if ((tmp % ep->ep.maxpacket) != 0) {
+				dev_err(ep->dev->dev,
+					"%s out fifo %d bytes, expected %d\n",
+					ep->ep.name, count, tmp);
+				cleanup = 1;
+			}
+			count = (tmp > 0) ? tmp : 0;
+		}
+
+		is_short = net2272_read_packet(ep, buf, req, count);
+
+		/* completion */
+		if (unlikely(cleanup || is_short ||
+				((req->req.actual == req->req.length)
+				 && !req->req.zero))) {
+
+			if (cleanup) {
+				net2272_out_flush(ep);
+				net2272_done(ep, req, -EOVERFLOW);
+			} else
+				net2272_done(ep, req, 0);
+
+			/* re-initialize endpoint transfer registers
+			 * otherwise they may result in erroneous pre-validation
+			 * for subsequent control reads
+			 */
+			if (unlikely(ep->num == 0)) {
+				net2272_ep_write(ep, EP_TRANSFER2, 0);
+				net2272_ep_write(ep, EP_TRANSFER1, 0);
+				net2272_ep_write(ep, EP_TRANSFER0, 0);
+			}
+
+			if (!list_empty(&ep->queue)) {
+				req = list_entry(ep->queue.next,
+					struct net2272_request, queue);
+				status = net2272_kick_dma(ep, req);
+				if ((status < 0) &&
+				    !(net2272_ep_read(ep, EP_STAT0) & (1 << BUFFER_EMPTY)))
+					goto top;
+			}
+			return 1;
+		}
+	} while (!(net2272_ep_read(ep, EP_STAT0) & (1 << BUFFER_EMPTY)));
+
+	return 0;
+}
+
+static void
+net2272_pio_advance(struct net2272_ep *ep)
+{
+	struct net2272_request *req;
+
+	if (unlikely(list_empty(&ep->queue)))
+		return;
+
+	req = list_entry(ep->queue.next, struct net2272_request, queue);
+	(ep->is_in ? net2272_write_fifo : net2272_read_fifo)(ep, req);
+}
+
+/* returns 0 on success, else negative errno */
+static int
+net2272_request_dma(struct net2272 *dev, unsigned ep, u32 buf,
+	unsigned len, unsigned dir)
+{
+	dev_vdbg(dev->dev, "request_dma ep %d buf %08x len %d dir %d\n",
+		ep, buf, len, dir);
+
+	/* The NET2272 only supports a single dma channel */
+	if (dev->dma_busy)
+		return -EBUSY;
+	/*
+	 * EP_TRANSFER (used to determine the number of bytes received
+	 * in an OUT transfer) is 24 bits wide; don't ask for more than that.
+	 */
+	if ((dir == 1) && (len > 0x1000000))
+		return -EINVAL;
+
+	dev->dma_busy = 1;
+
+	/* initialize platform's dma */
+#ifdef CONFIG_PCI
+	/* NET2272 addr, buffer addr, length, etc. */
+	switch (dev->dev_id) {
+	case PCI_DEVICE_ID_RDK1:
+		/* Setup PLX 9054 DMA mode */
+		writel((1 << LOCAL_BUS_WIDTH) |
+			(1 << TA_READY_INPUT_ENABLE) |
+			(0 << LOCAL_BURST_ENABLE) |
+			(1 << DONE_INTERRUPT_ENABLE) |
+			(1 << LOCAL_ADDRESSING_MODE) |
+			(1 << DEMAND_MODE) |
+			(1 << DMA_EOT_ENABLE) |
+			(1 << FAST_SLOW_TERMINATE_MODE_SELECT) |
+			(1 << DMA_CHANNEL_INTERRUPT_SELECT),
+			dev->rdk1.plx9054_base_addr + DMAMODE0);
+
+		writel(0x100000, dev->rdk1.plx9054_base_addr + DMALADR0);
+		writel(buf, dev->rdk1.plx9054_base_addr + DMAPADR0);
+		writel(len, dev->rdk1.plx9054_base_addr + DMASIZ0);
+		writel((dir << DIRECTION_OF_TRANSFER) |
+			(1 << INTERRUPT_AFTER_TERMINAL_COUNT),
+			dev->rdk1.plx9054_base_addr + DMADPR0);
+		writel((1 << LOCAL_DMA_CHANNEL_0_INTERRUPT_ENABLE) |
+			readl(dev->rdk1.plx9054_base_addr + INTCSR),
+			dev->rdk1.plx9054_base_addr + INTCSR);
+
+		break;
+	}
+#endif
+
+	net2272_write(dev, DMAREQ,
+		(0 << DMA_BUFFER_VALID) |
+		(1 << DMA_REQUEST_ENABLE) |
+		(1 << DMA_CONTROL_DACK) |
+		(dev->dma_eot_polarity << EOT_POLARITY) |
+		(dev->dma_dack_polarity << DACK_POLARITY) |
+		(dev->dma_dreq_polarity << DREQ_POLARITY) |
+		((ep >> 1) << DMA_ENDPOINT_SELECT));
+
+	(void) net2272_read(dev, SCRATCH);
+
+	return 0;
+}
+
+static void
+net2272_start_dma(struct net2272 *dev)
+{
+	/* start platform's dma controller */
+#ifdef CONFIG_PCI
+	switch (dev->dev_id) {
+	case PCI_DEVICE_ID_RDK1:
+		writeb((1 << CHANNEL_ENABLE) | (1 << CHANNEL_START),
+			dev->rdk1.plx9054_base_addr + DMACSR0);
+		break;
+	}
+#endif
+}
+
+/* returns 0 on success, else negative errno */
+static int
+net2272_kick_dma(struct net2272_ep *ep, struct net2272_request *req)
+{
+	unsigned size;
+	u8 tmp;
+
+	if (!use_dma || (ep->num < 1) || (ep->num > 2) || !ep->dma)
+		return -EINVAL;
+
+	/* don't use dma for odd-length transfers
+	 * otherwise, we'd need to deal with the last byte with pio
+	 */
+	if (req->req.length & 1)
+		return -EINVAL;
+
+	dev_vdbg(ep->dev->dev, "kick_dma %s req %p dma %08llx\n",
+		ep->ep.name, req, (unsigned long long) req->req.dma);
+
+	net2272_ep_write(ep, EP_RSPSET, 1 << ALT_NAK_OUT_PACKETS);
+
+	/* The NET2272 can only use DMA on one endpoint at a time */
+	if (ep->dev->dma_busy)
+		return -EBUSY;
+
+	/* Make sure we only DMA an even number of bytes (we'll use
+	 * pio to complete the transfer)
+	 */
+	size = req->req.length;
+	size &= ~1;
+
+	/* device-to-host transfer */
+	if (ep->is_in) {
+		/* initialize platform's dma controller */
+		if (net2272_request_dma(ep->dev, ep->num, req->req.dma, size, 0))
+			/* unable to obtain DMA channel; return error and use pio mode */
+			return -EBUSY;
+		req->req.actual += size;
+
+	/* host-to-device transfer */
+	} else {
+		tmp = net2272_ep_read(ep, EP_STAT0);
+
+		/* initialize platform's dma controller */
+		if (net2272_request_dma(ep->dev, ep->num, req->req.dma, size, 1))
+			/* unable to obtain DMA channel; return error and use pio mode */
+			return -EBUSY;
+
+		if (!(tmp & (1 << BUFFER_EMPTY)))
+			ep->not_empty = 1;
+		else
+			ep->not_empty = 0;
+
+
+		/* allow the endpoint's buffer to fill */
+		net2272_ep_write(ep, EP_RSPCLR, 1 << ALT_NAK_OUT_PACKETS);
+
+		/* this transfer completed and data's already in the fifo
+		 * return error so pio gets used.
+		 */
+		if (tmp & (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)) {
+
+			/* deassert dreq */
+			net2272_write(ep->dev, DMAREQ,
+				(0 << DMA_BUFFER_VALID) |
+				(0 << DMA_REQUEST_ENABLE) |
+				(1 << DMA_CONTROL_DACK) |
+				(ep->dev->dma_eot_polarity << EOT_POLARITY) |
+				(ep->dev->dma_dack_polarity << DACK_POLARITY) |
+				(ep->dev->dma_dreq_polarity << DREQ_POLARITY) |
+				((ep->num >> 1) << DMA_ENDPOINT_SELECT));
+
+			return -EBUSY;
+		}
+	}
+
+	/* Don't use per-packet interrupts: use dma interrupts only */
+	net2272_ep_write(ep, EP_IRQENB, 0);
+
+	net2272_start_dma(ep->dev);
+
+	return 0;
+}
+
+static void net2272_cancel_dma(struct net2272 *dev)
+{
+#ifdef CONFIG_PCI
+	switch (dev->dev_id) {
+	case PCI_DEVICE_ID_RDK1:
+		writeb(0, dev->rdk1.plx9054_base_addr + DMACSR0);
+		writeb(1 << CHANNEL_ABORT, dev->rdk1.plx9054_base_addr + DMACSR0);
+		while (!(readb(dev->rdk1.plx9054_base_addr + DMACSR0) &
+		         (1 << CHANNEL_DONE)))
+			continue;	/* wait for dma to stabalize */
+
+		/* dma abort generates an interrupt */
+		writeb(1 << CHANNEL_CLEAR_INTERRUPT,
+			dev->rdk1.plx9054_base_addr + DMACSR0);
+		break;
+	}
+#endif
+
+	dev->dma_busy = 0;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static int
+net2272_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+{
+	struct net2272_request *req;
+	struct net2272_ep *ep;
+	struct net2272 *dev;
+	unsigned long flags;
+	int status = -1;
+	u8 s;
+
+	req = container_of(_req, struct net2272_request, req);
+	if (!_req || !_req->complete || !_req->buf
+			|| !list_empty(&req->queue))
+		return -EINVAL;
+	ep = container_of(_ep, struct net2272_ep, ep);
+	if (!_ep || (!ep->desc && ep->num != 0))
+		return -EINVAL;
+	dev = ep->dev;
+	if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	/* set up dma mapping in case the caller didn't */
+	if (use_dma && ep->dma && _req->dma == DMA_ADDR_INVALID) {
+		_req->dma = dma_map_single(dev->dev, _req->buf, _req->length,
+			ep->is_in ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+		req->mapped = 1;
+	}
+
+	dev_vdbg(dev->dev, "%s queue req %p, len %d buf %p dma %08llx %s\n",
+		_ep->name, _req, _req->length, _req->buf,
+		(unsigned long long) _req->dma, _req->zero ? "zero" : "!zero");
+
+	spin_lock_irqsave(&dev->lock, flags);
+
+	_req->status = -EINPROGRESS;
+	_req->actual = 0;
+
+	/* kickstart this i/o queue? */
+	if (list_empty(&ep->queue) && !ep->stopped) {
+		/* maybe there's no control data, just status ack */
+		if (ep->num == 0 && _req->length == 0) {
+			net2272_done(ep, req, 0);
+			dev_vdbg(dev->dev, "%s status ack\n", ep->ep.name);
+			goto done;
+		}
+
+		/* Return zlp, don't let it block subsequent packets */
+		s = net2272_ep_read(ep, EP_STAT0);
+		if (s & (1 << BUFFER_EMPTY)) {
+			/* Buffer is empty check for a blocking zlp, handle it */
+			if ((s & (1 << NAK_OUT_PACKETS)) &&
+			    net2272_ep_read(ep, EP_STAT1) & (1 << LOCAL_OUT_ZLP)) {
+				dev_dbg(dev->dev, "WARNING: returning ZLP short packet termination!\n");
+				/*
+				 * Request is going to terminate with a short packet ...
+				 * hope the client is ready for it!
+				 */
+				status = net2272_read_fifo(ep, req);
+				/* clear short packet naking */
+				net2272_ep_write(ep, EP_STAT0, (1 << NAK_OUT_PACKETS));
+				goto done;
+			}
+		}
+
+		/* try dma first */
+		status = net2272_kick_dma(ep, req);
+
+		if (status < 0) {
+			/* dma failed (most likely in use by another endpoint)
+			 * fallback to pio
+			 */
+			status = 0;
+
+			if (ep->is_in)
+				status = net2272_write_fifo(ep, req);
+			else {
+				s = net2272_ep_read(ep, EP_STAT0);
+				if ((s & (1 << BUFFER_EMPTY)) == 0)
+					status = net2272_read_fifo(ep, req);
+			}
+
+			if (unlikely(status != 0)) {
+				if (status > 0)
+					status = 0;
+				req = NULL;
+			}
+		}
+	}
+	if (likely(req != 0))
+		list_add_tail(&req->queue, &ep->queue);
+
+	if (likely(!list_empty(&ep->queue)))
+		net2272_ep_write(ep, EP_RSPCLR, 1 << ALT_NAK_OUT_PACKETS);
+ done:
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return 0;
+}
+
+/* dequeue ALL requests */
+static void
+net2272_dequeue_all(struct net2272_ep *ep)
+{
+	struct net2272_request *req;
+
+	/* called with spinlock held */
+	ep->stopped = 1;
+
+	while (!list_empty(&ep->queue)) {
+		req = list_entry(ep->queue.next,
+				struct net2272_request,
+				queue);
+		net2272_done(ep, req, -ESHUTDOWN);
+	}
+}
+
+/* dequeue JUST ONE request */
+static int
+net2272_dequeue(struct usb_ep *_ep, struct usb_request *_req)
+{
+	struct net2272_ep *ep;
+	struct net2272_request *req;
+	unsigned long flags;
+	int stopped;
+
+	ep = container_of(_ep, struct net2272_ep, ep);
+	if (!_ep || (!ep->desc && ep->num != 0) || !_req)
+		return -EINVAL;
+
+	spin_lock_irqsave(&ep->dev->lock, flags);
+	stopped = ep->stopped;
+	ep->stopped = 1;
+
+	/* make sure it's still queued on this endpoint */
+	list_for_each_entry(req, &ep->queue, queue) {
+		if (&req->req == _req)
+			break;
+	}
+	if (&req->req != _req) {
+		spin_unlock_irqrestore(&ep->dev->lock, flags);
+		return -EINVAL;
+	}
+
+	/* queue head may be partially complete */
+	if (ep->queue.next == &req->queue) {
+		dev_dbg(ep->dev->dev, "unlink (%s) pio\n", _ep->name);
+		net2272_done(ep, req, -ECONNRESET);
+	}
+	req = NULL;
+	ep->stopped = stopped;
+
+	spin_unlock_irqrestore(&ep->dev->lock, flags);
+	return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static int
+net2272_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
+{
+	struct net2272_ep *ep;
+	unsigned long flags;
+	int ret = 0;
+
+	ep = container_of(_ep, struct net2272_ep, ep);
+	if (!_ep || (!ep->desc && ep->num != 0))
+		return -EINVAL;
+	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+	if (ep->desc /* not ep0 */ && usb_endpoint_xfer_isoc(ep->desc))
+		return -EINVAL;
+
+	spin_lock_irqsave(&ep->dev->lock, flags);
+	if (!list_empty(&ep->queue))
+		ret = -EAGAIN;
+	else if (ep->is_in && value && net2272_fifo_status(_ep) != 0)
+		ret = -EAGAIN;
+	else {
+		dev_vdbg(ep->dev->dev, "%s %s %s\n", _ep->name,
+			value ? "set" : "clear",
+			wedged ? "wedge" : "halt");
+		/* set/clear */
+		if (value) {
+			if (ep->num == 0)
+				ep->dev->protocol_stall = 1;
+			else
+				set_halt(ep);
+			if (wedged)
+				ep->wedged = 1;
+		} else {
+			clear_halt(ep);
+			ep->wedged = 0;
+		}
+	}
+	spin_unlock_irqrestore(&ep->dev->lock, flags);
+
+	return ret;
+}
+
+static int
+net2272_set_halt(struct usb_ep *_ep, int value)
+{
+	return net2272_set_halt_and_wedge(_ep, value, 0);
+}
+
+static int
+net2272_set_wedge(struct usb_ep *_ep)
+{
+	if (!_ep || _ep->name == ep0name)
+		return -EINVAL;
+	return net2272_set_halt_and_wedge(_ep, 1, 1);
+}
+
+static int
+net2272_fifo_status(struct usb_ep *_ep)
+{
+	struct net2272_ep *ep;
+	u16 avail;
+
+	ep = container_of(_ep, struct net2272_ep, ep);
+	if (!_ep || (!ep->desc && ep->num != 0))
+		return -ENODEV;
+	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return -ESHUTDOWN;
+
+	avail = net2272_ep_read(ep, EP_AVAIL1) << 8;
+	avail |= net2272_ep_read(ep, EP_AVAIL0);
+	if (avail > ep->fifo_size)
+		return -EOVERFLOW;
+	if (ep->is_in)
+		avail = ep->fifo_size - avail;
+	return avail;
+}
+
+static void
+net2272_fifo_flush(struct usb_ep *_ep)
+{
+	struct net2272_ep *ep;
+
+	ep = container_of(_ep, struct net2272_ep, ep);
+	if (!_ep || (!ep->desc && ep->num != 0))
+		return;
+	if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
+		return;
+
+	net2272_ep_write(ep, EP_STAT1, 1 << BUFFER_FLUSH);
+}
+
+static struct usb_ep_ops net2272_ep_ops = {
+	.enable        = net2272_enable,
+	.disable       = net2272_disable,
+
+	.alloc_request = net2272_alloc_request,
+	.free_request  = net2272_free_request,
+
+	.queue         = net2272_queue,
+	.dequeue       = net2272_dequeue,
+
+	.set_halt      = net2272_set_halt,
+	.set_wedge     = net2272_set_wedge,
+	.fifo_status   = net2272_fifo_status,
+	.fifo_flush    = net2272_fifo_flush,
+};
+
+/*---------------------------------------------------------------------------*/
+
+static int
+net2272_get_frame(struct usb_gadget *_gadget)
+{
+	struct net2272 *dev;
+	unsigned long flags;
+	u16 ret;
+
+	if (!_gadget)
+		return -ENODEV;
+	dev = container_of(_gadget, struct net2272, gadget);
+	spin_lock_irqsave(&dev->lock, flags);
+
+	ret = net2272_read(dev, FRAME1) << 8;
+	ret |= net2272_read(dev, FRAME0);
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+	return ret;
+}
+
+static int
+net2272_wakeup(struct usb_gadget *_gadget)
+{
+	struct net2272 *dev;
+	u8 tmp;
+	unsigned long flags;
+
+	if (!_gadget)
+		return 0;
+	dev = container_of(_gadget, struct net2272, gadget);
+
+	spin_lock_irqsave(&dev->lock, flags);
+	tmp = net2272_read(dev, USBCTL0);
+	if (tmp & (1 << IO_WAKEUP_ENABLE))
+		net2272_write(dev, USBCTL1, (1 << GENERATE_RESUME));
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return 0;
+}
+
+static int
+net2272_set_selfpowered(struct usb_gadget *_gadget, int value)
+{
+	struct net2272 *dev;
+
+	if (!_gadget)
+		return -ENODEV;
+	dev = container_of(_gadget, struct net2272, gadget);
+
+	dev->is_selfpowered = value;
+
+	return 0;
+}
+
+static int
+net2272_pullup(struct usb_gadget *_gadget, int is_on)
+{
+	struct net2272 *dev;
+	u8 tmp;
+	unsigned long flags;
+
+	if (!_gadget)
+		return -ENODEV;
+	dev = container_of(_gadget, struct net2272, gadget);
+
+	spin_lock_irqsave(&dev->lock, flags);
+	tmp = net2272_read(dev, USBCTL0);
+	dev->softconnect = (is_on != 0);
+	if (is_on)
+		tmp |= (1 << USB_DETECT_ENABLE);
+	else
+		tmp &= ~(1 << USB_DETECT_ENABLE);
+	net2272_write(dev, USBCTL0, tmp);
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	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 const struct usb_gadget_ops net2272_ops = {
+	.get_frame       = net2272_get_frame,
+	.wakeup          = net2272_wakeup,
+	.set_selfpowered = net2272_set_selfpowered,
+	.pullup			= net2272_pullup,
+	.start			= net2272_start,
+	.stop			= net2272_stop,
+};
+
+/*---------------------------------------------------------------------------*/
+
+static ssize_t
+net2272_show_registers(struct device *_dev, struct device_attribute *attr, char *buf)
+{
+	struct net2272 *dev;
+	char *next;
+	unsigned size, t;
+	unsigned long flags;
+	u8 t1, t2;
+	int i;
+	const char *s;
+
+	dev = dev_get_drvdata(_dev);
+	next = buf;
+	size = PAGE_SIZE;
+	spin_lock_irqsave(&dev->lock, flags);
+
+	if (dev->driver)
+		s = dev->driver->driver.name;
+	else
+		s = "(none)";
+
+	/* Main Control Registers */
+	t = scnprintf(next, size, "%s version %s,"
+		"chiprev %02x, locctl %02x\n"
+		"irqenb0 %02x irqenb1 %02x "
+		"irqstat0 %02x irqstat1 %02x\n",
+		driver_name, driver_vers, dev->chiprev,
+		net2272_read(dev, LOCCTL),
+		net2272_read(dev, IRQENB0),
+		net2272_read(dev, IRQENB1),
+		net2272_read(dev, IRQSTAT0),
+		net2272_read(dev, IRQSTAT1));
+	size -= t;
+	next += t;
+
+	/* DMA */
+	t1 = net2272_read(dev, DMAREQ);
+	t = scnprintf(next, size, "\ndmareq %02x: %s %s%s%s%s\n",
+		t1, ep_name[(t1 & 0x01) + 1],
+		t1 & (1 << DMA_CONTROL_DACK) ? "dack " : "",
+		t1 & (1 << DMA_REQUEST_ENABLE) ? "reqenb " : "",
+		t1 & (1 << DMA_REQUEST) ? "req " : "",
+		t1 & (1 << DMA_BUFFER_VALID) ? "valid " : "");
+	size -= t;
+	next += t;
+
+	/* USB Control Registers */
+	t1 = net2272_read(dev, USBCTL1);
+	if (t1 & (1 << VBUS_PIN)) {
+		if (t1 & (1 << USB_HIGH_SPEED))
+			s = "high speed";
+		else if (dev->gadget.speed == USB_SPEED_UNKNOWN)
+			s = "powered";
+		else
+			s = "full speed";
+	} else
+		s = "not attached";
+	t = scnprintf(next, size,
+		"usbctl0 %02x usbctl1 %02x addr 0x%02x (%s)\n",
+		net2272_read(dev, USBCTL0), t1,
+		net2272_read(dev, OURADDR), s);
+	size -= t;
+	next += t;
+
+	/* Endpoint Registers */
+	for (i = 0; i < 4; ++i) {
+		struct net2272_ep *ep;
+
+		ep = &dev->ep[i];
+		if (i && !ep->desc)
+			continue;
+
+		t1 = net2272_ep_read(ep, EP_CFG);
+		t2 = net2272_ep_read(ep, EP_RSPSET);
+		t = scnprintf(next, size,
+			"\n%s\tcfg %02x rsp (%02x) %s%s%s%s%s%s%s%s"
+			"irqenb %02x\n",
+			ep->ep.name, t1, t2,
+			(t2 & (1 << ALT_NAK_OUT_PACKETS)) ? "NAK " : "",
+			(t2 & (1 << HIDE_STATUS_PHASE)) ? "hide " : "",
+			(t2 & (1 << AUTOVALIDATE)) ? "auto " : "",
+			(t2 & (1 << INTERRUPT_MODE)) ? "interrupt " : "",
+			(t2 & (1 << CONTROL_STATUS_PHASE_HANDSHAKE)) ? "status " : "",
+			(t2 & (1 << NAK_OUT_PACKETS_MODE)) ? "NAKmode " : "",
+			(t2 & (1 << ENDPOINT_TOGGLE)) ? "DATA1 " : "DATA0 ",
+			(t2 & (1 << ENDPOINT_HALT)) ? "HALT " : "",
+			net2272_ep_read(ep, EP_IRQENB));
+		size -= t;
+		next += t;
+
+		t = scnprintf(next, size,
+			"\tstat0 %02x stat1 %02x avail %04x "
+			"(ep%d%s-%s)%s\n",
+			net2272_ep_read(ep, EP_STAT0),
+			net2272_ep_read(ep, EP_STAT1),
+			(net2272_ep_read(ep, EP_AVAIL1) << 8) | net2272_ep_read(ep, EP_AVAIL0),
+			t1 & 0x0f,
+			ep->is_in ? "in" : "out",
+			type_string(t1 >> 5),
+			ep->stopped ? "*" : "");
+		size -= t;
+		next += t;
+
+		t = scnprintf(next, size,
+			"\tep_transfer %06x\n",
+			((net2272_ep_read(ep, EP_TRANSFER2) & 0xff) << 16) |
+			((net2272_ep_read(ep, EP_TRANSFER1) & 0xff) << 8) |
+			((net2272_ep_read(ep, EP_TRANSFER0) & 0xff)));
+		size -= t;
+		next += t;
+
+		t1 = net2272_ep_read(ep, EP_BUFF_STATES) & 0x03;
+		t2 = (net2272_ep_read(ep, EP_BUFF_STATES) >> 2) & 0x03;
+		t = scnprintf(next, size,
+			"\tbuf-a %s buf-b %s\n",
+			buf_state_string(t1),
+			buf_state_string(t2));
+		size -= t;
+		next += t;
+	}
+
+	spin_unlock_irqrestore(&dev->lock, flags);
+
+	return PAGE_SIZE - size;
+}
+static DEVICE_ATTR(registers, S_IRUGO, net2272_show_registers, NULL);
+
+/*---------------------------------------------------------------------------*/
+
+static void
+net2272_set_fifo_mode(struct net2272 *dev, int mode)
+{
+	u8 tmp;
+
+	tmp = net2272_read(dev, LOCCTL) & 0x3f;
+	tmp |= (mode << 6);
+	net2272_write(dev, LOCCTL, tmp);
+
+	INIT_LIST_HEAD(&dev->gadget.ep_list);
+
+	/* always ep-a, ep-c ... maybe not ep-b */
+	list_add_tail(&dev->ep[1].ep.ep_list, &dev->gadget.ep_list);
+
+	switch (mode) {
+	case 0:
+		list_add_tail(&dev->ep[2].ep.ep_list, &dev->gadget.ep_list);
+		dev->ep[1].fifo_size = dev->ep[2].fifo_size = 512;
+		break;
+	case 1:
+		list_add_tail(&dev->ep[2].ep.ep_list, &dev->gadget.ep_list);
+		dev->ep[1].fifo_size = 1024;
+		dev->ep[2].fifo_size = 512;
+		break;
+	case 2:
+		list_add_tail(&dev->ep[2].ep.ep_list, &dev->gadget.ep_list);
+		dev->ep[1].fifo_size = dev->ep[2].fifo_size = 1024;
+		break;
+	case 3:
+		dev->ep[1].fifo_size = 1024;
+		break;
+	}
+
+	/* ep-c is always 2 512 byte buffers */
+	list_add_tail(&dev->ep[3].ep.ep_list, &dev->gadget.ep_list);
+	dev->ep[3].fifo_size = 512;
+}
+
+/*---------------------------------------------------------------------------*/
+
+static struct net2272 *the_controller;
+
+static void
+net2272_usb_reset(struct net2272 *dev)
+{
+	dev->gadget.speed = USB_SPEED_UNKNOWN;
+
+	net2272_cancel_dma(dev);
+
+	net2272_write(dev, IRQENB0, 0);
+	net2272_write(dev, IRQENB1, 0);
+
+	/* clear irq state */
+	net2272_write(dev, IRQSTAT0, 0xff);
+	net2272_write(dev, IRQSTAT1, ~(1 << SUSPEND_REQUEST_INTERRUPT));
+
+	net2272_write(dev, DMAREQ,
+		(0 << DMA_BUFFER_VALID) |
+		(0 << DMA_REQUEST_ENABLE) |
+		(1 << DMA_CONTROL_DACK) |
+		(dev->dma_eot_polarity << EOT_POLARITY) |
+		(dev->dma_dack_polarity << DACK_POLARITY) |
+		(dev->dma_dreq_polarity << DREQ_POLARITY) |
+		((dma_ep >> 1) << DMA_ENDPOINT_SELECT));
+
+	net2272_cancel_dma(dev);
+	net2272_set_fifo_mode(dev, (fifo_mode <= 3) ? fifo_mode : 0);
+
+	/* Set the NET2272 ep fifo data width to 16-bit mode and for correct byte swapping
+	 * note that the higher level gadget drivers are expected to convert data to little endian.
+	 * Enable byte swap for your local bus/cpu if needed by setting BYTE_SWAP in LOCCTL here
+	 */
+	net2272_write(dev, LOCCTL, net2272_read(dev, LOCCTL) | (1 << DATA_WIDTH));
+	net2272_write(dev, LOCCTL1, (dma_mode << DMA_MODE));
+}
+
+static void
+net2272_usb_reinit(struct net2272 *dev)
+{
+	int i;
+
+	/* basic endpoint init */
+	for (i = 0; i < 4; ++i) {
+		struct net2272_ep *ep = &dev->ep[i];
+
+		ep->ep.name = ep_name[i];
+		ep->dev = dev;
+		ep->num = i;
+		ep->not_empty = 0;
+
+		if (use_dma && ep->num == dma_ep)
+			ep->dma = 1;
+
+		if (i > 0 && i <= 3)
+			ep->fifo_size = 512;
+		else
+			ep->fifo_size = 64;
+		net2272_ep_reset(ep);
+	}
+	dev->ep[0].ep.maxpacket = 64;
+
+	dev->gadget.ep0 = &dev->ep[0].ep;
+	dev->ep[0].stopped = 0;
+	INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
+}
+
+static void
+net2272_ep0_start(struct net2272 *dev)
+{
+	struct net2272_ep *ep0 = &dev->ep[0];
+
+	net2272_ep_write(ep0, EP_RSPSET,
+		(1 << NAK_OUT_PACKETS_MODE) |
+		(1 << ALT_NAK_OUT_PACKETS));
+	net2272_ep_write(ep0, EP_RSPCLR,
+		(1 << HIDE_STATUS_PHASE) |
+		(1 << CONTROL_STATUS_PHASE_HANDSHAKE));
+	net2272_write(dev, USBCTL0,
+		(dev->softconnect << USB_DETECT_ENABLE) |
+		(1 << USB_ROOT_PORT_WAKEUP_ENABLE) |
+		(1 << IO_WAKEUP_ENABLE));
+	net2272_write(dev, IRQENB0,
+		(1 << SETUP_PACKET_INTERRUPT_ENABLE) |
+		(1 << ENDPOINT_0_INTERRUPT_ENABLE) |
+		(1 << DMA_DONE_INTERRUPT_ENABLE));
+	net2272_write(dev, IRQENB1,
+		(1 << VBUS_INTERRUPT_ENABLE) |
+		(1 << ROOT_PORT_RESET_INTERRUPT_ENABLE) |
+		(1 << SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE));
+}
+
+/* when a driver is successfully registered, it will receive
+ * control requests including set_configuration(), which enables
+ * non-control requests.  then usb traffic follows until a
+ * 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 *))
+{
+	struct net2272 *dev = the_controller;
+	int ret;
+	unsigned i;
+
+	if (!driver || !bind || !driver->unbind || !driver->setup ||
+	    driver->speed != USB_SPEED_HIGH)
+		return -EINVAL;
+	if (!dev)
+		return -ENODEV;
+	if (dev->driver)
+		return -EBUSY;
+
+	for (i = 0; i < 4; ++i)
+		dev->ep[i].irqs = 0;
+	/* hook up the driver ... */
+	dev->softconnect = 1;
+	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.
+	 */
+	net2272_ep0_start(dev);
+
+	dev_dbg(dev->dev, "%s ready\n", driver->driver.name);
+
+	return 0;
+}
+
+static void
+stop_activity(struct net2272 *dev, struct usb_gadget_driver *driver)
+{
+	int i;
+
+	/* don't disconnect if it's not connected */
+	if (dev->gadget.speed == USB_SPEED_UNKNOWN)
+		driver = NULL;
+
+	/* stop hardware; prevent new request submissions;
+	 * and kill any outstanding requests.
+	 */
+	net2272_usb_reset(dev);
+	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)
+{
+	struct net2272 *dev = the_controller;
+	unsigned long flags;
+
+	if (!dev)
+		return -ENODEV;
+	if (!driver || driver != dev->driver)
+		return -EINVAL;
+
+	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;
+
+	dev_dbg(dev->dev, "unregistered driver '%s'\n", driver->driver.name);
+	return 0;
+}
+
+/*---------------------------------------------------------------------------*/
+/* handle ep-a/ep-b dma completions */
+static void
+net2272_handle_dma(struct net2272_ep *ep)
+{
+	struct net2272_request *req;
+	unsigned len;
+	int status;
+
+	if (!list_empty(&ep->queue))
+		req = list_entry(ep->queue.next,
+				struct net2272_request, queue);
+	else
+		req = NULL;
+
+	dev_vdbg(ep->dev->dev, "handle_dma %s req %p\n", ep->ep.name, req);
+
+	/* Ensure DREQ is de-asserted */
+	net2272_write(ep->dev, DMAREQ,
+		(0 << DMA_BUFFER_VALID)
+	      | (0 << DMA_REQUEST_ENABLE)
+	      | (1 << DMA_CONTROL_DACK)
+	      | (ep->dev->dma_eot_polarity << EOT_POLARITY)
+	      | (ep->dev->dma_dack_polarity << DACK_POLARITY)
+	      | (ep->dev->dma_dreq_polarity << DREQ_POLARITY)
+	      | ((ep->dma >> 1) << DMA_ENDPOINT_SELECT));
+
+	ep->dev->dma_busy = 0;
+
+	net2272_ep_write(ep, EP_IRQENB,
+		  (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE)
+		| (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE)
+		| net2272_ep_read(ep, EP_IRQENB));
+
+	/* device-to-host transfer completed */
+	if (ep->is_in) {
+		/* validate a short packet or zlp if necessary */
+		if ((req->req.length % ep->ep.maxpacket != 0) ||
+				req->req.zero)
+			set_fifo_bytecount(ep, 0);
+
+		net2272_done(ep, req, 0);
+		if (!list_empty(&ep->queue)) {
+			req = list_entry(ep->queue.next,
+					struct net2272_request, queue);
+			status = net2272_kick_dma(ep, req);
+			if (status < 0)
+				net2272_pio_advance(ep);
+		}
+
+	/* host-to-device transfer completed */
+	} else {
+		/* terminated with a short packet? */
+		if (net2272_read(ep->dev, IRQSTAT0) &
+				(1 << DMA_DONE_INTERRUPT)) {
+			/* abort system dma */
+			net2272_cancel_dma(ep->dev);
+		}
+
+		/* EP_TRANSFER will contain the number of bytes
+		 * actually received.
+		 * NOTE: There is no overflow detection on EP_TRANSFER:
+		 * We can't deal with transfers larger than 2^24 bytes!
+		 */
+		len = (net2272_ep_read(ep, EP_TRANSFER2) << 16)
+			| (net2272_ep_read(ep, EP_TRANSFER1) << 8)
+			| (net2272_ep_read(ep, EP_TRANSFER0));
+
+		if (ep->not_empty)
+			len += 4;
+
+		req->req.actual += len;
+
+		/* get any remaining data */
+		net2272_pio_advance(ep);
+	}
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void
+net2272_handle_ep(struct net2272_ep *ep)
+{
+	struct net2272_request *req;
+	u8 stat0, stat1;
+
+	if (!list_empty(&ep->queue))
+		req = list_entry(ep->queue.next,
+			struct net2272_request, queue);
+	else
+		req = NULL;
+
+	/* ack all, and handle what we care about */
+	stat0 = net2272_ep_read(ep, EP_STAT0);
+	stat1 = net2272_ep_read(ep, EP_STAT1);
+	ep->irqs++;
+
+	dev_vdbg(ep->dev->dev, "%s ack ep_stat0 %02x, ep_stat1 %02x, req %p\n",
+		ep->ep.name, stat0, stat1, req ? &req->req : 0);
+
+	net2272_ep_write(ep, EP_STAT0, stat0 &
+		~((1 << NAK_OUT_PACKETS)
+		| (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT)));
+	net2272_ep_write(ep, EP_STAT1, stat1);
+
+	/* data packet(s) received (in the fifo, OUT)
+	 * direction must be validated, otherwise control read status phase
+	 * could be interpreted as a valid packet
+	 */
+	if (!ep->is_in && (stat0 & (1 << DATA_PACKET_RECEIVED_INTERRUPT)))
+		net2272_pio_advance(ep);
+	/* data packet(s) transmitted (IN) */
+	else if (stat0 & (1 << DATA_PACKET_TRANSMITTED_INTERRUPT))
+		net2272_pio_advance(ep);
+}
+
+static struct net2272_ep *
+net2272_get_ep_by_addr(struct net2272 *dev, u16 wIndex)
+{
+	struct net2272_ep *ep;
+
+	if ((wIndex & USB_ENDPOINT_NUMBER_MASK) == 0)
+		return &dev->ep[0];
+
+	list_for_each_entry(ep, &dev->gadget.ep_list, ep.ep_list) {
+		u8 bEndpointAddress;
+
+		if (!ep->desc)
+			continue;
+		bEndpointAddress = ep->desc->bEndpointAddress;
+		if ((wIndex ^ bEndpointAddress) & USB_DIR_IN)
+			continue;
+		if ((wIndex & 0x0f) == (bEndpointAddress & 0x0f))
+			return ep;
+	}
+	return NULL;
+}
+
+/*
+ * USB Test Packet:
+ * JKJKJKJK * 9
+ * JJKKJJKK * 8
+ * JJJJKKKK * 8
+ * JJJJJJJKKKKKKK * 8
+ * JJJJJJJK * 8
+ * {JKKKKKKK * 10}, JK
+ */
+static const u8 net2272_test_packet[] = {
+	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+	0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+	0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE, 0xEE,
+	0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD,
+	0xFC, 0x7E, 0xBF, 0xDF, 0xEF, 0xF7, 0xFD, 0x7E
+};
+
+static void
+net2272_set_test_mode(struct net2272 *dev, int mode)
+{
+	int i;
+
+	/* Disable all net2272 interrupts:
+	 * Nothing but a power cycle should stop the test.
+	 */
+	net2272_write(dev, IRQENB0, 0x00);
+	net2272_write(dev, IRQENB1, 0x00);
+
+	/* Force tranceiver to high-speed */
+	net2272_write(dev, XCVRDIAG, 1 << FORCE_HIGH_SPEED);
+
+	net2272_write(dev, PAGESEL, 0);
+	net2272_write(dev, EP_STAT0, 1 << DATA_PACKET_TRANSMITTED_INTERRUPT);
+	net2272_write(dev, EP_RSPCLR,
+			  (1 << CONTROL_STATUS_PHASE_HANDSHAKE)
+			| (1 << HIDE_STATUS_PHASE));
+	net2272_write(dev, EP_CFG, 1 << ENDPOINT_DIRECTION);
+	net2272_write(dev, EP_STAT1, 1 << BUFFER_FLUSH);
+
+	/* wait for status phase to complete */
+	while (!(net2272_read(dev, EP_STAT0) &
+				(1 << DATA_PACKET_TRANSMITTED_INTERRUPT)))
+		;
+
+	/* Enable test mode */
+	net2272_write(dev, USBTEST, mode);
+
+	/* load test packet */
+	if (mode == TEST_PACKET) {
+		/* switch to 8 bit mode */
+		net2272_write(dev, LOCCTL, net2272_read(dev, LOCCTL) &
+				~(1 << DATA_WIDTH));
+
+		for (i = 0; i < sizeof(net2272_test_packet); ++i)
+			net2272_write(dev, EP_DATA, net2272_test_packet[i]);
+
+		/* Validate test packet */
+		net2272_write(dev, EP_TRANSFER0, 0);
+	}
+}
+
+static void
+net2272_handle_stat0_irqs(struct net2272 *dev, u8 stat)
+{
+	struct net2272_ep *ep;
+	u8 num, scratch;
+
+	/* starting a control request? */
+	if (unlikely(stat & (1 << SETUP_PACKET_INTERRUPT))) {
+		union {
+			u8 raw[8];
+			struct usb_ctrlrequest	r;
+		} u;
+		int tmp = 0;
+		struct net2272_request *req;
+
+		if (dev->gadget.speed == USB_SPEED_UNKNOWN) {
+			if (net2272_read(dev, USBCTL1) & (1 << USB_HIGH_SPEED))
+				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");
+		}
+
+		ep = &dev->ep[0];
+		ep->irqs++;
+
+		/* make sure any leftover interrupt state is cleared */
+		stat &= ~(1 << ENDPOINT_0_INTERRUPT);
+		while (!list_empty(&ep->queue)) {
+			req = list_entry(ep->queue.next,
+				struct net2272_request, queue);
+			net2272_done(ep, req,
+				(req->req.actual == req->req.length) ? 0 : -EPROTO);
+		}
+		ep->stopped = 0;
+		dev->protocol_stall = 0;
+		net2272_ep_write(ep, EP_STAT0,
+			    (1 << DATA_IN_TOKEN_INTERRUPT)
+			  | (1 << DATA_OUT_TOKEN_INTERRUPT)
+			  | (1 << DATA_PACKET_TRANSMITTED_INTERRUPT)
+			  | (1 << DATA_PACKET_RECEIVED_INTERRUPT)
+			  | (1 << SHORT_PACKET_TRANSFERRED_INTERRUPT));
+		net2272_ep_write(ep, EP_STAT1,
+			    (1 << TIMEOUT)
+			  | (1 << USB_OUT_ACK_SENT)
+			  | (1 << USB_OUT_NAK_SENT)
+			  | (1 << USB_IN_ACK_RCVD)
+			  | (1 << USB_IN_NAK_SENT)
+			  | (1 << USB_STALL_SENT)
+			  | (1 << LOCAL_OUT_ZLP));
+
+		/*
+		 * Ensure Control Read pre-validation setting is beyond maximum size
+		 *  - Control Writes can leave non-zero values in EP_TRANSFER. If
+		 *    an EP0 transfer following the Control Write is a Control Read,
+		 *    the NET2272 sees the non-zero EP_TRANSFER as an unexpected
+		 *    pre-validation count.
+		 *  - Setting EP_TRANSFER beyond the maximum EP0 transfer size ensures
+		 *    the pre-validation count cannot cause an unexpected validatation
+		 */
+		net2272_write(dev, PAGESEL, 0);
+		net2272_write(dev, EP_TRANSFER2, 0xff);
+		net2272_write(dev, EP_TRANSFER1, 0xff);
+		net2272_write(dev, EP_TRANSFER0, 0xff);
+
+		u.raw[0] = net2272_read(dev, SETUP0);
+		u.raw[1] = net2272_read(dev, SETUP1);
+		u.raw[2] = net2272_read(dev, SETUP2);
+		u.raw[3] = net2272_read(dev, SETUP3);
+		u.raw[4] = net2272_read(dev, SETUP4);
+		u.raw[5] = net2272_read(dev, SETUP5);
+		u.raw[6] = net2272_read(dev, SETUP6);
+		u.raw[7] = net2272_read(dev, SETUP7);
+		/*
+		 * If you have a big endian cpu make sure le16_to_cpus
+		 * performs the proper byte swapping here...
+		 */
+		le16_to_cpus(&u.r.wValue);
+		le16_to_cpus(&u.r.wIndex);
+		le16_to_cpus(&u.r.wLength);
+
+		/* ack the irq */
+		net2272_write(dev, IRQSTAT0, 1 << SETUP_PACKET_INTERRUPT);
+		stat ^= (1 << SETUP_PACKET_INTERRUPT);
+
+		/* watch control traffic at the token level, and force
+		 * synchronization before letting the status phase happen.
+		 */
+		ep->is_in = (u.r.bRequestType & USB_DIR_IN) != 0;
+		if (ep->is_in) {
+			scratch = (1 << DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE)
+				| (1 << DATA_OUT_TOKEN_INTERRUPT_ENABLE)
+				| (1 << DATA_IN_TOKEN_INTERRUPT_ENABLE);
+			stop_out_naking(ep);
+		} else
+			scratch = (1 << DATA_PACKET_RECEIVED_INTERRUPT_ENABLE)
+				| (1 << DATA_OUT_TOKEN_INTERRUPT_ENABLE)
+				| (1 << DATA_IN_TOKEN_INTERRUPT_ENABLE);
+		net2272_ep_write(ep, EP_IRQENB, scratch);
+
+		if ((u.r.bRequestType & USB_TYPE_MASK) != USB_TYPE_STANDARD)
+			goto delegate;
+		switch (u.r.bRequest) {
+		case USB_REQ_GET_STATUS: {
+			struct net2272_ep *e;
+			u16 status = 0;
+
+			switch (u.r.bRequestType & USB_RECIP_MASK) {
+			case USB_RECIP_ENDPOINT:
+				e = net2272_get_ep_by_addr(dev, u.r.wIndex);
+				if (!e || u.r.wLength > 2)
+					goto do_stall;
+				if (net2272_ep_read(e, EP_RSPSET) & (1 << ENDPOINT_HALT))
+					status = __constant_cpu_to_le16(1);
+				else
+					status = __constant_cpu_to_le16(0);
+
+				/* don't bother with a request object! */
+				net2272_ep_write(&dev->ep[0], EP_IRQENB, 0);
+				writew(status, net2272_reg_addr(dev, EP_DATA));
+				set_fifo_bytecount(&dev->ep[0], 0);
+				allow_status(ep);
+				dev_vdbg(dev->dev, "%s stat %02x\n",
+					ep->ep.name, status);
+				goto next_endpoints;
+			case USB_RECIP_DEVICE:
+				if (u.r.wLength > 2)
+					goto do_stall;
+				if (dev->is_selfpowered)
+					status = (1 << USB_DEVICE_SELF_POWERED);
+
+				/* don't bother with a request object! */
+				net2272_ep_write(&dev->ep[0], EP_IRQENB, 0);
+				writew(status, net2272_reg_addr(dev, EP_DATA));
+				set_fifo_bytecount(&dev->ep[0], 0);
+				allow_status(ep);
+				dev_vdbg(dev->dev, "device stat %02x\n", status);
+				goto next_endpoints;
+			case USB_RECIP_INTERFACE:
+				if (u.r.wLength > 2)
+					goto do_stall;
+
+				/* don't bother with a request object! */
+				net2272_ep_write(&dev->ep[0], EP_IRQENB, 0);
+				writew(status, net2272_reg_addr(dev, EP_DATA));
+				set_fifo_bytecount(&dev->ep[0], 0);
+				allow_status(ep);
+				dev_vdbg(dev->dev, "interface status %02x\n", status);
+				goto next_endpoints;
+			}
+
+			break;
+		}
+		case USB_REQ_CLEAR_FEATURE: {
+			struct net2272_ep *e;
+
+			if (u.r.bRequestType != USB_RECIP_ENDPOINT)
+				goto delegate;
+			if (u.r.wValue != USB_ENDPOINT_HALT ||
+			    u.r.wLength != 0)
+				goto do_stall;
+			e = net2272_get_ep_by_addr(dev, u.r.wIndex);
+			if (!e)
+				goto do_stall;
+			if (e->wedged) {
+				dev_vdbg(dev->dev, "%s wedged, halt not cleared\n",
+					ep->ep.name);
+			} else {
+				dev_vdbg(dev->dev, "%s clear halt\n", ep->ep.name);
+				clear_halt(e);
+			}
+			allow_status(ep);
+			goto next_endpoints;
+		}
+		case USB_REQ_SET_FEATURE: {
+			struct net2272_ep *e;
+
+			if (u.r.bRequestType == USB_RECIP_DEVICE) {
+				if (u.r.wIndex != NORMAL_OPERATION)
+					net2272_set_test_mode(dev, (u.r.wIndex >> 8));
+				allow_status(ep);
+				dev_vdbg(dev->dev, "test mode: %d\n", u.r.wIndex);
+				goto next_endpoints;
+			} else if (u.r.bRequestType != USB_RECIP_ENDPOINT)
+				goto delegate;
+			if (u.r.wValue != USB_ENDPOINT_HALT ||
+			    u.r.wLength != 0)
+				goto do_stall;
+			e = net2272_get_ep_by_addr(dev, u.r.wIndex);
+			if (!e)
+				goto do_stall;
+			set_halt(e);
+			allow_status(ep);
+			dev_vdbg(dev->dev, "%s set halt\n", ep->ep.name);
+			goto next_endpoints;
+		}
+		case USB_REQ_SET_ADDRESS: {
+			net2272_write(dev, OURADDR, u.r.wValue & 0xff);
+			allow_status(ep);
+			break;
+		}
+		default:
+ delegate:
+			dev_vdbg(dev->dev, "setup %02x.%02x v%04x i%04x "
+				"ep_cfg %08x\n",
+				u.r.bRequestType, u.r.bRequest,
+				u.r.wValue, u.r.wIndex,
+				net2272_ep_read(ep, EP_CFG));
+			spin_unlock(&dev->lock);
+			tmp = dev->driver->setup(&dev->gadget, &u.r);
+			spin_lock(&dev->lock);
+		}
+
+		/* stall ep0 on error */
+		if (tmp < 0) {
+ do_stall:
+			dev_vdbg(dev->dev, "req %02x.%02x protocol STALL; stat %d\n",
+				u.r.bRequestType, u.r.bRequest, tmp);
+			dev->protocol_stall = 1;
+		}
+	/* endpoint dma irq? */
+	} else if (stat & (1 << DMA_DONE_INTERRUPT)) {
+		net2272_cancel_dma(dev);
+		net2272_write(dev, IRQSTAT0, 1 << DMA_DONE_INTERRUPT);
+		stat &= ~(1 << DMA_DONE_INTERRUPT);
+		num = (net2272_read(dev, DMAREQ) & (1 << DMA_ENDPOINT_SELECT))
+			? 2 : 1;
+
+		ep = &dev->ep[num];
+		net2272_handle_dma(ep);
+	}
+
+ next_endpoints:
+	/* endpoint data irq? */
+	scratch = stat & 0x0f;
+	stat &= ~0x0f;
+	for (num = 0; scratch; num++) {
+		u8 t;
+
+		/* does this endpoint's FIFO and queue need tending? */
+		t = 1 << num;
+		if ((scratch & t) == 0)
+			continue;
+		scratch ^= t;
+
+		ep = &dev->ep[num];
+		net2272_handle_ep(ep);
+	}
+
+	/* some interrupts we can just ignore */
+	stat &= ~(1 << SOF_INTERRUPT);
+
+	if (stat)
+		dev_dbg(dev->dev, "unhandled irqstat0 %02x\n", stat);
+}
+
+static void
+net2272_handle_stat1_irqs(struct net2272 *dev, u8 stat)
+{
+	u8 tmp, mask;
+
+	/* after disconnect there's nothing else to do! */
+	tmp = (1 << VBUS_INTERRUPT) | (1 << ROOT_PORT_RESET_INTERRUPT);
+	mask = (1 << USB_HIGH_SPEED) | (1 << USB_FULL_SPEED);
+
+	if (stat & tmp) {
+		net2272_write(dev, IRQSTAT1, tmp);
+		if ((((stat & (1 << ROOT_PORT_RESET_INTERRUPT)) &&
+				((net2272_read(dev, USBCTL1) & mask) == 0))
+			|| ((net2272_read(dev, USBCTL1) & (1 << VBUS_PIN))
+				== 0))
+				&& (dev->gadget.speed != USB_SPEED_UNKNOWN)) {
+			dev_dbg(dev->dev, "disconnect %s\n",
+				dev->driver->driver.name);
+			stop_activity(dev, dev->driver);
+			net2272_ep0_start(dev);
+			return;
+		}
+		stat &= ~tmp;
+
+		if (!stat)
+			return;
+	}
+
+	tmp = (1 << SUSPEND_REQUEST_CHANGE_INTERRUPT);
+	if (stat & tmp) {
+		net2272_write(dev, IRQSTAT1, tmp);
+		if (stat & (1 << SUSPEND_REQUEST_INTERRUPT)) {
+			if (dev->driver->suspend)
+				dev->driver->suspend(&dev->gadget);
+			if (!enable_suspend) {
+				stat &= ~(1 << SUSPEND_REQUEST_INTERRUPT);
+				dev_dbg(dev->dev, "Suspend disabled, ignoring\n");
+			}
+		} else {
+			if (dev->driver->resume)
+				dev->driver->resume(&dev->gadget);
+		}
+		stat &= ~tmp;
+	}
+
+	/* clear any other status/irqs */
+	if (stat)
+		net2272_write(dev, IRQSTAT1, stat);
+
+	/* some status we can just ignore */
+	stat &= ~((1 << CONTROL_STATUS_INTERRUPT)
+			| (1 << SUSPEND_REQUEST_INTERRUPT)
+			| (1 << RESUME_INTERRUPT));
+	if (!stat)
+		return;
+	else
+		dev_dbg(dev->dev, "unhandled irqstat1 %02x\n", stat);
+}
+
+static irqreturn_t net2272_irq(int irq, void *_dev)
+{
+	struct net2272 *dev = _dev;
+#if defined(PLX_PCI_RDK) || defined(PLX_PCI_RDK2)
+	u32 intcsr;
+#endif
+#if defined(PLX_PCI_RDK)
+	u8 dmareq;
+#endif
+	spin_lock(&dev->lock);
+#if defined(PLX_PCI_RDK)
+	intcsr = readl(dev->rdk1.plx9054_base_addr + INTCSR);
+
+	if ((intcsr & LOCAL_INTERRUPT_TEST) == LOCAL_INTERRUPT_TEST) {
+		writel(intcsr & ~(1 << PCI_INTERRUPT_ENABLE),
+				dev->rdk1.plx9054_base_addr + INTCSR);
+		net2272_handle_stat1_irqs(dev, net2272_read(dev, IRQSTAT1));
+		net2272_handle_stat0_irqs(dev, net2272_read(dev, IRQSTAT0));
+		intcsr = readl(dev->rdk1.plx9054_base_addr + INTCSR);
+		writel(intcsr | (1 << PCI_INTERRUPT_ENABLE),
+			dev->rdk1.plx9054_base_addr + INTCSR);
+	}
+	if ((intcsr & DMA_CHANNEL_0_TEST) == DMA_CHANNEL_0_TEST) {
+		writeb((1 << CHANNEL_CLEAR_INTERRUPT | (0 << CHANNEL_ENABLE)),
+				dev->rdk1.plx9054_base_addr + DMACSR0);
+
+		dmareq = net2272_read(dev, DMAREQ);
+		if (dmareq & 0x01)
+			net2272_handle_dma(&dev->ep[2]);
+		else
+			net2272_handle_dma(&dev->ep[1]);
+	}
+#endif
+#if defined(PLX_PCI_RDK2)
+	/* see if PCI int for us by checking irqstat */
+	intcsr = readl(dev->rdk2.fpga_base_addr + RDK2_IRQSTAT);
+	if (!intcsr & (1 << NET2272_PCI_IRQ))
+		return IRQ_NONE;
+	/* check dma interrupts */
+#endif
+	/* Platform/devcice interrupt handler */
+#if !defined(PLX_PCI_RDK)
+	net2272_handle_stat1_irqs(dev, net2272_read(dev, IRQSTAT1));
+	net2272_handle_stat0_irqs(dev, net2272_read(dev, IRQSTAT0));
+#endif
+	spin_unlock(&dev->lock);
+
+	return IRQ_HANDLED;
+}
+
+static int net2272_present(struct net2272 *dev)
+{
+	/*
+	 * Quick test to see if CPU can communicate properly with the NET2272.
+	 * Verifies connection using writes and reads to write/read and
+	 * read-only registers.
+	 *
+	 * This routine is strongly recommended especially during early bring-up
+	 * of new hardware, however for designs that do not apply Power On System
+	 * Tests (POST) it may discarded (or perhaps minimized).
+	 */
+	unsigned int ii;
+	u8 val, refval;
+
+	/* Verify NET2272 write/read SCRATCH register can write and read */
+	refval = net2272_read(dev, SCRATCH);
+	for (ii = 0; ii < 0x100; ii += 7) {
+		net2272_write(dev, SCRATCH, ii);
+		val = net2272_read(dev, SCRATCH);
+		if (val != ii) {
+			dev_dbg(dev->dev,
+				"%s: write/read SCRATCH register test failed: "
+				"wrote:0x%2.2x, read:0x%2.2x\n",
+				__func__, ii, val);
+			return -EINVAL;
+		}
+	}
+	/* To be nice, we write the original SCRATCH value back: */
+	net2272_write(dev, SCRATCH, refval);
+
+	/* Verify NET2272 CHIPREV register is read-only: */
+	refval = net2272_read(dev, CHIPREV_2272);
+	for (ii = 0; ii < 0x100; ii += 7) {
+		net2272_write(dev, CHIPREV_2272, ii);
+		val = net2272_read(dev, CHIPREV_2272);
+		if (val != refval) {
+			dev_dbg(dev->dev,
+				"%s: write/read CHIPREV register test failed: "
+				"wrote 0x%2.2x, read:0x%2.2x expected:0x%2.2x\n",
+				__func__, ii, val, refval);
+			return -EINVAL;
+		}
+	}
+
+	/*
+	 * Verify NET2272's "NET2270 legacy revision" register
+	 *  - NET2272 has two revision registers. The NET2270 legacy revision
+	 *    register should read the same value, regardless of the NET2272
+	 *    silicon revision.  The legacy register applies to NET2270
+	 *    firmware being applied to the NET2272.
+	 */
+	val = net2272_read(dev, CHIPREV_LEGACY);
+	if (val != NET2270_LEGACY_REV) {
+		/*
+		 * Unexpected legacy revision value
+		 * - Perhaps the chip is a NET2270?
+		 */
+		dev_dbg(dev->dev,
+			"%s: WARNING: UNEXPECTED NET2272 LEGACY REGISTER VALUE:\n"
+			" - CHIPREV_LEGACY: expected 0x%2.2x, got:0x%2.2x. (Not NET2272?)\n",
+			__func__, NET2270_LEGACY_REV, val);
+		return -EINVAL;
+	}
+
+	/*
+	 * Verify NET2272 silicon revision
+	 *  - This revision register is appropriate for the silicon version
+	 *    of the NET2272
+	 */
+	val = net2272_read(dev, CHIPREV_2272);
+	switch (val) {
+	case CHIPREV_NET2272_R1:
+		/*
+		 * NET2272 Rev 1 has DMA related errata:
+		 *  - Newer silicon (Rev 1A or better) required
+		 */
+		dev_dbg(dev->dev,
+			"%s: Rev 1 detected: newer silicon recommended for DMA support\n",
+			__func__);
+		break;
+	case CHIPREV_NET2272_R1A:
+		break;
+	default:
+		/* NET2272 silicon version *may* not work with this firmware */
+		dev_dbg(dev->dev,
+			"%s: unexpected silicon revision register value: "
+			" CHIPREV_2272: 0x%2.2x\n",
+			__func__, val);
+		/*
+		 * Return Success, even though the chip rev is not an expected value
+		 *  - Older, pre-built firmware can attempt to operate on newer silicon
+		 *  - Often, new silicon is perfectly compatible
+		 */
+	}
+
+	/* Success: NET2272 checks out OK */
+	return 0;
+}
+
+static void
+net2272_gadget_release(struct device *_dev)
+{
+	struct net2272 *dev = dev_get_drvdata(_dev);
+	kfree(dev);
+}
+
+/*---------------------------------------------------------------------------*/
+
+static void __devexit
+net2272_remove(struct net2272 *dev)
+{
+	usb_del_gadget_udc(&dev->gadget);
+
+	/* start with the driver above us */
+	if (dev->driver) {
+		/* should have been done already by driver model core */
+		dev_warn(dev->dev, "pci remove, driver '%s' is still registered\n",
+			dev->driver->driver.name);
+		usb_gadget_unregister_driver(dev->driver);
+	}
+
+	free_irq(dev->irq, dev);
+	iounmap(dev->base_addr);
+
+	device_unregister(&dev->gadget.dev);
+	device_remove_file(dev->dev, &dev_attr_registers);
+
+	dev_info(dev->dev, "unbind\n");
+	the_controller = NULL;
+}
+
+static struct net2272 * __devinit
+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);
+	}
+
+	/* alloc, and start init */
+	ret = kzalloc(sizeof(*ret), GFP_KERNEL);
+	if (!ret)
+		return ERR_PTR(-ENOMEM);
+
+	spin_lock_init(&ret->lock);
+	ret->irq = irq;
+	ret->dev = dev;
+	ret->gadget.ops = &net2272_ops;
+	ret->gadget.is_dualspeed = 1;
+
+	/* the "gadget" abstracts/virtualizes the controller */
+	dev_set_name(&ret->gadget.dev, "gadget");
+	ret->gadget.dev.parent = dev;
+	ret->gadget.dev.dma_mask = dev->dma_mask;
+	ret->gadget.dev.release = net2272_gadget_release;
+	ret->gadget.name = driver_name;
+
+	return ret;
+}
+
+static int __devinit
+net2272_probe_fin(struct net2272 *dev, unsigned int irqflags)
+{
+	int ret;
+
+	/* See if there... */
+	if (net2272_present(dev)) {
+		dev_warn(dev->dev, "2272 not found!\n");
+		ret = -ENODEV;
+		goto err;
+	}
+
+	net2272_usb_reset(dev);
+	net2272_usb_reinit(dev);
+
+	ret = request_irq(dev->irq, net2272_irq, irqflags, driver_name, dev);
+	if (ret) {
+		dev_err(dev->dev, "request interrupt %i failed\n", dev->irq);
+		goto err;
+	}
+
+	dev->chiprev = net2272_read(dev, CHIPREV_2272);
+
+	/* done */
+	dev_info(dev->dev, "%s\n", driver_desc);
+	dev_info(dev->dev, "irq %i, mem %p, chip rev %04x, dma %s\n",
+		dev->irq, dev->base_addr, dev->chiprev,
+		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;
+	ret = device_create_file(dev->dev, &dev_attr_registers);
+	if (ret)
+		goto err_dev_reg;
+
+	ret = usb_add_gadget_udc(dev->dev, &dev->gadget);
+	if (ret)
+		goto err_add_udc;
+
+	return 0;
+
+err_add_udc:
+	device_remove_file(dev->dev, &dev_attr_registers);
+ err_dev_reg:
+	device_unregister(&dev->gadget.dev);
+ err_irq:
+	free_irq(dev->irq, dev);
+ err:
+	return ret;
+}
+
+#ifdef CONFIG_PCI
+
+/*
+ * wrap this driver around the specified device, but
+ * don't respond over USB until a gadget driver binds to us
+ */
+
+static int __devinit
+net2272_rdk1_probe(struct pci_dev *pdev, struct net2272 *dev)
+{
+	unsigned long resource, len, tmp;
+	void __iomem *mem_mapped_addr[4];
+	int ret, i;
+
+	/*
+	 * BAR 0 holds PLX 9054 config registers
+	 * BAR 1 is i/o memory; unused here
+	 * BAR 2 holds EPLD config registers
+	 * BAR 3 holds NET2272 registers
+	 */
+
+	/* Find and map all address spaces */
+	for (i = 0; i < 4; ++i) {
+		if (i == 1)
+			continue;	/* BAR1 unused */
+
+		resource = pci_resource_start(pdev, i);
+		len = pci_resource_len(pdev, i);
+
+		if (!request_mem_region(resource, len, driver_name)) {
+			dev_dbg(dev->dev, "controller already in use\n");
+			ret = -EBUSY;
+			goto err;
+		}
+
+		mem_mapped_addr[i] = ioremap_nocache(resource, len);
+		if (mem_mapped_addr[i] == NULL) {
+			release_mem_region(resource, len);
+			dev_dbg(dev->dev, "can't map memory\n");
+			ret = -EFAULT;
+			goto err;
+		}
+	}
+
+	dev->rdk1.plx9054_base_addr = mem_mapped_addr[0];
+	dev->rdk1.epld_base_addr = mem_mapped_addr[2];
+	dev->base_addr = mem_mapped_addr[3];
+
+	/* Set PLX 9054 bus width (16 bits) */
+	tmp = readl(dev->rdk1.plx9054_base_addr + LBRD1);
+	writel((tmp & ~(3 << MEMORY_SPACE_LOCAL_BUS_WIDTH)) | W16_BIT,
+			dev->rdk1.plx9054_base_addr + LBRD1);
+
+	/* Enable PLX 9054 Interrupts */
+	writel(readl(dev->rdk1.plx9054_base_addr + INTCSR) |
+			(1 << PCI_INTERRUPT_ENABLE) |
+			(1 << LOCAL_INTERRUPT_INPUT_ENABLE),
+			dev->rdk1.plx9054_base_addr + INTCSR);
+
+	writeb((1 << CHANNEL_CLEAR_INTERRUPT | (0 << CHANNEL_ENABLE)),
+			dev->rdk1.plx9054_base_addr + DMACSR0);
+
+	/* reset */
+	writeb((1 << EPLD_DMA_ENABLE) |
+		(1 << DMA_CTL_DACK) |
+		(1 << DMA_TIMEOUT_ENABLE) |
+		(1 << USER) |
+		(0 << MPX_MODE) |
+		(1 << BUSWIDTH) |
+		(1 << NET2272_RESET),
+		dev->base_addr + EPLD_IO_CONTROL_REGISTER);
+
+	mb();
+	writeb(readb(dev->base_addr + EPLD_IO_CONTROL_REGISTER) &
+		~(1 << NET2272_RESET),
+		dev->base_addr + EPLD_IO_CONTROL_REGISTER);
+	udelay(200);
+
+	return 0;
+
+ err:
+	while (--i >= 0) {
+		iounmap(mem_mapped_addr[i]);
+		release_mem_region(pci_resource_start(pdev, i),
+			pci_resource_len(pdev, i));
+	}
+
+	return ret;
+}
+
+static int __devinit
+net2272_rdk2_probe(struct pci_dev *pdev, struct net2272 *dev)
+{
+	unsigned long resource, len;
+	void __iomem *mem_mapped_addr[2];
+	int ret, i;
+
+	/*
+	 * BAR 0 holds FGPA config registers
+	 * BAR 1 holds NET2272 registers
+	 */
+
+	/* Find and map all address spaces, bar2-3 unused in rdk 2 */
+	for (i = 0; i < 2; ++i) {
+		resource = pci_resource_start(pdev, i);
+		len = pci_resource_len(pdev, i);
+
+		if (!request_mem_region(resource, len, driver_name)) {
+			dev_dbg(dev->dev, "controller already in use\n");
+			ret = -EBUSY;
+			goto err;
+		}
+
+		mem_mapped_addr[i] = ioremap_nocache(resource, len);
+		if (mem_mapped_addr[i] == NULL) {
+			release_mem_region(resource, len);
+			dev_dbg(dev->dev, "can't map memory\n");
+			ret = -EFAULT;
+			goto err;
+		}
+	}
+
+	dev->rdk2.fpga_base_addr = mem_mapped_addr[0];
+	dev->base_addr = mem_mapped_addr[1];
+
+	mb();
+	/* Set 2272 bus width (16 bits) and reset */
+	writel((1 << CHIP_RESET), dev->rdk2.fpga_base_addr + RDK2_LOCCTLRDK);
+	udelay(200);
+	writel((1 << BUS_WIDTH), dev->rdk2.fpga_base_addr + RDK2_LOCCTLRDK);
+	/* Print fpga version number */
+	dev_info(dev->dev, "RDK2 FPGA version %08x\n",
+		readl(dev->rdk2.fpga_base_addr + RDK2_FPGAREV));
+	/* Enable FPGA Interrupts */
+	writel((1 << NET2272_PCI_IRQ), dev->rdk2.fpga_base_addr + RDK2_IRQENB);
+
+	return 0;
+
+ err:
+	while (--i >= 0) {
+		iounmap(mem_mapped_addr[i]);
+		release_mem_region(pci_resource_start(pdev, i),
+			pci_resource_len(pdev, i));
+	}
+
+	return ret;
+}
+
+static int __devinit
+net2272_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+	struct net2272 *dev;
+	int ret;
+
+	dev = net2272_probe_init(&pdev->dev, pdev->irq);
+	if (IS_ERR(dev))
+		return PTR_ERR(dev);
+	dev->dev_id = pdev->device;
+
+	if (pci_enable_device(pdev) < 0) {
+		ret = -ENODEV;
+		goto err_free;
+	}
+
+	pci_set_master(pdev);
+
+	switch (pdev->device) {
+	case PCI_DEVICE_ID_RDK1: ret = net2272_rdk1_probe(pdev, dev); break;
+	case PCI_DEVICE_ID_RDK2: ret = net2272_rdk2_probe(pdev, dev); break;
+	default: BUG();
+	}
+	if (ret)
+		goto err_pci;
+
+	ret = net2272_probe_fin(dev, 0);
+	if (ret)
+		goto err_pci;
+
+	pci_set_drvdata(pdev, dev);
+
+	return 0;
+
+ err_pci:
+	pci_disable_device(pdev);
+ err_free:
+	kfree(dev);
+
+	return ret;
+}
+
+static void __devexit
+net2272_rdk1_remove(struct pci_dev *pdev, struct net2272 *dev)
+{
+	int i;
+
+	/* disable PLX 9054 interrupts */
+	writel(readl(dev->rdk1.plx9054_base_addr + INTCSR) &
+		~(1 << PCI_INTERRUPT_ENABLE),
+		dev->rdk1.plx9054_base_addr + INTCSR);
+
+	/* clean up resources allocated during probe() */
+	iounmap(dev->rdk1.plx9054_base_addr);
+	iounmap(dev->rdk1.epld_base_addr);
+
+	for (i = 0; i < 4; ++i) {
+		if (i == 1)
+			continue;	/* BAR1 unused */
+		release_mem_region(pci_resource_start(pdev, i),
+			pci_resource_len(pdev, i));
+	}
+}
+
+static void __devexit
+net2272_rdk2_remove(struct pci_dev *pdev, struct net2272 *dev)
+{
+	int i;
+
+	/* disable fpga interrupts
+	writel(readl(dev->rdk1.plx9054_base_addr + INTCSR) &
+			~(1 << PCI_INTERRUPT_ENABLE),
+			dev->rdk1.plx9054_base_addr + INTCSR);
+	*/
+
+	/* clean up resources allocated during probe() */
+	iounmap(dev->rdk2.fpga_base_addr);
+
+	for (i = 0; i < 2; ++i)
+		release_mem_region(pci_resource_start(pdev, i),
+			pci_resource_len(pdev, i));
+}
+
+static void __devexit
+net2272_pci_remove(struct pci_dev *pdev)
+{
+	struct net2272 *dev = pci_get_drvdata(pdev);
+
+	net2272_remove(dev);
+
+	switch (pdev->device) {
+	case PCI_DEVICE_ID_RDK1: net2272_rdk1_remove(pdev, dev); break;
+	case PCI_DEVICE_ID_RDK2: net2272_rdk2_remove(pdev, dev); break;
+	default: BUG();
+	}
+
+	pci_disable_device(pdev);
+
+	kfree(dev);
+}
+
+/* Table of matching PCI IDs */
+static struct pci_device_id __devinitdata pci_ids[] = {
+	{	/* RDK 1 card */
+		.class       = ((PCI_CLASS_BRIDGE_OTHER << 8) | 0xfe),
+		.class_mask  = 0,
+		.vendor      = PCI_VENDOR_ID_PLX,
+		.device      = PCI_DEVICE_ID_RDK1,
+		.subvendor   = PCI_ANY_ID,
+		.subdevice   = PCI_ANY_ID,
+	},
+	{	/* RDK 2 card */
+		.class       = ((PCI_CLASS_BRIDGE_OTHER << 8) | 0xfe),
+		.class_mask  = 0,
+		.vendor      = PCI_VENDOR_ID_PLX,
+		.device      = PCI_DEVICE_ID_RDK2,
+		.subvendor   = PCI_ANY_ID,
+		.subdevice   = PCI_ANY_ID,
+	},
+	{ }
+};
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+static struct pci_driver net2272_pci_driver = {
+	.name     = driver_name,
+	.id_table = pci_ids,
+
+	.probe    = net2272_pci_probe,
+	.remove   = __devexit_p(net2272_pci_remove),
+};
+
+static int net2272_pci_register(void)
+{
+	return pci_register_driver(&net2272_pci_driver);
+}
+
+static void net2272_pci_unregister(void)
+{
+	pci_unregister_driver(&net2272_pci_driver);
+}
+
+#else
+static inline int net2272_pci_register(void) { return 0; }
+static inline void net2272_pci_unregister(void) { }
+#endif
+
+/*---------------------------------------------------------------------------*/
+
+static int __devinit
+net2272_plat_probe(struct platform_device *pdev)
+{
+	struct net2272 *dev;
+	int ret;
+	unsigned int irqflags;
+	resource_size_t base, len;
+	struct resource *iomem, *iomem_bus, *irq_res;
+
+	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	iomem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	iomem_bus = platform_get_resource(pdev, IORESOURCE_BUS, 0);
+	if (!irq_res || !iomem) {
+		dev_err(&pdev->dev, "must provide irq/base addr");
+		return -EINVAL;
+	}
+
+	dev = net2272_probe_init(&pdev->dev, irq_res->start);
+	if (IS_ERR(dev))
+		return PTR_ERR(dev);
+
+	irqflags = 0;
+	if (irq_res->flags & IORESOURCE_IRQ_HIGHEDGE)
+		irqflags |= IRQF_TRIGGER_RISING;
+	if (irq_res->flags & IORESOURCE_IRQ_LOWEDGE)
+		irqflags |= IRQF_TRIGGER_FALLING;
+	if (irq_res->flags & IORESOURCE_IRQ_HIGHLEVEL)
+		irqflags |= IRQF_TRIGGER_HIGH;
+	if (irq_res->flags & IORESOURCE_IRQ_LOWLEVEL)
+		irqflags |= IRQF_TRIGGER_LOW;
+
+	base = iomem->start;
+	len = resource_size(iomem);
+	if (iomem_bus)
+		dev->base_shift = iomem_bus->start;
+
+	if (!request_mem_region(base, len, driver_name)) {
+		dev_dbg(dev->dev, "get request memory region!\n");
+		ret = -EBUSY;
+		goto err;
+	}
+	dev->base_addr = ioremap_nocache(base, len);
+	if (!dev->base_addr) {
+		dev_dbg(dev->dev, "can't map memory\n");
+		ret = -EFAULT;
+		goto err_req;
+	}
+
+	ret = net2272_probe_fin(dev, IRQF_TRIGGER_LOW);
+	if (ret)
+		goto err_io;
+
+	platform_set_drvdata(pdev, dev);
+	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:
+	iounmap(dev->base_addr);
+ err_req:
+	release_mem_region(base, len);
+ err:
+	return ret;
+}
+
+static int __devexit
+net2272_plat_remove(struct platform_device *pdev)
+{
+	struct net2272 *dev = platform_get_drvdata(pdev);
+
+	net2272_remove(dev);
+
+	release_mem_region(pdev->resource[0].start,
+		resource_size(&pdev->resource[0]));
+
+	kfree(dev);
+
+	return 0;
+}
+
+static struct platform_driver net2272_plat_driver = {
+	.probe   = net2272_plat_probe,
+	.remove  = __devexit_p(net2272_plat_remove),
+	.driver  = {
+		.name  = driver_name,
+		.owner = THIS_MODULE,
+	},
+	/* FIXME .suspend, .resume */
+};
+MODULE_ALIAS("platform:net2272");
+
+static int __init net2272_init(void)
+{
+	int ret;
+
+	ret = net2272_pci_register();
+	if (ret)
+		return ret;
+	ret = platform_driver_register(&net2272_plat_driver);
+	if (ret)
+		goto err_pci;
+	return ret;
+
+err_pci:
+	net2272_pci_unregister();
+	return ret;
+}
+module_init(net2272_init);
+
+static void __exit net2272_cleanup(void)
+{
+	net2272_pci_unregister();
+	platform_driver_unregister(&net2272_plat_driver);
+}
+module_exit(net2272_cleanup);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("PLX Technology, Inc.");
+MODULE_LICENSE("GPL");

+ 601 - 0
drivers/usb/gadget/net2272.h

@@ -0,0 +1,601 @@
+/*
+ * PLX NET2272 high/full speed USB device controller
+ *
+ * Copyright (C) 2005-2006 PLX Technology, Inc.
+ * Copyright (C) 2006-2011 Analog Devices, Inc.
+ *
+ * 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.
+ *
+ * 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 __NET2272_H__
+#define __NET2272_H__
+
+/* Main Registers */
+#define REGADDRPTR			0x00
+#define REGDATA				0x01
+#define IRQSTAT0			0x02
+#define 	ENDPOINT_0_INTERRUPT			0
+#define 	ENDPOINT_A_INTERRUPT			1
+#define 	ENDPOINT_B_INTERRUPT			2
+#define 	ENDPOINT_C_INTERRUPT			3
+#define 	VIRTUALIZED_ENDPOINT_INTERRUPT		4
+#define 	SETUP_PACKET_INTERRUPT			5
+#define 	DMA_DONE_INTERRUPT			6
+#define 	SOF_INTERRUPT				7
+#define IRQSTAT1			0x03
+#define 	CONTROL_STATUS_INTERRUPT		1
+#define 	VBUS_INTERRUPT				2
+#define 	SUSPEND_REQUEST_INTERRUPT		3
+#define 	SUSPEND_REQUEST_CHANGE_INTERRUPT	4
+#define 	RESUME_INTERRUPT			5
+#define 	ROOT_PORT_RESET_INTERRUPT		6
+#define 	RESET_STATUS				7
+#define PAGESEL				0x04
+#define DMAREQ				0x1c
+#define 	DMA_ENDPOINT_SELECT			0
+#define 	DREQ_POLARITY				1
+#define 	DACK_POLARITY				2
+#define 	EOT_POLARITY				3
+#define 	DMA_CONTROL_DACK			4
+#define 	DMA_REQUEST_ENABLE			5
+#define 	DMA_REQUEST				6
+#define 	DMA_BUFFER_VALID			7
+#define SCRATCH				0x1d
+#define IRQENB0				0x20
+#define 	ENDPOINT_0_INTERRUPT_ENABLE		0
+#define 	ENDPOINT_A_INTERRUPT_ENABLE		1
+#define 	ENDPOINT_B_INTERRUPT_ENABLE		2
+#define 	ENDPOINT_C_INTERRUPT_ENABLE		3
+#define 	VIRTUALIZED_ENDPOINT_INTERRUPT_ENABLE	4
+#define 	SETUP_PACKET_INTERRUPT_ENABLE		5
+#define 	DMA_DONE_INTERRUPT_ENABLE		6
+#define 	SOF_INTERRUPT_ENABLE			7
+#define IRQENB1				0x21
+#define 	VBUS_INTERRUPT_ENABLE			2
+#define 	SUSPEND_REQUEST_INTERRUPT_ENABLE	3
+#define 	SUSPEND_REQUEST_CHANGE_INTERRUPT_ENABLE	4
+#define 	RESUME_INTERRUPT_ENABLE			5
+#define 	ROOT_PORT_RESET_INTERRUPT_ENABLE	6
+#define LOCCTL				0x22
+#define 	DATA_WIDTH				0
+#define 	LOCAL_CLOCK_OUTPUT			1
+#define 		LOCAL_CLOCK_OUTPUT_OFF			0
+#define 		LOCAL_CLOCK_OUTPUT_3_75MHZ		1
+#define 		LOCAL_CLOCK_OUTPUT_7_5MHZ		2
+#define 		LOCAL_CLOCK_OUTPUT_15MHZ		3
+#define 		LOCAL_CLOCK_OUTPUT_30MHZ		4
+#define 		LOCAL_CLOCK_OUTPUT_60MHZ		5
+#define 	DMA_SPLIT_BUS_MODE			4
+#define 	BYTE_SWAP				5
+#define 	BUFFER_CONFIGURATION			6
+#define 		BUFFER_CONFIGURATION_EPA512_EPB512	0
+#define 		BUFFER_CONFIGURATION_EPA1024_EPB512	1
+#define 		BUFFER_CONFIGURATION_EPA1024_EPB1024	2
+#define 		BUFFER_CONFIGURATION_EPA1024DB		3
+#define CHIPREV_LEGACY			0x23
+#define 		NET2270_LEGACY_REV			0x40
+#define LOCCTL1				0x24
+#define 	DMA_MODE				0
+#define 		SLOW_DREQ				0
+#define 		FAST_DREQ				1
+#define 		BURST_MODE				2
+#define 	DMA_DACK_ENABLE				2
+#define CHIPREV_2272			0x25
+#define 		CHIPREV_NET2272_R1			0x10
+#define 		CHIPREV_NET2272_R1A			0x11
+/* USB Registers */
+#define USBCTL0				0x18
+#define 	IO_WAKEUP_ENABLE			1
+#define 	USB_DETECT_ENABLE			3
+#define 	USB_ROOT_PORT_WAKEUP_ENABLE		5
+#define USBCTL1				0x19
+#define 	VBUS_PIN				0
+#define 		USB_FULL_SPEED				1
+#define 		USB_HIGH_SPEED				2
+#define 	GENERATE_RESUME				3
+#define 	VIRTUAL_ENDPOINT_ENABLE			4
+#define FRAME0				0x1a
+#define FRAME1				0x1b
+#define OURADDR				0x30
+#define 	FORCE_IMMEDIATE				7
+#define USBDIAG				0x31
+#define 	FORCE_TRANSMIT_CRC_ERROR		0
+#define 	PREVENT_TRANSMIT_BIT_STUFF		1
+#define 	FORCE_RECEIVE_ERROR			2
+#define 	FAST_TIMES				4
+#define USBTEST				0x32
+#define 	TEST_MODE_SELECT			0
+#define 		NORMAL_OPERATION			0
+#define 		TEST_J					1
+#define 		TEST_K					2
+#define 		TEST_SE0_NAK				3
+#define 		TEST_PACKET				4
+#define 		TEST_FORCE_ENABLE			5
+#define XCVRDIAG			0x33
+#define 	FORCE_FULL_SPEED			2
+#define 	FORCE_HIGH_SPEED			3
+#define 	OPMODE					4
+#define 		NORMAL_OPERATION			0
+#define 		NON_DRIVING				1
+#define 		DISABLE_BITSTUFF_AND_NRZI_ENCODE	2
+#define 	LINESTATE				6
+#define 		SE0_STATE				0
+#define 		J_STATE					1
+#define 		K_STATE					2
+#define 		SE1_STATE				3
+#define VIRTOUT0			0x34
+#define VIRTOUT1			0x35
+#define VIRTIN0				0x36
+#define VIRTIN1				0x37
+#define SETUP0				0x40
+#define SETUP1				0x41
+#define SETUP2				0x42
+#define SETUP3				0x43
+#define SETUP4				0x44
+#define SETUP5				0x45
+#define SETUP6				0x46
+#define SETUP7				0x47
+/* Endpoint Registers (Paged via PAGESEL) */
+#define EP_DATA				0x05
+#define EP_STAT0			0x06
+#define 	DATA_IN_TOKEN_INTERRUPT			0
+#define 	DATA_OUT_TOKEN_INTERRUPT		1
+#define 	DATA_PACKET_TRANSMITTED_INTERRUPT	2
+#define 	DATA_PACKET_RECEIVED_INTERRUPT		3
+#define 	SHORT_PACKET_TRANSFERRED_INTERRUPT	4
+#define 	NAK_OUT_PACKETS				5
+#define 	BUFFER_EMPTY				6
+#define 	BUFFER_FULL				7
+#define EP_STAT1			0x07
+#define 	TIMEOUT					0
+#define 	USB_OUT_ACK_SENT			1
+#define 	USB_OUT_NAK_SENT			2
+#define 	USB_IN_ACK_RCVD				3
+#define 	USB_IN_NAK_SENT				4
+#define 	USB_STALL_SENT				5
+#define 	LOCAL_OUT_ZLP				6
+#define 	BUFFER_FLUSH				7
+#define EP_TRANSFER0			0x08
+#define EP_TRANSFER1			0x09
+#define EP_TRANSFER2			0x0a
+#define EP_IRQENB			0x0b
+#define 	DATA_IN_TOKEN_INTERRUPT_ENABLE		0
+#define 	DATA_OUT_TOKEN_INTERRUPT_ENABLE		1
+#define 	DATA_PACKET_TRANSMITTED_INTERRUPT_ENABLE	2
+#define 	DATA_PACKET_RECEIVED_INTERRUPT_ENABLE	3
+#define 	SHORT_PACKET_TRANSFERRED_INTERRUPT_ENABLE	4
+#define EP_AVAIL0			0x0c
+#define EP_AVAIL1			0x0d
+#define EP_RSPCLR			0x0e
+#define EP_RSPSET			0x0f
+#define 	ENDPOINT_HALT				0
+#define 	ENDPOINT_TOGGLE				1
+#define 	NAK_OUT_PACKETS_MODE			2
+#define 	CONTROL_STATUS_PHASE_HANDSHAKE		3
+#define 	INTERRUPT_MODE				4
+#define 	AUTOVALIDATE				5
+#define 	HIDE_STATUS_PHASE			6
+#define 	ALT_NAK_OUT_PACKETS			7
+#define EP_MAXPKT0			0x28
+#define EP_MAXPKT1			0x29
+#define 	ADDITIONAL_TRANSACTION_OPPORTUNITIES	3
+#define 		NONE_ADDITIONAL_TRANSACTION		0
+#define 		ONE_ADDITIONAL_TRANSACTION		1
+#define 		TWO_ADDITIONAL_TRANSACTION		2
+#define EP_CFG				0x2a
+#define 	ENDPOINT_NUMBER				0
+#define 	ENDPOINT_DIRECTION			4
+#define 	ENDPOINT_TYPE				5
+#define 	ENDPOINT_ENABLE				7
+#define EP_HBW				0x2b
+#define 	HIGH_BANDWIDTH_OUT_TRANSACTION_PID	0
+#define 		DATA0_PID				0
+#define 		DATA1_PID				1
+#define 		DATA2_PID				2
+#define 		MDATA_PID				3
+#define EP_BUFF_STATES			0x2c
+#define 	BUFFER_A_STATE				0
+#define 	BUFFER_B_STATE				2
+#define 		BUFF_FREE				0
+#define 		BUFF_VALID				1
+#define 		BUFF_LCL				2
+#define 		BUFF_USB				3
+
+/*---------------------------------------------------------------------------*/
+
+#define PCI_DEVICE_ID_RDK1	0x9054
+
+/* PCI-RDK EPLD Registers */
+#define RDK_EPLD_IO_REGISTER1		0x00000000
+#define 	RDK_EPLD_USB_RESET				0
+#define 	RDK_EPLD_USB_POWERDOWN				1
+#define 	RDK_EPLD_USB_WAKEUP				2
+#define 	RDK_EPLD_USB_EOT				3
+#define 	RDK_EPLD_DPPULL					4
+#define RDK_EPLD_IO_REGISTER2		0x00000004
+#define 	RDK_EPLD_BUSWIDTH				0
+#define 	RDK_EPLD_USER					2
+#define 	RDK_EPLD_RESET_INTERRUPT_ENABLE			3
+#define 	RDK_EPLD_DMA_TIMEOUT_ENABLE			4
+#define RDK_EPLD_STATUS_REGISTER	0x00000008
+#define 	RDK_EPLD_USB_LRESET				0
+#define RDK_EPLD_REVISION_REGISTER	0x0000000c
+
+/* PCI-RDK PLX 9054 Registers */
+#define INTCSR				0x68
+#define 	PCI_INTERRUPT_ENABLE				8
+#define 	LOCAL_INTERRUPT_INPUT_ENABLE			11
+#define 	LOCAL_INPUT_INTERRUPT_ACTIVE			15
+#define 	LOCAL_DMA_CHANNEL_0_INTERRUPT_ENABLE		18
+#define 	LOCAL_DMA_CHANNEL_1_INTERRUPT_ENABLE		19
+#define 	DMA_CHANNEL_0_INTERRUPT_ACTIVE			21
+#define 	DMA_CHANNEL_1_INTERRUPT_ACTIVE			22
+#define CNTRL				0x6C
+#define 	RELOAD_CONFIGURATION_REGISTERS			29
+#define 	PCI_ADAPTER_SOFTWARE_RESET			30
+#define DMAMODE0			0x80
+#define 	LOCAL_BUS_WIDTH					0
+#define 	INTERNAL_WAIT_STATES				2
+#define 	TA_READY_INPUT_ENABLE				6
+#define 	LOCAL_BURST_ENABLE				8
+#define 	SCATTER_GATHER_MODE				9
+#define 	DONE_INTERRUPT_ENABLE				10
+#define 	LOCAL_ADDRESSING_MODE				11
+#define 	DEMAND_MODE					12
+#define 	DMA_EOT_ENABLE					14
+#define 	FAST_SLOW_TERMINATE_MODE_SELECT			15
+#define 	DMA_CHANNEL_INTERRUPT_SELECT			17
+#define DMAPADR0			0x84
+#define DMALADR0			0x88
+#define DMASIZ0				0x8c
+#define DMADPR0				0x90
+#define 	DESCRIPTOR_LOCATION				0
+#define 	END_OF_CHAIN					1
+#define 	INTERRUPT_AFTER_TERMINAL_COUNT			2
+#define 	DIRECTION_OF_TRANSFER				3
+#define DMACSR0				0xa8
+#define 	CHANNEL_ENABLE					0
+#define 	CHANNEL_START					1
+#define 	CHANNEL_ABORT					2
+#define 	CHANNEL_CLEAR_INTERRUPT				3
+#define 	CHANNEL_DONE					4
+#define DMATHR				0xb0
+#define LBRD1				0xf8
+#define 	MEMORY_SPACE_LOCAL_BUS_WIDTH			0
+#define 	W8_BIT						0
+#define 	W16_BIT						1
+
+/* Special OR'ing of INTCSR bits */
+#define LOCAL_INTERRUPT_TEST \
+	((1 << LOCAL_INPUT_INTERRUPT_ACTIVE) | \
+	 (1 << LOCAL_INTERRUPT_INPUT_ENABLE))
+
+#define DMA_CHANNEL_0_TEST \
+	((1 << DMA_CHANNEL_0_INTERRUPT_ACTIVE) | \
+	 (1 << LOCAL_DMA_CHANNEL_0_INTERRUPT_ENABLE))
+
+#define DMA_CHANNEL_1_TEST \
+	((1 << DMA_CHANNEL_1_INTERRUPT_ACTIVE) | \
+	 (1 << LOCAL_DMA_CHANNEL_1_INTERRUPT_ENABLE))
+
+/* EPLD Registers */
+#define RDK_EPLD_IO_REGISTER1			0x00000000
+#define 	RDK_EPLD_USB_RESET			0
+#define 	RDK_EPLD_USB_POWERDOWN			1
+#define 	RDK_EPLD_USB_WAKEUP			2
+#define 	RDK_EPLD_USB_EOT			3
+#define 	RDK_EPLD_DPPULL				4
+#define RDK_EPLD_IO_REGISTER2			0x00000004
+#define 	RDK_EPLD_BUSWIDTH			0
+#define 	RDK_EPLD_USER				2
+#define 	RDK_EPLD_RESET_INTERRUPT_ENABLE		3
+#define 	RDK_EPLD_DMA_TIMEOUT_ENABLE		4
+#define RDK_EPLD_STATUS_REGISTER		0x00000008
+#define RDK_EPLD_USB_LRESET				0
+#define RDK_EPLD_REVISION_REGISTER		0x0000000c
+
+#define EPLD_IO_CONTROL_REGISTER		0x400
+#define 	NET2272_RESET				0
+#define 	BUSWIDTH				1
+#define 	MPX_MODE				3
+#define 	USER					4
+#define 	DMA_TIMEOUT_ENABLE			5
+#define 	DMA_CTL_DACK				6
+#define 	EPLD_DMA_ENABLE				7
+#define EPLD_DMA_CONTROL_REGISTER		0x800
+#define 	SPLIT_DMA_MODE				0
+#define 	SPLIT_DMA_DIRECTION			1
+#define 	SPLIT_DMA_ENABLE			2
+#define 	SPLIT_DMA_INTERRUPT_ENABLE		3
+#define 	SPLIT_DMA_INTERRUPT			4
+#define 	EPLD_DMA_MODE				5
+#define 	EPLD_DMA_CONTROLLER_ENABLE		7
+#define SPLIT_DMA_ADDRESS_LOW			0xc00
+#define SPLIT_DMA_ADDRESS_HIGH			0x1000
+#define SPLIT_DMA_BYTE_COUNT_LOW		0x1400
+#define SPLIT_DMA_BYTE_COUNT_HIGH		0x1800
+#define EPLD_REVISION_REGISTER			0x1c00
+#define SPLIT_DMA_RAM				0x4000
+#define DMA_RAM_SIZE				0x1000
+
+/*---------------------------------------------------------------------------*/
+
+#define PCI_DEVICE_ID_RDK2	0x3272
+
+/* PCI-RDK version 2 registers */
+
+/* Main Control Registers */
+
+#define RDK2_IRQENB			0x00
+#define RDK2_IRQSTAT			0x04
+#define 	PB7				23
+#define 	PB6				22
+#define 	PB5				21
+#define 	PB4				20
+#define 	PB3				19
+#define 	PB2				18
+#define 	PB1				17
+#define 	PB0				16
+#define 	GP3				23
+#define 	GP2				23
+#define 	GP1				23
+#define 	GP0				23
+#define 	DMA_RETRY_ABORT			6
+#define 	DMA_PAUSE_DONE			5
+#define 	DMA_ABORT_DONE			4
+#define 	DMA_OUT_FIFO_TRANSFER_DONE	3
+#define 	DMA_LOCAL_DONE			2
+#define 	DMA_PCI_DONE			1
+#define 	NET2272_PCI_IRQ			0
+
+#define RDK2_LOCCTLRDK			0x08
+#define 	CHIP_RESET			3
+#define 	SPLIT_DMA			2
+#define 	MULTIPLEX_MODE			1
+#define 	BUS_WIDTH			0
+
+#define RDK2_GPIOCTL			0x10
+#define 	GP3_OUT_ENABLE					7
+#define 	GP2_OUT_ENABLE					6
+#define 	GP1_OUT_ENABLE					5
+#define 	GP0_OUT_ENABLE					4
+#define 	GP3_DATA					3
+#define 	GP2_DATA					2
+#define 	GP1_DATA					1
+#define 	GP0_DATA					0
+
+#define RDK2_LEDSW			0x14
+#define 	LED3				27
+#define 	LED2				26
+#define 	LED1				25
+#define 	LED0				24
+#define 	PBUTTON				16
+#define 	DIPSW				0
+
+#define RDK2_DIAG			0x18
+#define 	RDK2_FAST_TIMES				2
+#define 	FORCE_PCI_SERR				1
+#define 	FORCE_PCI_INT				0
+#define RDK2_FPGAREV			0x1C
+
+/* Dma Control registers */
+#define RDK2_DMACTL			0x80
+#define 	ADDR_HOLD				24
+#define 	RETRY_COUNT				16	/* 23:16 */
+#define 	FIFO_THRESHOLD				11	/* 15:11 */
+#define 	MEM_WRITE_INVALIDATE			10
+#define 	READ_MULTIPLE				9
+#define 	READ_LINE				8
+#define 	RDK2_DMA_MODE				6	/* 7:6 */
+#define 	CONTROL_DACK				5
+#define 	EOT_ENABLE				4
+#define 	EOT_POLARITY				3
+#define 	DACK_POLARITY				2
+#define 	DREQ_POLARITY				1
+#define 	DMA_ENABLE				0
+
+#define RDK2_DMASTAT			0x84
+#define 	GATHER_COUNT				12	/* 14:12 */
+#define 	FIFO_COUNT				6	/* 11:6 */
+#define 	FIFO_FLUSH				5
+#define 	FIFO_TRANSFER				4
+#define 	PAUSE_DONE				3
+#define 	ABORT_DONE				2
+#define 	DMA_ABORT				1
+#define 	DMA_START				0
+
+#define RDK2_DMAPCICOUNT		0x88
+#define 	DMA_DIRECTION				31
+#define 	DMA_PCI_BYTE_COUNT			0	/* 0:23 */
+
+#define RDK2_DMALOCCOUNT		0x8C	/* 0:23 dma local byte count */
+
+#define RDK2_DMAADDR			0x90	/* 2:31 PCI bus starting address */
+
+/*---------------------------------------------------------------------------*/
+
+#define REG_INDEXED_THRESHOLD	(1 << 5)
+
+/* DRIVER DATA STRUCTURES and UTILITIES */
+struct net2272_ep {
+	struct usb_ep ep;
+	struct net2272 *dev;
+	unsigned long irqs;
+
+	/* analogous to a host-side qh */
+	struct list_head queue;
+	const struct usb_endpoint_descriptor *desc;
+	unsigned num:8,
+	         fifo_size:12,
+	         stopped:1,
+	         wedged:1,
+	         is_in:1,
+	         is_iso:1,
+	         dma:1,
+	         not_empty:1;
+};
+
+struct net2272 {
+	/* each device provides one gadget, several endpoints */
+	struct usb_gadget gadget;
+	struct device *dev;
+	unsigned short dev_id;
+
+	spinlock_t lock;
+	struct net2272_ep ep[4];
+	struct usb_gadget_driver *driver;
+	unsigned protocol_stall:1,
+	         softconnect:1,
+	         is_selfpowered:1,
+	         wakeup:1,
+	         dma_eot_polarity:1,
+	         dma_dack_polarity:1,
+	         dma_dreq_polarity:1,
+	         dma_busy:1;
+	u16 chiprev;
+	u8 pagesel;
+
+	unsigned int irq;
+	unsigned short fifo_mode;
+
+	unsigned int base_shift;
+	u16 __iomem *base_addr;
+	union {
+#ifdef CONFIG_PCI
+		struct {
+			void __iomem *plx9054_base_addr;
+			void __iomem *epld_base_addr;
+		} rdk1;
+		struct {
+			/* Bar0, Bar1 is base_addr both mem-mapped */
+			void __iomem *fpga_base_addr;
+		} rdk2;
+#endif
+	};
+};
+
+static void __iomem *
+net2272_reg_addr(struct net2272 *dev, unsigned int reg)
+{
+	return dev->base_addr + (reg << dev->base_shift);
+}
+
+static void
+net2272_write(struct net2272 *dev, unsigned int reg, u8 value)
+{
+	if (reg >= REG_INDEXED_THRESHOLD) {
+		/*
+		 * Indexed register; use REGADDRPTR/REGDATA
+		 *  - Save and restore REGADDRPTR. This prevents REGADDRPTR from
+		 *    changes between other code sections, but it is time consuming.
+		 *  - Performance tips: either do not save and restore REGADDRPTR (if it
+		 *    is safe) or do save/restore operations only in critical sections.
+		u8 tmp = readb(dev->base_addr + REGADDRPTR);
+		 */
+		writeb((u8)reg, net2272_reg_addr(dev, REGADDRPTR));
+		writeb(value, net2272_reg_addr(dev, REGDATA));
+		/* writeb(tmp, net2272_reg_addr(dev, REGADDRPTR)); */
+	} else
+		writeb(value, net2272_reg_addr(dev, reg));
+}
+
+static u8
+net2272_read(struct net2272 *dev, unsigned int reg)
+{
+	u8 ret;
+
+	if (reg >= REG_INDEXED_THRESHOLD) {
+		/*
+		 * Indexed register; use REGADDRPTR/REGDATA
+		 *  - Save and restore REGADDRPTR. This prevents REGADDRPTR from
+		 *    changes between other code sections, but it is time consuming.
+		 *  - Performance tips: either do not save and restore REGADDRPTR (if it
+		 *    is safe) or do save/restore operations only in critical sections.
+		u8 tmp = readb(dev->base_addr + REGADDRPTR);
+		 */
+		writeb((u8)reg, net2272_reg_addr(dev, REGADDRPTR));
+		ret = readb(net2272_reg_addr(dev, REGDATA));
+		/* writeb(tmp, net2272_reg_addr(dev, REGADDRPTR)); */
+	} else
+		ret = readb(net2272_reg_addr(dev, reg));
+
+	return ret;
+}
+
+static void
+net2272_ep_write(struct net2272_ep *ep, unsigned int reg, u8 value)
+{
+	struct net2272 *dev = ep->dev;
+
+	if (dev->pagesel != ep->num) {
+		net2272_write(dev, PAGESEL, ep->num);
+		dev->pagesel = ep->num;
+	}
+	net2272_write(dev, reg, value);
+}
+
+static u8
+net2272_ep_read(struct net2272_ep *ep, unsigned int reg)
+{
+	struct net2272 *dev = ep->dev;
+
+	if (dev->pagesel != ep->num) {
+		net2272_write(dev, PAGESEL, ep->num);
+		dev->pagesel = ep->num;
+	}
+	return net2272_read(dev, reg);
+}
+
+static void allow_status(struct net2272_ep *ep)
+{
+	/* ep0 only */
+	net2272_ep_write(ep, EP_RSPCLR,
+		(1 << CONTROL_STATUS_PHASE_HANDSHAKE) |
+		(1 << ALT_NAK_OUT_PACKETS) |
+		(1 << NAK_OUT_PACKETS_MODE));
+	ep->stopped = 1;
+}
+
+static void set_halt(struct net2272_ep *ep)
+{
+	/* ep0 and bulk/intr endpoints */
+	net2272_ep_write(ep, EP_RSPCLR, 1 << CONTROL_STATUS_PHASE_HANDSHAKE);
+	net2272_ep_write(ep, EP_RSPSET, 1 << ENDPOINT_HALT);
+}
+
+static void clear_halt(struct net2272_ep *ep)
+{
+	/* ep0 and bulk/intr endpoints */
+	net2272_ep_write(ep, EP_RSPCLR,
+		(1 << ENDPOINT_HALT) | (1 << ENDPOINT_TOGGLE));
+}
+
+/* count (<= 4) bytes in the next fifo write will be valid */
+static void set_fifo_bytecount(struct net2272_ep *ep, unsigned count)
+{
+	/* net2272_ep_write will truncate to u8 for us */
+	net2272_ep_write(ep, EP_TRANSFER2, count >> 16);
+	net2272_ep_write(ep, EP_TRANSFER1, count >> 8);
+	net2272_ep_write(ep, EP_TRANSFER0, count);
+}
+
+struct net2272_request {
+	struct usb_request req;
+	struct list_head queue;
+	unsigned mapped:1,
+	         valid:1;
+};
+
+#endif

+ 13 - 61
drivers/usb/gadget/net2280.c

@@ -1410,11 +1410,17 @@ static int net2280_pullup(struct usb_gadget *_gadget, int is_on)
 	return 0;
 	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 const struct usb_gadget_ops net2280_ops = {
 static const struct usb_gadget_ops net2280_ops = {
 	.get_frame	= net2280_get_frame,
 	.get_frame	= net2280_get_frame,
 	.wakeup		= net2280_wakeup,
 	.wakeup		= net2280_wakeup,
 	.set_selfpowered = net2280_set_selfpowered,
 	.set_selfpowered = net2280_set_selfpowered,
 	.pullup		= net2280_pullup,
 	.pullup		= net2280_pullup,
+	.start		= net2280_start,
+	.stop		= net2280_stop,
 };
 };
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -1738,62 +1744,6 @@ static void set_fifo_mode (struct net2280 *dev, int mode)
 	list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list);
 	list_add_tail (&dev->ep [6].ep.ep_list, &dev->gadget.ep_list);
 }
 }
 
 
-/* just declare this in any driver that really need it */
-extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
-
-/**
- * net2280_set_fifo_mode - change allocation of fifo buffers
- * @gadget: access to the net2280 device that will be updated
- * @mode: 0 for default, four 1kB buffers (ep-a through ep-d);
- *	1 for two 2kB buffers (ep-a and ep-b only);
- *	2 for one 2kB buffer (ep-a) and two 1kB ones (ep-b, ep-c).
- *
- * returns zero on success, else negative errno.  when this succeeds,
- * the contents of gadget->ep_list may have changed.
- *
- * you may only call this function when endpoints a-d are all disabled.
- * use it whenever extra hardware buffering can help performance, such
- * as before enabling "high bandwidth" interrupt endpoints that use
- * maxpacket bigger than 512 (when double buffering would otherwise
- * be unavailable).
- */
-int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode)
-{
-	int			i;
-	struct net2280		*dev;
-	int			status = 0;
-	unsigned long		flags;
-
-	if (!gadget)
-		return -ENODEV;
-	dev = container_of (gadget, struct net2280, gadget);
-
-	spin_lock_irqsave (&dev->lock, flags);
-
-	for (i = 1; i <= 4; i++)
-		if (dev->ep [i].desc) {
-			status = -EINVAL;
-			break;
-		}
-	if (mode < 0 || mode > 2)
-		status = -EINVAL;
-	if (status == 0)
-		set_fifo_mode (dev, mode);
-	spin_unlock_irqrestore (&dev->lock, flags);
-
-	if (status == 0) {
-		if (mode == 1)
-			DEBUG (dev, "fifo:  ep-a 2K, ep-b 2K\n");
-		else if (mode == 2)
-			DEBUG (dev, "fifo:  ep-a 2K, ep-b 1K, ep-c 1K\n");
-		/* else all are 1K */
-	}
-	return status;
-}
-EXPORT_SYMBOL (net2280_set_fifo_mode);
-
-/*-------------------------------------------------------------------------*/
-
 /* keeping it simple:
 /* keeping it simple:
  * - one bus driver, initted first;
  * - one bus driver, initted first;
  * - one function driver, initted second
  * - one function driver, initted second
@@ -1930,7 +1880,7 @@ static void ep0_start (struct net2280 *dev)
  * disconnect is reported.  then a host may connect again, or
  * disconnect is reported.  then a host may connect again, or
  * the driver might get unbound.
  * the driver might get unbound.
  */
  */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int net2280_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 		int (*bind)(struct usb_gadget *))
 {
 {
 	struct net2280		*dev = the_controller;
 	struct net2280		*dev = the_controller;
@@ -1994,7 +1944,6 @@ err_unbind:
 	dev->driver = NULL;
 	dev->driver = NULL;
 	return retval;
 	return retval;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 
 static void
 static void
 stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver)
 stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver)
@@ -2022,7 +1971,7 @@ stop_activity (struct net2280 *dev, struct usb_gadget_driver *driver)
 	usb_reinit (dev);
 	usb_reinit (dev);
 }
 }
 
 
-int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+static int net2280_stop(struct usb_gadget_driver *driver)
 {
 {
 	struct net2280	*dev = the_controller;
 	struct net2280	*dev = the_controller;
 	unsigned long	flags;
 	unsigned long	flags;
@@ -2049,8 +1998,6 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 	DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name);
 	DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name);
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL (usb_gadget_unregister_driver);
-
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
@@ -2732,6 +2679,8 @@ static void net2280_remove (struct pci_dev *pdev)
 {
 {
 	struct net2280		*dev = pci_get_drvdata (pdev);
 	struct net2280		*dev = pci_get_drvdata (pdev);
 
 
+	usb_del_gadget_udc(&dev->gadget);
+
 	BUG_ON(dev->driver);
 	BUG_ON(dev->driver);
 
 
 	/* then clean up the resources we allocated during probe() */
 	/* then clean up the resources we allocated during probe() */
@@ -2916,6 +2865,9 @@ static int net2280_probe (struct pci_dev *pdev, const struct pci_device_id *id)
 	retval = device_create_file (&pdev->dev, &dev_attr_registers);
 	retval = device_create_file (&pdev->dev, &dev_attr_registers);
 	if (retval) goto done;
 	if (retval) goto done;
 
 
+	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+	if (retval)
+		goto done;
 	return 0;
 	return 0;
 
 
 done:
 done:

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

@@ -241,6 +241,7 @@ static struct usb_composite_driver nokia_driver = {
 	.name		= "g_nokia",
 	.name		= "g_nokia",
 	.dev		= &device_desc,
 	.dev		= &device_desc,
 	.strings	= dev_strings,
 	.strings	= dev_strings,
+	.max_speed	= USB_SPEED_HIGH,
 	.unbind		= __exit_p(nokia_unbind),
 	.unbind		= __exit_p(nokia_unbind),
 };
 };
 
 

+ 17 - 5
drivers/usb/gadget/omap_udc.c

@@ -1375,6 +1375,10 @@ static int omap_pullup(struct usb_gadget *gadget, int is_on)
 	return 0;
 	return 0;
 }
 }
 
 
+static int omap_udc_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int omap_udc_stop(struct usb_gadget_driver *driver);
+
 static struct usb_gadget_ops omap_gadget_ops = {
 static struct usb_gadget_ops omap_gadget_ops = {
 	.get_frame		= omap_get_frame,
 	.get_frame		= omap_get_frame,
 	.wakeup			= omap_wakeup,
 	.wakeup			= omap_wakeup,
@@ -1382,6 +1386,8 @@ static struct usb_gadget_ops omap_gadget_ops = {
 	.vbus_session		= omap_vbus_session,
 	.vbus_session		= omap_vbus_session,
 	.vbus_draw		= omap_vbus_draw,
 	.vbus_draw		= omap_vbus_draw,
 	.pullup			= omap_pullup,
 	.pullup			= omap_pullup,
+	.start			= omap_udc_start,
+	.stop			= omap_udc_stop,
 };
 };
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -2102,7 +2108,7 @@ static inline int machine_without_vbus_sense(void)
 		);
 		);
 }
 }
 
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int omap_udc_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 		int (*bind)(struct usb_gadget *))
 {
 {
 	int		status = -ENODEV;
 	int		status = -ENODEV;
@@ -2186,9 +2192,8 @@ done:
 		omap_udc_enable_clock(0);
 		omap_udc_enable_clock(0);
 	return status;
 	return status;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 
-int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
+static int omap_udc_stop(struct usb_gadget_driver *driver)
 {
 {
 	unsigned long	flags;
 	unsigned long	flags;
 	int		status = -ENODEV;
 	int		status = -ENODEV;
@@ -2222,8 +2227,6 @@ int usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
 	DBG("unregistered driver '%s'\n", driver->driver.name);
 	DBG("unregistered driver '%s'\n", driver->driver.name);
 	return status;
 	return status;
 }
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
@@ -2991,9 +2994,16 @@ known:
 
 
 	create_proc_file();
 	create_proc_file();
 	status = device_add(&udc->gadget.dev);
 	status = device_add(&udc->gadget.dev);
+	if (status)
+		goto cleanup4;
+
+	status = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
 	if (!status)
 	if (!status)
 		return status;
 		return status;
 	/* If fail, fall through */
 	/* If fail, fall through */
+cleanup4:
+	remove_proc_file();
+
 #ifdef	USE_ISO
 #ifdef	USE_ISO
 cleanup3:
 cleanup3:
 	free_irq(pdev->resource[2].start, udc);
 	free_irq(pdev->resource[2].start, udc);
@@ -3029,6 +3039,8 @@ static int __exit omap_udc_remove(struct platform_device *pdev)
 
 
 	if (!udc)
 	if (!udc)
 		return -ENODEV;
 		return -ENODEV;
+
+	usb_del_gadget_udc(&udc->gadget);
 	if (udc->driver)
 	if (udc->driver)
 		return -EBUSY;
 		return -EBUSY;
 
 

+ 12 - 4
drivers/usb/gadget/pch_udc.c

@@ -1176,6 +1176,9 @@ static int pch_udc_pcd_vbus_draw(struct usb_gadget *gadget, unsigned int mA)
 	return -EOPNOTSUPP;
 	return -EOPNOTSUPP;
 }
 }
 
 
+static int pch_udc_start(struct usb_gadget_driver *driver,
+	int (*bind)(struct usb_gadget *));
+static int pch_udc_stop(struct usb_gadget_driver *driver);
 static const struct usb_gadget_ops pch_udc_ops = {
 static const struct usb_gadget_ops pch_udc_ops = {
 	.get_frame = pch_udc_pcd_get_frame,
 	.get_frame = pch_udc_pcd_get_frame,
 	.wakeup = pch_udc_pcd_wakeup,
 	.wakeup = pch_udc_pcd_wakeup,
@@ -1183,6 +1186,8 @@ static const struct usb_gadget_ops pch_udc_ops = {
 	.pullup = pch_udc_pcd_pullup,
 	.pullup = pch_udc_pcd_pullup,
 	.vbus_session = pch_udc_pcd_vbus_session,
 	.vbus_session = pch_udc_pcd_vbus_session,
 	.vbus_draw = pch_udc_pcd_vbus_draw,
 	.vbus_draw = pch_udc_pcd_vbus_draw,
+	.start	= pch_udc_start,
+	.stop	= pch_udc_stop,
 };
 };
 
 
 /**
 /**
@@ -2690,7 +2695,7 @@ static int init_dma_pools(struct pch_udc_dev *dev)
 	return 0;
 	return 0;
 }
 }
 
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int pch_udc_start(struct usb_gadget_driver *driver,
 	int (*bind)(struct usb_gadget *))
 	int (*bind)(struct usb_gadget *))
 {
 {
 	struct pch_udc_dev	*dev = pch_udc;
 	struct pch_udc_dev	*dev = pch_udc;
@@ -2733,9 +2738,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 	dev->connected = 1;
 	dev->connected = 1;
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int pch_udc_stop(struct usb_gadget_driver *driver)
 {
 {
 	struct pch_udc_dev	*dev = pch_udc;
 	struct pch_udc_dev	*dev = pch_udc;
 
 
@@ -2761,7 +2765,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 	pch_udc_set_disconnect(dev);
 	pch_udc_set_disconnect(dev);
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 
 static void pch_udc_shutdown(struct pci_dev *pdev)
 static void pch_udc_shutdown(struct pci_dev *pdev)
 {
 {
@@ -2778,6 +2781,8 @@ static void pch_udc_remove(struct pci_dev *pdev)
 {
 {
 	struct pch_udc_dev	*dev = pci_get_drvdata(pdev);
 	struct pch_udc_dev	*dev = pci_get_drvdata(pdev);
 
 
+	usb_del_gadget_udc(&dev->gadget);
+
 	/* gadget driver must not be registered */
 	/* gadget driver must not be registered */
 	if (dev->driver)
 	if (dev->driver)
 		dev_err(&pdev->dev,
 		dev_err(&pdev->dev,
@@ -2953,6 +2958,9 @@ static int pch_udc_probe(struct pci_dev *pdev,
 
 
 	/* Put the device in disconnected state till a driver is bound */
 	/* Put the device in disconnected state till a driver is bound */
 	pch_udc_set_disconnect(dev);
 	pch_udc_set_disconnect(dev);
+	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+	if (retval)
+		goto finished;
 	return 0;
 	return 0;
 
 
 finished:
 finished:

+ 23 - 17
drivers/usb/gadget/printer.c

@@ -89,8 +89,7 @@ struct printer_dev {
 	u8			config;
 	u8			config;
 	s8			interface;
 	s8			interface;
 	struct usb_ep		*in_ep, *out_ep;
 	struct usb_ep		*in_ep, *out_ep;
-	const struct usb_endpoint_descriptor
-				*in, *out;
+
 	struct list_head	rx_reqs;	/* List of free RX structs */
 	struct list_head	rx_reqs;	/* List of free RX structs */
 	struct list_head	rx_reqs_active;	/* List of Active RX xfers */
 	struct list_head	rx_reqs_active;	/* List of Active RX xfers */
 	struct list_head	rx_buffers;	/* List of completed xfers */
 	struct list_head	rx_buffers;	/* List of completed xfers */
@@ -898,19 +897,20 @@ set_printer_interface(struct printer_dev *dev)
 {
 {
 	int			result = 0;
 	int			result = 0;
 
 
-	dev->in = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc);
+	dev->in_ep->desc = ep_desc(dev->gadget, &hs_ep_in_desc, &fs_ep_in_desc);
 	dev->in_ep->driver_data = dev;
 	dev->in_ep->driver_data = dev;
 
 
-	dev->out = ep_desc(dev->gadget, &hs_ep_out_desc, &fs_ep_out_desc);
+	dev->out_ep->desc = ep_desc(dev->gadget, &hs_ep_out_desc,
+				    &fs_ep_out_desc);
 	dev->out_ep->driver_data = dev;
 	dev->out_ep->driver_data = dev;
 
 
-	result = usb_ep_enable(dev->in_ep, dev->in);
+	result = usb_ep_enable(dev->in_ep);
 	if (result != 0) {
 	if (result != 0) {
 		DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
 		DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
 		goto done;
 		goto done;
 	}
 	}
 
 
-	result = usb_ep_enable(dev->out_ep, dev->out);
+	result = usb_ep_enable(dev->out_ep);
 	if (result != 0) {
 	if (result != 0) {
 		DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
 		DBG(dev, "enable %s --> %d\n", dev->in_ep->name, result);
 		goto done;
 		goto done;
@@ -921,8 +921,8 @@ done:
 	if (result != 0) {
 	if (result != 0) {
 		(void) usb_ep_disable(dev->in_ep);
 		(void) usb_ep_disable(dev->in_ep);
 		(void) usb_ep_disable(dev->out_ep);
 		(void) usb_ep_disable(dev->out_ep);
-		dev->in = NULL;
-		dev->out = NULL;
+		dev->in_ep->desc = NULL;
+		dev->out_ep->desc = NULL;
 	}
 	}
 
 
 	/* caller is responsible for cleanup on error */
 	/* caller is responsible for cleanup on error */
@@ -936,12 +936,14 @@ static void printer_reset_interface(struct printer_dev *dev)
 
 
 	DBG(dev, "%s\n", __func__);
 	DBG(dev, "%s\n", __func__);
 
 
-	if (dev->in)
+	if (dev->in_ep->desc)
 		usb_ep_disable(dev->in_ep);
 		usb_ep_disable(dev->in_ep);
 
 
-	if (dev->out)
+	if (dev->out_ep->desc)
 		usb_ep_disable(dev->out_ep);
 		usb_ep_disable(dev->out_ep);
 
 
+	dev->in_ep->desc = NULL;
+	dev->out_ep->desc = NULL;
 	dev->interface = -1;
 	dev->interface = -1;
 }
 }
 
 
@@ -1107,9 +1109,9 @@ static void printer_soft_reset(struct printer_dev *dev)
 		list_add(&req->list, &dev->tx_reqs);
 		list_add(&req->list, &dev->tx_reqs);
 	}
 	}
 
 
-	if (usb_ep_enable(dev->in_ep, dev->in))
+	if (usb_ep_enable(dev->in_ep))
 		DBG(dev, "Failed to enable USB in_ep\n");
 		DBG(dev, "Failed to enable USB in_ep\n");
-	if (usb_ep_enable(dev->out_ep, dev->out))
+	if (usb_ep_enable(dev->out_ep))
 		DBG(dev, "Failed to enable USB out_ep\n");
 		DBG(dev, "Failed to enable USB out_ep\n");
 
 
 	wake_up_interruptible(&dev->rx_wait);
 	wake_up_interruptible(&dev->rx_wait);
@@ -1149,6 +1151,8 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 			switch (wValue >> 8) {
 			switch (wValue >> 8) {
 
 
 			case USB_DT_DEVICE:
 			case USB_DT_DEVICE:
+				device_desc.bMaxPacketSize0 =
+					gadget->ep0->maxpacket;
 				value = min(wLength, (u16) sizeof device_desc);
 				value = min(wLength, (u16) sizeof device_desc);
 				memcpy(req->buf, &device_desc, value);
 				memcpy(req->buf, &device_desc, value);
 				break;
 				break;
@@ -1156,6 +1160,12 @@ printer_setup(struct usb_gadget *gadget, const struct usb_ctrlrequest *ctrl)
 			case USB_DT_DEVICE_QUALIFIER:
 			case USB_DT_DEVICE_QUALIFIER:
 				if (!gadget->is_dualspeed)
 				if (!gadget->is_dualspeed)
 					break;
 					break;
+				/*
+				 * assumes ep0 uses the same value for both
+				 * speeds
+				 */
+				dev_qualifier.bMaxPacketSize0 =
+					gadget->ep0->maxpacket;
 				value = min(wLength,
 				value = min(wLength,
 						(u16) sizeof dev_qualifier);
 						(u16) sizeof dev_qualifier);
 				memcpy(req->buf, &dev_qualifier, value);
 				memcpy(req->buf, &dev_qualifier, value);
@@ -1451,15 +1461,11 @@ autoconf_fail:
 	out_ep->driver_data = out_ep;	/* claim */
 	out_ep->driver_data = out_ep;	/* claim */
 
 
 #ifdef	CONFIG_USB_GADGET_DUALSPEED
 #ifdef	CONFIG_USB_GADGET_DUALSPEED
-	/* assumes ep0 uses the same value for both speeds ... */
-	dev_qualifier.bMaxPacketSize0 = device_desc.bMaxPacketSize0;
-
-	/* and that all endpoints are dual-speed */
+	/* assumes that all endpoints are dual-speed */
 	hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
 	hs_ep_in_desc.bEndpointAddress = fs_ep_in_desc.bEndpointAddress;
 	hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
 	hs_ep_out_desc.bEndpointAddress = fs_ep_out_desc.bEndpointAddress;
 #endif	/* DUALSPEED */
 #endif	/* DUALSPEED */
 
 
-	device_desc.bMaxPacketSize0 = gadget->ep0->maxpacket;
 	usb_gadget_set_selfpowered(gadget);
 	usb_gadget_set_selfpowered(gadget);
 
 
 	if (gadget->is_otg) {
 	if (gadget->is_otg) {

+ 13 - 6
drivers/usb/gadget/pxa25x_udc.c

@@ -1011,12 +1011,18 @@ static int pxa25x_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
 	return -EOPNOTSUPP;
 	return -EOPNOTSUPP;
 }
 }
 
 
+static int pxa25x_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int pxa25x_stop(struct usb_gadget_driver *driver);
+
 static const struct usb_gadget_ops pxa25x_udc_ops = {
 static const struct usb_gadget_ops pxa25x_udc_ops = {
 	.get_frame	= pxa25x_udc_get_frame,
 	.get_frame	= pxa25x_udc_get_frame,
 	.wakeup		= pxa25x_udc_wakeup,
 	.wakeup		= pxa25x_udc_wakeup,
 	.vbus_session	= pxa25x_udc_vbus_session,
 	.vbus_session	= pxa25x_udc_vbus_session,
 	.pullup		= pxa25x_udc_pullup,
 	.pullup		= pxa25x_udc_pullup,
 	.vbus_draw	= pxa25x_udc_vbus_draw,
 	.vbus_draw	= pxa25x_udc_vbus_draw,
+	.start		= pxa25x_start,
+	.stop		= pxa25x_stop,
 };
 };
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
@@ -1263,7 +1269,7 @@ static void udc_enable (struct pxa25x_udc *dev)
  * disconnect is reported.  then a host may connect again, or
  * disconnect is reported.  then a host may connect again, or
  * the driver might get unbound.
  * the driver might get unbound.
  */
  */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int pxa25x_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 		int (*bind)(struct usb_gadget *))
 {
 {
 	struct pxa25x_udc	*dev = the_controller;
 	struct pxa25x_udc	*dev = the_controller;
@@ -1322,7 +1328,6 @@ fail:
 bind_fail:
 bind_fail:
 	return retval;
 	return retval;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 
 static void
 static void
 stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver)
 stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver)
@@ -1351,7 +1356,7 @@ stop_activity(struct pxa25x_udc *dev, struct usb_gadget_driver *driver)
 	udc_reinit(dev);
 	udc_reinit(dev);
 }
 }
 
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int pxa25x_stop(struct usb_gadget_driver *driver)
 {
 {
 	struct pxa25x_udc	*dev = the_controller;
 	struct pxa25x_udc	*dev = the_controller;
 
 
@@ -1379,8 +1384,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 	dump_state(dev);
 	dump_state(dev);
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
@@ -2231,8 +2234,11 @@ static int __init pxa25x_udc_probe(struct platform_device *pdev)
 #endif
 #endif
 	create_debug_files(dev);
 	create_debug_files(dev);
 
 
-	return 0;
+	retval = usb_add_gadget_udc(&pdev->dev, &dev->gadget);
+	if (!retval)
+		return retval;
 
 
+	remove_debug_files(dev);
 #ifdef	CONFIG_ARCH_LUBBOCK
 #ifdef	CONFIG_ARCH_LUBBOCK
 lubbock_fail0:
 lubbock_fail0:
 	free_irq(LUBBOCK_USB_DISC_IRQ, dev);
 	free_irq(LUBBOCK_USB_DISC_IRQ, dev);
@@ -2261,6 +2267,7 @@ static int __exit pxa25x_udc_remove(struct platform_device *pdev)
 {
 {
 	struct pxa25x_udc *dev = platform_get_drvdata(pdev);
 	struct pxa25x_udc *dev = platform_get_drvdata(pdev);
 
 
+	usb_del_gadget_udc(&dev->gadget);
 	if (dev->driver)
 	if (dev->driver)
 		return -EBUSY;
 		return -EBUSY;
 
 

+ 16 - 7
drivers/usb/gadget/pxa27x_udc.c

@@ -1680,12 +1680,18 @@ static int pxa_udc_vbus_draw(struct usb_gadget *_gadget, unsigned mA)
 	return -EOPNOTSUPP;
 	return -EOPNOTSUPP;
 }
 }
 
 
+static int pxa27x_udc_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int pxa27x_udc_stop(struct usb_gadget_driver *driver);
+
 static const struct usb_gadget_ops pxa_udc_ops = {
 static const struct usb_gadget_ops pxa_udc_ops = {
 	.get_frame	= pxa_udc_get_frame,
 	.get_frame	= pxa_udc_get_frame,
 	.wakeup		= pxa_udc_wakeup,
 	.wakeup		= pxa_udc_wakeup,
 	.pullup		= pxa_udc_pullup,
 	.pullup		= pxa_udc_pullup,
 	.vbus_session	= pxa_udc_vbus_session,
 	.vbus_session	= pxa_udc_vbus_session,
 	.vbus_draw	= pxa_udc_vbus_draw,
 	.vbus_draw	= pxa_udc_vbus_draw,
+	.start		= pxa27x_udc_start,
+	.stop		= pxa27x_udc_stop,
 };
 };
 
 
 /**
 /**
@@ -1791,7 +1797,7 @@ static void udc_enable(struct pxa_udc *udc)
 }
 }
 
 
 /**
 /**
- * usb_gadget_probe_driver - Register gadget driver
+ * pxa27x_start - Register gadget driver
  * @driver: gadget driver
  * @driver: gadget driver
  * @bind: bind function
  * @bind: bind function
  *
  *
@@ -1805,7 +1811,7 @@ static void udc_enable(struct pxa_udc *udc)
  *
  *
  * Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise
  * Returns 0 if no error, -EINVAL, -ENODEV, -EBUSY otherwise
  */
  */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int pxa27x_udc_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 		int (*bind)(struct usb_gadget *))
 {
 {
 	struct pxa_udc *udc = the_controller;
 	struct pxa_udc *udc = the_controller;
@@ -1860,8 +1866,6 @@ add_fail:
 	udc->gadget.dev.driver = NULL;
 	udc->gadget.dev.driver = NULL;
 	return retval;
 	return retval;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
-
 
 
 /**
 /**
  * stop_activity - Stops udc endpoints
  * stop_activity - Stops udc endpoints
@@ -1888,12 +1892,12 @@ static void stop_activity(struct pxa_udc *udc, struct usb_gadget_driver *driver)
 }
 }
 
 
 /**
 /**
- * usb_gadget_unregister_driver - Unregister the gadget driver
+ * pxa27x_udc_stop - Unregister the gadget driver
  * @driver: gadget driver
  * @driver: gadget driver
  *
  *
  * Returns 0 if no error, -ENODEV, -EINVAL otherwise
  * Returns 0 if no error, -ENODEV, -EINVAL otherwise
  */
  */
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int pxa27x_udc_stop(struct usb_gadget_driver *driver)
 {
 {
 	struct pxa_udc *udc = the_controller;
 	struct pxa_udc *udc = the_controller;
 
 
@@ -1917,7 +1921,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 		return otg_set_peripheral(udc->transceiver, NULL);
 		return otg_set_peripheral(udc->transceiver, NULL);
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 
 /**
 /**
  * handle_ep0_ctrl_req - handle control endpoint control request
  * handle_ep0_ctrl_req - handle control endpoint control request
@@ -2516,9 +2519,14 @@ static int __init pxa_udc_probe(struct platform_device *pdev)
 			driver_name, IRQ_USB, retval);
 			driver_name, IRQ_USB, retval);
 		goto err_irq;
 		goto err_irq;
 	}
 	}
+	retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
+	if (retval)
+		goto err_add_udc;
 
 
 	pxa_init_debugfs(udc);
 	pxa_init_debugfs(udc);
 	return 0;
 	return 0;
+err_add_udc:
+	free_irq(udc->irq, udc);
 err_irq:
 err_irq:
 	iounmap(udc->regs);
 	iounmap(udc->regs);
 err_map:
 err_map:
@@ -2537,6 +2545,7 @@ static int __exit pxa_udc_remove(struct platform_device *_dev)
 	struct pxa_udc *udc = platform_get_drvdata(_dev);
 	struct pxa_udc *udc = platform_get_drvdata(_dev);
 	int gpio = udc->mach->gpio_pullup;
 	int gpio = udc->mach->gpio_pullup;
 
 
+	usb_del_gadget_udc(&udc->gadget);
 	usb_gadget_unregister_driver(udc->driver);
 	usb_gadget_unregister_driver(udc->driver);
 	free_irq(udc->irq, udc);
 	free_irq(udc->irq, udc);
 	pxa_cleanup_debugfs(udc);
 	pxa_cleanup_debugfs(udc);

+ 58 - 13
drivers/usb/gadget/r8a66597-udc.c

@@ -3,7 +3,7 @@
  *
  *
  * Copyright (C) 2006-2009 Renesas Solutions Corp.
  * Copyright (C) 2006-2009 Renesas Solutions Corp.
  *
  *
- * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ * Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by
@@ -576,7 +576,11 @@ static void init_controller(struct r8a66597 *r8a66597)
 	u16 endian = r8a66597->pdata->endian ? BIGEND : 0;
 	u16 endian = r8a66597->pdata->endian ? BIGEND : 0;
 
 
 	if (r8a66597->pdata->on_chip) {
 	if (r8a66597->pdata->on_chip) {
-		r8a66597_bset(r8a66597, 0x04, SYSCFG1);
+		if (r8a66597->pdata->buswait)
+			r8a66597_write(r8a66597, r8a66597->pdata->buswait,
+					SYSCFG1);
+		else
+			r8a66597_write(r8a66597, 0x0f, SYSCFG1);
 		r8a66597_bset(r8a66597, HSE, SYSCFG0);
 		r8a66597_bset(r8a66597, HSE, SYSCFG0);
 
 
 		r8a66597_bclr(r8a66597, USBE, SYSCFG0);
 		r8a66597_bclr(r8a66597, USBE, SYSCFG0);
@@ -618,6 +622,7 @@ static void disable_controller(struct r8a66597 *r8a66597)
 {
 {
 	if (r8a66597->pdata->on_chip) {
 	if (r8a66597->pdata->on_chip) {
 		r8a66597_bset(r8a66597, SCKE, SYSCFG0);
 		r8a66597_bset(r8a66597, SCKE, SYSCFG0);
+		r8a66597_bclr(r8a66597, UTST, TESTMODE);
 
 
 		/* disable interrupts */
 		/* disable interrupts */
 		r8a66597_write(r8a66597, 0, INTENB0);
 		r8a66597_write(r8a66597, 0, INTENB0);
@@ -635,6 +640,7 @@ static void disable_controller(struct r8a66597 *r8a66597)
 		r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
 		r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
 
 
 	} else {
 	} else {
+		r8a66597_bclr(r8a66597, UTST, TESTMODE);
 		r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
 		r8a66597_bclr(r8a66597, SCKE, SYSCFG0);
 		udelay(1);
 		udelay(1);
 		r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
 		r8a66597_bclr(r8a66597, PLLC, SYSCFG0);
@@ -999,10 +1005,29 @@ static void clear_feature(struct r8a66597 *r8a66597,
 
 
 static void set_feature(struct r8a66597 *r8a66597, struct usb_ctrlrequest *ctrl)
 static void set_feature(struct r8a66597 *r8a66597, struct usb_ctrlrequest *ctrl)
 {
 {
+	u16 tmp;
+	int timeout = 3000;
 
 
 	switch (ctrl->bRequestType & USB_RECIP_MASK) {
 	switch (ctrl->bRequestType & USB_RECIP_MASK) {
 	case USB_RECIP_DEVICE:
 	case USB_RECIP_DEVICE:
-		control_end(r8a66597, 1);
+		switch (le16_to_cpu(ctrl->wValue)) {
+		case USB_DEVICE_TEST_MODE:
+			control_end(r8a66597, 1);
+			/* Wait for the completion of status stage */
+			do {
+				tmp = r8a66597_read(r8a66597, INTSTS0) & CTSQ;
+				udelay(1);
+			} while (tmp != CS_IDST || timeout-- > 0);
+
+			if (tmp == CS_IDST)
+				r8a66597_bset(r8a66597,
+					      le16_to_cpu(ctrl->wIndex >> 8),
+					      TESTMODE);
+			break;
+		default:
+			pipe_stall(r8a66597, 0);
+			break;
+		}
 		break;
 		break;
 	case USB_RECIP_INTERFACE:
 	case USB_RECIP_INTERFACE:
 		control_end(r8a66597, 1);
 		control_end(r8a66597, 1);
@@ -1410,7 +1435,7 @@ static struct usb_ep_ops r8a66597_ep_ops = {
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 static struct r8a66597 *the_controller;
 static struct r8a66597 *the_controller;
 
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int r8a66597_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 		int (*bind)(struct usb_gadget *))
 {
 {
 	struct r8a66597 *r8a66597 = the_controller;
 	struct r8a66597 *r8a66597 = the_controller;
@@ -1444,6 +1469,7 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 		goto error;
 		goto error;
 	}
 	}
 
 
+	init_controller(r8a66597);
 	r8a66597_bset(r8a66597, VBSE, INTENB0);
 	r8a66597_bset(r8a66597, VBSE, INTENB0);
 	if (r8a66597_read(r8a66597, INTSTS0) & VBSTS) {
 	if (r8a66597_read(r8a66597, INTSTS0) & VBSTS) {
 		r8a66597_start_xclock(r8a66597);
 		r8a66597_start_xclock(r8a66597);
@@ -1462,9 +1488,8 @@ error:
 
 
 	return retval;
 	return retval;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int r8a66597_stop(struct usb_gadget_driver *driver)
 {
 {
 	struct r8a66597 *r8a66597 = the_controller;
 	struct r8a66597 *r8a66597 = the_controller;
 	unsigned long flags;
 	unsigned long flags;
@@ -1475,20 +1500,16 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 	spin_lock_irqsave(&r8a66597->lock, flags);
 	spin_lock_irqsave(&r8a66597->lock, flags);
 	if (r8a66597->gadget.speed != USB_SPEED_UNKNOWN)
 	if (r8a66597->gadget.speed != USB_SPEED_UNKNOWN)
 		r8a66597_usb_disconnect(r8a66597);
 		r8a66597_usb_disconnect(r8a66597);
-	spin_unlock_irqrestore(&r8a66597->lock, flags);
-
 	r8a66597_bclr(r8a66597, VBSE, INTENB0);
 	r8a66597_bclr(r8a66597, VBSE, INTENB0);
+	disable_controller(r8a66597);
+	spin_unlock_irqrestore(&r8a66597->lock, flags);
 
 
 	driver->unbind(&r8a66597->gadget);
 	driver->unbind(&r8a66597->gadget);
 
 
-	init_controller(r8a66597);
-	disable_controller(r8a66597);
-
 	device_del(&r8a66597->gadget.dev);
 	device_del(&r8a66597->gadget.dev);
 	r8a66597->driver = NULL;
 	r8a66597->driver = NULL;
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 static int r8a66597_get_frame(struct usb_gadget *_gadget)
 static int r8a66597_get_frame(struct usb_gadget *_gadget)
@@ -1497,14 +1518,33 @@ static int r8a66597_get_frame(struct usb_gadget *_gadget)
 	return r8a66597_read(r8a66597, FRMNUM) & 0x03FF;
 	return r8a66597_read(r8a66597, FRMNUM) & 0x03FF;
 }
 }
 
 
+static int r8a66597_pullup(struct usb_gadget *gadget, int is_on)
+{
+	struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget);
+	unsigned long flags;
+
+	spin_lock_irqsave(&r8a66597->lock, flags);
+	if (is_on)
+		r8a66597_bset(r8a66597, DPRPU, SYSCFG0);
+	else
+		r8a66597_bclr(r8a66597, DPRPU, SYSCFG0);
+	spin_unlock_irqrestore(&r8a66597->lock, flags);
+
+	return 0;
+}
+
 static struct usb_gadget_ops r8a66597_gadget_ops = {
 static struct usb_gadget_ops r8a66597_gadget_ops = {
 	.get_frame		= r8a66597_get_frame,
 	.get_frame		= r8a66597_get_frame,
+	.start			= r8a66597_start,
+	.stop			= r8a66597_stop,
+	.pullup			= r8a66597_pullup,
 };
 };
 
 
 static int __exit r8a66597_remove(struct platform_device *pdev)
 static int __exit r8a66597_remove(struct platform_device *pdev)
 {
 {
 	struct r8a66597		*r8a66597 = dev_get_drvdata(&pdev->dev);
 	struct r8a66597		*r8a66597 = dev_get_drvdata(&pdev->dev);
 
 
+	usb_del_gadget_udc(&r8a66597->gadget);
 	del_timer_sync(&r8a66597->timer);
 	del_timer_sync(&r8a66597->timer);
 	iounmap(r8a66597->reg);
 	iounmap(r8a66597->reg);
 	free_irq(platform_get_irq(pdev, 0), r8a66597);
 	free_irq(platform_get_irq(pdev, 0), r8a66597);
@@ -1645,11 +1685,15 @@ static int __init r8a66597_probe(struct platform_device *pdev)
 		goto clean_up3;
 		goto clean_up3;
 	r8a66597->ep0_req->complete = nop_completion;
 	r8a66597->ep0_req->complete = nop_completion;
 
 
-	init_controller(r8a66597);
+	ret = usb_add_gadget_udc(&pdev->dev, &r8a66597->gadget);
+	if (ret)
+		goto err_add_udc;
 
 
 	dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
 	dev_info(&pdev->dev, "version %s\n", DRIVER_VERSION);
 	return 0;
 	return 0;
 
 
+err_add_udc:
+	r8a66597_free_request(&r8a66597->ep[0].ep, r8a66597->ep0_req);
 clean_up3:
 clean_up3:
 	free_irq(irq, r8a66597);
 	free_irq(irq, r8a66597);
 clean_up2:
 clean_up2:
@@ -1679,6 +1723,7 @@ static struct platform_driver r8a66597_driver = {
 		.name =	(char *) udc_name,
 		.name =	(char *) udc_name,
 	},
 	},
 };
 };
+MODULE_ALIAS("platform:r8a66597_udc");
 
 
 static int __init r8a66597_udc_init(void)
 static int __init r8a66597_udc_init(void)
 {
 {

+ 1 - 1
drivers/usb/gadget/r8a66597-udc.h

@@ -3,7 +3,7 @@
  *
  *
  * Copyright (C) 2007-2009 Renesas Solutions Corp.
  * Copyright (C) 2007-2009 Renesas Solutions Corp.
  *
  *
- * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ * Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by

+ 15 - 4
drivers/usb/gadget/s3c-hsotg.c

@@ -2574,7 +2574,7 @@ static int s3c_hsotg_corereset(struct s3c_hsotg *hsotg)
 	return 0;
 	return 0;
 }
 }
 
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int s3c_hsotg_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 		int (*bind)(struct usb_gadget *))
 {
 {
 	struct s3c_hsotg *hsotg = our_hsotg;
 	struct s3c_hsotg *hsotg = our_hsotg;
@@ -2745,9 +2745,8 @@ err:
 	hsotg->gadget.dev.driver = NULL;
 	hsotg->gadget.dev.driver = NULL;
 	return ret;
 	return ret;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int s3c_hsotg_stop(struct usb_gadget_driver *driver)
 {
 {
 	struct s3c_hsotg *hsotg = our_hsotg;
 	struct s3c_hsotg *hsotg = our_hsotg;
 	int ep;
 	int ep;
@@ -2775,7 +2774,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 
 
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 
 static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget)
 static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget)
 {
 {
@@ -2784,6 +2782,8 @@ static int s3c_hsotg_gadget_getframe(struct usb_gadget *gadget)
 
 
 static struct usb_gadget_ops s3c_hsotg_gadget_ops = {
 static struct usb_gadget_ops s3c_hsotg_gadget_ops = {
 	.get_frame	= s3c_hsotg_gadget_getframe,
 	.get_frame	= s3c_hsotg_gadget_getframe,
+	.start		= s3c_hsotg_start,
+	.stop		= s3c_hsotg_stop,
 };
 };
 
 
 /**
 /**
@@ -3403,6 +3403,10 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
 	for (epnum = 0; epnum < S3C_HSOTG_EPS; epnum++)
 	for (epnum = 0; epnum < S3C_HSOTG_EPS; epnum++)
 		s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum);
 		s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum);
 
 
+	ret = usb_add_gadget_udc(&pdev->dev, &hsotg->gadget);
+	if (ret)
+		goto err_add_udc;
+
 	s3c_hsotg_create_debug(hsotg);
 	s3c_hsotg_create_debug(hsotg);
 
 
 	s3c_hsotg_dump(hsotg);
 	s3c_hsotg_dump(hsotg);
@@ -3410,6 +3414,11 @@ static int __devinit s3c_hsotg_probe(struct platform_device *pdev)
 	our_hsotg = hsotg;
 	our_hsotg = hsotg;
 	return 0;
 	return 0;
 
 
+err_add_udc:
+	s3c_hsotg_gate(pdev, false);
+	clk_disable(hsotg->clk);
+	clk_put(hsotg->clk);
+
 err_regs:
 err_regs:
 	iounmap(hsotg->regs);
 	iounmap(hsotg->regs);
 
 
@@ -3427,6 +3436,8 @@ static int __devexit s3c_hsotg_remove(struct platform_device *pdev)
 {
 {
 	struct s3c_hsotg *hsotg = platform_get_drvdata(pdev);
 	struct s3c_hsotg *hsotg = platform_get_drvdata(pdev);
 
 
+	usb_del_gadget_udc(&hsotg->gadget);
+
 	s3c_hsotg_delete_debug(hsotg);
 	s3c_hsotg_delete_debug(hsotg);
 
 
 	usb_gadget_unregister_driver(hsotg->driver);
 	usb_gadget_unregister_driver(hsotg->driver);

+ 13 - 4
drivers/usb/gadget/s3c-hsudc.c

@@ -1133,7 +1133,7 @@ static irqreturn_t s3c_hsudc_irq(int irq, void *_dev)
 	return IRQ_HANDLED;
 	return IRQ_HANDLED;
 }
 }
 
 
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int s3c_hsudc_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 		int (*bind)(struct usb_gadget *))
 {
 {
 	struct s3c_hsudc *hsudc = the_controller;
 	struct s3c_hsudc *hsudc = the_controller;
@@ -1181,9 +1181,8 @@ int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
 
 
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int s3c_hsudc_stop(struct usb_gadget_driver *driver)
 {
 {
 	struct s3c_hsudc *hsudc = the_controller;
 	struct s3c_hsudc *hsudc = the_controller;
 	unsigned long flags;
 	unsigned long flags;
@@ -1210,7 +1209,6 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
 			driver->driver.name);
 			driver->driver.name);
 	return 0;
 	return 0;
 }
 }
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
 
 
 static inline u32 s3c_hsudc_read_frameno(struct s3c_hsudc *hsudc)
 static inline u32 s3c_hsudc_read_frameno(struct s3c_hsudc *hsudc)
 {
 {
@@ -1224,6 +1222,8 @@ static int s3c_hsudc_gadget_getframe(struct usb_gadget *gadget)
 
 
 static struct usb_gadget_ops s3c_hsudc_gadget_ops = {
 static struct usb_gadget_ops s3c_hsudc_gadget_ops = {
 	.get_frame	= s3c_hsudc_gadget_getframe,
 	.get_frame	= s3c_hsudc_gadget_getframe,
+	.start		= s3c_hsudc_start,
+	.stop		= s3c_hsudc_stop,
 };
 };
 
 
 static int s3c_hsudc_probe(struct platform_device *pdev)
 static int s3c_hsudc_probe(struct platform_device *pdev)
@@ -1311,7 +1311,15 @@ static int s3c_hsudc_probe(struct platform_device *pdev)
 
 
 	disable_irq(hsudc->irq);
 	disable_irq(hsudc->irq);
 	local_irq_enable();
 	local_irq_enable();
+
+	ret = usb_add_gadget_udc(&pdev->dev, &hsudc->gadget);
+	if (ret)
+		goto err_add_udc;
+
 	return 0;
 	return 0;
+err_add_udc:
+	clk_disable(hsudc->uclk);
+	clk_put(hsudc->uclk);
 err_clk:
 err_clk:
 	free_irq(hsudc->irq, hsudc);
 	free_irq(hsudc->irq, hsudc);
 err_irq:
 err_irq:
@@ -1333,6 +1341,7 @@ static struct platform_driver s3c_hsudc_driver = {
 	},
 	},
 	.probe		= s3c_hsudc_probe,
 	.probe		= s3c_hsudc_probe,
 };
 };
+MODULE_ALIAS("platform:s3c-hsudc");
 
 
 static int __init s3c_hsudc_modinit(void)
 static int __init s3c_hsudc_modinit(void)
 {
 {

+ 28 - 32
drivers/usb/gadget/s3c2410_udc.c

@@ -1552,6 +1552,10 @@ static int s3c2410_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
 	return -ENOTSUPP;
 	return -ENOTSUPP;
 }
 }
 
 
+static int s3c2410_udc_start(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *));
+static int s3c2410_udc_stop(struct usb_gadget_driver *driver);
+
 static const struct usb_gadget_ops s3c2410_ops = {
 static const struct usb_gadget_ops s3c2410_ops = {
 	.get_frame		= s3c2410_udc_get_frame,
 	.get_frame		= s3c2410_udc_get_frame,
 	.wakeup			= s3c2410_udc_wakeup,
 	.wakeup			= s3c2410_udc_wakeup,
@@ -1559,6 +1563,8 @@ static const struct usb_gadget_ops s3c2410_ops = {
 	.pullup			= s3c2410_udc_pullup,
 	.pullup			= s3c2410_udc_pullup,
 	.vbus_session		= s3c2410_udc_vbus_session,
 	.vbus_session		= s3c2410_udc_vbus_session,
 	.vbus_draw		= s3c2410_vbus_draw,
 	.vbus_draw		= s3c2410_vbus_draw,
+	.start			= s3c2410_udc_start,
+	.stop			= s3c2410_udc_stop,
 };
 };
 
 
 static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd)
 static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd)
@@ -1567,7 +1573,7 @@ static void s3c2410_udc_command(enum s3c2410_udc_cmd_e cmd)
 		return;
 		return;
 
 
 	if (udc_info->udc_command) {
 	if (udc_info->udc_command) {
-		udc_info->udc_command(S3C2410_UDC_P_DISABLE);
+		udc_info->udc_command(cmd);
 	} else if (gpio_is_valid(udc_info->pullup_pin)) {
 	} else if (gpio_is_valid(udc_info->pullup_pin)) {
 		int value;
 		int value;
 
 
@@ -1672,10 +1678,7 @@ static void s3c2410_udc_enable(struct s3c2410_udc *dev)
 	s3c2410_udc_command(S3C2410_UDC_P_ENABLE);
 	s3c2410_udc_command(S3C2410_UDC_P_ENABLE);
 }
 }
 
 
-/*
- *	usb_gadget_probe_driver
- */
-int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+static int s3c2410_udc_start(struct usb_gadget_driver *driver,
 		int (*bind)(struct usb_gadget *))
 		int (*bind)(struct usb_gadget *))
 {
 {
 	struct s3c2410_udc *udc = the_controller;
 	struct s3c2410_udc *udc = the_controller;
@@ -1730,12 +1733,8 @@ register_error:
 	udc->gadget.dev.driver = NULL;
 	udc->gadget.dev.driver = NULL;
 	return retval;
 	return retval;
 }
 }
-EXPORT_SYMBOL(usb_gadget_probe_driver);
 
 
-/*
- *	usb_gadget_unregister_driver
- */
-int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+static int s3c2410_udc_stop(struct usb_gadget_driver *driver)
 {
 {
 	struct s3c2410_udc *udc = the_controller;
 	struct s3c2410_udc *udc = the_controller;
 
 
@@ -1955,6 +1954,10 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
 			goto err_vbus_irq;
 			goto err_vbus_irq;
 	}
 	}
 
 
+	retval = usb_add_gadget_udc(&pdev->dev, &udc->gadget);
+	if (retval)
+		goto err_add_udc;
+
 	if (s3c2410_udc_debugfs_root) {
 	if (s3c2410_udc_debugfs_root) {
 		udc->regs_info = debugfs_create_file("registers", S_IRUGO,
 		udc->regs_info = debugfs_create_file("registers", S_IRUGO,
 				s3c2410_udc_debugfs_root,
 				s3c2410_udc_debugfs_root,
@@ -1967,6 +1970,10 @@ static int s3c2410_udc_probe(struct platform_device *pdev)
 
 
 	return 0;
 	return 0;
 
 
+err_add_udc:
+	if (udc_info && !udc_info->udc_command &&
+			gpio_is_valid(udc_info->pullup_pin))
+		gpio_free(udc_info->pullup_pin);
 err_vbus_irq:
 err_vbus_irq:
 	if (udc_info && udc_info->vbus_pin > 0)
 	if (udc_info && udc_info->vbus_pin > 0)
 		free_irq(gpio_to_irq(udc_info->vbus_pin), udc);
 		free_irq(gpio_to_irq(udc_info->vbus_pin), udc);
@@ -1992,6 +1999,8 @@ static int s3c2410_udc_remove(struct platform_device *pdev)
 	unsigned int irq;
 	unsigned int irq;
 
 
 	dev_dbg(&pdev->dev, "%s()\n", __func__);
 	dev_dbg(&pdev->dev, "%s()\n", __func__);
+
+	usb_del_gadget_udc(&udc->gadget);
 	if (udc->driver)
 	if (udc->driver)
 		return -EBUSY;
 		return -EBUSY;
 
 
@@ -2048,26 +2057,22 @@ static int s3c2410_udc_resume(struct platform_device *pdev)
 #define s3c2410_udc_resume	NULL
 #define s3c2410_udc_resume	NULL
 #endif
 #endif
 
 
-static struct platform_driver udc_driver_2410 = {
-	.driver		= {
-		.name	= "s3c2410-usbgadget",
-		.owner	= THIS_MODULE,
-	},
-	.probe		= s3c2410_udc_probe,
-	.remove		= s3c2410_udc_remove,
-	.suspend	= s3c2410_udc_suspend,
-	.resume		= s3c2410_udc_resume,
+static const struct platform_device_id s3c_udc_ids[] = {
+	{ "s3c2410-usbgadget", },
+	{ "s3c2440-usbgadget", },
 };
 };
+MODULE_DEVICE_TABLE(platform, s3c_udc_ids);
 
 
-static struct platform_driver udc_driver_2440 = {
+static struct platform_driver udc_driver_24x0 = {
 	.driver		= {
 	.driver		= {
-		.name	= "s3c2440-usbgadget",
+		.name	= "s3c24x0-usbgadget",
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
 	},
 	},
 	.probe		= s3c2410_udc_probe,
 	.probe		= s3c2410_udc_probe,
 	.remove		= s3c2410_udc_remove,
 	.remove		= s3c2410_udc_remove,
 	.suspend	= s3c2410_udc_suspend,
 	.suspend	= s3c2410_udc_suspend,
 	.resume		= s3c2410_udc_resume,
 	.resume		= s3c2410_udc_resume,
+	.id_table	= s3c_udc_ids,
 };
 };
 
 
 static int __init udc_init(void)
 static int __init udc_init(void)
@@ -2083,11 +2088,7 @@ static int __init udc_init(void)
 		s3c2410_udc_debugfs_root = NULL;
 		s3c2410_udc_debugfs_root = NULL;
 	}
 	}
 
 
-	retval = platform_driver_register(&udc_driver_2410);
-	if (retval)
-		goto err;
-
-	retval = platform_driver_register(&udc_driver_2440);
+	retval = platform_driver_register(&udc_driver_24x0);
 	if (retval)
 	if (retval)
 		goto err;
 		goto err;
 
 
@@ -2100,13 +2101,10 @@ err:
 
 
 static void __exit udc_exit(void)
 static void __exit udc_exit(void)
 {
 {
-	platform_driver_unregister(&udc_driver_2410);
-	platform_driver_unregister(&udc_driver_2440);
+	platform_driver_unregister(&udc_driver_24x0);
 	debugfs_remove(s3c2410_udc_debugfs_root);
 	debugfs_remove(s3c2410_udc_debugfs_root);
 }
 }
 
 
-EXPORT_SYMBOL(usb_gadget_unregister_driver);
-
 module_init(udc_init);
 module_init(udc_init);
 module_exit(udc_exit);
 module_exit(udc_exit);
 
 
@@ -2114,5 +2112,3 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_VERSION(DRIVER_VERSION);
 MODULE_LICENSE("GPL");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s3c2410-usbgadget");
-MODULE_ALIAS("platform:s3c2440-usbgadget");

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

@@ -242,6 +242,7 @@ static struct usb_composite_driver gserial_driver = {
 	.name		= "g_serial",
 	.name		= "g_serial",
 	.dev		= &device_desc,
 	.dev		= &device_desc,
 	.strings	= dev_strings,
 	.strings	= dev_strings,
+	.max_speed	= USB_SPEED_HIGH,
 };
 };
 
 
 static int __init init(void)
 static int __init init(void)

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

@@ -494,7 +494,7 @@ static struct usb_descriptor_header *fsg_hs_function[] = {
 };
 };
 
 
 /* Maxpacket and other transfer characteristics vary by speed. */
 /* Maxpacket and other transfer characteristics vary by speed. */
-static struct usb_endpoint_descriptor *
+static __maybe_unused struct usb_endpoint_descriptor *
 fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
 fsg_ep_desc(struct usb_gadget *g, struct usb_endpoint_descriptor *fs,
 		struct usb_endpoint_descriptor *hs)
 		struct usb_endpoint_descriptor *hs)
 {
 {

+ 13 - 11
drivers/usb/gadget/u_ether.c

@@ -97,16 +97,17 @@ struct eth_dev {
 
 
 static unsigned qmult = 5;
 static unsigned qmult = 5;
 module_param(qmult, uint, S_IRUGO|S_IWUSR);
 module_param(qmult, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(qmult, "queue length multiplier at high speed");
+MODULE_PARM_DESC(qmult, "queue length multiplier at high/super speed");
 
 
 #else	/* full speed (low speed doesn't do bulk) */
 #else	/* full speed (low speed doesn't do bulk) */
 #define qmult		1
 #define qmult		1
 #endif
 #endif
 
 
-/* for dual-speed hardware, use deeper queues at highspeed */
+/* for dual-speed hardware, use deeper queues at high/super speed */
 static inline int qlen(struct usb_gadget *gadget)
 static inline int qlen(struct usb_gadget *gadget)
 {
 {
-	if (gadget_is_dualspeed(gadget) && gadget->speed == USB_SPEED_HIGH)
+	if (gadget_is_dualspeed(gadget) && (gadget->speed == USB_SPEED_HIGH ||
+					    gadget->speed == USB_SPEED_SUPER))
 		return qmult * DEFAULT_QLEN;
 		return qmult * DEFAULT_QLEN;
 	else
 	else
 		return DEFAULT_QLEN;
 		return DEFAULT_QLEN;
@@ -598,9 +599,10 @@ static netdev_tx_t eth_start_xmit(struct sk_buff *skb,
 
 
 	req->length = length;
 	req->length = length;
 
 
-	/* throttle highspeed IRQ rate back slightly */
+	/* throttle high/super speed IRQ rate back slightly */
 	if (gadget_is_dualspeed(dev->gadget))
 	if (gadget_is_dualspeed(dev->gadget))
-		req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH)
+		req->no_interrupt = (dev->gadget->speed == USB_SPEED_HIGH ||
+				     dev->gadget->speed == USB_SPEED_SUPER)
 			? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
 			? ((atomic_read(&dev->tx_qlen) % qmult) != 0)
 			: 0;
 			: 0;
 
 
@@ -693,8 +695,8 @@ static int eth_stop(struct net_device *net)
 		usb_ep_disable(link->out_ep);
 		usb_ep_disable(link->out_ep);
 		if (netif_carrier_ok(net)) {
 		if (netif_carrier_ok(net)) {
 			DBG(dev, "host still using in/out endpoints\n");
 			DBG(dev, "host still using in/out endpoints\n");
-			usb_ep_enable(link->in_ep, link->in);
-			usb_ep_enable(link->out_ep, link->out);
+			usb_ep_enable(link->in_ep);
+			usb_ep_enable(link->out_ep);
 		}
 		}
 	}
 	}
 	spin_unlock_irqrestore(&dev->lock, flags);
 	spin_unlock_irqrestore(&dev->lock, flags);
@@ -871,7 +873,7 @@ struct net_device *gether_connect(struct gether *link)
 		return ERR_PTR(-EINVAL);
 		return ERR_PTR(-EINVAL);
 
 
 	link->in_ep->driver_data = dev;
 	link->in_ep->driver_data = dev;
-	result = usb_ep_enable(link->in_ep, link->in);
+	result = usb_ep_enable(link->in_ep);
 	if (result != 0) {
 	if (result != 0) {
 		DBG(dev, "enable %s --> %d\n",
 		DBG(dev, "enable %s --> %d\n",
 			link->in_ep->name, result);
 			link->in_ep->name, result);
@@ -879,7 +881,7 @@ struct net_device *gether_connect(struct gether *link)
 	}
 	}
 
 
 	link->out_ep->driver_data = dev;
 	link->out_ep->driver_data = dev;
-	result = usb_ep_enable(link->out_ep, link->out);
+	result = usb_ep_enable(link->out_ep);
 	if (result != 0) {
 	if (result != 0) {
 		DBG(dev, "enable %s --> %d\n",
 		DBG(dev, "enable %s --> %d\n",
 			link->out_ep->name, result);
 			link->out_ep->name, result);
@@ -969,7 +971,7 @@ void gether_disconnect(struct gether *link)
 	}
 	}
 	spin_unlock(&dev->req_lock);
 	spin_unlock(&dev->req_lock);
 	link->in_ep->driver_data = NULL;
 	link->in_ep->driver_data = NULL;
-	link->in = NULL;
+	link->in_ep->desc = NULL;
 
 
 	usb_ep_disable(link->out_ep);
 	usb_ep_disable(link->out_ep);
 	spin_lock(&dev->req_lock);
 	spin_lock(&dev->req_lock);
@@ -984,7 +986,7 @@ void gether_disconnect(struct gether *link)
 	}
 	}
 	spin_unlock(&dev->req_lock);
 	spin_unlock(&dev->req_lock);
 	link->out_ep->driver_data = NULL;
 	link->out_ep->driver_data = NULL;
-	link->out = NULL;
+	link->out_ep->desc = NULL;
 
 
 	/* finish forgetting about this USB link episode */
 	/* finish forgetting about this USB link episode */
 	dev->header_len = 0;
 	dev->header_len = 0;

+ 0 - 4
drivers/usb/gadget/u_ether.h

@@ -52,10 +52,6 @@ struct gether {
 	struct usb_ep			*in_ep;
 	struct usb_ep			*in_ep;
 	struct usb_ep			*out_ep;
 	struct usb_ep			*out_ep;
 
 
-	/* descriptors match device speed at gether_connect() time */
-	struct usb_endpoint_descriptor	*in;
-	struct usb_endpoint_descriptor	*out;
-
 	bool				is_zlp_ok;
 	bool				is_zlp_ok;
 
 
 	u16				cdc_filter;
 	u16				cdc_filter;

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

@@ -1247,12 +1247,12 @@ int gserial_connect(struct gserial *gser, u8 port_num)
 	port = ports[port_num].port;
 	port = ports[port_num].port;
 
 
 	/* activate the endpoints */
 	/* activate the endpoints */
-	status = usb_ep_enable(gser->in, gser->in_desc);
+	status = usb_ep_enable(gser->in);
 	if (status < 0)
 	if (status < 0)
 		return status;
 		return status;
 	gser->in->driver_data = port;
 	gser->in->driver_data = port;
 
 
-	status = usb_ep_enable(gser->out, gser->out_desc);
+	status = usb_ep_enable(gser->out);
 	if (status < 0)
 	if (status < 0)
 		goto fail_out;
 		goto fail_out;
 	gser->out->driver_data = port;
 	gser->out->driver_data = port;

+ 0 - 2
drivers/usb/gadget/u_serial.h

@@ -35,8 +35,6 @@ struct gserial {
 
 
 	struct usb_ep			*in;
 	struct usb_ep			*in;
 	struct usb_ep			*out;
 	struct usb_ep			*out;
-	struct usb_endpoint_descriptor	*in_desc;
-	struct usb_endpoint_descriptor	*out_desc;
 
 
 	/* REVISIT avoid this CDC-ACM support harder ... */
 	/* REVISIT avoid this CDC-ACM support harder ... */
 	struct usb_cdc_line_coding port_line_coding;	/* 9600-8-N-1 etc */
 	struct usb_cdc_line_coding port_line_coding;	/* 9600-8-N-1 etc */

+ 484 - 0
drivers/usb/gadget/udc-core.c

@@ -0,0 +1,484 @@
+/**
+ * udc.c - Core UDC Framework
+ *
+ * Copyright (C) 2010 Texas Instruments
+ * Author: Felipe Balbi <balbi@ti.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2  of
+ * the License 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, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/err.h>
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/gadget.h>
+
+/**
+ * struct usb_udc - describes one usb device controller
+ * @driver - the gadget driver pointer. For use by the class code
+ * @dev - the child device to the actual controller
+ * @gadget - the gadget. For use by the class code
+ * @list - for use by the udc class driver
+ *
+ * This represents the internal data structure which is used by the UDC-class
+ * to hold information about udc driver and gadget together.
+ */
+struct usb_udc {
+	struct usb_gadget_driver	*driver;
+	struct usb_gadget		*gadget;
+	struct device			dev;
+	struct list_head		list;
+};
+
+static struct class *udc_class;
+static LIST_HEAD(udc_list);
+static DEFINE_MUTEX(udc_lock);
+
+/* ------------------------------------------------------------------------- */
+
+/**
+ * usb_gadget_start - tells usb device controller to start up
+ * @gadget: The gadget we want to get started
+ * @driver: The driver we want to bind to @gadget
+ * @bind: The bind function for @driver
+ *
+ * This call is issued by the UDC Class driver when it's about
+ * to register a gadget driver to the device controller, before
+ * calling gadget driver's bind() method.
+ *
+ * It allows the controller to be powered off until strictly
+ * necessary to have it powered on.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int usb_gadget_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *))
+{
+	return gadget->ops->start(driver, bind);
+}
+
+/**
+ * usb_gadget_udc_start - tells usb device controller to start up
+ * @gadget: The gadget we want to get started
+ * @driver: The driver we want to bind to @gadget
+ *
+ * This call is issued by the UDC Class driver when it's about
+ * to register a gadget driver to the device controller, before
+ * calling gadget driver's bind() method.
+ *
+ * It allows the controller to be powered off until strictly
+ * necessary to have it powered on.
+ *
+ * Returns zero on success, else negative errno.
+ */
+static inline int usb_gadget_udc_start(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
+{
+	return gadget->ops->udc_start(gadget, driver);
+}
+
+/**
+ * usb_gadget_stop - tells usb device controller we don't need it anymore
+ * @gadget: The device we want to stop activity
+ * @driver: The driver to unbind from @gadget
+ *
+ * This call is issued by the UDC Class driver after calling
+ * gadget driver's unbind() method.
+ *
+ * The details are implementation specific, but it can go as
+ * far as powering off UDC completely and disable its data
+ * line pullups.
+ */
+static inline void usb_gadget_stop(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
+{
+	gadget->ops->stop(driver);
+}
+
+/**
+ * usb_gadget_udc_stop - tells usb device controller we don't need it anymore
+ * @gadget: The device we want to stop activity
+ * @driver: The driver to unbind from @gadget
+ *
+ * This call is issued by the UDC Class driver after calling
+ * gadget driver's unbind() method.
+ *
+ * The details are implementation specific, but it can go as
+ * far as powering off UDC completely and disable its data
+ * line pullups.
+ */
+static inline void usb_gadget_udc_stop(struct usb_gadget *gadget,
+		struct usb_gadget_driver *driver)
+{
+	gadget->ops->udc_stop(gadget, driver);
+}
+
+/**
+ * usb_udc_release - release the usb_udc struct
+ * @dev: the dev member within usb_udc
+ *
+ * This is called by driver's core in order to free memory once the last
+ * reference is released.
+ */
+static void usb_udc_release(struct device *dev)
+{
+	struct usb_udc *udc;
+
+	udc = container_of(dev, struct usb_udc, dev);
+	dev_dbg(dev, "releasing '%s'\n", dev_name(dev));
+	kfree(udc);
+}
+
+static const struct attribute_group *usb_udc_attr_groups[];
+/**
+ * usb_add_gadget_udc - adds a new gadget to the udc class driver list
+ * @parent: the parent device to this udc. Usually the controller
+ * driver's device.
+ * @gadget: the gadget to be added to the list
+ *
+ * Returns zero on success, negative errno otherwise.
+ */
+int usb_add_gadget_udc(struct device *parent, struct usb_gadget *gadget)
+{
+	struct usb_udc		*udc;
+	int			ret = -ENOMEM;
+
+	udc = kzalloc(sizeof(*udc), GFP_KERNEL);
+	if (!udc)
+		goto err1;
+
+	device_initialize(&udc->dev);
+	udc->dev.release = usb_udc_release;
+	udc->dev.class = udc_class;
+	udc->dev.groups = usb_udc_attr_groups;
+	udc->dev.parent = parent;
+	ret = dev_set_name(&udc->dev, "%s", kobject_name(&parent->kobj));
+	if (ret)
+		goto err2;
+
+	udc->gadget = gadget;
+
+	mutex_lock(&udc_lock);
+	list_add_tail(&udc->list, &udc_list);
+
+	ret = device_add(&udc->dev);
+	if (ret)
+		goto err3;
+
+	mutex_unlock(&udc_lock);
+
+	return 0;
+err3:
+	list_del(&udc->list);
+	mutex_unlock(&udc_lock);
+
+err2:
+	put_device(&udc->dev);
+
+err1:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(usb_add_gadget_udc);
+
+static int udc_is_newstyle(struct usb_udc *udc)
+{
+	if (udc->gadget->ops->udc_start && udc->gadget->ops->udc_stop)
+		return 1;
+	return 0;
+}
+
+
+static void usb_gadget_remove_driver(struct usb_udc *udc)
+{
+	dev_dbg(&udc->dev, "unregistering UDC driver [%s]\n",
+			udc->gadget->name);
+
+	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
+
+	if (udc_is_newstyle(udc)) {
+		usb_gadget_disconnect(udc->gadget);
+		udc->driver->unbind(udc->gadget);
+		usb_gadget_udc_stop(udc->gadget, udc->driver);
+
+	} else {
+		usb_gadget_stop(udc->gadget, udc->driver);
+	}
+
+	udc->driver = NULL;
+	udc->dev.driver = NULL;
+}
+
+/**
+ * usb_del_gadget_udc - deletes @udc from udc_list
+ * @gadget: the gadget to be removed.
+ *
+ * This, will call usb_gadget_unregister_driver() if
+ * the @udc is still busy.
+ */
+void usb_del_gadget_udc(struct usb_gadget *gadget)
+{
+	struct usb_udc		*udc = NULL;
+
+	mutex_lock(&udc_lock);
+	list_for_each_entry(udc, &udc_list, list)
+		if (udc->gadget == gadget)
+			goto found;
+
+	dev_err(gadget->dev.parent, "gadget not registered.\n");
+	mutex_unlock(&udc_lock);
+
+	return;
+
+found:
+	dev_vdbg(gadget->dev.parent, "unregistering gadget\n");
+
+	list_del(&udc->list);
+	mutex_unlock(&udc_lock);
+
+	if (udc->driver)
+		usb_gadget_remove_driver(udc);
+
+	kobject_uevent(&udc->dev.kobj, KOBJ_REMOVE);
+	device_unregister(&udc->dev);
+}
+EXPORT_SYMBOL_GPL(usb_del_gadget_udc);
+
+/* ------------------------------------------------------------------------- */
+
+int usb_gadget_probe_driver(struct usb_gadget_driver *driver,
+		int (*bind)(struct usb_gadget *))
+{
+	struct usb_udc		*udc = NULL;
+	int			ret;
+
+	if (!driver || !bind || !driver->setup)
+		return -EINVAL;
+
+	mutex_lock(&udc_lock);
+	list_for_each_entry(udc, &udc_list, list) {
+		/* For now we take the first one */
+		if (!udc->driver)
+			goto found;
+	}
+
+	pr_debug("couldn't find an available UDC\n");
+	mutex_unlock(&udc_lock);
+	return -ENODEV;
+
+found:
+	dev_dbg(&udc->dev, "registering UDC driver [%s]\n",
+			driver->function);
+
+	udc->driver = driver;
+	udc->dev.driver = &driver->driver;
+
+	if (udc_is_newstyle(udc)) {
+		ret = bind(udc->gadget);
+		if (ret)
+			goto err1;
+		ret = usb_gadget_udc_start(udc->gadget, driver);
+		if (ret) {
+			driver->unbind(udc->gadget);
+			goto err1;
+		}
+		usb_gadget_connect(udc->gadget);
+	} else {
+
+		ret = usb_gadget_start(udc->gadget, driver, bind);
+		if (ret)
+			goto err1;
+
+	}
+
+	kobject_uevent(&udc->dev.kobj, KOBJ_CHANGE);
+	mutex_unlock(&udc_lock);
+	return 0;
+
+err1:
+	dev_err(&udc->dev, "failed to start %s: %d\n",
+			udc->driver->function, ret);
+	udc->driver = NULL;
+	udc->dev.driver = NULL;
+	mutex_unlock(&udc_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_probe_driver);
+
+int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+{
+	struct usb_udc		*udc = NULL;
+	int			ret = -ENODEV;
+
+	if (!driver || !driver->unbind)
+		return -EINVAL;
+
+	mutex_lock(&udc_lock);
+	list_for_each_entry(udc, &udc_list, list)
+		if (udc->driver == driver) {
+			usb_gadget_remove_driver(udc);
+			ret = 0;
+			break;
+		}
+
+	mutex_unlock(&udc_lock);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(usb_gadget_unregister_driver);
+
+/* ------------------------------------------------------------------------- */
+
+static ssize_t usb_udc_srp_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t n)
+{
+	struct usb_udc		*udc = dev_get_drvdata(dev);
+
+	if (sysfs_streq(buf, "1"))
+		usb_gadget_wakeup(udc->gadget);
+
+	return n;
+}
+static DEVICE_ATTR(srp, S_IWUSR, NULL, usb_udc_srp_store);
+
+static ssize_t usb_udc_softconn_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t n)
+{
+	struct usb_udc		*udc = dev_get_drvdata(dev);
+
+	if (sysfs_streq(buf, "connect")) {
+		usb_gadget_connect(udc->gadget);
+	} else if (sysfs_streq(buf, "disconnect")) {
+		usb_gadget_disconnect(udc->gadget);
+	} else {
+		dev_err(dev, "unsupported command '%s'\n", buf);
+		return -EINVAL;
+	}
+
+	return n;
+}
+static DEVICE_ATTR(soft_connect, S_IWUSR, NULL, usb_udc_softconn_store);
+
+static ssize_t usb_udc_speed_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+	struct usb_udc		*udc = container_of(dev, struct usb_udc, dev);
+	struct usb_gadget	*gadget = udc->gadget;
+
+	switch (gadget->speed) {
+	case USB_SPEED_LOW:
+		return snprintf(buf, PAGE_SIZE, "low-speed\n");
+	case USB_SPEED_FULL:
+		return snprintf(buf, PAGE_SIZE, "full-speed\n");
+	case USB_SPEED_HIGH:
+		return snprintf(buf, PAGE_SIZE, "high-speed\n");
+	case USB_SPEED_WIRELESS:
+		return snprintf(buf, PAGE_SIZE, "wireless\n");
+	case USB_SPEED_SUPER:
+		return snprintf(buf, PAGE_SIZE, "super-speed\n");
+	case USB_SPEED_UNKNOWN:	/* FALLTHROUGH */
+	default:
+		return snprintf(buf, PAGE_SIZE, "UNKNOWN\n");
+	}
+}
+static DEVICE_ATTR(speed, S_IRUSR, usb_udc_speed_show, NULL);
+
+#define USB_UDC_ATTR(name)					\
+ssize_t usb_udc_##name##_show(struct device *dev,		\
+		struct device_attribute *attr, char *buf)	\
+{								\
+	struct usb_udc		*udc = container_of(dev, struct usb_udc, dev); \
+	struct usb_gadget	*gadget = udc->gadget;		\
+								\
+	return snprintf(buf, PAGE_SIZE, "%d\n", gadget->name);	\
+}								\
+static DEVICE_ATTR(name, S_IRUSR, usb_udc_##name##_show, NULL)
+
+static USB_UDC_ATTR(is_dualspeed);
+static USB_UDC_ATTR(is_otg);
+static USB_UDC_ATTR(is_a_peripheral);
+static USB_UDC_ATTR(b_hnp_enable);
+static USB_UDC_ATTR(a_hnp_support);
+static USB_UDC_ATTR(a_alt_hnp_support);
+
+static struct attribute *usb_udc_attrs[] = {
+	&dev_attr_srp.attr,
+	&dev_attr_soft_connect.attr,
+	&dev_attr_speed.attr,
+
+	&dev_attr_is_dualspeed.attr,
+	&dev_attr_is_otg.attr,
+	&dev_attr_is_a_peripheral.attr,
+	&dev_attr_b_hnp_enable.attr,
+	&dev_attr_a_hnp_support.attr,
+	&dev_attr_a_alt_hnp_support.attr,
+	NULL,
+};
+
+static const struct attribute_group usb_udc_attr_group = {
+	.attrs = usb_udc_attrs,
+};
+
+static const struct attribute_group *usb_udc_attr_groups[] = {
+	&usb_udc_attr_group,
+	NULL,
+};
+
+static int usb_udc_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+	struct usb_udc		*udc = container_of(dev, struct usb_udc, dev);
+	int			ret;
+
+	ret = add_uevent_var(env, "USB_UDC_NAME=%s", udc->gadget->name);
+	if (ret) {
+		dev_err(dev, "failed to add uevent USB_UDC_NAME\n");
+		return ret;
+	}
+
+	if (udc->driver) {
+		ret = add_uevent_var(env, "USB_UDC_DRIVER=%s",
+				udc->driver->function);
+		if (ret) {
+			dev_err(dev, "failed to add uevent USB_UDC_DRIVER\n");
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static int __init usb_udc_init(void)
+{
+	udc_class = class_create(THIS_MODULE, "udc");
+	if (IS_ERR(udc_class)) {
+		pr_err("failed to create udc class --> %ld\n",
+				PTR_ERR(udc_class));
+		return PTR_ERR(udc_class);
+	}
+
+	udc_class->dev_uevent = usb_udc_uevent;
+	return 0;
+}
+subsys_initcall(usb_udc_init);
+
+static void __exit usb_udc_exit(void)
+{
+	class_destroy(udc_class);
+}
+module_exit(usb_udc_exit);
+
+MODULE_DESCRIPTION("UDC Framework");
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
+MODULE_LICENSE("GPL v2");

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

@@ -373,6 +373,7 @@ static struct usb_composite_driver webcam_driver = {
 	.name		= "g_webcam",
 	.name		= "g_webcam",
 	.dev		= &webcam_device_descriptor,
 	.dev		= &webcam_device_descriptor,
 	.strings	= webcam_device_strings,
 	.strings	= webcam_device_strings,
+	.max_speed	= USB_SPEED_HIGH,
 	.unbind		= webcam_unbind,
 	.unbind		= webcam_unbind,
 };
 };
 
 

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

@@ -340,6 +340,7 @@ static struct usb_composite_driver zero_driver = {
 	.name		= "zero",
 	.name		= "zero",
 	.dev		= &device_desc,
 	.dev		= &device_desc,
 	.strings	= dev_strings,
 	.strings	= dev_strings,
+	.max_speed	= USB_SPEED_SUPER,
 	.unbind		= zero_unbind,
 	.unbind		= zero_unbind,
 	.suspend	= zero_suspend,
 	.suspend	= zero_suspend,
 	.resume		= zero_resume,
 	.resume		= zero_resume,

+ 13 - 8
drivers/usb/host/ehci-hcd.c

@@ -94,7 +94,8 @@ static const char	hcd_name [] = "ehci_hcd";
 #define EHCI_IAA_MSECS		10		/* arbitrary */
 #define EHCI_IAA_MSECS		10		/* arbitrary */
 #define EHCI_IO_JIFFIES		(HZ/10)		/* io watchdog > irq_thresh */
 #define EHCI_IO_JIFFIES		(HZ/10)		/* io watchdog > irq_thresh */
 #define EHCI_ASYNC_JIFFIES	(HZ/20)		/* async idle timeout */
 #define EHCI_ASYNC_JIFFIES	(HZ/20)		/* async idle timeout */
-#define EHCI_SHRINK_FRAMES	5		/* async qh unlink delay */
+#define EHCI_SHRINK_JIFFIES	(DIV_ROUND_UP(HZ, 200) + 1)
+						/* 200-ms async qh unlink delay */
 
 
 /* Initial IRQ latency:  faster than hw default */
 /* Initial IRQ latency:  faster than hw default */
 static int log2_irq_thresh = 0;		// 0 to 6
 static int log2_irq_thresh = 0;		// 0 to 6
@@ -114,7 +115,7 @@ MODULE_PARM_DESC (ignore_oc, "ignore bogus hardware overcurrent indications");
 /* for link power management(LPM) feature */
 /* for link power management(LPM) feature */
 static unsigned int hird;
 static unsigned int hird;
 module_param(hird, int, S_IRUGO);
 module_param(hird, int, S_IRUGO);
-MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us\n");
+MODULE_PARM_DESC(hird, "host initiated resume duration, +1 for each 75us");
 
 
 #define	INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
 #define	INTR_MASK (STS_IAA | STS_FATAL | STS_PCD | STS_ERR | STS_INT)
 
 
@@ -152,10 +153,7 @@ timer_action(struct ehci_hcd *ehci, enum ehci_timer_action action)
 			break;
 			break;
 		/* case TIMER_ASYNC_SHRINK: */
 		/* case TIMER_ASYNC_SHRINK: */
 		default:
 		default:
-			/* add a jiffie since we synch against the
-			 * 8 KHz uframe counter.
-			 */
-			t = DIV_ROUND_UP(EHCI_SHRINK_FRAMES * HZ, 1000) + 1;
+			t = EHCI_SHRINK_JIFFIES;
 			break;
 			break;
 		}
 		}
 		mod_timer(&ehci->watchdog, t + jiffies);
 		mod_timer(&ehci->watchdog, t + jiffies);
@@ -340,6 +338,7 @@ static void ehci_work(struct ehci_hcd *ehci);
 #include "ehci-mem.c"
 #include "ehci-mem.c"
 #include "ehci-q.c"
 #include "ehci-q.c"
 #include "ehci-sched.c"
 #include "ehci-sched.c"
+#include "ehci-sysfs.c"
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
@@ -524,7 +523,7 @@ static void ehci_stop (struct usb_hcd *hcd)
 	ehci_reset (ehci);
 	ehci_reset (ehci);
 	spin_unlock_irq(&ehci->lock);
 	spin_unlock_irq(&ehci->lock);
 
 
-	remove_companion_file(ehci);
+	remove_sysfs_files(ehci);
 	remove_debug_files (ehci);
 	remove_debug_files (ehci);
 
 
 	/* root hub is shut down separately (first, when possible) */
 	/* root hub is shut down separately (first, when possible) */
@@ -574,6 +573,12 @@ static int ehci_init(struct usb_hcd *hcd)
 
 
 	hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
 	hcc_params = ehci_readl(ehci, &ehci->caps->hcc_params);
 
 
+	/*
+	 * by default set standard 80% (== 100 usec/uframe) max periodic
+	 * bandwidth as required by USB 2.0
+	 */
+	ehci->uframe_periodic_max = 100;
+
 	/*
 	/*
 	 * hw default: 1K periodic list heads, one per frame.
 	 * hw default: 1K periodic list heads, one per frame.
 	 * periodic_size can shrink by USBCMD update if hcc_params allows.
 	 * periodic_size can shrink by USBCMD update if hcc_params allows.
@@ -758,7 +763,7 @@ static int ehci_run (struct usb_hcd *hcd)
 	 * since the class device isn't created that early.
 	 * since the class device isn't created that early.
 	 */
 	 */
 	create_debug_files(ehci);
 	create_debug_files(ehci);
-	create_companion_file(ehci);
+	create_sysfs_files(ehci);
 
 
 	return 0;
 	return 0;
 }
 }

+ 2 - 76
drivers/usb/host/ehci-hub.c

@@ -471,29 +471,6 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
 
 
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
-/* Display the ports dedicated to the companion controller */
-static ssize_t show_companion(struct device *dev,
-			      struct device_attribute *attr,
-			      char *buf)
-{
-	struct ehci_hcd		*ehci;
-	int			nports, index, n;
-	int			count = PAGE_SIZE;
-	char			*ptr = buf;
-
-	ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
-	nports = HCS_N_PORTS(ehci->hcs_params);
-
-	for (index = 0; index < nports; ++index) {
-		if (test_bit(index, &ehci->companion_ports)) {
-			n = scnprintf(ptr, count, "%d\n", index + 1);
-			ptr += n;
-			count -= n;
-		}
-	}
-	return ptr - buf;
-}
-
 /*
 /*
  * Sets the owner of a port
  * Sets the owner of a port
  */
  */
@@ -528,58 +505,6 @@ static void set_owner(struct ehci_hcd *ehci, int portnum, int new_owner)
 	}
 	}
 }
 }
 
 
-/*
- * Dedicate or undedicate a port to the companion controller.
- * Syntax is "[-]portnum", where a leading '-' sign means
- * return control of the port to the EHCI controller.
- */
-static ssize_t store_companion(struct device *dev,
-			       struct device_attribute *attr,
-			       const char *buf, size_t count)
-{
-	struct ehci_hcd		*ehci;
-	int			portnum, new_owner;
-
-	ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
-	new_owner = PORT_OWNER;		/* Owned by companion */
-	if (sscanf(buf, "%d", &portnum) != 1)
-		return -EINVAL;
-	if (portnum < 0) {
-		portnum = - portnum;
-		new_owner = 0;		/* Owned by EHCI */
-	}
-	if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
-		return -ENOENT;
-	portnum--;
-	if (new_owner)
-		set_bit(portnum, &ehci->companion_ports);
-	else
-		clear_bit(portnum, &ehci->companion_ports);
-	set_owner(ehci, portnum, new_owner);
-	return count;
-}
-static DEVICE_ATTR(companion, 0644, show_companion, store_companion);
-
-static inline int create_companion_file(struct ehci_hcd *ehci)
-{
-	int	i = 0;
-
-	/* with integrated TT there is no companion! */
-	if (!ehci_is_TDI(ehci))
-		i = device_create_file(ehci_to_hcd(ehci)->self.controller,
-				       &dev_attr_companion);
-	return i;
-}
-
-static inline void remove_companion_file(struct ehci_hcd *ehci)
-{
-	/* with integrated TT there is no companion! */
-	if (!ehci_is_TDI(ehci))
-		device_remove_file(ehci_to_hcd(ehci)->self.controller,
-				   &dev_attr_companion);
-}
-
-
 /*-------------------------------------------------------------------------*/
 /*-------------------------------------------------------------------------*/
 
 
 static int check_reset_complete (
 static int check_reset_complete (
@@ -891,10 +816,11 @@ static int ehci_hub_control (
 			 * power switching; they're allowed to just limit the
 			 * power switching; they're allowed to just limit the
 			 * current.  khubd will turn the power back on.
 			 * current.  khubd will turn the power back on.
 			 */
 			 */
-			if (HCS_PPC (ehci->hcs_params)){
+			if ((temp & PORT_OC) && HCS_PPC(ehci->hcs_params)) {
 				ehci_writel(ehci,
 				ehci_writel(ehci,
 					temp & ~(PORT_RWC_BITS | PORT_POWER),
 					temp & ~(PORT_RWC_BITS | PORT_POWER),
 					status_reg);
 					status_reg);
+				temp = ehci_readl(ehci, status_reg);
 			}
 			}
 		}
 		}
 
 

+ 1 - 19
drivers/usb/host/ehci-msm.c

@@ -40,27 +40,9 @@ static int ehci_msm_reset(struct usb_hcd *hcd)
 	int retval;
 	int retval;
 
 
 	ehci->caps = USB_CAPLENGTH;
 	ehci->caps = USB_CAPLENGTH;
-	ehci->regs = USB_CAPLENGTH +
-		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));
-	dbg_hcs_params(ehci, "reset");
-	dbg_hcc_params(ehci, "reset");
-
-	/* cache the data to minimize the chip reads*/
-	ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
-
 	hcd->has_tt = 1;
 	hcd->has_tt = 1;
-	ehci->sbrn = HCD_USB2;
-
-	retval = ehci_halt(ehci);
-	if (retval)
-		return retval;
-
-	/* data structure init */
-	retval = ehci_init(hcd);
-	if (retval)
-		return retval;
 
 
-	retval = ehci_reset(ehci);
+	retval = ehci_setup(hcd);
 	if (retval)
 	if (retval)
 		return retval;
 		return retval;
 
 

+ 42 - 43
drivers/usb/host/ehci-q.c

@@ -103,7 +103,7 @@ qh_update (struct ehci_hcd *ehci, struct ehci_qh *qh, struct ehci_qtd *qtd)
 	if (!(hw->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
 	if (!(hw->hw_info1 & cpu_to_hc32(ehci, 1 << 14))) {
 		unsigned	is_out, epnum;
 		unsigned	is_out, epnum;
 
 
-		is_out = !(qtd->hw_token & cpu_to_hc32(ehci, 1 << 8));
+		is_out = qh->is_out;
 		epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f;
 		epnum = (hc32_to_cpup(ehci, &hw->hw_info1) >> 8) & 0x0f;
 		if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
 		if (unlikely (!usb_gettoggle (qh->dev, epnum, is_out))) {
 			hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
 			hw->hw_token &= ~cpu_to_hc32(ehci, QTD_TOGGLE);
@@ -946,6 +946,7 @@ done:
 	hw = qh->hw;
 	hw = qh->hw;
 	hw->hw_info1 = cpu_to_hc32(ehci, info1);
 	hw->hw_info1 = cpu_to_hc32(ehci, info1);
 	hw->hw_info2 = cpu_to_hc32(ehci, info2);
 	hw->hw_info2 = cpu_to_hc32(ehci, info2);
+	qh->is_out = !is_input;
 	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
 	usb_settoggle (urb->dev, usb_pipeendpoint (urb->pipe), !is_input, 1);
 	qh_refresh (ehci, qh);
 	qh_refresh (ehci, qh);
 	return qh;
 	return qh;
@@ -1231,6 +1232,8 @@ static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh)
 
 
 	prev->hw->hw_next = qh->hw->hw_next;
 	prev->hw->hw_next = qh->hw->hw_next;
 	prev->qh_next = qh->qh_next;
 	prev->qh_next = qh->qh_next;
+	if (ehci->qh_scan_next == qh)
+		ehci->qh_scan_next = qh->qh_next.qh;
 	wmb ();
 	wmb ();
 
 
 	/* If the controller isn't running, we don't have to wait for it */
 	/* If the controller isn't running, we don't have to wait for it */
@@ -1256,53 +1259,49 @@ static void scan_async (struct ehci_hcd *ehci)
 	struct ehci_qh		*qh;
 	struct ehci_qh		*qh;
 	enum ehci_timer_action	action = TIMER_IO_WATCHDOG;
 	enum ehci_timer_action	action = TIMER_IO_WATCHDOG;
 
 
-	ehci->stamp = ehci_readl(ehci, &ehci->regs->frame_index);
 	timer_action_done (ehci, TIMER_ASYNC_SHRINK);
 	timer_action_done (ehci, TIMER_ASYNC_SHRINK);
-rescan:
 	stopped = !HC_IS_RUNNING(ehci_to_hcd(ehci)->state);
 	stopped = !HC_IS_RUNNING(ehci_to_hcd(ehci)->state);
-	qh = ehci->async->qh_next.qh;
-	if (likely (qh != NULL)) {
-		do {
-			/* clean any finished work for this qh */
-			if (!list_empty(&qh->qtd_list) && (stopped ||
-					qh->stamp != ehci->stamp)) {
-				int temp;
-
-				/* unlinks could happen here; completion
-				 * reporting drops the lock.  rescan using
-				 * the latest schedule, but don't rescan
-				 * qhs we already finished (no looping)
-				 * unless the controller is stopped.
-				 */
-				qh = qh_get (qh);
-				qh->stamp = ehci->stamp;
-				temp = qh_completions (ehci, qh);
-				if (qh->needs_rescan)
-					unlink_async(ehci, qh);
-				qh_put (qh);
-				if (temp != 0) {
-					goto rescan;
-				}
-			}
 
 
-			/* unlink idle entries, reducing DMA usage as well
-			 * as HCD schedule-scanning costs.  delay for any qh
-			 * we just scanned, there's a not-unusual case that it
-			 * doesn't stay idle for long.
-			 * (plus, avoids some kind of re-activation race.)
+	ehci->qh_scan_next = ehci->async->qh_next.qh;
+	while (ehci->qh_scan_next) {
+		qh = ehci->qh_scan_next;
+		ehci->qh_scan_next = qh->qh_next.qh;
+ rescan:
+		/* clean any finished work for this qh */
+		if (!list_empty(&qh->qtd_list)) {
+			int temp;
+
+			/*
+			 * Unlinks could happen here; completion reporting
+			 * drops the lock.  That's why ehci->qh_scan_next
+			 * always holds the next qh to scan; if the next qh
+			 * gets unlinked then ehci->qh_scan_next is adjusted
+			 * in start_unlink_async().
 			 */
 			 */
-			if (list_empty(&qh->qtd_list)
-					&& qh->qh_state == QH_STATE_LINKED) {
-				if (!ehci->reclaim && (stopped ||
-					((ehci->stamp - qh->stamp) & 0x1fff)
-						>= EHCI_SHRINK_FRAMES * 8))
-					start_unlink_async(ehci, qh);
-				else
-					action = TIMER_ASYNC_SHRINK;
-			}
+			qh = qh_get(qh);
+			temp = qh_completions(ehci, qh);
+			if (qh->needs_rescan)
+				unlink_async(ehci, qh);
+			qh->unlink_time = jiffies + EHCI_SHRINK_JIFFIES;
+			qh_put(qh);
+			if (temp != 0)
+				goto rescan;
+		}
 
 
-			qh = qh->qh_next.qh;
-		} while (qh);
+		/* unlink idle entries, reducing DMA usage as well
+		 * as HCD schedule-scanning costs.  delay for any qh
+		 * we just scanned, there's a not-unusual case that it
+		 * doesn't stay idle for long.
+		 * (plus, avoids some kind of re-activation race.)
+		 */
+		if (list_empty(&qh->qtd_list)
+				&& qh->qh_state == QH_STATE_LINKED) {
+			if (!ehci->reclaim && (stopped ||
+					time_after_eq(jiffies, qh->unlink_time)))
+				start_unlink_async(ehci, qh);
+			else
+				action = TIMER_ASYNC_SHRINK;
+		}
 	}
 	}
 	if (action == TIMER_ASYNC_SHRINK)
 	if (action == TIMER_ASYNC_SHRINK)
 		timer_action (ehci, TIMER_ASYNC_SHRINK);
 		timer_action (ehci, TIMER_ASYNC_SHRINK);

+ 95 - 0
drivers/usb/host/ehci-s5p.c

@@ -189,6 +189,100 @@ static void s5p_ehci_shutdown(struct platform_device *pdev)
 		hcd->driver->shutdown(hcd);
 		hcd->driver->shutdown(hcd);
 }
 }
 
 
+#ifdef CONFIG_PM
+static int s5p_ehci_suspend(struct device *dev)
+{
+	struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = s5p_ehci->hcd;
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
+	unsigned long flags;
+	int rc = 0;
+
+	if (time_before(jiffies, ehci->next_statechange))
+		msleep(20);
+
+	/*
+	 * Root hub was already suspended. Disable irq emission and
+	 * mark HW unaccessible.  The PM and USB cores make sure that
+	 * the root hub is either suspended or stopped.
+	 */
+	ehci_prepare_ports_for_controller_suspend(ehci, device_may_wakeup(dev));
+	spin_lock_irqsave(&ehci->lock, flags);
+	ehci_writel(ehci, 0, &ehci->regs->intr_enable);
+	(void)ehci_readl(ehci, &ehci->regs->intr_enable);
+
+	clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+	spin_unlock_irqrestore(&ehci->lock, flags);
+
+	if (pdata && pdata->phy_exit)
+		pdata->phy_exit(pdev, S5P_USB_PHY_HOST);
+
+	return rc;
+}
+
+static int s5p_ehci_resume(struct device *dev)
+{
+	struct s5p_ehci_hcd *s5p_ehci = dev_get_drvdata(dev);
+	struct usb_hcd *hcd = s5p_ehci->hcd;
+	struct ehci_hcd *ehci = hcd_to_ehci(hcd);
+	struct platform_device *pdev = to_platform_device(dev);
+	struct s5p_ehci_platdata *pdata = pdev->dev.platform_data;
+
+	if (pdata && pdata->phy_init)
+		pdata->phy_init(pdev, S5P_USB_PHY_HOST);
+
+	if (time_before(jiffies, ehci->next_statechange))
+		msleep(100);
+
+	/* Mark hardware accessible again as we are out of D3 state by now */
+	set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+	if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF) {
+		int	mask = INTR_MASK;
+
+		ehci_prepare_ports_for_controller_resume(ehci);
+		if (!hcd->self.root_hub->do_remote_wakeup)
+			mask &= ~STS_PCD;
+		ehci_writel(ehci, mask, &ehci->regs->intr_enable);
+		ehci_readl(ehci, &ehci->regs->intr_enable);
+		return 0;
+	}
+
+	usb_root_hub_lost_power(hcd->self.root_hub);
+
+	(void) ehci_halt(ehci);
+	(void) ehci_reset(ehci);
+
+	/* emptying the schedule aborts any urbs */
+	spin_lock_irq(&ehci->lock);
+	if (ehci->reclaim)
+		end_unlink_async(ehci);
+	ehci_work(ehci);
+	spin_unlock_irq(&ehci->lock);
+
+	ehci_writel(ehci, ehci->command, &ehci->regs->command);
+	ehci_writel(ehci, FLAG_CF, &ehci->regs->configured_flag);
+	ehci_readl(ehci, &ehci->regs->command);	/* unblock posted writes */
+
+	/* here we "know" root ports should always stay powered */
+	ehci_port_power(ehci, 1);
+
+	hcd->state = HC_STATE_SUSPENDED;
+
+	return 0;
+}
+#else
+#define s5p_ehci_suspend	NULL
+#define s5p_ehci_resume		NULL
+#endif
+
+static const struct dev_pm_ops s5p_ehci_pm_ops = {
+	.suspend	= s5p_ehci_suspend,
+	.resume		= s5p_ehci_resume,
+};
+
 static struct platform_driver s5p_ehci_driver = {
 static struct platform_driver s5p_ehci_driver = {
 	.probe		= s5p_ehci_probe,
 	.probe		= s5p_ehci_probe,
 	.remove		= __devexit_p(s5p_ehci_remove),
 	.remove		= __devexit_p(s5p_ehci_remove),
@@ -196,6 +290,7 @@ static struct platform_driver s5p_ehci_driver = {
 	.driver = {
 	.driver = {
 		.name	= "s5p-ehci",
 		.name	= "s5p-ehci",
 		.owner	= THIS_MODULE,
 		.owner	= THIS_MODULE,
+		.pm	= &s5p_ehci_pm_ops,
 	}
 	}
 };
 };
 
 

+ 7 - 10
drivers/usb/host/ehci-sched.c

@@ -172,7 +172,7 @@ periodic_usecs (struct ehci_hcd *ehci, unsigned frame, unsigned uframe)
 		}
 		}
 	}
 	}
 #ifdef	DEBUG
 #ifdef	DEBUG
-	if (usecs > 100)
+	if (usecs > ehci->uframe_periodic_max)
 		ehci_err (ehci, "uframe %d sched overrun: %d usecs\n",
 		ehci_err (ehci, "uframe %d sched overrun: %d usecs\n",
 			frame * 8 + uframe, usecs);
 			frame * 8 + uframe, usecs);
 #endif
 #endif
@@ -709,11 +709,8 @@ static int check_period (
 	if (uframe >= 8)
 	if (uframe >= 8)
 		return 0;
 		return 0;
 
 
-	/*
-	 * 80% periodic == 100 usec/uframe available
-	 * convert "usecs we need" to "max already claimed"
-	 */
-	usecs = 100 - usecs;
+	/* convert "usecs we need" to "max already claimed" */
+	usecs = ehci->uframe_periodic_max - usecs;
 
 
 	/* we "know" 2 and 4 uframe intervals were rejected; so
 	/* we "know" 2 and 4 uframe intervals were rejected; so
 	 * for period 0, check _every_ microframe in the schedule.
 	 * for period 0, check _every_ microframe in the schedule.
@@ -1286,9 +1283,9 @@ itd_slot_ok (
 {
 {
 	uframe %= period;
 	uframe %= period;
 	do {
 	do {
-		/* can't commit more than 80% periodic == 100 usec */
+		/* can't commit more than uframe_periodic_max usec */
 		if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7)
 		if (periodic_usecs (ehci, uframe >> 3, uframe & 0x7)
-				> (100 - usecs))
+				> (ehci->uframe_periodic_max - usecs))
 			return 0;
 			return 0;
 
 
 		/* we know urb->interval is 2^N uframes */
 		/* we know urb->interval is 2^N uframes */
@@ -1345,7 +1342,7 @@ sitd_slot_ok (
 #endif
 #endif
 
 
 		/* check starts (OUT uses more than one) */
 		/* check starts (OUT uses more than one) */
-		max_used = 100 - stream->usecs;
+		max_used = ehci->uframe_periodic_max - stream->usecs;
 		for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) {
 		for (tmp = stream->raw_mask & 0xff; tmp; tmp >>= 1, uf++) {
 			if (periodic_usecs (ehci, frame, uf) > max_used)
 			if (periodic_usecs (ehci, frame, uf) > max_used)
 				return 0;
 				return 0;
@@ -1354,7 +1351,7 @@ sitd_slot_ok (
 		/* for IN, check CSPLIT */
 		/* for IN, check CSPLIT */
 		if (stream->c_usecs) {
 		if (stream->c_usecs) {
 			uf = uframe & 7;
 			uf = uframe & 7;
-			max_used = 100 - stream->c_usecs;
+			max_used = ehci->uframe_periodic_max - stream->c_usecs;
 			do {
 			do {
 				tmp = 1 << uf;
 				tmp = 1 << uf;
 				tmp <<= 8;
 				tmp <<= 8;

+ 190 - 0
drivers/usb/host/ehci-sysfs.c

@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2007 by Alan Stern
+ *
+ * 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.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* this file is part of ehci-hcd.c */
+
+
+/* Display the ports dedicated to the companion controller */
+static ssize_t show_companion(struct device *dev,
+			      struct device_attribute *attr,
+			      char *buf)
+{
+	struct ehci_hcd		*ehci;
+	int			nports, index, n;
+	int			count = PAGE_SIZE;
+	char			*ptr = buf;
+
+	ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
+	nports = HCS_N_PORTS(ehci->hcs_params);
+
+	for (index = 0; index < nports; ++index) {
+		if (test_bit(index, &ehci->companion_ports)) {
+			n = scnprintf(ptr, count, "%d\n", index + 1);
+			ptr += n;
+			count -= n;
+		}
+	}
+	return ptr - buf;
+}
+
+/*
+ * Dedicate or undedicate a port to the companion controller.
+ * Syntax is "[-]portnum", where a leading '-' sign means
+ * return control of the port to the EHCI controller.
+ */
+static ssize_t store_companion(struct device *dev,
+			       struct device_attribute *attr,
+			       const char *buf, size_t count)
+{
+	struct ehci_hcd		*ehci;
+	int			portnum, new_owner;
+
+	ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
+	new_owner = PORT_OWNER;		/* Owned by companion */
+	if (sscanf(buf, "%d", &portnum) != 1)
+		return -EINVAL;
+	if (portnum < 0) {
+		portnum = - portnum;
+		new_owner = 0;		/* Owned by EHCI */
+	}
+	if (portnum <= 0 || portnum > HCS_N_PORTS(ehci->hcs_params))
+		return -ENOENT;
+	portnum--;
+	if (new_owner)
+		set_bit(portnum, &ehci->companion_ports);
+	else
+		clear_bit(portnum, &ehci->companion_ports);
+	set_owner(ehci, portnum, new_owner);
+	return count;
+}
+static DEVICE_ATTR(companion, 0644, show_companion, store_companion);
+
+
+/*
+ * Display / Set uframe_periodic_max
+ */
+static ssize_t show_uframe_periodic_max(struct device *dev,
+					struct device_attribute *attr,
+					char *buf)
+{
+	struct ehci_hcd		*ehci;
+	int			n;
+
+	ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
+	n = scnprintf(buf, PAGE_SIZE, "%d\n", ehci->uframe_periodic_max);
+	return n;
+}
+
+
+static ssize_t store_uframe_periodic_max(struct device *dev,
+					struct device_attribute *attr,
+					const char *buf, size_t count)
+{
+	struct ehci_hcd		*ehci;
+	unsigned		uframe_periodic_max;
+	unsigned		frame, uframe;
+	unsigned short		allocated_max;
+	unsigned long		flags;
+	ssize_t			ret;
+
+	ehci = hcd_to_ehci(bus_to_hcd(dev_get_drvdata(dev)));
+	if (kstrtouint(buf, 0, &uframe_periodic_max) < 0)
+		return -EINVAL;
+
+	if (uframe_periodic_max < 100 || uframe_periodic_max >= 125) {
+		ehci_info(ehci, "rejecting invalid request for "
+				"uframe_periodic_max=%u\n", uframe_periodic_max);
+		return -EINVAL;
+	}
+
+	ret = -EINVAL;
+
+	/*
+	 * lock, so that our checking does not race with possible periodic
+	 * bandwidth allocation through submitting new urbs.
+	 */
+	spin_lock_irqsave (&ehci->lock, flags);
+
+	/*
+	 * for request to decrease max periodic bandwidth, we have to check
+	 * every microframe in the schedule to see whether the decrease is
+	 * possible.
+	 */
+	if (uframe_periodic_max < ehci->uframe_periodic_max) {
+		allocated_max = 0;
+
+		for (frame = 0; frame < ehci->periodic_size; ++frame)
+			for (uframe = 0; uframe < 7; ++uframe)
+				allocated_max = max(allocated_max,
+						    periodic_usecs (ehci, frame, uframe));
+
+		if (allocated_max > uframe_periodic_max) {
+			ehci_info(ehci,
+				"cannot decrease uframe_periodic_max becase "
+				"periodic bandwidth is already allocated "
+				"(%u > %u)\n",
+				allocated_max, uframe_periodic_max);
+			goto out_unlock;
+		}
+	}
+
+	/* increasing is always ok */
+
+	ehci_info(ehci, "setting max periodic bandwidth to %u%% "
+			"(== %u usec/uframe)\n",
+			100*uframe_periodic_max/125, uframe_periodic_max);
+
+	if (uframe_periodic_max != 100)
+		ehci_warn(ehci, "max periodic bandwidth set is non-standard\n");
+
+	ehci->uframe_periodic_max = uframe_periodic_max;
+	ret = count;
+
+out_unlock:
+	spin_unlock_irqrestore (&ehci->lock, flags);
+	return ret;
+}
+static DEVICE_ATTR(uframe_periodic_max, 0644, show_uframe_periodic_max, store_uframe_periodic_max);
+
+
+static inline int create_sysfs_files(struct ehci_hcd *ehci)
+{
+	struct device	*controller = ehci_to_hcd(ehci)->self.controller;
+	int	i = 0;
+
+	/* with integrated TT there is no companion! */
+	if (!ehci_is_TDI(ehci))
+		i = device_create_file(controller, &dev_attr_companion);
+	if (i)
+		goto out;
+
+	i = device_create_file(controller, &dev_attr_uframe_periodic_max);
+out:
+	return i;
+}
+
+static inline void remove_sysfs_files(struct ehci_hcd *ehci)
+{
+	struct device	*controller = ehci_to_hcd(ehci)->self.controller;
+
+	/* with integrated TT there is no companion! */
+	if (!ehci_is_TDI(ehci))
+		device_remove_file(controller, &dev_attr_companion);
+
+	device_remove_file(controller, &dev_attr_uframe_periodic_max);
+}

+ 5 - 1
drivers/usb/host/ehci.h

@@ -75,6 +75,7 @@ struct ehci_hcd {			/* one per controller */
 	struct ehci_qh		*async;
 	struct ehci_qh		*async;
 	struct ehci_qh		*dummy;		/* For AMD quirk use */
 	struct ehci_qh		*dummy;		/* For AMD quirk use */
 	struct ehci_qh		*reclaim;
 	struct ehci_qh		*reclaim;
+	struct ehci_qh		*qh_scan_next;
 	unsigned		scanning : 1;
 	unsigned		scanning : 1;
 
 
 	/* periodic schedule support */
 	/* periodic schedule support */
@@ -87,6 +88,8 @@ struct ehci_hcd {			/* one per controller */
 	union ehci_shadow	*pshadow;	/* mirror hw periodic table */
 	union ehci_shadow	*pshadow;	/* mirror hw periodic table */
 	int			next_uframe;	/* scan periodic, start here */
 	int			next_uframe;	/* scan periodic, start here */
 	unsigned		periodic_sched;	/* periodic activity count */
 	unsigned		periodic_sched;	/* periodic activity count */
+	unsigned		uframe_periodic_max; /* max periodic time per uframe */
+
 
 
 	/* list of itds & sitds completed while clock_frame was still active */
 	/* list of itds & sitds completed while clock_frame was still active */
 	struct list_head	cached_itd_list;
 	struct list_head	cached_itd_list;
@@ -117,7 +120,6 @@ struct ehci_hcd {			/* one per controller */
 	struct timer_list	iaa_watchdog;
 	struct timer_list	iaa_watchdog;
 	struct timer_list	watchdog;
 	struct timer_list	watchdog;
 	unsigned long		actions;
 	unsigned long		actions;
-	unsigned		stamp;
 	unsigned		periodic_stamp;
 	unsigned		periodic_stamp;
 	unsigned		random_frame;
 	unsigned		random_frame;
 	unsigned long		next_statechange;
 	unsigned long		next_statechange;
@@ -343,6 +345,7 @@ struct ehci_qh {
 	struct ehci_qh		*reclaim;	/* next to reclaim */
 	struct ehci_qh		*reclaim;	/* next to reclaim */
 
 
 	struct ehci_hcd		*ehci;
 	struct ehci_hcd		*ehci;
+	unsigned long		unlink_time;
 
 
 	/*
 	/*
 	 * Do NOT use atomic operations for QH refcounting. On some CPUs
 	 * Do NOT use atomic operations for QH refcounting. On some CPUs
@@ -374,6 +377,7 @@ struct ehci_qh {
 #define NO_FRAME ((unsigned short)~0)			/* pick new start */
 #define NO_FRAME ((unsigned short)~0)			/* pick new start */
 
 
 	struct usb_device	*dev;		/* access to TT */
 	struct usb_device	*dev;		/* access to TT */
+	unsigned		is_out:1;	/* bulk or intr OUT */
 	unsigned		clearing_tt:1;	/* Clear-TT-Buf in progress */
 	unsigned		clearing_tt:1;	/* Clear-TT-Buf in progress */
 };
 };
 
 

+ 1 - 1
drivers/usb/host/ohci-sh.c

@@ -3,7 +3,7 @@
  *
  *
  * Copyright (C) 2008 Renesas Solutions Corp.
  * Copyright (C) 2008 Renesas Solutions Corp.
  *
  *
- * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ * Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by

+ 49 - 7
drivers/usb/host/pci-quirks.c

@@ -35,6 +35,8 @@
 #define OHCI_INTRSTATUS		0x0c
 #define OHCI_INTRSTATUS		0x0c
 #define OHCI_INTRENABLE		0x10
 #define OHCI_INTRENABLE		0x10
 #define OHCI_INTRDISABLE	0x14
 #define OHCI_INTRDISABLE	0x14
+#define OHCI_FMINTERVAL		0x34
+#define OHCI_HCR		(1 << 0)	/* host controller reset */
 #define OHCI_OCR		(1 << 3)	/* ownership change request */
 #define OHCI_OCR		(1 << 3)	/* ownership change request */
 #define OHCI_CTRL_RWC		(1 << 9)	/* remote wakeup connected */
 #define OHCI_CTRL_RWC		(1 << 9)	/* remote wakeup connected */
 #define OHCI_CTRL_IR		(1 << 8)	/* interrupt routing */
 #define OHCI_CTRL_IR		(1 << 8)	/* interrupt routing */
@@ -497,6 +499,32 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
 
 
 	/* reset controller, preserving RWC (and possibly IR) */
 	/* reset controller, preserving RWC (and possibly IR) */
 	writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
 	writel(control & OHCI_CTRL_MASK, base + OHCI_CONTROL);
+	readl(base + OHCI_CONTROL);
+
+	/* Some NVIDIA controllers stop working if kept in RESET for too long */
+	if (pdev->vendor == PCI_VENDOR_ID_NVIDIA) {
+		u32 fminterval;
+		int cnt;
+
+		/* drive reset for at least 50 ms (7.1.7.5) */
+		msleep(50);
+
+		/* software reset of the controller, preserving HcFmInterval */
+		fminterval = readl(base + OHCI_FMINTERVAL);
+		writel(OHCI_HCR, base + OHCI_CMDSTATUS);
+
+		/* reset requires max 10 us delay */
+		for (cnt = 30; cnt > 0; --cnt) {	/* ... allow extra time */
+			if ((readl(base + OHCI_CMDSTATUS) & OHCI_HCR) == 0)
+				break;
+			udelay(1);
+		}
+		writel(fminterval, base + OHCI_FMINTERVAL);
+
+		/* Now we're in the SUSPEND state with all devices reset
+		 * and wakeups and interrupts disabled
+		 */
+	}
 
 
 	/*
 	/*
 	 * disable interrupts
 	 * disable interrupts
@@ -507,20 +535,34 @@ static void __devinit quirk_usb_handoff_ohci(struct pci_dev *pdev)
 	iounmap(base);
 	iounmap(base);
 }
 }
 
 
+static const struct dmi_system_id __initconst ehci_dmi_nohandoff_table[] = {
+	{
+		/*  Pegatron Lucid (ExoPC) */
+		.matches = {
+			DMI_MATCH(DMI_BOARD_NAME, "EXOPG06411"),
+			DMI_MATCH(DMI_BIOS_VERSION, "Lucid-CE-133"),
+		},
+	},
+	{
+		/*  Pegatron Lucid (Ordissimo AIRIS) */
+		.matches = {
+			DMI_MATCH(DMI_BOARD_NAME, "M11JB"),
+			DMI_MATCH(DMI_BIOS_VERSION, "Lucid-GE-133"),
+		},
+	},
+	{ }
+};
+
 static void __devinit ehci_bios_handoff(struct pci_dev *pdev,
 static void __devinit ehci_bios_handoff(struct pci_dev *pdev,
 					void __iomem *op_reg_base,
 					void __iomem *op_reg_base,
 					u32 cap, u8 offset)
 					u32 cap, u8 offset)
 {
 {
 	int try_handoff = 1, tried_handoff = 0;
 	int try_handoff = 1, tried_handoff = 0;
 
 
-	/* The Pegatron Lucid (ExoPC) tablet sporadically waits for 90
-	 * seconds trying the handoff on its unused controller.  Skip
-	 * it. */
+	/* The Pegatron Lucid tablet sporadically waits for 98 seconds trying
+	 * the handoff on its unused controller.  Skip it. */
 	if (pdev->vendor == 0x8086 && pdev->device == 0x283a) {
 	if (pdev->vendor == 0x8086 && pdev->device == 0x283a) {
-		const char *dmi_bn = dmi_get_system_info(DMI_BOARD_NAME);
-		const char *dmi_bv = dmi_get_system_info(DMI_BIOS_VERSION);
-		if (dmi_bn && !strcmp(dmi_bn, "EXOPG06411") &&
-		    dmi_bv && !strcmp(dmi_bv, "Lucid-CE-133"))
+		if (dmi_check_system(ehci_dmi_nohandoff_table))
 			try_handoff = 0;
 			try_handoff = 0;
 	}
 	}
 
 

+ 3 - 3
drivers/usb/host/r8a66597-hcd.c

@@ -6,7 +6,7 @@
  * Portions Copyright (C) 2004-2005 David Brownell
  * Portions Copyright (C) 2004-2005 David Brownell
  * Portions Copyright (C) 1999 Roman Weissgaerber
  * Portions Copyright (C) 1999 Roman Weissgaerber
  *
  *
- * Author : Yoshihiro Shimoda <shimoda.yoshihiro@renesas.com>
+ * Author : Yoshihiro Shimoda <yoshihiro.shimoda.uh@renesas.com>
  *
  *
  * This program is free software; you can redistribute it and/or modify
  * 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
  * it under the terms of the GNU General Public License as published by
@@ -1438,7 +1438,7 @@ static void packet_write(struct r8a66597 *r8a66597, u16 pipenum)
 	if (pipenum > 0)
 	if (pipenum > 0)
 		r8a66597_write(r8a66597, ~(1 << pipenum), BEMPSTS);
 		r8a66597_write(r8a66597, ~(1 << pipenum), BEMPSTS);
 	if (urb->transfer_buffer) {
 	if (urb->transfer_buffer) {
-		r8a66597_write_fifo(r8a66597, td->pipe->fifoaddr, buf, size);
+		r8a66597_write_fifo(r8a66597, td->pipe, buf, size);
 		if (!usb_pipebulk(urb->pipe) || td->maxpacket != size)
 		if (!usb_pipebulk(urb->pipe) || td->maxpacket != size)
 			r8a66597_write(r8a66597, BVAL, td->pipe->fifoctr);
 			r8a66597_write(r8a66597, BVAL, td->pipe->fifoctr);
 	}
 	}
@@ -2306,7 +2306,7 @@ static int r8a66597_bus_resume(struct usb_hcd *hcd)
 
 
 		dbg("resume port = %d", port);
 		dbg("resume port = %d", port);
 		rh->port &= ~USB_PORT_STAT_SUSPEND;
 		rh->port &= ~USB_PORT_STAT_SUSPEND;
-		rh->port |= USB_PORT_STAT_C_SUSPEND < 16;
+		rh->port |= USB_PORT_STAT_C_SUSPEND << 16;
 		r8a66597_mdfy(r8a66597, RESUME, RESUME | UACT, dvstctr_reg);
 		r8a66597_mdfy(r8a66597, RESUME, RESUME | UACT, dvstctr_reg);
 		msleep(50);
 		msleep(50);
 		r8a66597_mdfy(r8a66597, UACT, RESUME | UACT, dvstctr_reg);
 		r8a66597_mdfy(r8a66597, UACT, RESUME | UACT, dvstctr_reg);

+ 21 - 17
drivers/usb/host/r8a66597.h

@@ -201,11 +201,26 @@ static inline void r8a66597_write(struct r8a66597 *r8a66597, u16 val,
 	iowrite16(val, r8a66597->reg + offset);
 	iowrite16(val, r8a66597->reg + offset);
 }
 }
 
 
+static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
+				 u16 val, u16 pat, unsigned long offset)
+{
+	u16 tmp;
+	tmp = r8a66597_read(r8a66597, offset);
+	tmp = tmp & (~pat);
+	tmp = tmp | val;
+	r8a66597_write(r8a66597, tmp, offset);
+}
+
+#define r8a66597_bclr(r8a66597, val, offset)	\
+			r8a66597_mdfy(r8a66597, 0, val, offset)
+#define r8a66597_bset(r8a66597, val, offset)	\
+			r8a66597_mdfy(r8a66597, val, 0, offset)
+
 static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
 static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
-				       unsigned long offset, u16 *buf,
+				       struct r8a66597_pipe *pipe, u16 *buf,
 				       int len)
 				       int len)
 {
 {
-	void __iomem *fifoaddr = r8a66597->reg + offset;
+	void __iomem *fifoaddr = r8a66597->reg + pipe->fifoaddr;
 	unsigned long count;
 	unsigned long count;
 	unsigned char *pb;
 	unsigned char *pb;
 	int i;
 	int i;
@@ -230,26 +245,15 @@ static inline void r8a66597_write_fifo(struct r8a66597 *r8a66597,
 		iowrite16_rep(fifoaddr, buf, len);
 		iowrite16_rep(fifoaddr, buf, len);
 		if (unlikely(odd)) {
 		if (unlikely(odd)) {
 			buf = &buf[len];
 			buf = &buf[len];
+			if (r8a66597->pdata->wr0_shorted_to_wr1)
+				r8a66597_bclr(r8a66597, MBW_16, pipe->fifosel);
 			iowrite8((unsigned char)*buf, fifoaddr);
 			iowrite8((unsigned char)*buf, fifoaddr);
+			if (r8a66597->pdata->wr0_shorted_to_wr1)
+				r8a66597_bset(r8a66597, MBW_16, pipe->fifosel);
 		}
 		}
 	}
 	}
 }
 }
 
 
-static inline void r8a66597_mdfy(struct r8a66597 *r8a66597,
-				 u16 val, u16 pat, unsigned long offset)
-{
-	u16 tmp;
-	tmp = r8a66597_read(r8a66597, offset);
-	tmp = tmp & (~pat);
-	tmp = tmp | val;
-	r8a66597_write(r8a66597, tmp, offset);
-}
-
-#define r8a66597_bclr(r8a66597, val, offset)	\
-			r8a66597_mdfy(r8a66597, 0, val, offset)
-#define r8a66597_bset(r8a66597, val, offset)	\
-			r8a66597_mdfy(r8a66597, val, 0, offset)
-
 static inline unsigned long get_syscfg_reg(int port)
 static inline unsigned long get_syscfg_reg(int port)
 {
 {
 	return port == 0 ? SYSCFG0 : SYSCFG1;
 	return port == 0 ? SYSCFG0 : SYSCFG1;

+ 11 - 11
drivers/usb/host/xhci-dbg.c

@@ -266,11 +266,11 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
 		xhci_dbg(xhci, "Interrupter target = 0x%x\n",
 		xhci_dbg(xhci, "Interrupter target = 0x%x\n",
 			 GET_INTR_TARGET(le32_to_cpu(trb->link.intr_target)));
 			 GET_INTR_TARGET(le32_to_cpu(trb->link.intr_target)));
 		xhci_dbg(xhci, "Cycle bit = %u\n",
 		xhci_dbg(xhci, "Cycle bit = %u\n",
-			 (unsigned int) (le32_to_cpu(trb->link.control) & TRB_CYCLE));
+			 le32_to_cpu(trb->link.control) & TRB_CYCLE);
 		xhci_dbg(xhci, "Toggle cycle bit = %u\n",
 		xhci_dbg(xhci, "Toggle cycle bit = %u\n",
-			 (unsigned int) (le32_to_cpu(trb->link.control) & LINK_TOGGLE));
+			 le32_to_cpu(trb->link.control) & LINK_TOGGLE);
 		xhci_dbg(xhci, "No Snoop bit = %u\n",
 		xhci_dbg(xhci, "No Snoop bit = %u\n",
-			 (unsigned int) (le32_to_cpu(trb->link.control) & TRB_NO_SNOOP));
+			 le32_to_cpu(trb->link.control) & TRB_NO_SNOOP);
 		break;
 		break;
 	case TRB_TYPE(TRB_TRANSFER):
 	case TRB_TYPE(TRB_TRANSFER):
 		address = le64_to_cpu(trb->trans_event.buffer);
 		address = le64_to_cpu(trb->trans_event.buffer);
@@ -284,9 +284,9 @@ void xhci_debug_trb(struct xhci_hcd *xhci, union xhci_trb *trb)
 		address = le64_to_cpu(trb->event_cmd.cmd_trb);
 		address = le64_to_cpu(trb->event_cmd.cmd_trb);
 		xhci_dbg(xhci, "Command TRB pointer = %llu\n", address);
 		xhci_dbg(xhci, "Command TRB pointer = %llu\n", address);
 		xhci_dbg(xhci, "Completion status = %u\n",
 		xhci_dbg(xhci, "Completion status = %u\n",
-			 (unsigned int) GET_COMP_CODE(le32_to_cpu(trb->event_cmd.status)));
+			 GET_COMP_CODE(le32_to_cpu(trb->event_cmd.status)));
 		xhci_dbg(xhci, "Flags = 0x%x\n",
 		xhci_dbg(xhci, "Flags = 0x%x\n",
-			 (unsigned int) le32_to_cpu(trb->event_cmd.flags));
+			 le32_to_cpu(trb->event_cmd.flags));
 		break;
 		break;
 	default:
 	default:
 		xhci_dbg(xhci, "Unknown TRB with TRB type ID %u\n",
 		xhci_dbg(xhci, "Unknown TRB with TRB type ID %u\n",
@@ -318,10 +318,10 @@ void xhci_debug_segment(struct xhci_hcd *xhci, struct xhci_segment *seg)
 	for (i = 0; i < TRBS_PER_SEGMENT; ++i) {
 	for (i = 0; i < TRBS_PER_SEGMENT; ++i) {
 		trb = &seg->trbs[i];
 		trb = &seg->trbs[i];
 		xhci_dbg(xhci, "@%016llx %08x %08x %08x %08x\n", addr,
 		xhci_dbg(xhci, "@%016llx %08x %08x %08x %08x\n", addr,
-			 (u32)lower_32_bits(le64_to_cpu(trb->link.segment_ptr)),
-			 (u32)upper_32_bits(le64_to_cpu(trb->link.segment_ptr)),
-			 (unsigned int) le32_to_cpu(trb->link.intr_target),
-			 (unsigned int) le32_to_cpu(trb->link.control));
+			 lower_32_bits(le64_to_cpu(trb->link.segment_ptr)),
+			 upper_32_bits(le64_to_cpu(trb->link.segment_ptr)),
+			 le32_to_cpu(trb->link.intr_target),
+			 le32_to_cpu(trb->link.control));
 		addr += sizeof(*trb);
 		addr += sizeof(*trb);
 	}
 	}
 }
 }
@@ -402,8 +402,8 @@ void xhci_dbg_erst(struct xhci_hcd *xhci, struct xhci_erst *erst)
 			 addr,
 			 addr,
 			 lower_32_bits(le64_to_cpu(entry->seg_addr)),
 			 lower_32_bits(le64_to_cpu(entry->seg_addr)),
 			 upper_32_bits(le64_to_cpu(entry->seg_addr)),
 			 upper_32_bits(le64_to_cpu(entry->seg_addr)),
-			 (unsigned int) le32_to_cpu(entry->seg_size),
-			 (unsigned int) le32_to_cpu(entry->rsvd));
+			 le32_to_cpu(entry->seg_size),
+			 le32_to_cpu(entry->rsvd));
 		addr += sizeof(*entry);
 		addr += sizeof(*entry);
 	}
 	}
 }
 }

+ 13 - 13
drivers/usb/host/xhci-mem.c

@@ -89,8 +89,8 @@ static void xhci_link_segments(struct xhci_hcd *xhci, struct xhci_segment *prev,
 		return;
 		return;
 	prev->next = next;
 	prev->next = next;
 	if (link_trbs) {
 	if (link_trbs) {
-		prev->trbs[TRBS_PER_SEGMENT-1].link.
-			segment_ptr = cpu_to_le64(next->dma);
+		prev->trbs[TRBS_PER_SEGMENT-1].link.segment_ptr =
+			cpu_to_le64(next->dma);
 
 
 		/* Set the last TRB in the segment to have a TRB type ID of Link TRB */
 		/* Set the last TRB in the segment to have a TRB type ID of Link TRB */
 		val = le32_to_cpu(prev->trbs[TRBS_PER_SEGMENT-1].link.control);
 		val = le32_to_cpu(prev->trbs[TRBS_PER_SEGMENT-1].link.control);
@@ -187,8 +187,8 @@ static struct xhci_ring *xhci_ring_alloc(struct xhci_hcd *xhci,
 
 
 	if (link_trbs) {
 	if (link_trbs) {
 		/* See section 4.9.2.1 and 6.4.4.1 */
 		/* See section 4.9.2.1 and 6.4.4.1 */
-		prev->trbs[TRBS_PER_SEGMENT-1].link.
-			control |= cpu_to_le32(LINK_TOGGLE);
+		prev->trbs[TRBS_PER_SEGMENT-1].link.control |=
+			cpu_to_le32(LINK_TOGGLE);
 		xhci_dbg(xhci, "Wrote link toggle flag to"
 		xhci_dbg(xhci, "Wrote link toggle flag to"
 				" segment %p (virtual), 0x%llx (DMA)\n",
 				" segment %p (virtual), 0x%llx (DMA)\n",
 				prev, (unsigned long long)prev->dma);
 				prev, (unsigned long long)prev->dma);
@@ -549,8 +549,8 @@ struct xhci_stream_info *xhci_alloc_stream_info(struct xhci_hcd *xhci,
 		addr = cur_ring->first_seg->dma |
 		addr = cur_ring->first_seg->dma |
 			SCT_FOR_CTX(SCT_PRI_TR) |
 			SCT_FOR_CTX(SCT_PRI_TR) |
 			cur_ring->cycle_state;
 			cur_ring->cycle_state;
-		stream_info->stream_ctx_array[cur_stream].
-			stream_ring = cpu_to_le64(addr);
+		stream_info->stream_ctx_array[cur_stream].stream_ring =
+			cpu_to_le64(addr);
 		xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n",
 		xhci_dbg(xhci, "Setting stream %d ring ptr to 0x%08llx\n",
 				cur_stream, (unsigned long long) addr);
 				cur_stream, (unsigned long long) addr);
 
 
@@ -786,7 +786,7 @@ int xhci_alloc_virt_device(struct xhci_hcd *xhci, int slot_id,
 	xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n",
 	xhci_dbg(xhci, "Set slot id %d dcbaa entry %p to 0x%llx\n",
 		 slot_id,
 		 slot_id,
 		 &xhci->dcbaa->dev_context_ptrs[slot_id],
 		 &xhci->dcbaa->dev_context_ptrs[slot_id],
-		 (unsigned long long) le64_to_cpu(xhci->dcbaa->dev_context_ptrs[slot_id]));
+		 le64_to_cpu(xhci->dcbaa->dev_context_ptrs[slot_id]));
 
 
 	return 1;
 	return 1;
 fail:
 fail:
@@ -890,19 +890,19 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
 	ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
 	ctrl_ctx->add_flags = cpu_to_le32(SLOT_FLAG | EP0_FLAG);
 
 
 	/* 3) Only the control endpoint is valid - one endpoint context */
 	/* 3) Only the control endpoint is valid - one endpoint context */
-	slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | (u32) udev->route);
+	slot_ctx->dev_info |= cpu_to_le32(LAST_CTX(1) | udev->route);
 	switch (udev->speed) {
 	switch (udev->speed) {
 	case USB_SPEED_SUPER:
 	case USB_SPEED_SUPER:
-		slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_SS);
+		slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_SS);
 		break;
 		break;
 	case USB_SPEED_HIGH:
 	case USB_SPEED_HIGH:
-		slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_HS);
+		slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_HS);
 		break;
 		break;
 	case USB_SPEED_FULL:
 	case USB_SPEED_FULL:
-		slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_FS);
+		slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_FS);
 		break;
 		break;
 	case USB_SPEED_LOW:
 	case USB_SPEED_LOW:
-		slot_ctx->dev_info |= cpu_to_le32((u32) SLOT_SPEED_LS);
+		slot_ctx->dev_info |= cpu_to_le32(SLOT_SPEED_LS);
 		break;
 		break;
 	case USB_SPEED_WIRELESS:
 	case USB_SPEED_WIRELESS:
 		xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
 		xhci_dbg(xhci, "FIXME xHCI doesn't support wireless speeds\n");
@@ -916,7 +916,7 @@ int xhci_setup_addressable_virt_dev(struct xhci_hcd *xhci, struct usb_device *ud
 	port_num = xhci_find_real_port_number(xhci, udev);
 	port_num = xhci_find_real_port_number(xhci, udev);
 	if (!port_num)
 	if (!port_num)
 		return -EINVAL;
 		return -EINVAL;
-	slot_ctx->dev_info2 |= cpu_to_le32((u32) ROOT_HUB_PORT(port_num));
+	slot_ctx->dev_info2 |= cpu_to_le32(ROOT_HUB_PORT(port_num));
 	/* Set the port number in the virtual_device to the faked port number */
 	/* Set the port number in the virtual_device to the faked port number */
 	for (top_dev = udev; top_dev->parent && top_dev->parent->parent;
 	for (top_dev = udev; top_dev->parent && top_dev->parent->parent;
 			top_dev = top_dev->parent)
 			top_dev = top_dev->parent)

+ 17 - 25
drivers/usb/host/xhci-ring.c

@@ -113,15 +113,13 @@ static int last_trb(struct xhci_hcd *xhci, struct xhci_ring *ring,
 	if (ring == xhci->event_ring)
 	if (ring == xhci->event_ring)
 		return trb == &seg->trbs[TRBS_PER_SEGMENT];
 		return trb == &seg->trbs[TRBS_PER_SEGMENT];
 	else
 	else
-		return (le32_to_cpu(trb->link.control) & TRB_TYPE_BITMASK)
-			== TRB_TYPE(TRB_LINK);
+		return TRB_TYPE_LINK_LE32(trb->link.control);
 }
 }
 
 
 static int enqueue_is_link_trb(struct xhci_ring *ring)
 static int enqueue_is_link_trb(struct xhci_ring *ring)
 {
 {
 	struct xhci_link_trb *link = &ring->enqueue->link;
 	struct xhci_link_trb *link = &ring->enqueue->link;
-	return ((le32_to_cpu(link->control) & TRB_TYPE_BITMASK) ==
-		TRB_TYPE(TRB_LINK));
+	return TRB_TYPE_LINK_LE32(link->control);
 }
 }
 
 
 /* Updates trb to point to the next TRB in the ring, and updates seg if the next
 /* Updates trb to point to the next TRB in the ring, and updates seg if the next
@@ -372,7 +370,7 @@ static struct xhci_segment *find_trb_seg(
 	while (cur_seg->trbs > trb ||
 	while (cur_seg->trbs > trb ||
 			&cur_seg->trbs[TRBS_PER_SEGMENT - 1] < trb) {
 			&cur_seg->trbs[TRBS_PER_SEGMENT - 1] < trb) {
 		generic_trb = &cur_seg->trbs[TRBS_PER_SEGMENT - 1].generic;
 		generic_trb = &cur_seg->trbs[TRBS_PER_SEGMENT - 1].generic;
-		if (le32_to_cpu(generic_trb->field[3]) & LINK_TOGGLE)
+		if (generic_trb->field[3] & cpu_to_le32(LINK_TOGGLE))
 			*cycle_state ^= 0x1;
 			*cycle_state ^= 0x1;
 		cur_seg = cur_seg->next;
 		cur_seg = cur_seg->next;
 		if (cur_seg == start_seg)
 		if (cur_seg == start_seg)
@@ -489,8 +487,8 @@ void xhci_find_new_dequeue_state(struct xhci_hcd *xhci,
 	}
 	}
 
 
 	trb = &state->new_deq_ptr->generic;
 	trb = &state->new_deq_ptr->generic;
-	if ((le32_to_cpu(trb->field[3]) & TRB_TYPE_BITMASK) ==
-	    TRB_TYPE(TRB_LINK) && (le32_to_cpu(trb->field[3]) & LINK_TOGGLE))
+	if (TRB_TYPE_LINK_LE32(trb->field[3]) &&
+	    (trb->field[3] & cpu_to_le32(LINK_TOGGLE)))
 		state->new_cycle_state ^= 0x1;
 		state->new_cycle_state ^= 0x1;
 	next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr);
 	next_trb(xhci, ep_ring, &state->new_deq_seg, &state->new_deq_ptr);
 
 
@@ -525,8 +523,7 @@ static void td_to_noop(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
 	for (cur_seg = cur_td->start_seg, cur_trb = cur_td->first_trb;
 	for (cur_seg = cur_td->start_seg, cur_trb = cur_td->first_trb;
 			true;
 			true;
 			next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) {
 			next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) {
-		if ((le32_to_cpu(cur_trb->generic.field[3]) & TRB_TYPE_BITMASK)
-		    == TRB_TYPE(TRB_LINK)) {
+		if (TRB_TYPE_LINK_LE32(cur_trb->generic.field[3])) {
 			/* Unchain any chained Link TRBs, but
 			/* Unchain any chained Link TRBs, but
 			 * leave the pointers intact.
 			 * leave the pointers intact.
 			 */
 			 */
@@ -1000,7 +997,7 @@ static void handle_reset_ep_completion(struct xhci_hcd *xhci,
 	 * but we don't care.
 	 * but we don't care.
 	 */
 	 */
 	xhci_dbg(xhci, "Ignoring reset ep completion code of %u\n",
 	xhci_dbg(xhci, "Ignoring reset ep completion code of %u\n",
-		 (unsigned int) GET_COMP_CODE(le32_to_cpu(event->status)));
+		 GET_COMP_CODE(le32_to_cpu(event->status)));
 
 
 	/* HW with the reset endpoint quirk needs to have a configure endpoint
 	/* HW with the reset endpoint quirk needs to have a configure endpoint
 	 * command complete before the endpoint can be used.  Queue that here
 	 * command complete before the endpoint can be used.  Queue that here
@@ -1458,7 +1455,8 @@ static int xhci_requires_manual_halt_cleanup(struct xhci_hcd *xhci,
 		 * endpoint anyway.  Check if a babble halted the
 		 * endpoint anyway.  Check if a babble halted the
 		 * endpoint.
 		 * endpoint.
 		 */
 		 */
-		if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) == EP_STATE_HALTED)
+		if ((ep_ctx->ep_info & cpu_to_le32(EP_STATE_MASK)) ==
+		    cpu_to_le32(EP_STATE_HALTED))
 			return 1;
 			return 1;
 
 
 	return 0;
 	return 0;
@@ -1753,10 +1751,8 @@ static int process_isoc_td(struct xhci_hcd *xhci, struct xhci_td *td,
 		for (cur_trb = ep_ring->dequeue,
 		for (cur_trb = ep_ring->dequeue,
 		     cur_seg = ep_ring->deq_seg; cur_trb != event_trb;
 		     cur_seg = ep_ring->deq_seg; cur_trb != event_trb;
 		     next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) {
 		     next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) {
-			if ((le32_to_cpu(cur_trb->generic.field[3]) &
-			 TRB_TYPE_BITMASK) != TRB_TYPE(TRB_TR_NOOP) &&
-			    (le32_to_cpu(cur_trb->generic.field[3]) &
-			 TRB_TYPE_BITMASK) != TRB_TYPE(TRB_LINK))
+			if (!TRB_TYPE_NOOP_LE32(cur_trb->generic.field[3]) &&
+			    !TRB_TYPE_LINK_LE32(cur_trb->generic.field[3]))
 				len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2]));
 				len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2]));
 		}
 		}
 		len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) -
 		len += TRB_LEN(le32_to_cpu(cur_trb->generic.field[2])) -
@@ -1885,10 +1881,8 @@ static int process_bulk_intr_td(struct xhci_hcd *xhci, struct xhci_td *td,
 		for (cur_trb = ep_ring->dequeue, cur_seg = ep_ring->deq_seg;
 		for (cur_trb = ep_ring->dequeue, cur_seg = ep_ring->deq_seg;
 				cur_trb != event_trb;
 				cur_trb != event_trb;
 				next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) {
 				next_trb(xhci, ep_ring, &cur_seg, &cur_trb)) {
-			if ((le32_to_cpu(cur_trb->generic.field[3]) &
-			 TRB_TYPE_BITMASK) != TRB_TYPE(TRB_TR_NOOP) &&
-			    (le32_to_cpu(cur_trb->generic.field[3]) &
-			 TRB_TYPE_BITMASK) != TRB_TYPE(TRB_LINK))
+			if (!TRB_TYPE_NOOP_LE32(cur_trb->generic.field[3]) &&
+			    !TRB_TYPE_LINK_LE32(cur_trb->generic.field[3]))
 				td->urb->actual_length +=
 				td->urb->actual_length +=
 					TRB_LEN(le32_to_cpu(cur_trb->generic.field[2]));
 					TRB_LEN(le32_to_cpu(cur_trb->generic.field[2]));
 		}
 		}
@@ -2047,8 +2041,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
 				  TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
 				  TRB_TO_SLOT_ID(le32_to_cpu(event->flags)),
 				  ep_index);
 				  ep_index);
 			xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",
 			xhci_dbg(xhci, "Event TRB with TRB type ID %u\n",
-				 (unsigned int) (le32_to_cpu(event->flags)
-						 & TRB_TYPE_BITMASK)>>10);
+				 (le32_to_cpu(event->flags) &
+				  TRB_TYPE_BITMASK)>>10);
 			xhci_print_trb_offsets(xhci, (union xhci_trb *) event);
 			xhci_print_trb_offsets(xhci, (union xhci_trb *) event);
 			if (ep->skip) {
 			if (ep->skip) {
 				ep->skip = false;
 				ep->skip = false;
@@ -2119,9 +2113,7 @@ static int handle_tx_event(struct xhci_hcd *xhci,
 		 * corresponding TD has been cancelled. Just ignore
 		 * corresponding TD has been cancelled. Just ignore
 		 * the TD.
 		 * the TD.
 		 */
 		 */
-		if ((le32_to_cpu(event_trb->generic.field[3])
-			     & TRB_TYPE_BITMASK)
-				 == TRB_TYPE(TRB_TR_NOOP)) {
+		if (TRB_TYPE_NOOP_LE32(event_trb->generic.field[3])) {
 			xhci_dbg(xhci,
 			xhci_dbg(xhci,
 				 "event_trb is a no-op TRB. Skip it\n");
 				 "event_trb is a no-op TRB. Skip it\n");
 			goto cleanup;
 			goto cleanup;
@@ -2452,7 +2444,7 @@ static int prepare_ring(struct xhci_hcd *xhci, struct xhci_ring *ep_ring,
 				next->link.control |= cpu_to_le32(TRB_CHAIN);
 				next->link.control |= cpu_to_le32(TRB_CHAIN);
 
 
 			wmb();
 			wmb();
-			next->link.control ^= cpu_to_le32((u32) TRB_CYCLE);
+			next->link.control ^= cpu_to_le32(TRB_CYCLE);
 
 
 			/* Toggle the cycle bit after the last ring segment. */
 			/* Toggle the cycle bit after the last ring segment. */
 			if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {
 			if (last_trb_on_last_seg(xhci, ring, ring->enq_seg, next)) {

+ 4 - 6
drivers/usb/host/xhci.c

@@ -1342,8 +1342,8 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
 	/* If the HC already knows the endpoint is disabled,
 	/* If the HC already knows the endpoint is disabled,
 	 * or the HCD has noted it is disabled, ignore this request
 	 * or the HCD has noted it is disabled, ignore this request
 	 */
 	 */
-	if ((le32_to_cpu(ep_ctx->ep_info) & EP_STATE_MASK) ==
-	    EP_STATE_DISABLED ||
+	if (((ep_ctx->ep_info & cpu_to_le32(EP_STATE_MASK)) ==
+	     cpu_to_le32(EP_STATE_DISABLED)) ||
 	    le32_to_cpu(ctrl_ctx->drop_flags) &
 	    le32_to_cpu(ctrl_ctx->drop_flags) &
 	    xhci_get_endpoint_flag(&ep->desc)) {
 	    xhci_get_endpoint_flag(&ep->desc)) {
 		xhci_warn(xhci, "xHCI %s called with disabled ep %p\n",
 		xhci_warn(xhci, "xHCI %s called with disabled ep %p\n",
@@ -1758,8 +1758,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
 		/* Enqueue pointer can be left pointing to the link TRB,
 		/* Enqueue pointer can be left pointing to the link TRB,
 		 * we must handle that
 		 * we must handle that
 		 */
 		 */
-		if ((le32_to_cpu(command->command_trb->link.control)
-		     & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK))
+		if (TRB_TYPE_LINK_LE32(command->command_trb->link.control))
 			command->command_trb =
 			command->command_trb =
 				xhci->cmd_ring->enq_seg->next->trbs;
 				xhci->cmd_ring->enq_seg->next->trbs;
 
 
@@ -2559,8 +2558,7 @@ int xhci_discover_or_reset_device(struct usb_hcd *hcd, struct usb_device *udev)
 	/* Enqueue pointer can be left pointing to the link TRB,
 	/* Enqueue pointer can be left pointing to the link TRB,
 	 * we must handle that
 	 * we must handle that
 	 */
 	 */
-	if ((le32_to_cpu(reset_device_cmd->command_trb->link.control)
-	     & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK))
+	if (TRB_TYPE_LINK_LE32(reset_device_cmd->command_trb->link.control))
 		reset_device_cmd->command_trb =
 		reset_device_cmd->command_trb =
 			xhci->cmd_ring->enq_seg->next->trbs;
 			xhci->cmd_ring->enq_seg->next->trbs;
 
 

+ 7 - 0
drivers/usb/host/xhci.h

@@ -1072,6 +1072,13 @@ union xhci_trb {
 /* Get NEC firmware revision. */
 /* Get NEC firmware revision. */
 #define	TRB_NEC_GET_FW		49
 #define	TRB_NEC_GET_FW		49
 
 
+#define TRB_TYPE_LINK(x)	(((x) & TRB_TYPE_BITMASK) == TRB_TYPE(TRB_LINK))
+/* Above, but for __le32 types -- can avoid work by swapping constants: */
+#define TRB_TYPE_LINK_LE32(x)	(((x) & cpu_to_le32(TRB_TYPE_BITMASK)) == \
+				 cpu_to_le32(TRB_TYPE(TRB_LINK)))
+#define TRB_TYPE_NOOP_LE32(x)	(((x) & cpu_to_le32(TRB_TYPE_BITMASK)) == \
+				 cpu_to_le32(TRB_TYPE(TRB_TR_NOOP)))
+
 #define NEC_FW_MINOR(p)		(((p) >> 0) & 0xff)
 #define NEC_FW_MINOR(p)		(((p) >> 0) & 0xff)
 #define NEC_FW_MAJOR(p)		(((p) >> 8) & 0xff)
 #define NEC_FW_MAJOR(p)		(((p) >> 8) & 0xff)
 
 

+ 6 - 3
drivers/usb/mon/mon_text.c

@@ -670,6 +670,9 @@ int mon_text_add(struct mon_bus *mbus, const struct usb_bus *ubus)
 	int busnum = ubus? ubus->busnum: 0;
 	int busnum = ubus? ubus->busnum: 0;
 	int rc;
 	int rc;
 
 
+	if (mon_dir == NULL)
+		return 0;
+
 	if (ubus != NULL) {
 	if (ubus != NULL) {
 		rc = snprintf(name, NAMESZ, "%dt", busnum);
 		rc = snprintf(name, NAMESZ, "%dt", busnum);
 		if (rc <= 0 || rc >= NAMESZ)
 		if (rc <= 0 || rc >= NAMESZ)
@@ -740,12 +743,12 @@ int __init mon_text_init(void)
 
 
 	mondir = debugfs_create_dir("usbmon", usb_debug_root);
 	mondir = debugfs_create_dir("usbmon", usb_debug_root);
 	if (IS_ERR(mondir)) {
 	if (IS_ERR(mondir)) {
-		printk(KERN_NOTICE TAG ": debugfs is not available\n");
-		return -ENODEV;
+		/* debugfs not available, but we can use usbmon without it */
+		return 0;
 	}
 	}
 	if (mondir == NULL) {
 	if (mondir == NULL) {
 		printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
 		printk(KERN_NOTICE TAG ": unable to create usbmon directory\n");
-		return -ENODEV;
+		return -ENOMEM;
 	}
 	}
 	mon_dir = mondir;
 	mon_dir = mondir;
 	return 0;
 	return 0;

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.